Skip to main content

tinyboot_protocol/
crc.rs

1/// CRC16 initial value.
2pub const CRC_INIT: u16 = 0xFFFF;
3
4/// CRC16-CCITT (poly 0x1021, init 0xFFFF).
5///
6/// Bit-bang implementation — no lookup table, minimal flash footprint.
7/// Call incrementally by passing the previous return value as `crc`:
8///
9/// ```
10/// # use tinyboot_protocol::crc::crc16;
11/// let mut crc = 0xFFFF;
12/// crc = crc16(crc, b"1234");
13/// crc = crc16(crc, b"56789");
14/// assert_eq!(crc, 0x29B1);
15/// ```
16pub fn crc16(mut crc: u16, data: &[u8]) -> u16 {
17    for &b in data {
18        crc ^= (b as u16) << 8;
19        for _ in 0..8 {
20            crc = if crc & 0x8000 != 0 {
21                (crc << 1) ^ 0x1021
22            } else {
23                crc << 1
24            };
25        }
26    }
27    crc
28}
29
30#[cfg(test)]
31mod tests {
32    use super::*;
33
34    #[test]
35    fn check_value() {
36        assert_eq!(crc16(0xFFFF, b"123456789"), 0x29B1);
37    }
38
39    #[test]
40    fn incremental() {
41        let mut crc = 0xFFFF;
42        crc = crc16(crc, b"1234");
43        crc = crc16(crc, b"56789");
44        assert_eq!(crc, 0x29B1);
45    }
46
47    #[test]
48    fn empty() {
49        assert_eq!(crc16(0xFFFF, b""), 0xFFFF);
50    }
51
52    #[test]
53    fn single_byte() {
54        // Known value: CRC16-CCITT of [0x00] with init 0xFFFF
55        let crc = crc16(0xFFFF, &[0x00]);
56        assert_eq!(crc, 0xE1F0);
57    }
58}