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);
}