Add comprehensive README for workspace functionality and implementation

This commit is contained in:
2026-02-21 01:01:39 +01:00
parent d0212f4e38
commit 380084029a

237
README.md Normal file
View File

@@ -0,0 +1,237 @@
# DD3 LoRa Bridge Rust Port (Host-First, Test-First)
This repository is a Rust workspace port of the DD3 LoRa Bridge with compatibility as the primary goal.
The implementation is organized so protocol, contracts, and state-machine behavior can be validated on host without hardware.
## Source of Truth
- Authoritative requirements:
- https://git.mannheim.ccc.de/C3MA/DD3-LoRa-Bridge-MultiSender/src/branch/lora-refactor/Requirements.md
- Pinned C++ baseline for compatibility and fixtures:
- `vendor/dd3-cpp` at commit `a3c61f9b929fbc55bfb502b443fba2f98023b3f1`
## Workspace Layout
- `crates/dd3_protocol`
- Pure protocol crate (manual wire codec, no serde for wire)
- CRC16-CCITT, LoRa frame encode/decode, ACK payload codec
- Payload schema v3 encode/decode (sparse 30-slot present mask)
- Chunk reassembly with deterministic reset/error behavior
- `crates/dd3_contracts`
- Pure contracts/formatting crate
- MQTT state JSON, HA discovery topic/payload, CSV formatting
- Device ID sanitize/normalize, HTML escape, URL component encode
- Manufacturer constant lock: `HA_MANUFACTURER = "AcidBurns"`
- `crates/dd3_core`
- Deterministic sender state machine and receiver pipeline
- Trait-based I/O boundaries (`Clock`, `Radio`, `Publisher`, `Storage`, `StatusSink`)
- `crates/dd3_sim`
- Host simulator for deterministic behavior tests
- Fake clock, fake lossy/duplicate/delayed radio, scenario runner and mocks
- `crates/dd3_firmware`
- Embedded integration placeholder crate
- Feature flags for `esp-idf` / `esp-hal`, role-selection scaffold
- `crates/xtask`
- Fixture sync/provenance checks and manufacturer drift guard
Other folders:
- `fixtures/`
- Protocol binary fixtures (`frames`, `chunks`, `payload_v3`)
- Contract snapshots (`mqtt_state`, `ha_discovery`, `sd_csv`)
- `docs/`
- `SPEC_LINKS.md`, `TEST_STRATEGY.md`, `INTEROP_CHECKLIST.md`
- `fuzz/`
- Fuzz targets for decode/sanitize entry points
## What Is Implemented
### 1) Byte-Exact Protocol Compatibility (`dd3_protocol`)
Implementation details:
- Frame format:
- `[msg_kind:1][short_id_be:2][payload][crc16_ccitt_be:2]`
- Message kinds:
- `BatchUp = 0`
- `AckDown = 1`
- ACK payload format:
- Fixed 7 bytes: `[flags:1][batch_id_be:2][epoch_utc_be:4]`
- `flags bit0 = time_valid`
- CRC:
- CRC16-CCITT with init `0xFFFF`, poly `0x1021`
- Payload schema v3:
- 30-slot sparse window with strict `present_mask` and `n` validation
- Supports sync-request packets (`n == 0`, `present_mask == 0`)
- Chunk reassembly:
- Deterministic in-order completion
- Reset on mismatch/out-of-order/invalid total length
### 2) Contract Stability (`dd3_contracts`)
Implementation details:
- Home Assistant discovery contract:
- Topic: `homeassistant/sensor/<device_id>/<key>/config`
- `unique_id = <device_id>_<key>`
- Device metadata includes model `DD3-LoRa-Bridge` and manufacturer `AcidBurns`
- MQTT state JSON:
- Stable key set and semantics (legacy keys intentionally absent)
- CSV output:
- Fixed header:
- `ts_utc,ts_hms_local,p_w,p1_w,p2_w,p3_w,e_kwh,bat_v,bat_pct,rssi,snr,err_m,err_d,err_tx,err_last`
- Stable numeric formatting and optional `snr` blank when NaN
- Sanitization/escaping:
- `sanitize_device_id` accepts `XXXX` or `dd3-XXXX`, normalizes to `dd3-XXXX`
- Rejects traversal/percent/invalid-hex forms
- Includes `html_escape` and URL component encoding
### 3) Deterministic Sender/Receiver Core (`dd3_core`)
Sender state machine implementation:
- Unsynced guardrail:
- Sends only sync-request packets every 15s until valid ACK time bootstrap
- Time bootstrap gate:
- Requires `time_valid=1` and `epoch >= MIN_ACCEPTED_EPOCH_UTC`
- Cadence:
- Sampling at 1 Hz
- Batch cadence at 30s
- Stop-and-wait:
- One inflight batch only
- Retries reuse cached encoded bytes
- ACK handling:
- Adaptive receive windows from airtime + RTT/miss-streak logic
- Bounded retries (`BATCH_MAX_RETRIES`)
- Catch-up and queueing:
- Immediate send when backlog exists and no ACK pending
- Queue depth bounded to `BATCH_QUEUE_DEPTH`
- Fault counters:
- Reset on first valid sync and each UTC hour boundary after sync
Receiver pipeline implementation:
- Continuous RX validation pipeline:
- Frame decode -> reassembly -> payload decode -> sparse reconstruction
- Sender identity checks before updates:
- Unknown/mismatched sender is rejected before publish/log updates
- ACK behavior:
- ACK repeats per baseline constants
- Duplicate handling:
- Duplicate batches are ACKed
- Duplicate publish/log is suppressed
- Duplicate counters are updated
### 4) Simulator (`dd3_sim`)
Implementation details:
- `FakeClock` with deterministic time advancement
- `FakeRadioBus` with configurable:
- packet loss
- duplication
- delay
- `ScenarioRunner` and mocks for:
- publisher
- storage
- status sink
Implemented scenario tests cover:
- no receiver: sync-requests only
- bootstrap unlock via valid ACK
- packet loss progression without duplicate commit
- ACK mismatch ignored
- backpressure queue bounded
- duplicate batch suppression with counter updates
### 5) Firmware Placeholder (`dd3_firmware`)
- Compile-safe scaffold for embedded integration
- Role detection function for GPIO14 exists as placeholder
- Full hardware integration is intentionally deferred
## Test Strategy and Coverage
The repo follows four test pillars documented in `docs/TEST_STRATEGY.md`:
1. Byte-exact protocol compatibility
2. Contract stability
3. Deterministic state-machine behavior
4. Fuzz/property robustness
Key test files:
- `crates/dd3_protocol/tests/protocol_tests.rs`
- `crates/dd3_contracts/tests/contracts_tests.rs`
- `crates/dd3_sim/tests/state_machine_tests.rs`
## Fixtures and Provenance
- Fixture metadata is tracked in `fixtures/protocol/SOURCES.md`
- Fixture tooling is in `crates/xtask/src/main.rs`
Commands:
- `cargo run -p xtask -- sync-fixtures`
- `cargo run -p xtask -- verify-fixture-sources`
- `cargo run -p xtask -- check-manufacturer`
Note on `full_30` payload fixture:
- Upstream pinned baseline vector contains a truncated raw byte array.
- This repo stores both:
- `fixtures/protocol/payload_v3/full_30_upstream_raw.bin` (raw upstream)
- `fixtures/protocol/payload_v3/full_30.bin` (canonicalized for codec semantics)
## Constants Locked to Baseline
See `docs/SPEC_LINKS.md` for full extraction references. Key locked values include:
- `MIN_ACCEPTED_EPOCH_UTC = 1769904000`
- `SYNC_REQUEST_INTERVAL_MS = 15000`
- `METER_SAMPLE_INTERVAL_MS = 1000`
- `METER_SEND_INTERVAL_MS = 30000`
- `BATCH_MAX_RETRIES = 2`
- `BATCH_QUEUE_DEPTH = 10`
- `ACK_REPEAT_COUNT = 3`
- `ACK_REPEAT_DELAY_MS = 200`
- `HA_MANUFACTURER = "AcidBurns"`
## Build and Run
Prerequisites:
- Rust stable toolchain (`rustup`, `cargo`, `rustfmt`, `clippy`)
- On Windows MSVC target: Visual C++ Build Tools (`link.exe` available)
Commands:
- `make test`
- `make lint`
- `make fuzz-smoke`
Equivalent cargo commands:
- `cargo test --workspace`
- `cargo fmt --all -- --check`
- `cargo clippy --workspace --all-targets -- -D warnings`
## Interoperability Plan
Use `docs/INTEROP_CHECKLIST.md` for two-way verification:
- Rust Receiver <-> C++ Sender
- Rust Sender <-> C++ Receiver
- MQTT/CSV contract comparison checks
## Current Scope and Next Phase
Current scope is host-first protocol/contracts/core/sim validation.
Next phase is hardware integration in `dd3_firmware`:
- real GPIO14 role read (HIGH sender / LOW receiver)
- radio + transport glue on embedded target
- time/local-date partitioning wiring with platform services