//! Shared types and peripheral wiring for ESP32-S3 boards. //! //! Delegates MCU-level init to `hal::esp32s3` and defines peripheral-level //! types (RadioDriver, display) used by ESP32-S3 board files. //! Each board defines its own comm types (UsbParts/UartParts) directly. use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_time::Delay; use esp_hal::gpio::{Input, InputConfig, Level, Output, OutputConfig, Pull}; use lora_phy::iv::GenericSx126xInterfaceVariant; use lora_phy::sx126x::{self, Sx1262, Sx126x}; use crate::hal::esp32s3 as mcu; // ── Re-export MCU types ───────────────────────────────────────────── 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>; type Iv = GenericSx126xInterfaceVariant, Input<'static>>; type RadioSpiDevice = SpiDevice<'static, NoopRawMutex, SpiBus, Nss>; pub type RadioDriver = Sx126x; // ── Peripheral bundles ────────────────────────────────────────────── pub struct RadioParts { pub driver: RadioDriver, pub delay: Delay, } pub struct DisplayParts { pub i2c: DisplayI2c, } // ── 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. pub fn init_radio( spi_bus: &'static embassy_sync::mutex::Mutex, nss_pin: esp_hal::peripherals::GPIO8<'static>, reset_pin: esp_hal::peripherals::GPIO12<'static>, dio1_pin: esp_hal::peripherals::GPIO14<'static>, busy_pin: esp_hal::peripherals::GPIO13<'static>, ) -> RadioParts { let nss = Output::new(nss_pin, Level::High, OutputConfig::default()); let spi_device = SpiDevice::new(spi_bus, nss); let reset = Output::new(reset_pin, Level::High, OutputConfig::default()); let dio1 = Input::new(dio1_pin, InputConfig::default().with_pull(Pull::Down)); let busy = Input::new(busy_pin, InputConfig::default().with_pull(Pull::Down)); let iv = GenericSx126xInterfaceVariant::new(reset, dio1, busy, None, None) .expect("SX1262 interface init"); let sx_config = sx126x::Config { chip: Sx1262, tcxo_ctrl: Some(sx126x::TcxoCtrlVoltage::Ctrl1V8), use_dcdc: true, rx_boost: false, }; RadioParts { driver: Sx126x::new(spi_device, iv, sx_config), delay: Delay, } }