refactor: complete hsmc conversion and add debug-checkpoint feature

Finishes the hsmc migration that was staged across the prior two
commits:

- Radio task is now a single `machine.run().await`; all I/O lives in
  state-scoped `during:` activities (`next_command`, `next_packet`,
  `perform_tx`). The old `push/drain` helpers, the imperative
  top-level `select`, `handle_cmd`, `handle_rx_result`, and
  `execute_transmit` are gone. `StartingRx` / `ResumingRx` intermediate
  states model the host-visible difference between a responding and a
  silent RX re-arm.

- Host/USB task is now an hsmc statechart (Disconnected/Connected)
  with entry/exit actions handling display wake, radio StopRx, and
  display reset — replacing the open-coded `was_connected` edge
  detector. The `protocol_loop` keeps its imperative read path because
  `read_packet` blocks.

- New `debug-checkpoint` cargo feature ships a dedicated
  `debug_blink.rs` task and a shared atomic counter that code along
  the boot/dispatch/TX path bumps at notable points. A ladder-latching
  write policy preserves the deepest TX phase reached on the first
  attempt until reboot — diagnostic output for UART-only boards where
  defmt would corrupt the host protocol. Zero footprint when the
  feature is off.

- Silence a stray `clippy::unit_arg` on `led_off` / `led_blip` in the
  display task for boards with `LedDriver = ()`.
This commit is contained in:
swaits committed 2026-04-16 13:28:44 -06:00
1 parent c6ef9559ec
commit 388d07e90f
7 files changed
+902 -438

No files matched your search

+18 -5
View File
@@ -19,6 +19,8 @@
mod board;
#[cfg(not(test))]
mod channel;
#[cfg(all(not(test), feature = "debug-checkpoint"))]
mod debug_blink;
#[cfg(not(test))]
mod display;
#[cfg(not(test))]
@@ -97,10 +99,21 @@ async fn run(spawner: Spawner) {
);
if let Some(dp) = parts.display {
#[allow(clippy::unit_arg)] // LedDriver is () for boards without LEDs
spawner.spawn(
display::display_task(dp, parts.led, &RADIO_EVENTS, &DISPLAY_COMMANDS)
.expect("spawn display_task"),
);
#[cfg(feature = "debug-checkpoint")]
{
// LED is taken over by the checkpoint blinker; the display
// init struct is dropped unused for this debug build.
let _ = dp;
spawner
.spawn(debug_blink::debug_blink_task(parts.led).expect("spawn debug_blink_task"));
}
#[cfg(not(feature = "debug-checkpoint"))]
{
#[allow(clippy::unit_arg)] // LedDriver is () for boards without LEDs
spawner.spawn(
display::display_task(dp, parts.led, &RADIO_EVENTS, &DISPLAY_COMMANDS)
.expect("spawn display_task"),
);
}
}
}