refactor: LoRaBoard trait for compile-time board completeness verification

Every board's Board struct now implements the LoRaBoard trait, which
enforces that NAME, TX_POWER_RANGE, init(), and mac_address() are all
provided. Missing any of these is a compile error — no "good intentions"
needed.

The trait verifies metadata and initialization. Tasks use the board's
concrete types directly (Embassy tasks must be concrete). Board-specific
type aliases (RadioDriver, UsbDriver, DisplayI2c) and struct definitions
(RadioParts, UsbParts, DisplayParts) remain in each board file.

- New: src/board/traits.rs (LoRaBoard trait definition)
- Modified: all 3 board files (implement trait, remove standalone constants)
- Modified: main.rs (import trait for init)
- Modified: radio/task.rs (use Board::TX_POWER_RANGE via trait)
- Modified: display/task.rs (use Board::NAME via trait)
- Modified: build.rs (exclude traits.rs from board discovery)
- Removed: embedded-hal-async direct dep (not needed for trait approach)
This commit is contained in:
swaits committed 2026-03-30 08:44:39 -06:00
1 parent 99a01b867e
commit 2633daf437
11 files changed
+107 -55

No files matched your search

+12 -4
View File
@@ -1,3 +1,4 @@
use super::traits::LoRaBoard;
use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice;
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
use embassy_time::Delay;
@@ -25,8 +26,6 @@ pub type UsbDriver = esp_hal::otg_fs::asynch::Driver<'static>;
pub type DisplayI2c = I2c<'static, esp_hal::Async>;
/// TX power range for this board's radio (SX1262).
pub const TX_POWER_RANGE: (i8, i8) = (-9, 22);
// ── Peripheral bundles ───────────────────────────────────────────────
@@ -50,12 +49,21 @@ pub struct Board {
p: esp_hal::peripherals::Peripherals,
}
impl Board {
pub fn init() -> Self {
impl LoRaBoard for Board {
const NAME: &'static str = "Heltec V3";
const TX_POWER_RANGE: (i8, i8) = (-9, 22);
fn init() -> Self {
let p = esp_hal::init(esp_hal::Config::default());
Self { p }
}
fn mac_address() -> [u8; 6] {
esp_hal::efuse::Efuse::mac_address()
}
}
impl Board {
pub fn into_parts(self) -> (RadioParts, UsbParts, Option<DisplayParts>) {
let p = self.p;