embedded_onewire/
utils.rs

1#[derive(Debug, Default)]
2/// Calculate CRC-8 used in 1-Wire communications.
3pub struct OneWireCrc(u8);
4
5impl OneWireCrc {
6    /// Get the current CRC value
7    pub fn value(&self) -> u8 {
8        self.0
9    }
10
11    /// Update the CRC with the incoming byte.
12    ///
13    /// # Arguments
14    /// * `byte` - The byte to update the CRC with.
15    ///
16    /// # Note
17    /// This method uses a lookup table for CRC calculation if the `crc-table` feature is enabled.
18    /// Otherwise, it uses bit shifts and XOR operations for CRC calculation.
19    #[inline(always)]
20    pub fn update(&mut self, byte: u8) {
21        #[cfg(feature = "crc-table")]
22        {
23            self.update_table(byte); // Use the lookup table for CRC calculation
24        }
25        #[cfg(not(feature = "crc-table"))]
26        {
27            self.update_calc(byte); // Use the direct calculation for CRC
28        }
29    }
30
31    /// Valudate a sequence of bytes where the last byte is the 1-Wire CRC of
32    /// the previous bytes.
33    ///
34    /// # Note
35    /// For such a sequence, the CRC should be `0x00`.
36    pub fn validate(sequence: &[u8]) -> bool {
37        let mut crc = OneWireCrc(0);
38        for &byte in sequence.iter() {
39            crc.update(byte); // Update CRC with the all bytes of the ROM
40        }
41        crc.0 == 0x0 // If the last byte of the ROM is the CRC, the result should be 0
42    }
43
44    #[allow(dead_code)]
45    pub(crate) fn update_table(&mut self, byte: u8) {
46        const ONEWIRE_SRC_TABLE: [u8; 256] = [
47            0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65, 157, 195, 33,
48            127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220, 35, 125, 159, 193, 66, 28,
49            254, 160, 225, 191, 93, 3, 128, 222, 60, 98, 190, 224, 2, 92, 223, 129, 99, 61, 124,
50            34, 192, 158, 29, 67, 161, 255, 70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102,
51            229, 187, 89, 7, 219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196,
52            154, 101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36, 248, 166,
53            68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185, 140, 210, 48, 110, 237,
54            179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205, 17, 79, 173, 243, 112, 46, 204, 146,
55            211, 141, 111, 49, 178, 236, 14, 80, 175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209,
56            143, 12, 82, 176, 238, 50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207,
57            45, 115, 202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139, 87,
58            9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22, 233, 183, 85, 11,
59            136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168, 116, 42, 200, 150, 21, 75, 169,
60            247, 182, 232, 10, 84, 215, 137, 107, 53,
61        ];
62        self.0 = ONEWIRE_SRC_TABLE[(self.0 ^ byte) as usize];
63    }
64
65    #[allow(dead_code)]
66    pub(crate) fn update_calc(&mut self, byte: u8) {
67        let mut crc = self.0 ^ byte;
68        for _ in 0..8 {
69            if crc & 0x01 == 0x01 {
70                crc = (crc >> 1) ^ 0x8C; // Polynomial: x^8 + x^5 + x^4 + 1
71            } else {
72                crc >>= 1;
73            }
74        }
75        self.0 = crc;
76    }
77}
78
79mod test {
80    #[test]
81    fn test_crc_update() {
82        use super::OneWireCrc;
83        #[cfg(test)]
84        extern crate std;
85        use rand::prelude::*;
86        let mut rng = rand::rng();
87        let buf = (0..100)
88            .map(|_| rng.random::<u8>())
89            .collect::<std::vec::Vec<u8>>();
90        let mut crc = OneWireCrc::default();
91        for &byte in buf.iter() {
92            crc.update(byte);
93        }
94        let table = crc.value();
95        std::println!("CRC after calc: {table:#04x}");
96        let mut crc = OneWireCrc::default();
97        for &byte in buf.iter() {
98            crc.update_table(byte);
99        }
100        let calc = crc.value();
101        std::println!("CRC after table: {calc:#04x}");
102        assert_eq!(table, calc, "CRC values do not match");
103    }
104}