From feb23d4a6a8a29edd9bd8a7a9542d1b2948e3cb8 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Fri, 20 Oct 2023 11:24:13 +0300 Subject: [PATCH 1/6] sx1261: Use driver specific configuration struct instead of BoardType Instead of using lora-phy's BoardType/ChipType enum, switch to driver-specific configuration struct. --- src/sx1261_2/mod.rs | 83 +++++++++++++++++++------------ src/sx1261_2/radio_kind_params.rs | 1 - 2 files changed, 51 insertions(+), 33 deletions(-) diff --git a/src/sx1261_2/mod.rs b/src/sx1261_2/mod.rs index 4eb3334..21543b0 100644 --- a/src/sx1261_2/mod.rs +++ b/src/sx1261_2/mod.rs @@ -31,10 +31,32 @@ const SX126X_MAX_LORA_SYMB_NUM_TIMEOUT: u8 = 248; // Time required for the TCXO to wakeup [ms]. const BRD_TCXO_WAKEUP_TIME: u32 = 10; +/// Supported SX126x chip variants +#[derive(Clone, PartialEq)] +pub enum Sx126xVariant { + /// Semtech SX1261 + Sx1261, + /// Semtech SX1261 + Sx1262, + /// STM32WL System-On-Chip with SX126x-based sub-GHz radio + Stm32wl, // XXX: Drop and switch to board-specific configuration? + // STM32 manuals don't really specify which sx126x chip is used. + // Original code in set_tx_power_and_ramp_time assumes Sx1262-specific power rates +} + +/// Configuration for SX126x-based boards +pub struct Config { + /// LoRa chip variant on this board + pub chip: Sx126xVariant, + /// Configuration for TCXO and its voltage selection + pub txco_ctrl: Option, +} + /// Base for the RadioKind implementation for the LoRa chip kind and board type pub struct SX1261_2 { board_type: BoardType, intf: SpiInterface, + config: Config, } impl SX1261_2 @@ -43,10 +65,14 @@ where IV: InterfaceVariant, { /// Create an instance of the RadioKind implementation for the LoRa chip kind and board type - pub fn new(board_type: BoardType, spi: SPI, mut iv: IV) -> Self { + pub fn new(board_type: BoardType, spi: SPI, mut iv: IV, config: Config) -> Self { iv.set_board_type(board_type); let intf = SpiInterface::new(spi, iv); - Self { board_type, intf } + Self { + board_type, + intf, + config, + } } // Utility functions @@ -233,7 +259,7 @@ where // Use DIO2 to control an RF Switch, depending on the board type. async fn init_rf_switch(&mut self) -> Result<(), RadioError> { - if self.board_type != BoardType::Stm32wlSx1262 { + if self.config.chip != Sx126xVariant::Stm32wl { let op_code_and_indicator = [OpCode::SetRFSwitchMode.value(), true as u8]; self.intf.write(&op_code_and_indicator, false).await?; } @@ -289,30 +315,19 @@ where } async fn set_oscillator(&mut self) -> Result<(), RadioError> { - // voltage used to control the TCXO on/off from DIO3 - let voltage = match self.board_type { - BoardType::CustomBoard | BoardType::Stm32l0Sx1276 => { - return Err(RadioError::BoardTypeUnsupportedForRadioKind); - } - BoardType::Rak3172Sx1262 => { - // uses XTAL instead of TCXO - return Ok(()); - } - BoardType::GenericSx1261 - | BoardType::RpPicoWaveshareSx1262 - | BoardType::Rak4631Sx1262 - | BoardType::Stm32wlSx1262 => TcxoCtrlVoltage::Ctrl1V7, - BoardType::HeltecWifiLoraV31262 => TcxoCtrlVoltage::Ctrl1V8, - }; - let timeout = BRD_TCXO_WAKEUP_TIME << 6; // duration allowed for TCXO to reach 32MHz - let op_code_and_tcxo_control = [ - OpCode::SetTCXOMode.value(), - voltage.value() & 0x07, - Self::timeout_1(timeout), - Self::timeout_2(timeout), - Self::timeout_3(timeout), - ]; - self.intf.write(&op_code_and_tcxo_control, false).await + if let Some(voltage) = self.config.txco_ctrl { + let timeout = BRD_TCXO_WAKEUP_TIME << 6; // duration allowed for TCXO to reach 32MHz + let op_code_and_tcxo_control = [ + OpCode::SetTCXOMode.value(), + voltage.value() & 0x07, + Self::timeout_1(timeout), + Self::timeout_2(timeout), + Self::timeout_3(timeout), + ]; + self.intf.write(&op_code_and_tcxo_control, false).await?; + } + + Ok(()) } // Set the power regulators operating mode to DC_DC. Using only LDO implies that the Rx/Tx current is doubled. @@ -355,8 +370,9 @@ where false => RampTime::Ramp200Us, // for instance, on initialization }; - let chip_type: ChipType = self.board_type.into(); - if chip_type == ChipType::Sx1261 { + // TODO: Switch to match so all chip variants are covered + let chip_type = &self.config.chip; + if chip_type == &Sx126xVariant::Sx1261 { if !(-17..=15).contains(&output_power) { return Err(RadioError::InvalidOutputPower); } @@ -812,7 +828,8 @@ where self.intf.write(&op_code_and_masks, false).await } - /// Process the radio IRQ. Log unexpected interrupts, but only bail out on timeout. Packets from other devices can cause unexpected interrupts. + /// Process the radio IRQ. Log unexpected interrupts, but only bail out on timeout. + /// Packets from other devices can cause unexpected interrupts. async fn process_irq( &mut self, radio_mode: RadioMode, @@ -965,8 +982,10 @@ where /// The random numbers produced by the generator do not have a uniform or Gaussian distribution. /// If uniformity is needed, perform appropriate software post-processing. async fn get_random_number(&mut self) -> Result { - // The stm32wl often returns 0 on the first random number generation operation. Documentation for the stm32wl does not recommend LNA register modification. - if self.board_type == BoardType::Stm32wlSx1262 { + // The stm32wl often returns 0 on the first random number generation operation. + // Documentation for the stm32wl does not recommend LNA register modification. + // XXX: Ideally this should result in a compile-time error... + if self.config.chip == Sx126xVariant::Stm32wl { return Err(RadioError::RngUnsupported); } self.set_irq_params(None).await?; diff --git a/src/sx1261_2/radio_kind_params.rs b/src/sx1261_2/radio_kind_params.rs index e56839f..9cac6c6 100644 --- a/src/sx1261_2/radio_kind_params.rs +++ b/src/sx1261_2/radio_kind_params.rs @@ -208,7 +208,6 @@ impl CalibrationParams { } #[derive(Clone, Copy)] -#[allow(dead_code)] pub enum TcxoCtrlVoltage { Ctrl1V6 = 0x00, Ctrl1V7 = 0x01, From 78c734104e9eea08de1668fa7a5ef28321dc3f24 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Fri, 20 Oct 2023 11:29:32 +0300 Subject: [PATCH 2/6] sx127x: Use driver specific configuration struct instead of BoardType Instead of using lora-phy's BoardType/ChipType enum, switch to driver-specific configuration struct. --- src/sx1276_7_8_9/mod.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/sx1276_7_8_9/mod.rs b/src/sx1276_7_8_9/mod.rs index 5d33eff..aeafb1e 100644 --- a/src/sx1276_7_8_9/mod.rs +++ b/src/sx1276_7_8_9/mod.rs @@ -19,10 +19,21 @@ const TCXO_FOR_OSCILLATOR: u8 = 0x10u8; // Frequency synthesizer step for frequency calculation (Hz) const FREQUENCY_SYNTHESIZER_STEP: f64 = 61.03515625; // FXOSC (32 MHz) * 1000000 (Hz/MHz) / 524288 (2^19) +/// Supported SX127x chip variants for further device-specific customizations +/// Currently SX1276, SX1277, SX1278 and SX1279 are supported +pub enum Sx127xVariant {} + +/// Configuration for SX127x-based boards +pub struct Config { + /// LoRa chip variant on this board + pub chip: Sx127xVariant, +} + /// Base for the RadioKind implementation for the LoRa chip kind and board type pub struct SX1276_7_8_9 { board_type: BoardType, intf: SpiInterface, + _config: Config, } impl SX1276_7_8_9 @@ -31,10 +42,10 @@ where IV: InterfaceVariant, { /// Create an instance of the RadioKind implementation for the LoRa chip kind and board type - pub fn new(board_type: BoardType, spi: SPI, mut iv: IV) -> Self { + pub fn new(board_type: BoardType, spi: SPI, mut iv: IV, _config: Config) -> Self { iv.set_board_type(board_type); let intf = SpiInterface::new(spi, iv); - Self { board_type, intf } + Self { board_type, intf, _config } } // Utility functions From 5954eb47781440276f2d52d36b8a4d09e49b0c81 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Fri, 20 Oct 2023 11:53:39 +0300 Subject: [PATCH 3/6] Drop ChipType enum Now that all drivers are using board configuration structure, we can drop global ChipType enum. --- src/mod_params.rs | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/src/mod_params.rs b/src/mod_params.rs index 3781e0a..ec1c8c7 100644 --- a/src/mod_params.rs +++ b/src/mod_params.rs @@ -70,34 +70,6 @@ pub enum BoardType { Stm32wlSx1262, } -/// LoRa chips supported by this crate -#[derive(Clone, Copy, PartialEq)] -#[allow(missing_docs)] -pub enum ChipType { - CustomChip, - Sx1261, - Sx1262, - Sx1276, - Sx1277, - Sx1278, - Sx1279, -} - -impl From for ChipType { - fn from(board_type: BoardType) -> Self { - match board_type { - BoardType::CustomBoard => ChipType::CustomChip, - BoardType::GenericSx1261 => ChipType::Sx1261, - BoardType::HeltecWifiLoraV31262 => ChipType::Sx1262, - BoardType::RpPicoWaveshareSx1262 => ChipType::Sx1262, - BoardType::Rak4631Sx1262 => ChipType::Sx1262, - BoardType::Rak3172Sx1262 => ChipType::Sx1262, - BoardType::Stm32l0Sx1276 => ChipType::Sx1276, - BoardType::Stm32wlSx1262 => ChipType::Sx1262, - } - } -} - /// The state of the radio #[derive(Clone, Copy, defmt::Format, PartialEq)] #[allow(missing_docs)] From 4aec19b677792229d46c72fcf2fe6e02dc8c3d98 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Fri, 20 Oct 2023 11:58:03 +0300 Subject: [PATCH 4/6] Drop BoardType enum Now that all drivers are using board configuration structure, we can drop global BoardType enum. --- src/lib.rs | 5 ----- src/mod_params.rs | 18 ------------------ src/mod_traits.rs | 4 ---- src/sx1261_2/mod.rs | 14 ++------------ src/sx1276_7_8_9/mod.rs | 10 ++-------- 5 files changed, 4 insertions(+), 47 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f59a0f3..1d98e4a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,11 +61,6 @@ where Ok(lora) } - /// Get the board type of the LoRa board - pub fn get_board_type(&self) -> BoardType { - self.radio_kind.get_board_type() - } - /// Create modulation parameters for a communication channel pub fn create_modulation_params( &mut self, diff --git a/src/mod_params.rs b/src/mod_params.rs index ec1c8c7..c6d4ce3 100644 --- a/src/mod_params.rs +++ b/src/mod_params.rs @@ -52,24 +52,6 @@ pub struct PacketStatus { pub snr: i16, } -/// LoRa boards supported by this crate. -/// In addition, custom boards (possibly proprietary) can be supported by using the custom board and chip types and -/// external implementations of the RadioKind and (in some cases) InterfaceVariant traits. For instance: -/// let iv = ExternalInterfaceVariantImpl::new(..params...) -/// LoRa::new(ExternalRadioKindImpl::new(BoardType::CustomBoard, spi, iv), ...other_params...) -#[derive(Clone, Copy, PartialEq)] -#[allow(missing_docs)] -pub enum BoardType { - CustomBoard, - GenericSx1261, // placeholder for Sx1261-specific features - HeltecWifiLoraV31262, - RpPicoWaveshareSx1262, - Rak4631Sx1262, - Rak3172Sx1262, - Stm32l0Sx1276, - Stm32wlSx1262, -} - /// The state of the radio #[derive(Clone, Copy, defmt::Format, PartialEq)] #[allow(missing_docs)] diff --git a/src/mod_traits.rs b/src/mod_traits.rs index 68eb9a5..dd9a802 100644 --- a/src/mod_traits.rs +++ b/src/mod_traits.rs @@ -5,8 +5,6 @@ use crate::mod_params::*; /// Functions implemented for an embedded framework for an MCU/LoRa chip combination /// to allow this crate to control the LoRa chip. pub trait InterfaceVariant { - /// Set the LoRa board type - fn set_board_type(&mut self, board_type: BoardType); /// Reset the LoRa chip async fn reset(&mut self, delay: &mut impl DelayUs) -> Result<(), RadioError>; /// Wait for the LoRa chip to become available for an operation @@ -42,8 +40,6 @@ pub enum IrqState { /// Functions implemented for a specific kind of LoRa chip, called internally by the outward facing /// LoRa physical layer API pub trait RadioKind { - /// Get the specific type of the LoRa board (for example, Stm32wlSx1262) - fn get_board_type(&self) -> BoardType; /// Create modulation parameters specific to the LoRa chip kind and type fn create_modulation_params( &self, diff --git a/src/sx1261_2/mod.rs b/src/sx1261_2/mod.rs index 21543b0..de20b68 100644 --- a/src/sx1261_2/mod.rs +++ b/src/sx1261_2/mod.rs @@ -54,7 +54,6 @@ pub struct Config { /// Base for the RadioKind implementation for the LoRa chip kind and board type pub struct SX1261_2 { - board_type: BoardType, intf: SpiInterface, config: Config, } @@ -65,14 +64,9 @@ where IV: InterfaceVariant, { /// Create an instance of the RadioKind implementation for the LoRa chip kind and board type - pub fn new(board_type: BoardType, spi: SPI, mut iv: IV, config: Config) -> Self { - iv.set_board_type(board_type); + pub fn new(spi: SPI, iv: IV, config: Config) -> Self { let intf = SpiInterface::new(spi, iv); - Self { - board_type, - intf, - config, - } + Self { intf, config } } // Utility functions @@ -182,10 +176,6 @@ where SPI: SpiDevice, IV: InterfaceVariant, { - fn get_board_type(&self) -> BoardType { - self.board_type - } - fn create_modulation_params( &self, spreading_factor: SpreadingFactor, diff --git a/src/sx1276_7_8_9/mod.rs b/src/sx1276_7_8_9/mod.rs index aeafb1e..68eb5ec 100644 --- a/src/sx1276_7_8_9/mod.rs +++ b/src/sx1276_7_8_9/mod.rs @@ -31,7 +31,6 @@ pub struct Config { /// Base for the RadioKind implementation for the LoRa chip kind and board type pub struct SX1276_7_8_9 { - board_type: BoardType, intf: SpiInterface, _config: Config, } @@ -42,10 +41,9 @@ where IV: InterfaceVariant, { /// Create an instance of the RadioKind implementation for the LoRa chip kind and board type - pub fn new(board_type: BoardType, spi: SPI, mut iv: IV, _config: Config) -> Self { - iv.set_board_type(board_type); + pub fn new(spi: SPI, iv: IV, _config: Config) -> Self { let intf = SpiInterface::new(spi, iv); - Self { board_type, intf, _config } + Self { intf, _config } } // Utility functions @@ -91,10 +89,6 @@ where SPI: SpiDevice, IV: InterfaceVariant, { - fn get_board_type(&self) -> BoardType { - self.board_type - } - fn create_modulation_params( &self, spreading_factor: SpreadingFactor, From 8ee9b2df8ee03472ab0544a70ddb17f20a6ba4af Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Wed, 25 Oct 2023 17:02:03 +0300 Subject: [PATCH 5/6] Drop unneeded BoardTypeUnsupportedForRadioKind error Now that BoardType/ChipType has been removed, we can drop unused BoardTypeUnsupportedForRadioKind error kind. --- src/mod_params.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mod_params.rs b/src/mod_params.rs index c6d4ce3..03479db 100644 --- a/src/mod_params.rs +++ b/src/mod_params.rs @@ -5,7 +5,7 @@ pub use lora_modulation::{Bandwidth, CodingRate, SpreadingFactor}; /// Errors types reported during LoRa physical layer processing #[allow(clippy::upper_case_acronyms)] #[derive(Debug, defmt::Format, PartialEq)] -#[allow(dead_code, missing_docs)] +#[allow(missing_docs)] pub enum RadioError { SPI, Reset, @@ -41,7 +41,6 @@ pub enum RadioError { DutyCycleRxContinuousUnsupported, CADUnexpected, RngUnsupported, - BoardTypeUnsupportedForRadioKind, } /// Status for a received packet From a930c39fb3f7ec4f3b97b16a7e60218d7f510db7 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Wed, 25 Oct 2023 17:02:40 +0300 Subject: [PATCH 6/6] Update README regarding BoardType/ChipType removal --- README.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/README.md b/README.md index 3462462..e7577e9 100644 --- a/README.md +++ b/README.md @@ -58,13 +58,7 @@ Example RadioKind implementations and ancillary information: ## LoRa board-specific support -LoRa boards use LoRa chip features differently. To suppport these variations within a radio kind implementation, BoardType and ChipType are available: - -- scroll to BoardType and ChipType. - -One can add a LoRa board (the board name includes the chip type in case the board may include a range of chip types) and the ChipType, then modify the radio kind processing to support board-specific features. The ChipType is used for generic checks, alleviating the need to add a new board type check in places where a generic check will do. BoardType checks only need to be implemented where the specificity is board-related. There are examples of each type of check here: - -- search for BoardType and ChipType. +Board-specific configuration can be handled via the chip driver specific Config struct. ## Chat