Replaces the ad-hoc display loop with a declarative hsmc statechart
(Off/On.{Splash.{LearnMore,Info}, Dashboard.{Listening,Transmitting}})
and swaps the Radio→Display channel from a RadioStatus watch to a
typed RadioEvent queue. The radio task now emits discrete mode and
packet events instead of publishing full status snapshots; the
display consumes them through the statechart, which also handles the
5 s splash alternation and 1 s sparkline tick via `on(after …)` /
`on(every …)` transitions.
Also:
- Add hsmc dep and embassy/tokio feature shims (hsmc proc macro
evaluates `cfg(feature = "embassy")` in this crate).
- Fix USB disconnect path in `host/usb.rs` so the DTR branch always
runs on read error (was early-continuing, starving display/radio
reset).
55 lines
2.1 KiB
Rust
55 lines
2.1 KiB
Rust
//! Inter-task communication channels.
|
|
//!
|
|
//! - [`CommandChannel`]: USB → Radio (host commands)
|
|
//! - [`ResponseChannel`]: Radio → USB (firmware responses)
|
|
//! - [`DisplayCommandChannel`]: USB → Display (on/off/reset)
|
|
//! - [`RadioEventChannel`]: Radio → Display (typed events from the radio)
|
|
|
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
|
use embassy_sync::channel::Channel;
|
|
|
|
use crate::protocol::{Command, RadioConfig, Response};
|
|
|
|
/// 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
|
|
Reset,
|
|
}
|
|
|
|
/// USB-to-display command channel (depth 4: display commands are rare events).
|
|
pub type DisplayCommandChannel = Channel<CriticalSectionRawMutex, DisplayCommand, 4>;
|
|
|
|
/// Host-to-radio command channel (depth 16: buffer bursty host command sequences).
|
|
pub type CommandChannel = Channel<CriticalSectionRawMutex, Command, 16>;
|
|
|
|
/// Radio-to-host response channel (depth 32: buffer RX packets while USB writes).
|
|
pub type ResponseChannel = Channel<CriticalSectionRawMutex, Response, 32>;
|
|
|
|
/// 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.
|
|
#[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),
|
|
}
|
|
|
|
/// Radio → Display event stream (depth 32: buffer RX bursts while the
|
|
/// display drains slowly).
|
|
pub type RadioEventChannel = Channel<CriticalSectionRawMutex, RadioEvent, 32>;
|