diff --git a/firmware/src/board/esp32s3.rs b/firmware/src/board/esp32s3.rs index 5026991a..dfb6d59a 100644 --- a/firmware/src/board/esp32s3.rs +++ b/firmware/src/board/esp32s3.rs @@ -47,6 +47,34 @@ pub struct DisplayParts { pub mac: [u8; 6], } +// ── Display driver ────────────────────────────────────────────────── + +pub type DisplayDriver = ssd1306::Ssd1306Async< + ssd1306::prelude::I2CInterface, + ssd1306::size::DisplaySize128x64, + ssd1306::mode::BufferedGraphicsModeAsync, +>; + +/// Construct and initialize an SSD1306 display from raw I2C. +pub async fn create_display(i2c: DisplayI2c) -> Option { + use ssd1306::mode::DisplayConfigAsync; + use ssd1306::prelude::{Brightness, DisplayRotation}; + use ssd1306::size::DisplaySize128x64; + use ssd1306::{I2CDisplayInterface, Ssd1306Async}; + + let interface = I2CDisplayInterface::new(i2c); + let mut display = Ssd1306Async::new(interface, DisplaySize128x64, DisplayRotation::Rotate0) + .into_buffered_graphics_mode(); + + embassy_time::Timer::after_millis(100).await; + if display.init().await.is_err() { + defmt::error!("SSD1306 display init failed"); + return None; + } + let _ = display.set_brightness(Brightness::BRIGHTEST).await; + Some(display) +} + // ── Shared peripheral init helpers ────────────────────────────────── /// Construct SX1262 radio from an initialized SPI bus. diff --git a/firmware/src/board/heltec_v3.rs b/firmware/src/board/heltec_v3.rs index 4c089a82..8b717262 100644 --- a/firmware/src/board/heltec_v3.rs +++ b/firmware/src/board/heltec_v3.rs @@ -5,7 +5,10 @@ use super::traits::LoRaBoard; use crate::hal::esp32s3 as mcu; #[allow(unused_imports)] // Re-exported for other modules (display, radio, uart tasks) -pub use super::esp32s3::{DisplayI2c, DisplayParts, RadioDriver, RadioParts, UartDriver, UartParts}; +pub use super::esp32s3::{ + create_display, DisplayDriver, DisplayI2c, DisplayParts, RadioDriver, RadioParts, UartDriver, + UartParts, +}; // ── Board init ────────────────────────────────────────────────────── diff --git a/firmware/src/board/heltec_v4.rs b/firmware/src/board/heltec_v4.rs index c1872e30..607e90be 100644 --- a/firmware/src/board/heltec_v4.rs +++ b/firmware/src/board/heltec_v4.rs @@ -5,7 +5,10 @@ use super::traits::LoRaBoard; use crate::hal::esp32s3 as mcu; #[allow(unused_imports)] // Re-exported for other modules (display, radio, usb tasks) -pub use super::esp32s3::{DisplayI2c, DisplayParts, RadioDriver, RadioParts, UsbDriver, UsbParts}; +pub use super::esp32s3::{ + create_display, DisplayDriver, DisplayI2c, DisplayParts, RadioDriver, RadioParts, UsbDriver, + UsbParts, +}; // ── Board implementation ──────────────────────────────────────────── diff --git a/firmware/src/board/rak_wisblock_4631.rs b/firmware/src/board/rak_wisblock_4631.rs index 5dc937e7..e9808fe4 100644 --- a/firmware/src/board/rak_wisblock_4631.rs +++ b/firmware/src/board/rak_wisblock_4631.rs @@ -21,6 +21,31 @@ pub type RadioDriver = Sx126x; pub type UsbDriver = mcu::UsbNrfDriver; pub type DisplayI2c = mcu::I2cBus; +pub type DisplayDriver = ssd1306::Ssd1306Async< + ssd1306::prelude::I2CInterface, + ssd1306::size::DisplaySize128x64, + ssd1306::mode::BufferedGraphicsModeAsync, +>; + +pub async fn create_display(i2c: DisplayI2c) -> Option { + use ssd1306::mode::DisplayConfigAsync; + use ssd1306::prelude::{Brightness, DisplayRotation}; + use ssd1306::size::DisplaySize128x64; + use ssd1306::{I2CDisplayInterface, Ssd1306Async}; + + let interface = I2CDisplayInterface::new(i2c); + let mut display = Ssd1306Async::new(interface, DisplaySize128x64, DisplayRotation::Rotate0) + .into_buffered_graphics_mode(); + + embassy_time::Timer::after_millis(100).await; + if display.init().await.is_err() { + defmt::error!("SSD1306 display init failed"); + return None; + } + let _ = display.set_brightness(Brightness::BRIGHTEST).await; + Some(display) +} + // ── Peripheral bundles ────────────────────────────────────────────── pub struct RadioParts { diff --git a/firmware/src/board/wio_tracker_l1.rs b/firmware/src/board/wio_tracker_l1.rs index 464c901f..b1ac908b 100644 --- a/firmware/src/board/wio_tracker_l1.rs +++ b/firmware/src/board/wio_tracker_l1.rs @@ -21,6 +21,20 @@ pub type RadioDriver = Sx126x; pub type UsbDriver = mcu::UsbNrfDriver; pub type DisplayI2c = mcu::I2cBus; +pub type DisplayDriver = crate::driver::sh1106::Sh1106; + +pub async fn create_display(i2c: DisplayI2c) -> Option { + let mut display = crate::driver::sh1106::Sh1106::new(i2c, 0x3D); + + embassy_time::Timer::after_millis(100).await; + if display.init().await.is_err() { + defmt::error!("SH1106 display init failed"); + return None; + } + let _ = display.set_brightness(0xFF).await; + Some(display) +} + // ── Peripheral bundles ────────────────────────────────────────────── pub struct RadioParts { diff --git a/firmware/src/display.rs b/firmware/src/display.rs index 4a735611..998daa30 100644 --- a/firmware/src/display.rs +++ b/firmware/src/display.rs @@ -123,52 +123,10 @@ pub async fn display_task( mac: &mac_str, }; - cfg_if::cfg_if! { - if #[cfg(feature = "wio_tracker_l1")] { - let mut display = crate::driver::sh1106::Sh1106::new(parts.i2c, 0x3D); - - Timer::after_millis(100).await; - - if display.init().await.is_err() { - defmt::error!("SH1106 init failed — retrying"); - Timer::after_millis(500).await; - if display.init().await.is_err() { - defmt::error!("SH1106 init failed twice, giving up"); - return; - } - } - if display.set_brightness(0xFF).await.is_err() { - defmt::warn!("display brightness set failed"); - } - } else { - use ssd1306::mode::DisplayConfigAsync; - use ssd1306::prelude::DisplayRotation; - use ssd1306::size::DisplaySize128x64; - use ssd1306::{I2CDisplayInterface, Ssd1306Async}; - - let interface = I2CDisplayInterface::new(parts.i2c); - let mut display = Ssd1306Async::new(interface, DisplaySize128x64, DisplayRotation::Rotate0) - .into_buffered_graphics_mode(); - - Timer::after_millis(100).await; - - if display.init().await.is_err() { - defmt::error!("SSD1306 init failed — retrying"); - Timer::after_millis(500).await; - if display.init().await.is_err() { - defmt::error!("SSD1306 init failed twice, giving up"); - return; - } - } - if display - .set_brightness(ssd1306::prelude::Brightness::BRIGHTEST) - .await - .is_err() - { - defmt::warn!("display brightness set failed"); - } - } - } + let Some(mut display) = crate::board::create_display(parts.i2c).await else { + defmt::error!("display init failed, giving up"); + return; + }; let mut state = DisplayState::new(); let Some(mut receiver) = status.receiver() else {