Skip to main content

rf24ble/
data_manipulation.rs

1//! A module that holds functions related to manipulating data in accordance with BLE specs.
2
3/// Reverse the bit order for each byte in the given `buf`.
4///
5/// This does not alter the buffer's Endianness.
6pub fn reverse_bits(buf: &mut [u8]) {
7    for byte in buf {
8        *byte = byte.reverse_bits();
9    }
10}
11
12/// Whiten or de-whiten the given `buf` using the given `coefficient`.
13///
14/// This is used to avoid transmitting long consecutive repetitions of `0`s and `1`s.
15/// The given `coefficient` shall be the index of
16/// [`BLE_CHANNEL`](value@crate::radio::BLE_CHANNEL) for the radio channel that
17/// transmits or receives the data.
18pub fn whiten(buf: &mut [u8], coefficient: u8) {
19    let mut coefficient = coefficient;
20    for byte in buf {
21        let mut result = *byte;
22        let mut mask = 1u8;
23        for _ in 0u8..8 {
24            if (coefficient & 1) == 1 {
25                coefficient ^= 0x88;
26                result ^= mask;
27            }
28            mask <<= 1;
29            coefficient >>= 1;
30        }
31        *byte = result;
32    }
33}
34
35/// Calculate a 24 bit CRC checksum for the given `buf`.
36///
37/// The returned buffer shall be appended to the transmitted payload
38/// *before* applying [`reverse_bits()`] and [`whiten()`].
39pub fn crc24_ble(data: &[u8]) -> [u8; 3] {
40    let degree_polynomial: u32 = 0x65B;
41    let mut crc: u32 = 0x555555;
42    for byte in data {
43        let copy = *byte;
44        crc ^= (copy.reverse_bits() as u32) << 16;
45        for _ in 0u8..8 {
46            if (crc & 0x800000) > 0 {
47                crc = (crc << 1) ^ degree_polynomial;
48            } else {
49                crc <<= 1;
50            }
51        }
52        crc &= 0xFFFFFF;
53    }
54    let mut checksum = crc.to_be_bytes();
55    reverse_bits(&mut checksum);
56    let mut result = [0u8; 3];
57    result.copy_from_slice(&checksum[1..4]);
58    result
59}
60
61#[cfg(test)]
62mod test {
63    use super::{crc24_ble, reverse_bits, whiten};
64
65    #[test]
66    fn reverse() {
67        let mut buf = [0u8; 11];
68        buf.copy_from_slice(b"Hello World");
69        reverse_bits(&mut buf);
70        let mut expected = [
71            0x12, 0xA6, 0x36, 0x36, 0xF6, 0x04, 0xEA, 0xF6, 0x4E, 0x36, 0x26,
72        ];
73        assert_eq!(buf, expected);
74
75        reverse_bits(&mut buf);
76        expected.copy_from_slice(b"Hello World");
77        assert_eq!(buf, expected);
78    }
79
80    #[test]
81    fn whitening() {
82        let coefficient = (2 + 37) | 0x40;
83
84        let mut buf = [0u8; 11];
85        buf.copy_from_slice(b"Hello World");
86        whiten(&mut buf, coefficient);
87
88        let expected: [u8; 11] = [
89            0x57, 0x52, 0x26, 0x33, 0xEA, 0xD6, 0xCB, 0xF5, 0xB3, 0xBA, 0xA1,
90        ];
91        assert_eq!(buf, expected);
92
93        // de-whiten (w/ same coefficient) should
94        // restore the buffer to original content
95        whiten(&mut buf, coefficient);
96        let mut expected = [0u8; 11];
97        expected.copy_from_slice(b"Hello World");
98        assert_eq!(buf, expected);
99    }
100
101    #[test]
102    fn crc() {
103        let buffer = b"Hello World";
104        let checksum = crc24_ble(buffer);
105
106        // ensure original buffer is unaltered
107        assert_eq!(buffer, b"Hello World");
108
109        let expected = [0xB6u8, 0x8C, 0xB0];
110        assert_eq!(expected, checksum);
111    }
112}