donglora-protocol 1.1.0

DongLoRa wire protocol types and COBS framing — shared between firmware and host crates
Documentation
//! CRC-16/CCITT-FALSE — the wire-level integrity check used by DongLoRa Protocol.
//!
//! Polynomial `0x1021`, initial value `0xFFFF`, no reflection, XOR-out `0x0000`.
//! This is the same variant also known as CRC-16/AUTOSAR or
//! CRC-16/IBM-3740. It is **NOT** the same as CRC-16/KERMIT,
//! CRC-16/XMODEM, or plain "CRC-16/CCITT" — those use different initial
//! values or reflect their inputs.
//!
//! Check value: `crc16("123456789") == 0x29B1`. A module-level test pins
//! this, and `tests/vectors.rs` anchors every Appendix C wire example.

/// CRC-16/CCITT-FALSE of `data`.
pub fn crc16(data: &[u8]) -> u16 {
    let mut crc: u16 = 0xFFFF;
    for &byte in data {
        crc ^= (byte as u16) << 8;
        for _ in 0..8 {
            if crc & 0x8000 != 0 {
                crc = (crc << 1) ^ 0x1021;
            } else {
                crc <<= 1;
            }
        }
    }
    crc
}

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

    #[test]
    fn check_value_matches_spec() {
        // PROTOCOL.md §2.2: CRC-16/CCITT-FALSE of ASCII "123456789" is 0x29B1.
        assert_eq!(crc16(b"123456789"), 0x29B1);
    }

    #[test]
    fn empty_input_is_initial_value() {
        // No reflection, no XOR-out: empty input leaves the init value untouched.
        assert_eq!(crc16(&[]), 0xFFFF);
    }

    #[test]
    fn single_zero_byte() {
        // 0xFFFF XOR 0x0000 = 0xFFFF, then 8 shift-and-maybe-xor rounds.
        // Worked out by hand against the reference impl in Appendix B.
        assert_eq!(crc16(&[0x00]), 0xE1F0);
    }

    #[test]
    fn differs_from_kermit_variant() {
        // CRC-16/KERMIT of "123456789" is 0x2189 — if we ever accidentally
        // swap init or reflection, this vector catches it.
        assert_ne!(crc16(b"123456789"), 0x2189);
    }
}