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.
This commit is contained in:
29 files changed
+7115
-2285
No files matched your search
+57
@@ -0,0 +1,57 @@
|
||||
//! 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);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user