This repository has been archived on 2026-08-31. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
donglora/DESIGN.md
T
swaitsandClaude Opus 4.6 f1df675363 refactor: rename project to DongLoRa
Rebrand from lora-dongle to DongLoRa (portmanteau of dongle + LoRa).
Lowercase donglora in Cargo package name, firmware filenames, and code.
Splash screen shows "DongLoRa" in 9x15 bold.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 20:42:55 -06:00

105 lines
4.5 KiB
Markdown

# 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, keyboard, or sensors,
use them. 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.
10. **Support all common LoRa boards.** This project supports every common LoRa
board, and even some uncommon ones. The architecture is designed to accommodate
them cleanly. If the code isn't structured for a new board, fix the code.
11. **Standard toolchain.** No custom Rust forks or special SDKs. Use stock `rustup`
channels (stable, nightly). Xtensa targets use nightly + `-Zbuild-std`; Cortex-M
and RISC-V targets use stable. Boards that need the `esp` toolchain (via `espup`)
are supported but gracefully skipped when the toolchain isn't installed.
## 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.
## Peripheral Model
Boards can have optional peripherals beyond the radio and USB. The board's
`into_parts()` returns `Option<T>` slots for each, and the corresponding task is
only spawned when present.
| Peripheral | Slot | Task | Examples |
|---|---|---|---|
| Display | `Option<DisplayParts>` | `display_task` | SSD1306 OLED, ST7789 TFT |
| Input | `Option<InputParts>` | `input_task` | T-Deck keyboard, buttons |
| Telemetry | `Option<TelemetryParts>` | `telemetry_task` | Battery voltage, temperature |
**Board files are always separate.** A T-Deck is `t_deck.rs`, not a variant of
Heltec V3. Each board owns its own init code and pin mappings. Shared logic between
boards that use the same MCU can be factored into helper modules if it earns its
keep, but never prematurely.
## 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 |
| Rust toolchain | Stock `rustup` (stable/nightly) | No forks; `espup` for Xtensa boards only |
| Firmware output | `firmware/donglora-{board}-{profile}.elf` | Readable names, not buried in `target/` |