Files
protocol-rs/src/crc.rs
T
swaits 4cccb65124 feat!: protocol v2 wire format and module restructure
The wire protocol is re-specified as DongLoRa Protocol v2 (see PROTOCOL.md). Every type_id, tag-correlation rule, and field layout is incompatible with 0.1.0.

* Add PROTOCOL.md as the normative spec for the v2 wire format.

* Replace framing.rs with a streaming FrameDecoder that emits (type_id, tag, payload) triples on each COBS-delimited, CRC-checked frame.

* Split the single-file lib.rs into dedicated modules: frame, commands, events, errors, modulation, info, crc, chip_id. Re-exports preserve convenience imports at the crate root.

* Replace RadioConfig / Bandwidth with a Modulation enum covering LoRa, FSK/GFSK, LR-FHSS, and FLRC, each with its own typed parameter struct.

* Add TxFlags, RxOrigin, SetConfigResult, OkPayload to model v2 response shapes, and RadioChipId for GET_INFO.

* Rewrite fuzz corpus: replace the 4 cobs_* / command_roundtrip targets with decoder_feed, frame_roundtrip, lora_config_roundtrip, and parse_device_message; drop parse_radio_config.

* Expand proptest and mutation-killer coverage for the new wire shape.

* Rewrite canonical-byte test vectors against the v2 spec.
2026-04-22 09:21:11 -06:00

58 lines
1.8 KiB
Rust

//! 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);
}
}