feat!: migrate firmware to DongLoRa Protocol v2 wire format
Wire-incompatible break with the 0.x protocol. Every host-side path (UART, USB CDC, framing, radio dispatcher, display update channel) speaks the v2 wire format defined in PROTOCOL.md.
* Replace the host framing path with streaming FrameDecoder + encode_frame from donglora-protocol, matching the new (type_id, tag, payload) shape.
* Update src/channel.rs and src/host/{uart,usb,framing}.rs for the new frame semantics: per-request tag echo, CRC checked in the decoder, async ERR fan-out on tag 0.
* Rework src/radio.rs to emit RX / TX_DONE / OK / ERR messages in v2 shape, including RxOrigin, TxDonePayload, and SetConfigResult codes.
* Update src/protocol.rs glue to re-export v2 types from donglora-protocol and drop the legacy 0.x shim surface.
* Refresh PROTOCOL.md to the v2 normative spec (kept in sync with the donglora-protocol crate).
* Minor display and main-loop cleanups needed for the new radio event shape.
This commit is contained in:
11 files changed
+2950
-958
No files matched your search
+62
-32
@@ -1,54 +1,84 @@
|
||||
//! Inter-task communication channels.
|
||||
//! Inter-task communication channels for DongLoRa Protocol v2.
|
||||
//!
|
||||
//! - [`CommandChannel`]: USB → Radio (host commands)
|
||||
//! - [`ResponseChannel`]: Radio → USB (firmware responses)
|
||||
//! - [`DisplayCommandChannel`]: USB → Display (on/off/reset)
|
||||
//! - [`RadioEventChannel`]: Radio → Display (typed events from the radio)
|
||||
//! - [`CommandChannel`]: host_task → radio_task (tag-correlated commands)
|
||||
//! - [`OutboundChannel`]: radio_task → host_task (tag-correlated OK/ERR/TX_DONE
|
||||
//! and tag-0 async RX/ERR events in one queue)
|
||||
//! - [`DisplayCommandChannel`]: host_task → display_task (internal only —
|
||||
//! `On` on connect, `Reset` on disconnect; no longer driven from the wire)
|
||||
//! - [`RadioEventChannel`]: radio_task → display_task (typed mode/packet events)
|
||||
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::channel::Channel;
|
||||
|
||||
use crate::protocol::{Command, RadioConfig, Response};
|
||||
use crate::protocol::{Command, DeviceMessage, LoRaConfig};
|
||||
|
||||
/// Display commands routed from host_task to display_task.
|
||||
#[derive(Debug, Clone, Copy, defmt::Format)]
|
||||
pub enum DisplayCommand {
|
||||
On,
|
||||
Off,
|
||||
#[allow(dead_code)] // only used by USB host task, not UART
|
||||
// ── Host → Radio: tag-correlated commands ───────────────────────────
|
||||
|
||||
/// An event flowing from the host task into the radio task.
|
||||
///
|
||||
/// `Command` carries a non-zero correlation tag (the host framing layer
|
||||
/// rejects tag=0 before it reaches here). `Reset` is a lifecycle signal
|
||||
/// from the host transport layer (DTR drop, UART teardown, or spec §3.4
|
||||
/// inactivity timeout) telling the radio to park back to Unconfigured
|
||||
/// and drain queues silently.
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum InboundEvent {
|
||||
Command { tag: u16, cmd: Command },
|
||||
Reset,
|
||||
}
|
||||
|
||||
/// USB-to-display command channel (depth 4: display commands are rare events).
|
||||
pub type DisplayCommandChannel = Channel<CriticalSectionRawMutex, DisplayCommand, 4>;
|
||||
/// Host-to-radio event channel (depth 8).
|
||||
pub type CommandChannel = Channel<CriticalSectionRawMutex, InboundEvent, 8>;
|
||||
|
||||
/// Host-to-radio command channel (depth 16: buffer bursty host command sequences).
|
||||
pub type CommandChannel = Channel<CriticalSectionRawMutex, Command, 16>;
|
||||
// ── Radio → Host: OK / ERR / TX_DONE / RX / async ERR ──────────────
|
||||
|
||||
/// Radio-to-host response channel (depth 32: buffer RX packets while USB writes).
|
||||
pub type ResponseChannel = Channel<CriticalSectionRawMutex, Response, 32>;
|
||||
/// One outbound D→H frame carrying its tag. Tag-correlated messages
|
||||
/// (OK, ERR in response, TX_DONE) carry the originating command's tag;
|
||||
/// async events (RX, async ERR) carry `tag = 0x0000`.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct OutboundFrame {
|
||||
pub tag: u16,
|
||||
pub msg: DeviceMessage,
|
||||
}
|
||||
|
||||
/// Radio → downstream typed events. The radio task emits one of these at
|
||||
/// every mode transition and every RF packet. Mode events and data events
|
||||
/// are separate: `EnteredRx` / `EnteredTx` / `Idle` describe what the radio
|
||||
/// is *doing now*, while `PacketRx` / `PacketTx` describe *what just
|
||||
/// happened* without implying a mode change.
|
||||
/// Radio-to-host outbound channel (depth 32: enough to hold a burst of
|
||||
/// RX events + queued command responses without stalling the radio ISR).
|
||||
pub type OutboundChannel = Channel<CriticalSectionRawMutex, OutboundFrame, 32>;
|
||||
|
||||
// ── Internal: display commands (no longer wire-visible) ────────────
|
||||
|
||||
/// Internal display command routed from host_task to display_task. The
|
||||
/// wire protocol no longer carries DisplayOn/Off (`PROTOCOL.md §15.2`);
|
||||
/// these values drive the display statechart from local events only.
|
||||
#[derive(Debug, Clone, Copy, defmt::Format)]
|
||||
#[allow(dead_code)] // `Off` is reserved for future diagnostic paths.
|
||||
pub enum DisplayCommand {
|
||||
/// Host connected (DTR rose on USB, or UART came up). Wake display.
|
||||
On,
|
||||
/// Host disconnected. Park display.
|
||||
Off,
|
||||
/// Reset cumulative counters (e.g., on config change).
|
||||
Reset,
|
||||
}
|
||||
|
||||
/// Host-to-display command channel.
|
||||
pub type DisplayCommandChannel = Channel<CriticalSectionRawMutex, DisplayCommand, 4>;
|
||||
|
||||
// ── Radio → Display: typed packet/mode events ──────────────────────
|
||||
|
||||
/// Radio → downstream typed events. These drive the display; they are
|
||||
/// NOT the same thing as `OutboundFrame` (which goes out the host
|
||||
/// transport). Mode events describe what the radio is doing now; packet
|
||||
/// events describe what just happened.
|
||||
#[derive(Debug, Clone, defmt::Format)]
|
||||
pub enum RadioEvent {
|
||||
/// Radio is now in RX mode.
|
||||
EnteredRx,
|
||||
/// Radio is now in TX mode.
|
||||
EnteredTx,
|
||||
/// Radio is now idle.
|
||||
Idle,
|
||||
/// A packet was received with these link metrics.
|
||||
PacketRx { rssi: i16, snr: Option<i16> },
|
||||
/// A packet was transmitted successfully.
|
||||
PacketTx,
|
||||
/// `SetConfig` applied a new validated config.
|
||||
ConfigChanged(RadioConfig),
|
||||
ConfigChanged(LoRaConfig),
|
||||
}
|
||||
|
||||
/// Radio → Display event stream (depth 32: buffer RX bursts while the
|
||||
/// display drains slowly).
|
||||
pub type RadioEventChannel = Channel<CriticalSectionRawMutex, RadioEvent, 32>;
|
||||
Reference in new issue
Block a user