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
pub fn calculate_crc5(data: &[u8], poly: u8, init: u8, ref_in: bool, ref_out: bool, xor_out: u8) -> u8 {
    let mut crc = init;
    for d in data.iter() {
        let c = if ref_in { (*d).reverse_bits() } else { *d };
        let mut i = 0x80;
        while i > 0 {
            let mut bit = (crc & 0x10) != 0;
            if (c & i) != 0 {
                bit = !bit;
            }
            crc <<= 1;
            if bit {
                crc ^= poly;
            }
            i >>= 1;
        }
        crc &= 0x1f;
    }
    if ref_out {
        crc = crc.reverse_bits() >> 3;
    }
    crc ^ xor_out
}

pub const CRC5_POLY: u8 = 0x5;
pub fn crc5(data: &[u8]) -> u8 {
    calculate_crc5(data, CRC5_POLY, 0x1f, true, true, 0x1f)
}

#[cfg(test)]
mod tests {
    use super::*;

    fn check_sequence() -> Vec<u8> {
        "123456789".to_owned().into_bytes()
    }

    fn check_sequence_long() -> Vec<u8> {
        "helloworldchris!".to_owned().into_bytes()
    }

    #[test]
    fn test_crc5() {
        assert_eq!(crc5(&check_sequence()), 0x19);
    }

    #[test]
    fn test_crc5_long() {
        assert_eq!(crc5(&check_sequence_long()), 0xa);
    }

    #[test]
    fn test_crc5_long_long() {
        let mut data = check_sequence_long();
        data.append(&mut check_sequence_long());
        assert_eq!(crc5(&data), 0x1b);
    }

    #[test]
    fn test_crc5_long_long_long() {
        let mut data = check_sequence_long();
        data.append(&mut check_sequence_long());
        data.append(&mut check_sequence_long());
        assert_eq!(crc5(&data), 0xc);
    }
}