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

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
Description
Same as DD3-LoRa-Bridge-MultiSender just with Rust
Readme 72 KiB
Languages
Rust 99.8%
Makefile 0.2%