1#![allow(missing_docs)]
2
3use super::mod_params::{PacketParams, RadioError};
4use super::mod_traits::RadioKind;
5use super::{DelayNs, LoRa, RxMode};
6
7use lora_modulation::BaseBandModulationParams;
8use lorawan_device::async_device::{
9 radio::{PhyRxTx, RxConfig, RxMode as LorawanRxMode, RxQuality, RxStatus, TxConfig},
10 Timings,
11};
12
13const DEFAULT_RX_WINDOW_LEAD_TIME: u32 = 50;
14
15pub struct LorawanRadio<RK, DLY, const P: u8, const G: i8 = 0>
20where
21 RK: RadioKind,
22 DLY: DelayNs,
23{
24 pub(crate) lora: LoRa<RK, DLY>,
25 rx_pkt_params: Option<PacketParams>,
26 rx_window_lead_time: u32,
27 rx_window_buffer: u32,
28}
29
30impl<RK, DLY, const P: u8, const G: i8> From<LoRa<RK, DLY>> for LorawanRadio<RK, DLY, P, G>
31where
32 RK: RadioKind,
33 DLY: DelayNs,
34{
35 fn from(lora: LoRa<RK, DLY>) -> Self {
36 Self {
37 lora,
38 rx_pkt_params: None,
39 rx_window_lead_time: DEFAULT_RX_WINDOW_LEAD_TIME,
40 rx_window_buffer: DEFAULT_RX_WINDOW_LEAD_TIME,
41 }
42 }
43}
44
45impl<RK, DLY, const P: u8, const G: i8> LorawanRadio<RK, DLY, P, G>
46where
47 RK: RadioKind,
48 DLY: DelayNs,
49{
50 pub fn set_rx_window_lead_time(&mut self, lt: u32) {
51 self.rx_window_lead_time = lt;
52 }
53 pub fn set_rx_window_buffer(&mut self, buffer: u32) {
54 self.rx_window_buffer = buffer;
55 }
56}
57
58impl<RK, DLY, const P: u8, const G: i8> Timings for LorawanRadio<RK, DLY, P, G>
60where
61 RK: RadioKind,
62 DLY: DelayNs,
63{
64 fn get_rx_window_buffer(&self) -> u32 {
65 self.rx_window_lead_time
66 }
67
68 fn get_rx_window_lead_time_ms(&self) -> u32 {
69 self.rx_window_lead_time
70 }
71}
72
73#[derive(Debug, defmt::Format)]
74pub enum Error {
75 Radio(RadioError),
76 NoRxParams,
77}
78
79impl From<RadioError> for Error {
80 fn from(err: RadioError) -> Self {
81 Error::Radio(err)
82 }
83}
84
85impl<RK, DLY, const P: u8, const G: i8> PhyRxTx for LorawanRadio<RK, DLY, P, G>
88where
89 RK: RadioKind,
90 DLY: DelayNs,
91{
92 type PhyError = Error;
93
94 const ANTENNA_GAIN: i8 = G;
95
96 const MAX_RADIO_POWER: u8 = P;
97
98 async fn tx(&mut self, config: TxConfig, buffer: &[u8]) -> Result<u32, Self::PhyError> {
99 let mdltn_params = self.lora.create_modulation_params(
100 config.rf.bb.sf,
101 config.rf.bb.bw,
102 config.rf.bb.cr,
103 config.rf.frequency,
104 )?;
105 let mut tx_pkt_params = self
106 .lora
107 .create_tx_packet_params(8, false, true, false, &mdltn_params)?;
108
109 self.lora
110 .prepare_for_tx(&mdltn_params, &mut tx_pkt_params, config.pw.into(), buffer)
111 .await?;
112 self.lora.tx().await?;
113 Ok(0)
114 }
115
116 async fn setup_rx(&mut self, config: RxConfig) -> Result<(), Self::PhyError> {
117 let mdltn_params = self.lora.create_modulation_params(
118 config.rf.bb.sf,
119 config.rf.bb.bw,
120 config.rf.bb.cr,
121 config.rf.frequency,
122 )?;
123 let rx_pkt_params = self
124 .lora
125 .create_rx_packet_params(8, false, 255, true, true, &mdltn_params)?;
126 self.lora
127 .prepare_for_rx(RxMode::from(config.mode, config.rf.bb), &mdltn_params, &rx_pkt_params)
128 .await?;
129 self.rx_pkt_params = Some(rx_pkt_params);
130 Ok(())
131 }
132
133 async fn rx_single(&mut self, buf: &mut [u8]) -> Result<RxStatus, Self::PhyError> {
134 if let Some(rx_params) = &self.rx_pkt_params {
135 match self.lora.rx(rx_params, buf).await {
136 Ok((len, q)) => Ok(RxStatus::Rx(len as usize, RxQuality::new(q.rssi, q.snr as i8))),
137 Err(RadioError::ReceiveTimeout) => Ok(RxStatus::RxTimeout),
138 Err(err) => Err(err.into()),
139 }
140 } else {
141 Err(Error::NoRxParams)
142 }
143 }
144 async fn rx_continuous(&mut self, receiving_buffer: &mut [u8]) -> Result<(usize, RxQuality), Self::PhyError> {
145 if let Some(rx_params) = &self.rx_pkt_params {
146 match self.lora.rx(rx_params, receiving_buffer).await {
147 Ok((received_len, rx_pkt_status)) => {
148 Ok((
149 received_len as usize,
150 RxQuality::new(rx_pkt_status.rssi, rx_pkt_status.snr as i8), ))
152 }
153 Err(err) => Err(err.into()),
154 }
155 } else {
156 Err(Error::NoRxParams)
157 }
158 }
159 async fn low_power(&mut self) -> Result<(), Self::PhyError> {
160 self.lora.sleep(false).await.map_err(|e| e.into())
161 }
162}
163
164impl RxMode {
165 fn from(mode: LorawanRxMode, bb: BaseBandModulationParams) -> Self {
166 match mode {
167 LorawanRxMode::Continuous => RxMode::Continuous,
168 LorawanRxMode::Single { ms } => {
169 const PREAMBLE_SYMBOLS: u16 = 13; let num_symbols = PREAMBLE_SYMBOLS + bb.delay_in_symbols(ms);
173 RxMode::Single(num_symbols)
174 }
175 }
176 }
177}