1mod radio_kind_params;
2mod sx1272;
3pub use sx1272::Sx1272;
4mod sx1276;
5pub use sx1276::Sx1276;
6
7use defmt::debug;
8use embedded_hal_async::delay::DelayNs;
9use embedded_hal_async::spi::*;
10use radio_kind_params::*;
11
12use crate::mod_params::*;
13use crate::mod_traits::IrqState;
14use crate::{InterfaceVariant, RadioKind, SpiInterface};
15
16const LORA_MAC_PUBLIC_SYNCWORD: u8 = 0x34; const LORA_MAC_PRIVATE_SYNCWORD: u8 = 0x12; const TCXO_FOR_OSCILLATOR: u8 = 0x10u8;
22
23const FREQUENCY_SYNTHESIZER_STEP: f64 = 61.03515625; const SX127X_MIN_LORA_SYMB_NUM_TIMEOUT: u16 = 4;
28const SX127X_MAX_LORA_SYMB_NUM_TIMEOUT: u16 = 1023;
29
30const SX1272_RSSI_OFFSET: i16 = -139;
32const SX1276_RSSI_OFFSET_LF: i16 = -164;
33const SX1276_RSSI_OFFSET_HF: i16 = -157;
34const SX1276_RF_MID_BAND_THRESH: u32 = 525_000_000;
35
36pub struct Config<C: Sx127xVariant> {
38 pub chip: C,
40 pub tcxo_used: bool,
42 pub tx_boost: bool,
45 pub rx_boost: bool,
47}
48
49pub struct Sx127x<SPI, IV, C: Sx127xVariant + Sized> {
51 intf: SpiInterface<SPI, IV>,
52 config: Config<C>,
53}
54
55impl<SPI, IV, C> Sx127x<SPI, IV, C>
56where
57 SPI: SpiDevice<u8>,
58 IV: InterfaceVariant,
59 C: Sx127xVariant,
60{
61 pub fn new(spi: SPI, iv: IV, config: Config<C>) -> Self {
63 let intf = SpiInterface::new(spi, iv);
64 Self { intf, config }
65 }
66
67 async fn write_register(&mut self, register: Register, value: u8) -> Result<(), RadioError> {
69 let write_buffer = [register.write_addr(), value];
70 self.intf.write(&write_buffer, false).await
71 }
72
73 async fn read_register(&mut self, register: Register) -> Result<u8, RadioError> {
74 let write_buffer = [register.read_addr()];
75 let mut read_buffer = [0x00u8];
76 self.intf.read(&write_buffer, &mut read_buffer).await?;
77 Ok(read_buffer[0])
78 }
79
80 async fn read_buffer(&mut self, register: Register, buf: &mut [u8]) -> Result<(), RadioError> {
81 self.intf.read(&[register.read_addr()], buf).await
82 }
83
84 async fn write_buffer(&mut self, register: Register, buf: &[u8]) -> Result<(), RadioError> {
85 self.intf.write_with_payload(&[register.write_addr()], buf, false).await
86 }
87
88 async fn set_lora_symbol_num_timeout(&mut self, symbol_num: u16) -> Result<(), RadioError> {
90 let val = symbol_num.min(SX127X_MAX_LORA_SYMB_NUM_TIMEOUT);
91
92 let symbol_num_msb = ((val >> 8) & 0x03) as u8;
93 let symbol_num_lsb = (val & 0xff) as u8;
94 let mut config_2 = self.read_register(Register::RegModemConfig2).await?;
95 config_2 = (config_2 & 0xfcu8) | symbol_num_msb;
96 self.write_register(Register::RegModemConfig2, config_2).await?;
97 self.write_register(Register::RegSymbTimeoutLsb, symbol_num_lsb).await
98 }
99
100 async fn set_ocp(&mut self, ocp_trim: OcpTrim) -> Result<(), RadioError> {
102 self.write_register(Register::RegOcp, ocp_trim.value()).await
103 }
104}
105
106impl<SPI, IV, C> RadioKind for Sx127x<SPI, IV, C>
107where
108 SPI: SpiDevice<u8>,
109 IV: InterfaceVariant,
110 C: Sx127xVariant,
111{
112 async fn init_lora(&mut self, is_public_network: bool) -> Result<(), RadioError> {
113 if self.config.tcxo_used {
114 self.write_register(C::reg_txco(), TCXO_FOR_OSCILLATOR).await?;
115 }
116
117 let syncword = if is_public_network {
118 LORA_MAC_PUBLIC_SYNCWORD
119 } else {
120 LORA_MAC_PRIVATE_SYNCWORD
121 };
122 self.write_register(Register::RegSyncWord, syncword).await?;
123
124 self.set_tx_rx_buffer_base_address(0, 0).await?;
125 Ok(())
126 }
127
128 fn create_modulation_params(
129 &self,
130 spreading_factor: SpreadingFactor,
131 bandwidth: Bandwidth,
132 coding_rate: CodingRate,
133 frequency_in_hz: u32,
134 ) -> Result<ModulationParams, RadioError> {
135 spreading_factor_value(spreading_factor)?;
137 coding_rate_value(coding_rate)?;
138 C::bandwidth_value(bandwidth)?;
139 if ((bandwidth == Bandwidth::_250KHz) || (bandwidth == Bandwidth::_500KHz)) && (frequency_in_hz < 400_000_000) {
140 return Err(RadioError::InvalidBandwidthForFrequency);
141 }
142
143 let bw_in_hz = u32::from(bandwidth);
145 let symbol_duration = 1000 / (bw_in_hz / (0x01u32 << spreading_factor_value(spreading_factor)?));
146 let mut low_data_rate_optimize = 0x00u8;
147 if symbol_duration > 16 {
148 low_data_rate_optimize = 0x01u8
149 }
150
151 Ok(ModulationParams {
152 spreading_factor,
153 bandwidth,
154 coding_rate,
155 low_data_rate_optimize,
156 frequency_in_hz,
157 })
158 }
159
160 fn create_packet_params(
161 &self,
162 preamble_length: u16,
163 implicit_header: bool,
164 payload_length: u8,
165 crc_on: bool,
166 iq_inverted: bool,
167 modulation_params: &ModulationParams,
168 ) -> Result<PacketParams, RadioError> {
169 if (modulation_params.spreading_factor == SpreadingFactor::_6) && !implicit_header {
171 return Err(RadioError::InvalidSF6ExplicitHeaderRequest);
172 }
173
174 Ok(PacketParams {
175 preamble_length,
176 implicit_header,
177 payload_length,
178 crc_on,
179 iq_inverted,
180 })
181 }
182
183 async fn reset(&mut self, delay: &mut impl DelayNs) -> Result<(), RadioError> {
184 self.intf.iv.reset(delay).await?;
185 self.set_sleep(false, delay).await?; Ok(())
187 }
188
189 async fn ensure_ready(&mut self, _mode: RadioMode) -> Result<(), RadioError> {
190 Ok(())
191 }
192
193 async fn set_standby(&mut self) -> Result<(), RadioError> {
194 self.write_register(Register::RegOpMode, LoRaMode::Standby.value())
195 .await?;
196 self.intf.iv.disable_rf_switch().await
197 }
198
199 async fn set_sleep(&mut self, _warm_start_if_possible: bool, _delay: &mut impl DelayNs) -> Result<(), RadioError> {
200 self.intf.iv.disable_rf_switch().await?;
202 let buf = [Register::RegOpMode.write_addr(), LoRaMode::Sleep.value()];
203 self.intf.write(&buf, true).await?;
205
206 Ok(())
207 }
208
209 async fn set_tx_rx_buffer_base_address(
210 &mut self,
211 tx_base_addr: usize,
212 rx_base_addr: usize,
213 ) -> Result<(), RadioError> {
214 if tx_base_addr > 255 || rx_base_addr > 255 {
215 return Err(RadioError::InvalidBaseAddress(tx_base_addr, rx_base_addr));
216 }
217 self.write_register(Register::RegFifoTxBaseAddr, 0x00u8).await?;
218 self.write_register(Register::RegFifoRxBaseAddr, 0x00u8).await
219 }
220
221 async fn set_tx_power_and_ramp_time(
227 &mut self,
228 p_out: i32,
229 _mdltn_params: Option<&ModulationParams>,
230 is_tx_prep: bool,
231 ) -> Result<(), RadioError> {
232 debug!("tx power = {}", p_out);
233
234 C::set_tx_power(self, p_out, self.config.tx_boost).await?;
236
237 let ramp_time = match is_tx_prep {
238 true => RampTime::Ramp40Us, false => RampTime::Ramp250Us, };
241
242 let val = C::ramp_value(ramp_time);
243 self.write_register(Register::RegPaRamp, val).await
244 }
245
246 async fn set_modulation_params(&mut self, mdltn_params: &ModulationParams) -> Result<(), RadioError> {
247 let sf_val = spreading_factor_value(mdltn_params.spreading_factor)?;
248 let bw_val = C::bandwidth_value(mdltn_params.bandwidth)?;
249 let coding_rate_denominator_val = coding_rate_denominator_value(mdltn_params.coding_rate)?;
250 debug!(
251 "sf = {}, bw = {}, cr_denom = {}",
252 sf_val, bw_val, coding_rate_denominator_val
253 );
254 let (opt, thr) = match mdltn_params.spreading_factor {
256 SpreadingFactor::_6 => (0x05, 0x0c),
257 _ => (0x03, 0x0a),
258 };
259 let reg_val = self.read_register(Register::RegDetectionOptimize).await?;
260 let val = (reg_val & 0b0111_1000) | opt;
262 self.write_register(Register::RegDetectionOptimize, val).await?;
263 self.write_register(Register::RegDetectionThreshold, thr).await?;
264 C::set_modulation_params(self, mdltn_params).await?;
267
268 Ok(())
269 }
270
271 async fn set_packet_params(&mut self, pkt_params: &PacketParams) -> Result<(), RadioError> {
272 self.write_register(
273 Register::RegPreambleMsb,
274 ((pkt_params.preamble_length >> 8) & 0x00ff) as u8,
275 )
276 .await?;
277 self.write_register(Register::RegPreambleLsb, (pkt_params.preamble_length & 0x00ff) as u8)
278 .await?;
279
280 C::set_packet_params(self, pkt_params).await?;
281
282 let (iq1, iq2) = match pkt_params.iq_inverted {
290 true => (1 << 6, 0x19),
291 false => (1 << 0, 0x1d),
292 };
293 self.write_register(Register::RegInvertiq, (0x13 << 1) | iq1).await?;
295 self.write_register(Register::RegInvertiq2, iq2).await?;
296 Ok(())
297 }
298
299 async fn calibrate_image(&mut self, _frequency_in_hz: u32) -> Result<(), RadioError> {
301 Ok(())
303 }
304
305 async fn set_channel(&mut self, frequency_in_hz: u32) -> Result<(), RadioError> {
306 debug!("channel = {}", frequency_in_hz);
307 let frf = (frequency_in_hz as f64 / FREQUENCY_SYNTHESIZER_STEP) as u32;
308 self.write_register(Register::RegFrfMsb, ((frf & 0x00FF0000) >> 16) as u8)
309 .await?;
310 self.write_register(Register::RegFrfMid, ((frf & 0x0000FF00) >> 8) as u8)
311 .await?;
312 self.write_register(Register::RegFrfLsb, (frf & 0x000000FF) as u8).await
313 }
314
315 async fn set_payload(&mut self, payload: &[u8]) -> Result<(), RadioError> {
316 self.write_register(Register::RegFifoAddrPtr, 0x00u8).await?;
317 self.write_register(Register::RegPayloadLength, 0x00u8).await?;
318 self.write_buffer(Register::RegFifo, payload).await?;
319 self.write_register(Register::RegPayloadLength, payload.len() as u8)
320 .await
321 }
322
323 async fn do_tx(&mut self) -> Result<(), RadioError> {
324 self.intf.iv.enable_rf_switch_tx().await?;
325
326 self.write_register(Register::RegOpMode, LoRaMode::Tx.value()).await
327 }
328
329 async fn do_rx(&mut self, rx_mode: RxMode) -> Result<(), RadioError> {
330 let (num_symbols, mode) = match rx_mode {
331 RxMode::DutyCycle(_) => Err(RadioError::DutyCycleUnsupported),
332 RxMode::Single(ns) => Ok((ns.max(SX127X_MIN_LORA_SYMB_NUM_TIMEOUT), LoRaMode::RxSingle)),
333 RxMode::Continuous => Ok((0, LoRaMode::RxContinuous)),
334 }?;
335
336 self.intf.iv.enable_rf_switch_rx().await?;
337
338 self.set_lora_symbol_num_timeout(num_symbols).await?;
339
340 let lna_gain = if self.config.rx_boost {
341 LnaGain::G1.boosted_value()
342 } else {
343 LnaGain::G1.value()
344 };
345 self.write_register(Register::RegLna, lna_gain).await?;
346
347 self.write_register(Register::RegFifoAddrPtr, 0x00u8).await?;
348 self.write_register(Register::RegPayloadLength, 0xffu8).await?;
349
350 self.write_register(Register::RegOpMode, mode.value()).await
351 }
352
353 async fn get_rx_payload(
354 &mut self,
355 _rx_pkt_params: &PacketParams,
356 receiving_buffer: &mut [u8],
357 ) -> Result<u8, RadioError> {
358 let payload_length = self.read_register(Register::RegRxNbBytes).await?;
359 if (payload_length as usize) > receiving_buffer.len() {
360 return Err(RadioError::PayloadSizeMismatch(
361 payload_length as usize,
362 receiving_buffer.len(),
363 ));
364 }
365 let fifo_addr = self.read_register(Register::RegFifoRxCurrentAddr).await?;
366 self.write_register(Register::RegFifoAddrPtr, fifo_addr).await?;
367 self.read_buffer(Register::RegFifo, &mut receiving_buffer[0..payload_length as usize])
368 .await?;
369 self.write_register(Register::RegFifoAddrPtr, 0x00u8).await?;
370
371 Ok(payload_length)
372 }
373
374 async fn get_rx_packet_status(&mut self) -> Result<PacketStatus, RadioError> {
375 let snr = {
376 let packet_snr = self.read_register(Register::RegPktSnrValue).await?;
377 packet_snr as i8 as i16 / 4
378 };
379
380 let rssi = {
381 let packet_rssi = self.read_register(Register::RegPktRssiValue).await?;
382
383 let rssi_offset = C::rssi_offset(self).await?;
384
385 if snr >= 0 {
386 rssi_offset + (packet_rssi as f32 * 16.0 / 15.0) as i16
387 } else {
388 rssi_offset + (packet_rssi as i16) + snr
389 }
390 };
391
392 Ok(PacketStatus { rssi, snr })
393 }
394
395 async fn do_cad(&mut self, _mdltn_params: &ModulationParams) -> Result<(), RadioError> {
396 self.intf.iv.enable_rf_switch_rx().await?;
397
398 let mut lna_gain_final = LnaGain::G1.value();
399 if self.config.rx_boost {
400 lna_gain_final = LnaGain::G1.boosted_value();
401 }
402 self.write_register(Register::RegLna, lna_gain_final).await?;
403
404 self.write_register(Register::RegOpMode, LoRaMode::Cad.value()).await
405 }
406
407 async fn set_irq_params(&mut self, radio_mode: Option<RadioMode>) -> Result<(), RadioError> {
411 match radio_mode {
412 Some(RadioMode::Transmit) => {
413 self.write_register(
414 Register::RegIrqFlagsMask,
415 IrqMask::All.value() ^ IrqMask::TxDone.value(),
416 )
417 .await?;
418
419 let mut dio_mapping_1 = self.read_register(Register::RegDioMapping1).await?;
420 dio_mapping_1 = (dio_mapping_1 & DioMapping1Dio0::Mask.value()) | DioMapping1Dio0::TxDone.value();
421 self.write_register(Register::RegDioMapping1, dio_mapping_1).await?;
422
423 self.write_register(Register::RegIrqFlags, 0x00u8).await?;
424 }
425 Some(RadioMode::Receive(_)) => {
426 self.write_register(
427 Register::RegIrqFlagsMask,
428 IrqMask::All.value()
429 ^ (IrqMask::RxDone.value()
430 | IrqMask::RxTimeout.value()
431 | IrqMask::CRCError.value()
432 | IrqMask::HeaderValid.value()),
433 )
434 .await?;
435
436 let dio_mapping_1 = self.read_register(Register::RegDioMapping1).await?;
441 let val = (dio_mapping_1 & DioMapping1Dio0::Mask.value() & DioMapping1Dio3::Mask.value())
442 | (DioMapping1Dio0::RxDone.value() | DioMapping1Dio3::ValidHeader.value());
443 self.write_register(Register::RegDioMapping1, val).await?;
444
445 self.write_register(Register::RegIrqFlags, 0x00u8).await?;
446 }
447 Some(RadioMode::ChannelActivityDetection) => {
448 self.write_register(
449 Register::RegIrqFlagsMask,
450 IrqMask::All.value() ^ (IrqMask::CADDone.value() | IrqMask::CADActivityDetected.value()),
451 )
452 .await?;
453
454 let mut dio_mapping_1 = self.read_register(Register::RegDioMapping1).await?;
455 dio_mapping_1 = (dio_mapping_1 & DioMapping1Dio0::Mask.value()) | DioMapping1Dio0::CadDone.value();
456 self.write_register(Register::RegDioMapping1, dio_mapping_1).await?;
457
458 self.write_register(Register::RegIrqFlags, 0x00u8).await?;
459 }
460 _ => {
461 self.write_register(Register::RegIrqFlagsMask, IrqMask::All.value())
462 .await?;
463
464 let mut dio_mapping_1 = self.read_register(Register::RegDioMapping1).await?;
465 dio_mapping_1 = (dio_mapping_1 & DioMapping1Dio0::Mask.value()) | DioMapping1Dio0::Other.value();
466 self.write_register(Register::RegDioMapping1, dio_mapping_1).await?;
467 self.write_register(Register::RegIrqFlags, 0xffu8).await?;
468 }
469 }
470
471 Ok(())
472 }
473
474 async fn await_irq(&mut self) -> Result<(), RadioError> {
475 self.intf.iv.await_irq().await
476 }
477
478 async fn process_irq_event(
484 &mut self,
485 radio_mode: RadioMode,
486 cad_activity_detected: Option<&mut bool>,
487 clear_interrupts: bool,
488 ) -> Result<Option<IrqState>, RadioError> {
489 let irq_flags = self.read_register(Register::RegIrqFlags).await?;
490 if clear_interrupts {
491 self.write_register(Register::RegIrqFlags, 0xffu8).await?; }
493
494 match radio_mode {
495 RadioMode::Transmit => {
496 if (irq_flags & IrqMask::TxDone.value()) == IrqMask::TxDone.value() {
497 debug!("TxDone in radio mode {}", radio_mode);
498 return Ok(Some(IrqState::Done));
499 }
500 }
501 RadioMode::Receive(RxMode::Continuous) | RadioMode::Receive(RxMode::Single(_)) => {
502 if (irq_flags & IrqMask::RxDone.value()) == IrqMask::RxDone.value() {
503 debug!("RxDone in radio mode {}", radio_mode);
504 return Ok(Some(IrqState::Done));
505 }
506 if (irq_flags & IrqMask::RxTimeout.value()) == IrqMask::RxTimeout.value() {
507 debug!("RxTimeout in radio mode {}", radio_mode);
508 return Err(RadioError::ReceiveTimeout);
509 }
510 if IrqMask::HeaderValid.is_set_in(irq_flags) {
511 debug!("HeaderValid in radio mode {}", radio_mode);
512 return Ok(Some(IrqState::PreambleReceived));
513 }
514 }
515 RadioMode::ChannelActivityDetection => {
516 if (irq_flags & IrqMask::CADDone.value()) == IrqMask::CADDone.value() {
517 debug!("CADDone in radio mode {}", radio_mode);
518 if cad_activity_detected.is_some() {
520 *(cad_activity_detected.unwrap()) =
522 (irq_flags & IrqMask::CADActivityDetected.value()) == IrqMask::CADActivityDetected.value();
523 }
524 return Ok(Some(IrqState::Done));
525 }
526 }
527 RadioMode::Sleep | RadioMode::Standby => {
528 defmt::warn!("IRQ during sleep/standby?");
529 }
530 RadioMode::FrequencySynthesis => todo!(),
531 RadioMode::Receive(RxMode::DutyCycle(_)) => todo!(),
532 }
533
534 Ok(None)
536 }
537 async fn set_tx_continuous_wave_mode(&mut self) -> Result<(), RadioError> {
539 C::set_tx_continuous_wave_mode(self).await
540 }
541}