kernel/hil/crc.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.
//! Interface for CRC computation.
use crate::utilities::leasable_buffer::SubSliceMut;
use crate::ErrorCode;
/// Client for CRC algorithm implementations
///
/// Implement this trait and use [`Crc::set_client`] in order to
/// receive callbacks from the CRC implementation.
pub trait Client {
/// Called when the current data chunk has been processed by the
/// CRC engine. Further data may be supplied when this callback is
/// received.
fn input_done(&self, result: Result<(), ErrorCode>, buffer: SubSliceMut<'static, u8>);
/// Called when the CRC computation is finished.
fn crc_done(&self, result: Result<CrcOutput, ErrorCode>);
}
/// CRC algorithms
///
/// In all cases, input bytes are bit-reversed (i.e., consumed from LSB to MSB.)
///
/// Algorithms prefixed with `Sam4L` are native to that chip and thus require
/// no software post-processing on platforms using it.
///
#[derive(Copy, Clone)]
pub enum CrcAlgorithm {
/// Polynomial 0x04C11DB7, output reversed then inverted
/// ("CRC-32")
Crc32,
/// Polynomial 0x1EDC6F41, output reversed then inverted
/// ("CRC-32C" / "Castagnoli")
Crc32C,
/// Polynomial 0x1021, no output post-processing ("CRC-16-CCITT")
Crc16CCITT,
}
/// CRC output type
///
/// Individual CRC algorithms can have different output lengths. This
/// type represents the different [`CrcAlgorithm`] outputs
/// respectively.
#[derive(Copy, Clone)]
pub enum CrcOutput {
/// Output of [`CrcAlgorithm::Crc32`]
Crc32(u32),
/// Output of [`CrcAlgorithm::Crc32C`]
Crc32C(u32),
/// Output of [`CrcAlgorithm::Crc16CCITT`]
Crc16CCITT(u16),
}
impl CrcOutput {
pub fn algorithm(&self) -> CrcAlgorithm {
match self {
CrcOutput::Crc32(_) => CrcAlgorithm::Crc32,
CrcOutput::Crc32C(_) => CrcAlgorithm::Crc32C,
CrcOutput::Crc16CCITT(_) => CrcAlgorithm::Crc16CCITT,
}
}
}
pub trait Crc<'a> {
/// Set the client to be used for callbacks of the CRC
/// implementation.
fn set_client(&self, client: &'a dyn Client);
/// Check whether a given CRC algorithm is supported by a CRC
/// implementation.
///
/// Returns true if the algorithm specified is supported.
fn algorithm_supported(&self, algorithm: CrcAlgorithm) -> bool;
/// Set the CRC algorithm to use.
///
/// Calling this method may enable the CRC engine in case of a
/// physical unit.
///
/// If the device is currently processing a chunk of data or
/// calculating a CRC, this operation will be refused, returning
/// [`ErrorCode::BUSY`]. If a CRC calculation currently has
/// pending data, it will be cancelled and the CRC engine's state
/// reset.
///
/// [`ErrorCode::NOSUPPORT`] will be returned if the algorithm
/// requested is not supported. To non-invasively check whether a
/// given algorithm is supported by a CRC implementation, use
/// [`Crc::algorithm_supported`].
fn set_algorithm(&self, algorithm: CrcAlgorithm) -> Result<(), ErrorCode>;
/// Input chunked data into the CRC implementation.
///
/// Calling this method may enable the CRC engine in case of a
/// physical unit.
///
/// If [`Crc::set_algorithm`] has not been invoked before, this
/// method must return [`ErrorCode::RESERVE`].
///
/// If the device is currently already processing a chunk of data
/// or calculating a CRC, [`ErrorCode::BUSY`] must be returned.
///
/// After the chunk of data has been processed,
/// [`Client::input_done`] is called.
///
/// The implementation may only read a part of the passed
/// [`SubSliceMut`]. It will return the bytes read and will
/// resize the returned [`SubSliceMut`] appropriately prior to
/// passing it back through [`Client::input_done`].
fn input(
&self,
data: SubSliceMut<'static, u8>,
) -> Result<(), (ErrorCode, SubSliceMut<'static, u8>)>;
/// Request calculation of the CRC.
///
/// Calling this method may enable the CRC engine in case of a
/// physical unit.
///
/// If [`Crc::set_algorithm`] has not been invoked before, this
/// method must return [`ErrorCode::RESERVE`].
///
/// If the device is currently processing a chunk of data or
/// calculating a CRC, [`ErrorCode::BUSY`] must be returned.
///
/// After the CRC has been calculated, [`Client::crc_done`] is
/// called.
fn compute(&self) -> Result<(), ErrorCode>;
/// Disable the CRC unit until susequent calls to methods which
/// will enable the CRC unit again.
fn disable(&self);
}