From 41b5775268f0bca234c2042bc193e92edcc1acb5 Mon Sep 17 00:00:00 2001 From: Stephen Waits Date: Tue, 7 Apr 2026 12:37:31 -0600 Subject: [PATCH] refactor: unify SimpleLed via embedded-hal, remove Option from BoardParts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added embedded-hal 1.0 as direct dep (already transitive via embedded-hal-async) - SimpleLed 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 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 --- Cargo.lock | 1 + Cargo.toml | 1 + src/board/esp32s3.rs | 14 -------------- src/board/heltec_v3.rs | 6 +++--- src/board/heltec_v3_uart.rs | 6 +++--- src/board/heltec_v4.rs | 6 +++--- src/board/rak_wisblock_4631.rs | 2 +- src/board/traits.rs | 2 +- src/board/wio_tracker_l1.rs | 18 ++---------------- src/display.rs | 30 ++++++++++++------------------ src/driver/mod.rs | 3 +++ src/driver/simple_led.rs | 20 ++++++++++++++++++++ 12 files changed, 50 insertions(+), 59 deletions(-) create mode 100644 src/driver/simple_led.rs diff --git a/Cargo.lock b/Cargo.lock index ddb4ae3..2bcea85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -390,6 +390,7 @@ dependencies = [ "embassy-usb", "embassy-usb-driver", "embedded-graphics", + "embedded-hal 1.0.0", "embedded-hal-async", "embedded-io-async 0.7.0", "esp-backtrace", diff --git a/Cargo.toml b/Cargo.toml index 51e3745..623ab70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ categories = ["embedded", "hardware-support", "no-std"] cfg-if = "1.0" critical-section = "1.2" defmt = "1.0" +embedded-hal = "1.0" embedded-hal-async = "1.0" embassy-embedded-hal = "0.6" embassy-executor = "0.9" diff --git a/src/board/esp32s3.rs b/src/board/esp32s3.rs index 5e42792..1a1cda5 100644 --- a/src/board/esp32s3.rs +++ b/src/board/esp32s3.rs @@ -18,20 +18,6 @@ use crate::hal::esp32s3 as mcu; 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 ─────────────────────────────────────── type Nss = Output<'static>; diff --git a/src/board/heltec_v3.rs b/src/board/heltec_v3.rs index a63bf21..cec9e69 100644 --- a/src/board/heltec_v3.rs +++ b/src/board/heltec_v3.rs @@ -11,7 +11,7 @@ use static_cell::StaticCell; use super::esp32s3; use super::traits::{BoardParts, LoRaBoard}; -use super::esp32s3::SimpleLed; +use crate::driver::simple_led::SimpleLed; use crate::hal::esp32s3 as mcu; pub use super::esp32s3::{ @@ -19,7 +19,7 @@ pub use super::esp32s3::{ }; pub type UsbDriver = esp_hal::otg_fs::asynch::Driver<'static>; -pub type LedDriver = SimpleLed; +pub type LedDriver = SimpleLed>; pub struct UsbParts { pub driver: UsbDriver, @@ -84,7 +84,7 @@ impl LoRaBoard for Board { // White LED on GPIO35 let led_pin = Output::new(p.GPIO35, Level::Low, OutputConfig::default()); - let led = Some(SimpleLed(led_pin)); + let led = SimpleLed(led_pin); BoardParts { radio, diff --git a/src/board/heltec_v3_uart.rs b/src/board/heltec_v3_uart.rs index 7edb4f6..80c1b49 100644 --- a/src/board/heltec_v3_uart.rs +++ b/src/board/heltec_v3_uart.rs @@ -10,7 +10,7 @@ use esp_hal::gpio::{Level, Output, OutputConfig}; use super::esp32s3; use super::traits::{BoardParts, LoRaBoard}; -use super::esp32s3::SimpleLed; +use crate::driver::simple_led::SimpleLed; use crate::hal::esp32s3 as mcu; 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 LedDriver = SimpleLed; +pub type LedDriver = SimpleLed>; pub struct UartParts { pub driver: UartDriver, @@ -80,7 +80,7 @@ impl LoRaBoard for Board { // White LED on GPIO35 let led_pin = Output::new(p.GPIO35, Level::Low, OutputConfig::default()); - let led = Some(SimpleLed(led_pin)); + let led = SimpleLed(led_pin); BoardParts { radio, diff --git a/src/board/heltec_v4.rs b/src/board/heltec_v4.rs index ce79f01..3aa77c5 100644 --- a/src/board/heltec_v4.rs +++ b/src/board/heltec_v4.rs @@ -3,7 +3,7 @@ use static_cell::StaticCell; use super::esp32s3; use super::traits::{BoardParts, LoRaBoard}; -use super::esp32s3::SimpleLed; +use crate::driver::simple_led::SimpleLed; use crate::hal::esp32s3 as mcu; pub use super::esp32s3::{ @@ -12,7 +12,7 @@ pub use super::esp32s3::{ pub type UsbDriver = esp_hal::otg_fs::asynch::Driver<'static>; -pub type LedDriver = SimpleLed; +pub type LedDriver = SimpleLed>; pub struct UsbParts { pub driver: UsbDriver, @@ -77,7 +77,7 @@ impl LoRaBoard for Board { // Orange LED on GPIO35 let led_pin = Output::new(p.GPIO35, Level::Low, OutputConfig::default()); - let led = Some(SimpleLed(led_pin)); + let led = SimpleLed(led_pin); BoardParts { radio, diff --git a/src/board/rak_wisblock_4631.rs b/src/board/rak_wisblock_4631.rs index 3d694d8..c17ccc1 100644 --- a/src/board/rak_wisblock_4631.rs +++ b/src/board/rak_wisblock_4631.rs @@ -137,7 +137,7 @@ impl LoRaBoard for Board { radio, host, display, - led: None, + led: (), mac: Self::mac_address(), } } diff --git a/src/board/traits.rs b/src/board/traits.rs index 339af0f..28b6812 100644 --- a/src/board/traits.rs +++ b/src/board/traits.rs @@ -56,6 +56,6 @@ pub struct BoardParts { pub radio: R, pub host: C, pub display: Option, - pub led: Option, + pub led: L, pub mac: [u8; 6], } diff --git a/src/board/wio_tracker_l1.rs b/src/board/wio_tracker_l1.rs index 2c63cb8..ccf1c2b 100644 --- a/src/board/wio_tracker_l1.rs +++ b/src/board/wio_tracker_l1.rs @@ -21,21 +21,7 @@ pub type RadioDriver = Sx126x; pub type UsbDriver = mcu::UsbNrfDriver; pub type DisplayI2c = mcu::I2cBus; -// ── LED driver (green LED on P1.01) ───────────────────────────────── - -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 LedDriver = crate::driver::simple_led::SimpleLed>; pub type DisplayDriver = crate::driver::sh1106::Sh1106; @@ -148,7 +134,7 @@ impl LoRaBoard for Board { // Green LED on P1.01 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 { radio, diff --git a/src/display.rs b/src/display.rs index 48619a8..0d29ba7 100644 --- a/src/display.rs +++ b/src/display.rs @@ -109,7 +109,7 @@ fn render_current( #[task] pub async fn display_task( parts: DisplayParts, - mut led: Option, + mut led: LedDriver, status: &'static StatusWatch, display_commands: &'static DisplayCommandChannel, ) { @@ -176,17 +176,15 @@ pub async fn display_task( let _ = display.flush().await; // Brief LED blink: red on TX, green scaled by SNR on RX - if let Some(ref mut led) = led { - if tx_packet { - led.set_rgb(32, 0, 0).await; - Timer::after_millis(50).await; - led.set_rgb(0, 0, 0).await; - } else if rx_packet { - let b = snr_brightness(last_snr); - led.set_rgb(0, b, 0).await; - Timer::after_millis(50).await; - led.set_rgb(0, 0, 0).await; - } + if tx_packet { + led.set_rgb(32, 0, 0).await; + Timer::after_millis(50).await; + led.set_rgb(0, 0, 0).await; + } else if rx_packet { + let b = snr_brightness(last_snr); + led.set_rgb(0, b, 0).await; + Timer::after_millis(50).await; + led.set_rgb(0, 0, 0).await; } } } @@ -196,9 +194,7 @@ pub async fn display_task( state.display_on = false; render::blank(&mut display); 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 => { state.disconnected = false; @@ -213,9 +209,7 @@ pub async fn display_task( state = DisplayState::new(); render::splash(&mut display, &board_info); 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(()) => { diff --git a/src/driver/mod.rs b/src/driver/mod.rs index f895c6c..9a0f6a4 100644 --- a/src/driver/mod.rs +++ b/src/driver/mod.rs @@ -1,2 +1,5 @@ #[cfg(feature = "wio_tracker_l1")] pub mod sh1106; + +#[cfg(any(feature = "heltec_v3", feature = "heltec_v3_uart", feature = "heltec_v4", feature = "wio_tracker_l1"))] +pub mod simple_led; diff --git a/src/driver/simple_led.rs b/src/driver/simple_led.rs new file mode 100644 index 0000000..6839a0c --- /dev/null +++ b/src/driver/simple_led.rs @@ -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

(pub P); + +impl RgbLed for SimpleLed

{ + 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(); + } + } +}