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 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 3781e0a..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 @@ -52,52 +51,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, -} - -/// 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)] 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 4eb3334..de20b68 100644 --- a/src/sx1261_2/mod.rs +++ b/src/sx1261_2/mod.rs @@ -31,10 +31,31 @@ 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 +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) -> 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 } + Self { intf, config } } // Utility functions @@ -156,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, @@ -233,7 +249,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 +305,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 +360,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 +818,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 +972,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, diff --git a/src/sx1276_7_8_9/mod.rs b/src/sx1276_7_8_9/mod.rs index 5d33eff..68eb5ec 100644 --- a/src/sx1276_7_8_9/mod.rs +++ b/src/sx1276_7_8_9/mod.rs @@ -19,10 +19,20 @@ 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 +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) -> 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 } + Self { intf, _config } } // Utility functions @@ -80,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,