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:
- Pinned C++ baseline for compatibility and fixtures:
vendor/dd3-cppat commita3c61f9b929fbc55bfb502b443fba2f98023b3f1
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)
- Protocol binary fixtures (
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 = 0AckDown = 1
- ACK payload format:
- Fixed 7 bytes:
[flags:1][batch_id_be:2][epoch_utc_be:4] flags bit0 = time_valid
- Fixed 7 bytes:
- CRC:
- CRC16-CCITT with init
0xFFFF, poly0x1021
- CRC16-CCITT with init
- Payload schema v3:
- 30-slot sparse window with strict
present_maskandnvalidation - Supports sync-request packets (
n == 0,present_mask == 0)
- 30-slot sparse window with strict
- 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-Bridgeand manufacturerAcidBurns
- Topic:
- 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
snrblank when NaN
- Fixed header:
- Sanitization/escaping:
sanitize_device_idacceptsXXXXordd3-XXXX, normalizes todd3-XXXX- Rejects traversal/percent/invalid-hex forms
- Includes
html_escapeand 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=1andepoch >= MIN_ACCEPTED_EPOCH_UTC
- Requires
- 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:
FakeClockwith deterministic time advancementFakeRadioBuswith configurable:- packet loss
- duplication
- delay
ScenarioRunnerand 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:
- Byte-exact protocol compatibility
- Contract stability
- Deterministic state-machine behavior
- Fuzz/property robustness
Key test files:
crates/dd3_protocol/tests/protocol_tests.rscrates/dd3_contracts/tests/contracts_tests.rscrates/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-fixturescargo run -p xtask -- verify-fixture-sourcescargo 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 = 1769904000SYNC_REQUEST_INTERVAL_MS = 15000METER_SAMPLE_INTERVAL_MS = 1000METER_SEND_INTERVAL_MS = 30000BATCH_MAX_RETRIES = 2BATCH_QUEUE_DEPTH = 10ACK_REPEAT_COUNT = 3ACK_REPEAT_DELAY_MS = 200HA_MANUFACTURER = "AcidBurns"
Build and Run
Prerequisites:
- Rust stable toolchain (
rustup,cargo,rustfmt,clippy) - On Windows MSVC target: Visual C++ Build Tools (
link.exeavailable)
Commands:
make testmake lintmake fuzz-smoke
Equivalent cargo commands:
cargo test --workspacecargo fmt --all -- --checkcargo 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