#[cfg(feature = "stm32wl")] use embassy_stm32::interrupt::*; #[cfg(feature = "stm32wl")] use embassy_stm32::{pac, PeripheralRef}; #[cfg(feature = "stm32wl")] use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; #[cfg(feature = "stm32wl")] use embassy_sync::signal::Signal; use embedded_hal::digital::v2::OutputPin; use embedded_hal_async::delay::DelayUs; use embedded_hal_async::digital::Wait; use lora_phy::mod_params::RadioError::*; use lora_phy::mod_params::{BoardType, RadioError}; use lora_phy::mod_traits::InterfaceVariant; #[cfg(feature = "stm32wl")] static IRQ_SIGNAL: Signal = Signal::new(); #[cfg(feature = "stm32wl")] /// Base for the InterfaceVariant implementation for an stm32wl/sx1262 combination pub struct Stm32wlInterfaceVariant<'a, CTRL> { board_type: BoardType, irq: PeripheralRef<'a, SUBGHZ_RADIO>, rf_switch_rx: Option, rf_switch_tx: Option, } #[cfg(feature = "stm32wl")] impl<'a, CTRL> Stm32wlInterfaceVariant<'a, CTRL> where CTRL: OutputPin, { /// Create an InterfaceVariant instance for an stm32wl/sx1262 combination pub fn new( irq: PeripheralRef<'a, SUBGHZ_RADIO>, rf_switch_rx: Option, rf_switch_tx: Option, ) -> Result { irq.disable(); irq.set_handler(Self::on_interrupt); Ok(Self { board_type: BoardType::Stm32wlSx1262, // updated when associated with a specific LoRa board irq, rf_switch_rx, rf_switch_tx, }) } fn on_interrupt(_: *mut ()) { unsafe { SUBGHZ_RADIO::steal() }.disable(); IRQ_SIGNAL.signal(()); } } #[cfg(feature = "stm32wl")] impl InterfaceVariant for Stm32wlInterfaceVariant<'_, CTRL> where CTRL: OutputPin, { fn set_board_type(&mut self, board_type: BoardType) { self.board_type = board_type; } async fn set_nss_low(&mut self) -> Result<(), RadioError> { let pwr = pac::PWR; unsafe { pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::LOW)); } Ok(()) } async fn set_nss_high(&mut self) -> Result<(), RadioError> { let pwr = pac::PWR; unsafe { pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::HIGH)); } Ok(()) } async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> { let rcc = pac::RCC; unsafe { rcc.csr().modify(|w| w.set_rfrst(true)); rcc.csr().modify(|w| w.set_rfrst(false)); } Ok(()) } async fn wait_on_busy(&mut self) -> Result<(), RadioError> { let pwr = pac::PWR; while unsafe { pwr.sr2().read().rfbusys() == pac::pwr::vals::Rfbusys::BUSY } {} Ok(()) } async fn await_irq(&mut self) -> Result<(), RadioError> { self.irq.enable(); IRQ_SIGNAL.wait().await; Ok(()) } async fn enable_rf_switch_rx(&mut self) -> Result<(), RadioError> { match &mut self.rf_switch_tx { Some(pin) => pin.set_low().map_err(|_| RfSwitchTx)?, None => (), }; match &mut self.rf_switch_rx { Some(pin) => pin.set_high().map_err(|_| RfSwitchRx), None => Ok(()), } } async fn enable_rf_switch_tx(&mut self) -> Result<(), RadioError> { match &mut self.rf_switch_rx { Some(pin) => pin.set_low().map_err(|_| RfSwitchRx)?, None => (), }; match &mut self.rf_switch_tx { Some(pin) => pin.set_high().map_err(|_| RfSwitchTx), None => Ok(()), } } async fn disable_rf_switch(&mut self) -> Result<(), RadioError> { match &mut self.rf_switch_rx { Some(pin) => pin.set_low().map_err(|_| RfSwitchRx)?, None => (), }; match &mut self.rf_switch_tx { Some(pin) => pin.set_low().map_err(|_| RfSwitchTx), None => Ok(()), } } } /// Base for the InterfaceVariant implementation for an stm32l0/sx1276 combination pub struct Stm32l0InterfaceVariant { board_type: BoardType, nss: CTRL, reset: CTRL, irq: WAIT, rf_switch_rx: Option, rf_switch_tx: Option, } impl Stm32l0InterfaceVariant where CTRL: OutputPin, WAIT: Wait, { /// Create an InterfaceVariant instance for an stm32l0/sx1276 combination pub fn new( nss: CTRL, reset: CTRL, irq: WAIT, rf_switch_rx: Option, rf_switch_tx: Option, ) -> Result { Ok(Self { board_type: BoardType::Stm32l0Sx1276, // updated when associated with a specific LoRa board nss, reset, irq, rf_switch_rx, rf_switch_tx, }) } } impl InterfaceVariant for Stm32l0InterfaceVariant where CTRL: OutputPin, WAIT: Wait, { fn set_board_type(&mut self, board_type: BoardType) { self.board_type = board_type; } async fn set_nss_low(&mut self) -> Result<(), RadioError> { self.nss.set_low().map_err(|_| NSS) } async fn set_nss_high(&mut self) -> Result<(), RadioError> { self.nss.set_high().map_err(|_| NSS) } async fn reset(&mut self, delay: &mut impl DelayUs) -> Result<(), RadioError> { delay.delay_ms(10).await; self.reset.set_low().map_err(|_| Reset)?; delay.delay_ms(10).await; self.reset.set_high().map_err(|_| Reset)?; delay.delay_ms(10).await; Ok(()) } async fn wait_on_busy(&mut self) -> Result<(), RadioError> { Ok(()) } async fn await_irq(&mut self) -> Result<(), RadioError> { self.irq.wait_for_high().await.map_err(|_| Irq) } async fn enable_rf_switch_rx(&mut self) -> Result<(), RadioError> { match &mut self.rf_switch_tx { Some(pin) => pin.set_low().map_err(|_| RfSwitchTx)?, None => (), }; match &mut self.rf_switch_rx { Some(pin) => pin.set_high().map_err(|_| RfSwitchRx), None => Ok(()), } } async fn enable_rf_switch_tx(&mut self) -> Result<(), RadioError> { match &mut self.rf_switch_rx { Some(pin) => pin.set_low().map_err(|_| RfSwitchRx)?, None => (), }; match &mut self.rf_switch_tx { Some(pin) => pin.set_high().map_err(|_| RfSwitchTx), None => Ok(()), } } async fn disable_rf_switch(&mut self) -> Result<(), RadioError> { match &mut self.rf_switch_rx { Some(pin) => pin.set_low().map_err(|_| RfSwitchRx)?, None => (), }; match &mut self.rf_switch_tx { Some(pin) => pin.set_low().map_err(|_| RfSwitchTx), None => Ok(()), } } } /// Base for the InterfaceVariant implementation for a generic Sx126x LoRa board pub struct GenericSx126xInterfaceVariant { board_type: BoardType, nss: CTRL, reset: CTRL, dio1: WAIT, busy: WAIT, rf_switch_rx: Option, rf_switch_tx: Option, } impl GenericSx126xInterfaceVariant where CTRL: OutputPin, WAIT: Wait, { /// Create an InterfaceVariant instance for an nrf52840/sx1262 combination pub fn new( nss: CTRL, reset: CTRL, dio1: WAIT, busy: WAIT, rf_switch_rx: Option, rf_switch_tx: Option, ) -> Result { Ok(Self { board_type: BoardType::Rak4631Sx1262, // updated when associated with a specific LoRa board nss, reset, dio1, busy, rf_switch_rx, rf_switch_tx, }) } } impl InterfaceVariant for GenericSx126xInterfaceVariant where CTRL: OutputPin, WAIT: Wait, { fn set_board_type(&mut self, board_type: BoardType) { self.board_type = board_type; } async fn set_nss_low(&mut self) -> Result<(), RadioError> { self.nss.set_low().map_err(|_| NSS) } async fn set_nss_high(&mut self) -> Result<(), RadioError> { self.nss.set_high().map_err(|_| NSS) } async fn reset(&mut self, delay: &mut impl DelayUs) -> Result<(), RadioError> { delay.delay_ms(10).await; self.reset.set_low().map_err(|_| Reset)?; delay.delay_ms(20).await; self.reset.set_high().map_err(|_| Reset)?; delay.delay_ms(10).await; Ok(()) } async fn wait_on_busy(&mut self) -> Result<(), RadioError> { self.busy.wait_for_low().await.map_err(|_| Busy) } async fn await_irq(&mut self) -> Result<(), RadioError> { if self.board_type != BoardType::RpPicoWaveshareSx1262 { self.dio1.wait_for_high().await.map_err(|_| DIO1)?; } else { self.dio1.wait_for_rising_edge().await.map_err(|_| DIO1)?; } Ok(()) } async fn enable_rf_switch_rx(&mut self) -> Result<(), RadioError> { match &mut self.rf_switch_tx { Some(pin) => pin.set_low().map_err(|_| RfSwitchTx)?, None => (), }; match &mut self.rf_switch_rx { Some(pin) => pin.set_high().map_err(|_| RfSwitchRx), None => Ok(()), } } async fn enable_rf_switch_tx(&mut self) -> Result<(), RadioError> { match &mut self.rf_switch_rx { Some(pin) => pin.set_low().map_err(|_| RfSwitchRx)?, None => (), }; match &mut self.rf_switch_tx { Some(pin) => pin.set_high().map_err(|_| RfSwitchTx), None => Ok(()), } } async fn disable_rf_switch(&mut self) -> Result<(), RadioError> { match &mut self.rf_switch_rx { Some(pin) => pin.set_low().map_err(|_| RfSwitchRx)?, None => (), }; match &mut self.rf_switch_tx { Some(pin) => pin.set_low().map_err(|_| RfSwitchTx), None => Ok(()), } } }