2023-04-21 08:20:46 +02:00
|
|
|
#[cfg(feature = "stm32wl")]
|
2023-05-25 01:09:04 +02:00
|
|
|
use embassy_stm32::interrupt;
|
|
|
|
#[cfg(feature = "stm32wl")]
|
2023-06-08 16:08:40 +02:00
|
|
|
use embassy_stm32::interrupt::InterruptExt;
|
2023-04-21 08:20:46 +02:00
|
|
|
#[cfg(feature = "stm32wl")]
|
2023-05-25 01:09:04 +02:00
|
|
|
use embassy_stm32::pac;
|
2023-04-21 08:20:46 +02:00
|
|
|
#[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;
|
|
|
|
|
2023-05-25 01:09:04 +02:00
|
|
|
/// Interrupt handler.
|
|
|
|
#[cfg(feature = "stm32wl")]
|
|
|
|
pub struct InterruptHandler {}
|
|
|
|
|
|
|
|
#[cfg(feature = "stm32wl")]
|
2023-06-08 16:08:40 +02:00
|
|
|
impl interrupt::typelevel::Handler<interrupt::typelevel::SUBGHZ_RADIO> for InterruptHandler {
|
2023-05-25 01:09:04 +02:00
|
|
|
unsafe fn on_interrupt() {
|
2023-06-08 16:08:40 +02:00
|
|
|
interrupt::SUBGHZ_RADIO.disable();
|
2023-05-25 01:09:04 +02:00
|
|
|
IRQ_SIGNAL.signal(());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-21 08:20:46 +02:00
|
|
|
#[cfg(feature = "stm32wl")]
|
|
|
|
static IRQ_SIGNAL: Signal<CriticalSectionRawMutex, ()> = Signal::new();
|
|
|
|
|
|
|
|
#[cfg(feature = "stm32wl")]
|
|
|
|
/// Base for the InterfaceVariant implementation for an stm32wl/sx1262 combination
|
2023-05-25 01:09:04 +02:00
|
|
|
pub struct Stm32wlInterfaceVariant<CTRL> {
|
2023-04-21 08:20:46 +02:00
|
|
|
board_type: BoardType,
|
|
|
|
rf_switch_rx: Option<CTRL>,
|
|
|
|
rf_switch_tx: Option<CTRL>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "stm32wl")]
|
2023-05-25 01:09:04 +02:00
|
|
|
impl<'a, CTRL> Stm32wlInterfaceVariant<CTRL>
|
2023-04-21 08:20:46 +02:00
|
|
|
where
|
|
|
|
CTRL: OutputPin,
|
|
|
|
{
|
|
|
|
/// Create an InterfaceVariant instance for an stm32wl/sx1262 combination
|
|
|
|
pub fn new(
|
2023-06-08 16:08:40 +02:00
|
|
|
_irq: impl interrupt::typelevel::Binding<interrupt::typelevel::SUBGHZ_RADIO, InterruptHandler>,
|
2023-04-21 08:20:46 +02:00
|
|
|
rf_switch_rx: Option<CTRL>,
|
|
|
|
rf_switch_tx: Option<CTRL>,
|
|
|
|
) -> Result<Self, RadioError> {
|
2023-06-08 16:08:40 +02:00
|
|
|
interrupt::SUBGHZ_RADIO.disable();
|
2023-04-21 08:20:46 +02:00
|
|
|
Ok(Self {
|
|
|
|
board_type: BoardType::Stm32wlSx1262, // updated when associated with a specific LoRa board
|
|
|
|
rf_switch_rx,
|
|
|
|
rf_switch_tx,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "stm32wl")]
|
2023-05-25 01:09:04 +02:00
|
|
|
impl<CTRL> InterfaceVariant for Stm32wlInterfaceVariant<CTRL>
|
2023-04-21 08:20:46 +02:00
|
|
|
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> {
|
2023-09-18 03:00:59 +02:00
|
|
|
pac::PWR.subghzspicr().modify(|w| w.set_nss(false));
|
2023-04-21 08:20:46 +02:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
async fn set_nss_high(&mut self) -> Result<(), RadioError> {
|
2023-09-18 03:00:59 +02:00
|
|
|
pac::PWR.subghzspicr().modify(|w| w.set_nss(true));
|
2023-04-21 08:20:46 +02:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> {
|
2023-09-18 03:00:59 +02:00
|
|
|
pac::RCC.csr().modify(|w| w.set_rfrst(true));
|
|
|
|
pac::RCC.csr().modify(|w| w.set_rfrst(false));
|
2023-04-21 08:20:46 +02:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
async fn wait_on_busy(&mut self) -> Result<(), RadioError> {
|
2023-09-18 03:00:59 +02:00
|
|
|
while pac::PWR.sr2().read().rfbusys() {}
|
2023-04-21 08:20:46 +02:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn await_irq(&mut self) -> Result<(), RadioError> {
|
2023-06-08 16:08:40 +02:00
|
|
|
unsafe { interrupt::SUBGHZ_RADIO.enable() };
|
2023-04-21 08:20:46 +02:00
|
|
|
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<CTRL, WAIT> {
|
|
|
|
board_type: BoardType,
|
|
|
|
nss: CTRL,
|
|
|
|
reset: CTRL,
|
|
|
|
irq: WAIT,
|
|
|
|
rf_switch_rx: Option<CTRL>,
|
|
|
|
rf_switch_tx: Option<CTRL>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<CTRL, WAIT> Stm32l0InterfaceVariant<CTRL, WAIT>
|
|
|
|
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<CTRL>,
|
|
|
|
rf_switch_tx: Option<CTRL>,
|
|
|
|
) -> Result<Self, RadioError> {
|
|
|
|
Ok(Self {
|
|
|
|
board_type: BoardType::Stm32l0Sx1276, // updated when associated with a specific LoRa board
|
|
|
|
nss,
|
|
|
|
reset,
|
|
|
|
irq,
|
|
|
|
rf_switch_rx,
|
|
|
|
rf_switch_tx,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<CTRL, WAIT> InterfaceVariant for Stm32l0InterfaceVariant<CTRL, WAIT>
|
|
|
|
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<CTRL, WAIT> {
|
|
|
|
board_type: BoardType,
|
|
|
|
nss: CTRL,
|
|
|
|
reset: CTRL,
|
|
|
|
dio1: WAIT,
|
|
|
|
busy: WAIT,
|
|
|
|
rf_switch_rx: Option<CTRL>,
|
|
|
|
rf_switch_tx: Option<CTRL>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<CTRL, WAIT> GenericSx126xInterfaceVariant<CTRL, WAIT>
|
|
|
|
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<CTRL>,
|
|
|
|
rf_switch_tx: Option<CTRL>,
|
|
|
|
) -> Result<Self, RadioError> {
|
|
|
|
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<CTRL, WAIT> InterfaceVariant for GenericSx126xInterfaceVariant<CTRL, WAIT>
|
|
|
|
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> {
|
2023-09-13 00:53:27 +02:00
|
|
|
self.dio1.wait_for_high().await.map_err(|_| DIO1)?;
|
2023-04-21 08:20:46 +02:00
|
|
|
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(()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|