refactor: unify SimpleLed via embedded-hal, remove Option<L> from BoardParts

- Added embedded-hal 1.0 as direct dep (already transitive via embedded-hal-async)
- SimpleLed<P: OutputPin> now generic over any HAL — single definition in driver/
- Removed duplicate SimpleLed from board/esp32s3.rs and board/wio_tracker_l1.rs
- Changed BoardParts.led from Option<L> to L — boards with no LED use ()
- Display task calls led.set_rgb() unconditionally (no-op for () boards)
- RAK board: led: () instead of led: None
This commit is contained in:
swaits committed 2026-04-07 12:40:55 -06:00
1 parent e60465f181
commit 1c93b77d0b
12 files changed
+39 -48

No files matched your search

+1
View File
@@ -390,6 +390,7 @@ dependencies = [
"embassy-usb", "embassy-usb",
"embassy-usb-driver", "embassy-usb-driver",
"embedded-graphics", "embedded-graphics",
"embedded-hal 1.0.0",
"embedded-hal-async", "embedded-hal-async",
"embedded-io-async 0.7.0", "embedded-io-async 0.7.0",
"esp-backtrace", "esp-backtrace",
+1
View File
@@ -21,6 +21,7 @@ categories = ["embedded", "hardware-support", "no-std"]
cfg-if = "1.0" cfg-if = "1.0"
critical-section = "1.2" critical-section = "1.2"
defmt = "1.0" defmt = "1.0"
embedded-hal = "1.0"
embedded-hal-async = "1.0" embedded-hal-async = "1.0"
embassy-embedded-hal = "0.6" embassy-embedded-hal = "0.6"
embassy-executor = "0.9" embassy-executor = "0.9"
-14
View File
@@ -18,20 +18,6 @@ use crate::hal::esp32s3 as mcu;
pub use mcu::{I2cBus as DisplayI2c, SpiBus}; pub use mcu::{I2cBus as DisplayI2c, SpiBus};
// ── LED driver ──────────────────────────────────────────────────────
pub struct SimpleLed(pub Output<'static>);
impl super::traits::RgbLed for SimpleLed {
async fn set_rgb(&mut self, r: u8, g: u8, b: u8) {
if r > 0 || g > 0 || b > 0 {
self.0.set_high();
} else {
self.0.set_low();
}
}
}
// ── Concrete peripheral types ─────────────────────────────────────── // ── Concrete peripheral types ───────────────────────────────────────
type Nss = Output<'static>; type Nss = Output<'static>;
+3 -3
View File
@@ -11,7 +11,7 @@ use static_cell::StaticCell;
use super::esp32s3; use super::esp32s3;
use super::traits::{BoardParts, LoRaBoard}; use super::traits::{BoardParts, LoRaBoard};
use super::esp32s3::SimpleLed; use crate::driver::simple_led::SimpleLed;
use crate::hal::esp32s3 as mcu; use crate::hal::esp32s3 as mcu;
pub use super::esp32s3::{ pub use super::esp32s3::{
@@ -19,7 +19,7 @@ pub use super::esp32s3::{
}; };
pub type UsbDriver = esp_hal::otg_fs::asynch::Driver<'static>; pub type UsbDriver = esp_hal::otg_fs::asynch::Driver<'static>;
pub type LedDriver = SimpleLed; pub type LedDriver = SimpleLed<Output<'static>>;
pub struct UsbParts { pub struct UsbParts {
pub driver: UsbDriver, pub driver: UsbDriver,
@@ -84,7 +84,7 @@ impl LoRaBoard for Board {
// White LED on GPIO35 // White LED on GPIO35
let led_pin = Output::new(p.GPIO35, Level::Low, OutputConfig::default()); let led_pin = Output::new(p.GPIO35, Level::Low, OutputConfig::default());
let led = Some(SimpleLed(led_pin)); let led = SimpleLed(led_pin);
BoardParts { BoardParts {
radio, radio,
+3 -3
View File
@@ -10,7 +10,7 @@ use esp_hal::gpio::{Level, Output, OutputConfig};
use super::esp32s3; use super::esp32s3;
use super::traits::{BoardParts, LoRaBoard}; use super::traits::{BoardParts, LoRaBoard};
use super::esp32s3::SimpleLed; use crate::driver::simple_led::SimpleLed;
use crate::hal::esp32s3 as mcu; use crate::hal::esp32s3 as mcu;
pub use super::esp32s3::{ pub use super::esp32s3::{
@@ -18,7 +18,7 @@ pub use super::esp32s3::{
}; };
pub type UartDriver = esp_hal::uart::Uart<'static, esp_hal::Async>; pub type UartDriver = esp_hal::uart::Uart<'static, esp_hal::Async>;
pub type LedDriver = SimpleLed; pub type LedDriver = SimpleLed<Output<'static>>;
pub struct UartParts { pub struct UartParts {
pub driver: UartDriver, pub driver: UartDriver,
@@ -80,7 +80,7 @@ impl LoRaBoard for Board {
// White LED on GPIO35 // White LED on GPIO35
let led_pin = Output::new(p.GPIO35, Level::Low, OutputConfig::default()); let led_pin = Output::new(p.GPIO35, Level::Low, OutputConfig::default());
let led = Some(SimpleLed(led_pin)); let led = SimpleLed(led_pin);
BoardParts { BoardParts {
radio, radio,
+3 -3
View File
@@ -3,7 +3,7 @@ use static_cell::StaticCell;
use super::esp32s3; use super::esp32s3;
use super::traits::{BoardParts, LoRaBoard}; use super::traits::{BoardParts, LoRaBoard};
use super::esp32s3::SimpleLed; use crate::driver::simple_led::SimpleLed;
use crate::hal::esp32s3 as mcu; use crate::hal::esp32s3 as mcu;
pub use super::esp32s3::{ pub use super::esp32s3::{
@@ -12,7 +12,7 @@ pub use super::esp32s3::{
pub type UsbDriver = esp_hal::otg_fs::asynch::Driver<'static>; pub type UsbDriver = esp_hal::otg_fs::asynch::Driver<'static>;
pub type LedDriver = SimpleLed; pub type LedDriver = SimpleLed<Output<'static>>;
pub struct UsbParts { pub struct UsbParts {
pub driver: UsbDriver, pub driver: UsbDriver,
@@ -77,7 +77,7 @@ impl LoRaBoard for Board {
// Orange LED on GPIO35 // Orange LED on GPIO35
let led_pin = Output::new(p.GPIO35, Level::Low, OutputConfig::default()); let led_pin = Output::new(p.GPIO35, Level::Low, OutputConfig::default());
let led = Some(SimpleLed(led_pin)); let led = SimpleLed(led_pin);
BoardParts { BoardParts {
radio, radio,
+1 -1
View File
@@ -137,7 +137,7 @@ impl LoRaBoard for Board {
radio, radio,
host, host,
display, display,
led: None, led: (),
mac: Self::mac_address(), mac: Self::mac_address(),
} }
} }
+1 -1
View File
@@ -56,6 +56,6 @@ pub struct BoardParts<R, C, D, L> {
pub radio: R, pub radio: R,
pub host: C, pub host: C,
pub display: Option<D>, pub display: Option<D>,
pub led: Option<L>, pub led: L,
pub mac: [u8; 6], pub mac: [u8; 6],
} }
+2 -16
View File
@@ -21,21 +21,7 @@ pub type RadioDriver = Sx126x<RadioSpiDevice, Iv, Sx1262>;
pub type UsbDriver = mcu::UsbNrfDriver; pub type UsbDriver = mcu::UsbNrfDriver;
pub type DisplayI2c = mcu::I2cBus; pub type DisplayI2c = mcu::I2cBus;
// ── LED driver (green LED on P1.01) ───────────────────────────────── pub type LedDriver = crate::driver::simple_led::SimpleLed<Output<'static>>;
pub struct SimpleLed(pub Output<'static>);
impl super::traits::RgbLed for SimpleLed {
async fn set_rgb(&mut self, r: u8, g: u8, b: u8) {
if r > 0 || g > 0 || b > 0 {
self.0.set_high();
} else {
self.0.set_low();
}
}
}
pub type LedDriver = SimpleLed;
pub type DisplayDriver = crate::driver::sh1106::Sh1106<DisplayI2c>; pub type DisplayDriver = crate::driver::sh1106::Sh1106<DisplayI2c>;
@@ -148,7 +134,7 @@ impl LoRaBoard for Board {
// Green LED on P1.01 // Green LED on P1.01
let led_pin = Output::new(p.P1_01, Level::Low, OutputDrive::Standard); let led_pin = Output::new(p.P1_01, Level::Low, OutputDrive::Standard);
let led = Some(SimpleLed(led_pin)); let led = crate::driver::simple_led::SimpleLed(led_pin);
BoardParts { BoardParts {
radio, radio,
+1 -7
View File
@@ -109,7 +109,7 @@ fn render_current(
#[task] #[task]
pub async fn display_task( pub async fn display_task(
parts: DisplayParts, parts: DisplayParts,
mut led: Option<LedDriver>, mut led: LedDriver,
status: &'static StatusWatch, status: &'static StatusWatch,
display_commands: &'static DisplayCommandChannel, display_commands: &'static DisplayCommandChannel,
) { ) {
@@ -176,7 +176,6 @@ pub async fn display_task(
let _ = display.flush().await; let _ = display.flush().await;
// Brief LED blink: red on TX, green scaled by SNR on RX // Brief LED blink: red on TX, green scaled by SNR on RX
if let Some(ref mut led) = led {
if tx_packet { if tx_packet {
led.set_rgb(32, 0, 0).await; led.set_rgb(32, 0, 0).await;
Timer::after_millis(50).await; Timer::after_millis(50).await;
@@ -189,17 +188,14 @@ pub async fn display_task(
} }
} }
} }
}
Either3::Second(cmd) => match cmd { Either3::Second(cmd) => match cmd {
DisplayCommand::Off => { DisplayCommand::Off => {
state.disconnected = false; state.disconnected = false;
state.display_on = false; state.display_on = false;
render::blank(&mut display); render::blank(&mut display);
let _ = display.flush().await; let _ = display.flush().await;
if let Some(ref mut led) = led {
led.set_rgb(0, 0, 0).await; led.set_rgb(0, 0, 0).await;
} }
}
DisplayCommand::On => { DisplayCommand::On => {
state.disconnected = false; state.disconnected = false;
state.display_on = true; state.display_on = true;
@@ -213,10 +209,8 @@ pub async fn display_task(
state = DisplayState::new(); state = DisplayState::new();
render::splash(&mut display, &board_info); render::splash(&mut display, &board_info);
let _ = display.flush().await; let _ = display.flush().await;
if let Some(ref mut led) = led {
led.set_rgb(0, 0, 0).await; led.set_rgb(0, 0, 0).await;
} }
}
}, },
Either3::Third(()) => { Either3::Third(()) => {
// Timer tick: advance sparkline slot // Timer tick: advance sparkline slot
+3
View File
@@ -1,2 +1,5 @@
#[cfg(feature = "wio_tracker_l1")] #[cfg(feature = "wio_tracker_l1")]
pub mod sh1106; pub mod sh1106;
#[cfg(any(feature = "heltec_v3", feature = "heltec_v3_uart", feature = "heltec_v4", feature = "wio_tracker_l1"))]
pub mod simple_led;
+20
View File
@@ -0,0 +1,20 @@
//! Simple single-color LED driver (GPIO on/off).
//!
//! Generic over any `OutputPin`. Any non-zero RGB value turns the LED on;
//! all zeros turns it off.
use embedded_hal::digital::OutputPin;
use crate::board::RgbLed;
pub struct SimpleLed<P>(pub P);
impl<P: OutputPin> RgbLed for SimpleLed<P> {
async fn set_rgb(&mut self, r: u8, g: u8, b: u8) {
if r > 0 || g > 0 || b > 0 {
let _ = self.0.set_high();
} else {
let _ = self.0.set_low();
}
}
}