From 4d2db87daed8f4b6707c3dc3883c2e06478c8f30 Mon Sep 17 00:00:00 2001 From: Stephen Waits Date: Thu, 26 Mar 2026 15:16:31 -0600 Subject: [PATCH] feat: initial lora-dongle firmware scaffold MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Transparent LoRa-over-USB dongle firmware supporting Heltec V3 (ESP32-S3) and RAK 4631 (nRF52840) boards. Actor-model architecture with typed channels between USB, radio, and display tasks. - Protocol: Command/Response enums with COBS+postcard framing design - Board abstraction: auto-discovered via build.rs Jinja2 codegen - Radio task: SX1262 state machine (Idle → Receiving ↔ Transmitting) - Display task: optional SSD1306 dashboard via StatusWatch - RAK 4631: fully wired SPI/USB/I2C peripherals, clippy-clean - Heltec V3: structure in place, awaits espup Xtensa toolchain --- DESIGN.md | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 DESIGN.md diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 0000000..0b46f71 --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,76 @@ +# Design Principles + +These are the non-negotiable first principles of this project. Every design decision, +naming choice, module boundary, and abstraction is evaluated against them. When in +doubt, choose simplicity and clarity over cleverness. + +## What This Is + +A transparent LoRa radio over USB. Plug the dongle into your PC, talk to any LoRa +radio within range. That's it. + +## What This Is Not + +Not a mesh network node. Not a Meshtastic device. Not a protocol implementation. Not +an application framework. This firmware has no opinion about what you do with your +radio — it just gives you clean access to it. + +## Principles + +1. **Single purpose.** Transparent LoRa radio over USB. No mesh, no routing, no + application logic. Ever. + +2. **Protocol-agnostic.** The firmware is a dumb pipe. It exposes clean LoRa + parameters (frequency, bandwidth, spreading factor, coding rate, sync word, TX + power) and nothing else. No raw register access, no chip-specific leakage. + +3. **Host-driven.** The firmware makes zero autonomous decisions. The radio idles on + boot until the host commands it. No persistence across reboots. The host is always + in control. + +4. **Zero-config.** Boots, enumerates USB, waits for commands. The host plugs in and + goes. + +5. **Robustness over features.** Tasks never panic. Errors are reported to the host. + The radio self-recovers. Ship fewer features, but make them bulletproof. + +6. **Minimal footprint.** Avoid heavy dependencies. Keep the binary small. Every + dependency must justify its inclusion. + +7. **Auto-detect peripherals.** If the board has a display, use it. No user + configuration required. + +8. **World-class Rust.** Fully leverage the type system for safety. Strict `no_std`. + Always clippy-clean. Thoughtfully designed — everything has an obvious home. + Anyone who reads this code should immediately think *"this is nice."* + +9. **Easy board support.** Adding a new board means dropping a `.rs` file and adding + a Cargo feature. Nothing else changes. + +## Architecture + +``` +Host PC + │ USB CDC-ACM (COBS-framed postcard) + ▼ +usb_task ──Command──► radio_task ──► SX1262 + ◄──Response── │ + StatusWatch + ▼ + display_task (optional) ──► OLED/TFT +``` + +Each task exclusively owns its peripheral. No shared state except typed channels and +a watch signal. Pure actor model. + +## Technical Decisions + +| Decision | Choice | Why | +|---|---|---| +| USB framing | COBS + postcard | Compact, `no_std` native, battle-tested | +| Serialization | postcard + serde | Zero-alloc binary codec, perfect for embedded | +| Async runtime | Embassy | De facto standard for async embedded Rust | +| Display | Radio status dashboard | Freq, BW, SF, packet counts, RSSI/SNR | +| Boot behavior | Idle until host commands | Host-driven principle | +| Persistence | None | Always start fresh, true dumb pipe | +| Board codegen | Jinja2 via build.rs | Auto-discovers boards from filesystem |