for u8 {
- fn from(ht: HseTrim) -> Self {
- ht.val
- }
-}
-
-impl Default for HseTrim {
- fn default() -> Self {
- Self::POR
- }
-}
diff --git a/embassy-stm32/src/subghz/irq.rs b/embassy-stm32/src/subghz/irq.rs
deleted file mode 100644
index b56b8ad9..00000000
--- a/embassy-stm32/src/subghz/irq.rs
+++ /dev/null
@@ -1,292 +0,0 @@
-/// Interrupt lines.
-///
-/// Argument of [`CfgIrq::irq_enable`] and [`CfgIrq::irq_disable`].
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum IrqLine {
- /// Global interrupt.
- Global,
- /// Interrupt line 1.
- ///
- /// This will output to the [`RfIrq0`](crate::gpio::RfIrq0) pin.
- Line1,
- /// Interrupt line 2.
- ///
- /// This will output to the [`RfIrq1`](crate::gpio::RfIrq1) pin.
- Line2,
- /// Interrupt line 3.
- ///
- /// This will output to the [`RfIrq2`](crate::gpio::RfIrq2) pin.
- Line3,
-}
-
-impl IrqLine {
- pub(super) const fn offset(&self) -> usize {
- match self {
- IrqLine::Global => 1,
- IrqLine::Line1 => 3,
- IrqLine::Line2 => 5,
- IrqLine::Line3 => 7,
- }
- }
-}
-
-/// IRQ bit mapping
-///
-/// See table 37 "IRQ bit mapping and definition" in the reference manual for
-/// more information.
-#[repr(u16)]
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum Irq {
- /// Packet transmission finished.
- ///
- /// * Packet type: LoRa and GFSK
- /// * Operation: TX
- TxDone = (1 << 0),
- /// Packet reception finished.
- ///
- /// * Packet type: LoRa and GFSK
- /// * Operation: RX
- RxDone = (1 << 1),
- /// Preamble detected.
- ///
- /// * Packet type: LoRa and GFSK
- /// * Operation: RX
- PreambleDetected = (1 << 2),
- /// Synchronization word valid.
- ///
- /// * Packet type: GFSK
- /// * Operation: RX
- SyncDetected = (1 << 3),
- /// Header valid.
- ///
- /// * Packet type: LoRa
- /// * Operation: RX
- HeaderValid = (1 << 4),
- /// Header CRC error.
- ///
- /// * Packet type: LoRa
- /// * Operation: RX
- HeaderErr = (1 << 5),
- /// Dual meaning error.
- ///
- /// For GFSK RX this indicates a preamble, syncword, address, CRC, or length
- /// error.
- ///
- /// For LoRa RX this indicates a CRC error.
- Err = (1 << 6),
- /// Channel activity detection finished.
- ///
- /// * Packet type: LoRa
- /// * Operation: CAD
- CadDone = (1 << 7),
- /// Channel activity detected.
- ///
- /// * Packet type: LoRa
- /// * Operation: CAD
- CadDetected = (1 << 8),
- /// RX or TX timeout.
- ///
- /// * Packet type: LoRa and GFSK
- /// * Operation: RX and TX
- Timeout = (1 << 9),
-}
-
-impl Irq {
- /// Get the bitmask for an IRQ.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::Irq;
- ///
- /// assert_eq!(Irq::TxDone.mask(), 0x0001);
- /// assert_eq!(Irq::Timeout.mask(), 0x0200);
- /// ```
- pub const fn mask(self) -> u16 {
- self as u16
- }
-}
-
-/// Argument for [`set_irq_cfg`].
-///
-/// [`set_irq_cfg`]: crate::subghz::SubGhz::set_irq_cfg
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct CfgIrq {
- buf: [u8; 9],
-}
-
-impl CfgIrq {
- /// Create a new `CfgIrq`.
- ///
- /// This is the same as `default`, but in a `const` function.
- ///
- /// The default value has all interrupts disabled on all lines.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::CfgIrq;
- ///
- /// const IRQ_CFG: CfgIrq = CfgIrq::new();
- /// ```
- pub const fn new() -> CfgIrq {
- CfgIrq {
- buf: [
- super::OpCode::CfgDioIrq as u8,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- ],
- }
- }
-
- /// Enable an interrupt.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{CfgIrq, Irq, IrqLine};
- ///
- /// const IRQ_CFG: CfgIrq = CfgIrq::new()
- /// .irq_enable(IrqLine::Global, Irq::TxDone)
- /// .irq_enable(IrqLine::Global, Irq::Timeout);
- /// # assert_eq!(IRQ_CFG.as_slice()[1], 0x02);
- /// # assert_eq!(IRQ_CFG.as_slice()[2], 0x01);
- /// # assert_eq!(IRQ_CFG.as_slice()[3], 0x00);
- /// ```
- #[must_use = "irq_enable returns a modified CfgIrq"]
- pub const fn irq_enable(mut self, line: IrqLine, irq: Irq) -> CfgIrq {
- let mask: u16 = irq as u16;
- let offset: usize = line.offset();
- self.buf[offset] |= ((mask >> 8) & 0xFF) as u8;
- self.buf[offset + 1] |= (mask & 0xFF) as u8;
- self
- }
-
- /// Enable an interrupt on all lines.
- ///
- /// As far as I can tell with empirical testing all IRQ lines need to be
- /// enabled for the internal interrupt to be pending in the NVIC.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{CfgIrq, Irq};
- ///
- /// const IRQ_CFG: CfgIrq = CfgIrq::new()
- /// .irq_enable_all(Irq::TxDone)
- /// .irq_enable_all(Irq::Timeout);
- /// # assert_eq!(IRQ_CFG.as_slice()[1], 0x02);
- /// # assert_eq!(IRQ_CFG.as_slice()[2], 0x01);
- /// # assert_eq!(IRQ_CFG.as_slice()[3], 0x02);
- /// # assert_eq!(IRQ_CFG.as_slice()[4], 0x01);
- /// # assert_eq!(IRQ_CFG.as_slice()[5], 0x02);
- /// # assert_eq!(IRQ_CFG.as_slice()[6], 0x01);
- /// # assert_eq!(IRQ_CFG.as_slice()[7], 0x02);
- /// # assert_eq!(IRQ_CFG.as_slice()[8], 0x01);
- /// ```
- #[must_use = "irq_enable_all returns a modified CfgIrq"]
- pub const fn irq_enable_all(mut self, irq: Irq) -> CfgIrq {
- let mask: [u8; 2] = irq.mask().to_be_bytes();
-
- self.buf[1] |= mask[0];
- self.buf[2] |= mask[1];
- self.buf[3] |= mask[0];
- self.buf[4] |= mask[1];
- self.buf[5] |= mask[0];
- self.buf[6] |= mask[1];
- self.buf[7] |= mask[0];
- self.buf[8] |= mask[1];
-
- self
- }
-
- /// Disable an interrupt.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{CfgIrq, Irq, IrqLine};
- ///
- /// const IRQ_CFG: CfgIrq = CfgIrq::new()
- /// .irq_enable(IrqLine::Global, Irq::TxDone)
- /// .irq_enable(IrqLine::Global, Irq::Timeout)
- /// .irq_disable(IrqLine::Global, Irq::TxDone)
- /// .irq_disable(IrqLine::Global, Irq::Timeout);
- /// # assert_eq!(IRQ_CFG.as_slice()[1], 0x00);
- /// # assert_eq!(IRQ_CFG.as_slice()[2], 0x00);
- /// # assert_eq!(IRQ_CFG.as_slice()[3], 0x00);
- /// ```
- #[must_use = "irq_disable returns a modified CfgIrq"]
- pub const fn irq_disable(mut self, line: IrqLine, irq: Irq) -> CfgIrq {
- let mask: u16 = !(irq as u16);
- let offset: usize = line.offset();
- self.buf[offset] &= ((mask >> 8) & 0xFF) as u8;
- self.buf[offset + 1] &= (mask & 0xFF) as u8;
- self
- }
-
- /// Disable an interrupt on all lines.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{CfgIrq, Irq};
- ///
- /// const IRQ_CFG: CfgIrq = CfgIrq::new()
- /// .irq_enable_all(Irq::TxDone)
- /// .irq_enable_all(Irq::Timeout)
- /// .irq_disable_all(Irq::TxDone)
- /// .irq_disable_all(Irq::Timeout);
- /// # assert_eq!(IRQ_CFG, CfgIrq::new());
- /// ```
- #[must_use = "irq_disable_all returns a modified CfgIrq"]
- pub const fn irq_disable_all(mut self, irq: Irq) -> CfgIrq {
- let mask: [u8; 2] = (!irq.mask()).to_be_bytes();
-
- self.buf[1] &= mask[0];
- self.buf[2] &= mask[1];
- self.buf[3] &= mask[0];
- self.buf[4] &= mask[1];
- self.buf[5] &= mask[0];
- self.buf[6] &= mask[1];
- self.buf[7] &= mask[0];
- self.buf[8] &= mask[1];
-
- self
- }
-
- /// Extracts a slice containing the packet.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{CfgIrq, Irq};
- ///
- /// const IRQ_CFG: CfgIrq = CfgIrq::new()
- /// .irq_enable_all(Irq::TxDone)
- /// .irq_enable_all(Irq::Timeout);
- ///
- /// assert_eq!(
- /// IRQ_CFG.as_slice(),
- /// &[0x08, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01]
- /// );
- /// ```
- pub const fn as_slice(&self) -> &[u8] {
- &self.buf
- }
-}
-
-impl Default for CfgIrq {
- fn default() -> Self {
- Self::new()
- }
-}
diff --git a/embassy-stm32/src/subghz/lora_sync_word.rs b/embassy-stm32/src/subghz/lora_sync_word.rs
deleted file mode 100644
index 2c163104..00000000
--- a/embassy-stm32/src/subghz/lora_sync_word.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-/// LoRa synchronization word.
-///
-/// Argument of [`set_lora_sync_word`][crate::subghz::SubGhz::set_lora_sync_word].
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum LoRaSyncWord {
- /// LoRa private network.
- Private,
- /// LoRa public network.
- Public,
-}
-
-impl LoRaSyncWord {
- pub(crate) const fn bytes(self) -> [u8; 2] {
- match self {
- LoRaSyncWord::Private => [0x14, 0x24],
- LoRaSyncWord::Public => [0x34, 0x44],
- }
- }
-}
diff --git a/embassy-stm32/src/subghz/mod.rs b/embassy-stm32/src/subghz/mod.rs
deleted file mode 100644
index cd566ba2..00000000
--- a/embassy-stm32/src/subghz/mod.rs
+++ /dev/null
@@ -1,1004 +0,0 @@
-//! Sub-GHz radio operating in the 150 - 960 MHz ISM band
-//!
-//! The main radio type is [`SubGhz`].
-//!
-//! ## LoRa user notice
-//!
-//! The Sub-GHz radio may have an undocumented erratum, see this ST community
-//! post for more information: [link]
-//!
-//! [link]: https://community.st.com/s/question/0D53W00000hR8kpSAC/stm32wl55-erratum-clairification
-//!
-//! NOTE: This HAL is based on https://github.com/newAM/stm32wl-hal, but adopted for use with the stm32-metapac
-//! and SPI HALs.
-
-mod bit_sync;
-mod cad_params;
-mod calibrate;
-mod fallback_mode;
-mod hse_trim;
-mod irq;
-mod lora_sync_word;
-mod mod_params;
-mod ocp;
-mod op_error;
-mod pa_config;
-mod packet_params;
-mod packet_status;
-mod packet_type;
-mod pkt_ctrl;
-mod pmode;
-mod pwr_ctrl;
-mod reg_mode;
-mod rf_frequency;
-mod rx_timeout_stop;
-mod sleep_cfg;
-mod smps;
-mod standby_clk;
-mod stats;
-mod status;
-mod tcxo_mode;
-mod timeout;
-mod tx_params;
-mod value_error;
-
-pub use bit_sync::BitSync;
-pub use cad_params::{CadParams, ExitMode, NbCadSymbol};
-pub use calibrate::{Calibrate, CalibrateImage};
-use embassy_hal_common::ratio::Ratio;
-pub use fallback_mode::FallbackMode;
-pub use hse_trim::HseTrim;
-pub use irq::{CfgIrq, Irq, IrqLine};
-pub use lora_sync_word::LoRaSyncWord;
-pub use mod_params::{
- BpskModParams, CodingRate, FskBandwidth, FskBitrate, FskFdev, FskModParams, FskPulseShape, LoRaBandwidth,
- LoRaModParams, SpreadingFactor,
-};
-pub use ocp::Ocp;
-pub use op_error::OpError;
-pub use pa_config::{PaConfig, PaSel};
-pub use packet_params::{
- AddrComp, BpskPacketParams, CrcType, GenericPacketParams, HeaderType, LoRaPacketParams, PreambleDetection,
-};
-pub use packet_status::{FskPacketStatus, LoRaPacketStatus};
-pub use packet_type::PacketType;
-pub use pkt_ctrl::{InfSeqSel, PktCtrl};
-pub use pmode::PMode;
-pub use pwr_ctrl::{CurrentLim, PwrCtrl};
-pub use reg_mode::RegMode;
-pub use rf_frequency::RfFreq;
-pub use rx_timeout_stop::RxTimeoutStop;
-pub use sleep_cfg::{SleepCfg, Startup};
-pub use smps::SmpsDrv;
-pub use standby_clk::StandbyClk;
-pub use stats::{FskStats, LoRaStats, Stats};
-pub use status::{CmdStatus, Status, StatusMode};
-pub use tcxo_mode::{TcxoMode, TcxoTrim};
-pub use timeout::Timeout;
-pub use tx_params::{RampTime, TxParams};
-pub use value_error::ValueError;
-
-use crate::dma::NoDma;
-use crate::peripherals::SUBGHZSPI;
-use crate::rcc::sealed::RccPeripheral;
-use crate::spi::{BitOrder, Config as SpiConfig, Spi, MODE_0};
-use crate::time::Hertz;
-use crate::{pac, Peripheral};
-
-/// Passthrough for SPI errors (for now)
-pub type Error = crate::spi::Error;
-
-struct Nss {
- _priv: (),
-}
-
-impl Nss {
- #[inline(always)]
- pub fn new() -> Nss {
- Self::clear();
- Nss { _priv: () }
- }
-
- /// Clear NSS, enabling SPI transactions
- #[inline(always)]
- fn clear() {
- let pwr = pac::PWR;
- unsafe {
- pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::LOW));
- }
- }
-
- /// Set NSS, disabling SPI transactions
- #[inline(always)]
- fn set() {
- let pwr = pac::PWR;
- unsafe {
- pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::HIGH));
- }
- }
-}
-
-impl Drop for Nss {
- fn drop(&mut self) {
- Self::set()
- }
-}
-
-/// Wakeup the radio from sleep mode.
-///
-/// # Safety
-///
-/// 1. This must not be called when the SubGHz radio is in use.
-/// 2. This must not be called when the SubGHz SPI bus is in use.
-///
-/// # Example
-///
-/// See [`SubGhz::set_sleep`]
-#[inline]
-unsafe fn wakeup() {
- Nss::clear();
- // RM0453 rev 2 page 171 section 5.7.2 "Sleep mode"
- // on a firmware request via the sub-GHz radio SPI NSS signal
- // (keeping sub-GHz radio SPI NSS low for at least 20 μs)
- //
- // I have found this to be a more reliable mechanism for ensuring NSS is
- // pulled low for long enough to wake the radio.
- while rfbusys() {}
- Nss::set();
-}
-
-/// Returns `true` if the radio is busy.
-///
-/// This may not be set immediately after NSS going low.
-///
-/// See RM0461 Rev 4 section 5.3 page 181 "Radio busy management" for more
-/// details.
-#[inline]
-fn rfbusys() -> bool {
- // safety: atmoic read with no side-effects
- //unsafe { (*pac::PWR::ptr()).sr2.read().rfbusys().is_busy() }
- let pwr = pac::PWR;
- unsafe { pwr.sr2().read().rfbusys() == pac::pwr::vals::Rfbusys::BUSY }
-}
-
-/*
-/// Returns `true` if the radio is busy or NSS is low.
-///
-/// See RM0461 Rev 4 section 5.3 page 181 "Radio busy management" for more
-/// details.
-#[inline]
-fn rfbusyms() -> bool {
- let pwr = pac::PWR;
- unsafe { pwr.sr2().read().rfbusyms() == pac::pwr::vals::Rfbusyms::BUSY }
-}
-*/
-
-/// Sub-GHz radio peripheral
-pub struct SubGhz<'d, Tx, Rx> {
- spi: Spi<'d, SUBGHZSPI, Tx, Rx>,
-}
-
-impl<'d, Tx, Rx> SubGhz<'d, Tx, Rx> {
- fn pulse_radio_reset() {
- let rcc = pac::RCC;
- unsafe {
- rcc.csr().modify(|w| w.set_rfrst(true));
- rcc.csr().modify(|w| w.set_rfrst(false));
- }
- }
-
- // TODO: This should be replaced with async handling based on IRQ
- fn poll_not_busy(&self) {
- let mut count: u32 = 1_000_000;
- while rfbusys() {
- count -= 1;
- if count == 0 {
- let pwr = pac::PWR;
- unsafe {
- panic!(
- "rfbusys timeout pwr.sr2=0x{:X} pwr.subghzspicr=0x{:X} pwr.cr1=0x{:X}",
- pwr.sr2().read().0,
- pwr.subghzspicr().read().0,
- pwr.cr1().read().0
- );
- }
- }
- }
- }
-
- /// Create a new sub-GHz radio driver from a peripheral.
- ///
- /// This will reset the radio and the SPI bus, and enable the peripheral
- /// clock.
- pub fn new(
- peri: impl Peripheral + 'd,
- txdma: impl Peripheral
+ 'd,
- rxdma: impl Peripheral
+ 'd,
- ) -> Self {
- Self::pulse_radio_reset();
-
- // see RM0453 rev 1 section 7.2.13 page 291
- // The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two.
- // The SUBGHZSPI_SCK clock maximum speed must not exceed 16 MHz.
- let clk = Hertz(core::cmp::min(SUBGHZSPI::frequency().0 / 2, 16_000_000));
- let mut config = SpiConfig::default();
- config.mode = MODE_0;
- config.bit_order = BitOrder::MsbFirst;
- let spi = Spi::new_subghz(peri, txdma, rxdma, clk, config);
-
- unsafe { wakeup() };
-
- SubGhz { spi }
- }
-
- pub fn is_busy(&mut self) -> bool {
- rfbusys()
- }
-
- pub fn reset(&mut self) {
- Self::pulse_radio_reset();
- }
-}
-
-impl<'d> SubGhz<'d, NoDma, NoDma> {
- fn read(&mut self, opcode: OpCode, data: &mut [u8]) -> Result<(), Error> {
- self.poll_not_busy();
- {
- let _nss: Nss = Nss::new();
- self.spi.blocking_write(&[opcode as u8])?;
- self.spi.blocking_transfer_in_place(data)?;
- }
- self.poll_not_busy();
- Ok(())
- }
-
- /// Read one byte from the sub-Ghz radio.
- fn read_1(&mut self, opcode: OpCode) -> Result {
- let mut buf: [u8; 1] = [0; 1];
- self.read(opcode, &mut buf)?;
- Ok(buf[0])
- }
-
- /// Read a fixed number of bytes from the sub-Ghz radio.
- fn read_n(&mut self, opcode: OpCode) -> Result<[u8; N], Error> {
- let mut buf: [u8; N] = [0; N];
- self.read(opcode, &mut buf)?;
- Ok(buf)
- }
-
- fn write(&mut self, data: &[u8]) -> Result<(), Error> {
- self.poll_not_busy();
- {
- let _nss: Nss = Nss::new();
- self.spi.blocking_write(data)?;
- }
- self.poll_not_busy();
- Ok(())
- }
-
- pub fn write_buffer(&mut self, offset: u8, data: &[u8]) -> Result<(), Error> {
- self.poll_not_busy();
- {
- let _nss: Nss = Nss::new();
- self.spi.blocking_write(&[OpCode::WriteBuffer as u8, offset])?;
- self.spi.blocking_write(data)?;
- }
- self.poll_not_busy();
-
- Ok(())
- }
-
- /// Read the radio buffer at the given offset.
- ///
- /// The offset and length of a received packet is provided by
- /// [`rx_buffer_status`](Self::rx_buffer_status).
- pub fn read_buffer(&mut self, offset: u8, buf: &mut [u8]) -> Result {
- let mut status_buf: [u8; 1] = [0];
-
- self.poll_not_busy();
- {
- let _nss: Nss = Nss::new();
- self.spi.blocking_write(&[OpCode::ReadBuffer as u8, offset])?;
- self.spi.blocking_transfer_in_place(&mut status_buf)?;
- self.spi.blocking_transfer_in_place(buf)?;
- }
- self.poll_not_busy();
-
- Ok(status_buf[0].into())
- }
-}
-
-// helper to pack register writes into a single buffer to avoid multiple DMA
-// transfers
-macro_rules! wr_reg {
- [$reg:ident, $($data:expr),+] => {
- &[
- OpCode::WriteRegister as u8,
- Register::$reg.address().to_be_bytes()[0],
- Register::$reg.address().to_be_bytes()[1],
- $($data),+
- ]
- };
-}
-
-// 5.8.2
-/// Register access
-impl<'d> SubGhz<'d, NoDma, NoDma> {
- // register write with variable length data
- fn write_register(&mut self, register: Register, data: &[u8]) -> Result<(), Error> {
- let addr: [u8; 2] = register.address().to_be_bytes();
-
- self.poll_not_busy();
- {
- let _nss: Nss = Nss::new();
- self.spi
- .blocking_write(&[OpCode::WriteRegister as u8, addr[0], addr[1]])?;
- self.spi.blocking_write(data)?;
- }
- self.poll_not_busy();
-
- Ok(())
- }
-
- /// Set the LoRa bit synchronization.
- pub fn set_bit_sync(&mut self, bs: BitSync) -> Result<(), Error> {
- self.write(wr_reg![GBSYNC, bs.as_bits()])
- }
-
- /// Set the generic packet control register.
- pub fn set_pkt_ctrl(&mut self, pkt_ctrl: PktCtrl) -> Result<(), Error> {
- self.write(wr_reg![GPKTCTL1A, pkt_ctrl.as_bits()])
- }
-
- /// Set the initial value for generic packet whitening.
- ///
- /// This sets the first 8 bits, the 9th bit is set with
- /// [`set_pkt_ctrl`](Self::set_pkt_ctrl).
- pub fn set_init_whitening(&mut self, init: u8) -> Result<(), Error> {
- self.write(wr_reg![GWHITEINIRL, init])
- }
-
- /// Set the initial value for generic packet CRC polynomial.
- pub fn set_crc_polynomial(&mut self, polynomial: u16) -> Result<(), Error> {
- let bytes: [u8; 2] = polynomial.to_be_bytes();
- self.write(wr_reg![GCRCINIRH, bytes[0], bytes[1]])
- }
-
- /// Set the generic packet CRC polynomial.
- pub fn set_initial_crc_polynomial(&mut self, polynomial: u16) -> Result<(), Error> {
- let bytes: [u8; 2] = polynomial.to_be_bytes();
- self.write(wr_reg![GCRCPOLRH, bytes[0], bytes[1]])
- }
-
- /// Set the synchronization word registers.
- pub fn set_sync_word(&mut self, sync_word: &[u8; 8]) -> Result<(), Error> {
- self.write_register(Register::GSYNC7, sync_word)
- }
-
- /// Set the LoRa synchronization word registers.
- pub fn set_lora_sync_word(&mut self, sync_word: LoRaSyncWord) -> Result<(), Error> {
- let bytes: [u8; 2] = sync_word.bytes();
- self.write(wr_reg![LSYNCH, bytes[0], bytes[1]])
- }
-
- /// Set the RX gain control.
- pub fn set_rx_gain(&mut self, pmode: PMode) -> Result<(), Error> {
- self.write(wr_reg![RXGAINC, pmode as u8])
- }
-
- /// Set the power amplifier over current protection.
- pub fn set_pa_ocp(&mut self, ocp: Ocp) -> Result<(), Error> {
- self.write(wr_reg![PAOCP, ocp as u8])
- }
-
- /// Restart the radio RTC.
- ///
- /// This is used to workaround an erratum for [`set_rx_duty_cycle`].
- ///
- /// [`set_rx_duty_cycle`]: crate::subghz::SubGhz::set_rx_duty_cycle
- pub fn restart_rtc(&mut self) -> Result<(), Error> {
- self.write(wr_reg![RTCCTLR, 0b1])
- }
-
- /// Set the radio real-time-clock period.
- ///
- /// This is used to workaround an erratum for [`set_rx_duty_cycle`].
- ///
- /// [`set_rx_duty_cycle`]: crate::subghz::SubGhz::set_rx_duty_cycle
- pub fn set_rtc_period(&mut self, period: Timeout) -> Result<(), Error> {
- let tobits: u32 = period.into_bits();
- self.write(wr_reg![
- RTCPRDR2,
- (tobits >> 16) as u8,
- (tobits >> 8) as u8,
- tobits as u8
- ])
- }
-
- /// Set the HSE32 crystal OSC_IN load capacitor trimming.
- pub fn set_hse_in_trim(&mut self, trim: HseTrim) -> Result<(), Error> {
- self.write(wr_reg![HSEINTRIM, trim.into()])
- }
-
- /// Set the HSE32 crystal OSC_OUT load capacitor trimming.
- pub fn set_hse_out_trim(&mut self, trim: HseTrim) -> Result<(), Error> {
- self.write(wr_reg![HSEOUTTRIM, trim.into()])
- }
-
- /// Set the SMPS clock detection enabled.
- ///
- /// SMPS clock detection must be enabled fore enabling the SMPS.
- pub fn set_smps_clock_det_en(&mut self, en: bool) -> Result<(), Error> {
- self.write(wr_reg![SMPSC0, (en as u8) << 6])
- }
-
- /// Set the power current limiting.
- pub fn set_pwr_ctrl(&mut self, pwr_ctrl: PwrCtrl) -> Result<(), Error> {
- self.write(wr_reg![PC, pwr_ctrl.as_bits()])
- }
-
- /// Set the maximum SMPS drive capability.
- pub fn set_smps_drv(&mut self, drv: SmpsDrv) -> Result<(), Error> {
- self.write(wr_reg![SMPSC2, (drv as u8) << 1])
- }
-
- /// Set the node address.
- ///
- /// Used with [`GenericPacketParams::set_addr_comp`] to filter packets based
- /// on node address.
- pub fn set_node_addr(&mut self, addr: u8) -> Result<(), Error> {
- self.write(wr_reg![NODE, addr])
- }
-
- /// Set the broadcast address.
- ///
- /// Used with [`GenericPacketParams::set_addr_comp`] to filter packets based
- /// on broadcast address.
- pub fn set_broadcast_addr(&mut self, addr: u8) -> Result<(), Error> {
- self.write(wr_reg![BROADCAST, addr])
- }
-
- /// Set both the broadcast address and node address.
- ///
- /// This is a combination of [`set_node_addr`] and [`set_broadcast_addr`]
- /// in a single SPI transfer.
- ///
- /// [`set_node_addr`]: Self::set_node_addr
- /// [`set_broadcast_addr`]: Self::set_broadcast_addr
- pub fn set_addrs(&mut self, node: u8, broadcast: u8) -> Result<(), Error> {
- self.write(wr_reg![NODE, node, broadcast])
- }
-}
-
-// 5.8.3
-/// Operating mode commands
-impl<'d> SubGhz<'d, NoDma, NoDma> {
- /// Put the radio into sleep mode.
- ///
- /// This command is only accepted in standby mode.
- /// The cfg argument allows some optional functions to be maintained
- /// in sleep mode.
- ///
- /// # Safety
- ///
- /// 1. After the `set_sleep` command, the sub-GHz radio NSS must not go low
- /// for 500 μs.
- /// No reason is provided, the reference manual (RM0453 rev 2) simply
- /// says "you must".
- /// 2. The radio cannot be used while in sleep mode.
- /// 3. The radio must be woken up with [`wakeup`] before resuming use.
- ///
- /// # Example
- ///
- /// Put the radio into sleep mode.
- ///
- /// ```no_run
- /// # let dp = unsafe { embassy_stm32::pac::Peripherals::steal() };
- /// # let mut sg = embassy_stm32::subghz::SubGhz::new(p.SUBGHZSPI, ...);
- /// use embassy_stm32::{
- /// subghz::{wakeup, SleepCfg, StandbyClk},
- /// };
- ///
- /// sg.set_standby(StandbyClk::Rc)?;
- /// unsafe { sg.set_sleep(SleepCfg::default())? };
- /// embassy_time::Timer::after(embassy_time::Duration::from_micros(500)).await;
- /// unsafe { wakeup() };
- /// # Ok::<(), embassy_stm32::subghz::Error>(())
- /// ```
- pub unsafe fn set_sleep(&mut self, cfg: SleepCfg) -> Result<(), Error> {
- // poll for busy before, but not after
- // radio idles with busy high while in sleep mode
- self.poll_not_busy();
- {
- let _nss: Nss = Nss::new();
- self.spi.blocking_write(&[OpCode::SetSleep as u8, u8::from(cfg)])?;
- }
- Ok(())
- }
-
- /// Put the radio into standby mode.
- pub fn set_standby(&mut self, standby_clk: StandbyClk) -> Result<(), Error> {
- self.write(&[OpCode::SetStandby as u8, u8::from(standby_clk)])
- }
-
- /// Put the subghz radio into frequency synthesis mode.
- ///
- /// The RF-PLL frequency must be set with [`set_rf_frequency`] before using
- /// this command.
- ///
- /// Check the datasheet for more information, this is a test command but
- /// I honestly do not see any use for it. Please update this description
- /// if you know more than I do.
- ///
- /// [`set_rf_frequency`]: crate::subghz::SubGhz::set_rf_frequency
- pub fn set_fs(&mut self) -> Result<(), Error> {
- self.write(&[OpCode::SetFs.into()])
- }
-
- /// Setup the sub-GHz radio for TX.
- pub fn set_tx(&mut self, timeout: Timeout) -> Result<(), Error> {
- let tobits: u32 = timeout.into_bits();
- self.write(&[
- OpCode::SetTx.into(),
- (tobits >> 16) as u8,
- (tobits >> 8) as u8,
- tobits as u8,
- ])
- }
-
- /// Setup the sub-GHz radio for RX.
- pub fn set_rx(&mut self, timeout: Timeout) -> Result<(), Error> {
- let tobits: u32 = timeout.into_bits();
- self.write(&[
- OpCode::SetRx.into(),
- (tobits >> 16) as u8,
- (tobits >> 8) as u8,
- tobits as u8,
- ])
- }
-
- /// Allows selection of the receiver event which stops the RX timeout timer.
- pub fn set_rx_timeout_stop(&mut self, rx_timeout_stop: RxTimeoutStop) -> Result<(), Error> {
- self.write(&[OpCode::SetStopRxTimerOnPreamble.into(), rx_timeout_stop.into()])
- }
-
- /// Put the radio in non-continuous RX mode.
- ///
- /// This command must be sent in Standby mode.
- /// This command is only functional with FSK and LoRa packet type.
- ///
- /// The following steps are performed:
- /// 1. Save sub-GHz radio configuration.
- /// 2. Enter Receive mode and listen for a preamble for the specified `rx_period`.
- /// 3. Upon the detection of a preamble, the `rx_period` timeout is stopped
- /// and restarted with the value 2 x `rx_period` + `sleep_period`.
- /// During this new period, the sub-GHz radio looks for the detection of
- /// a synchronization word when in (G)FSK modulation mode,
- /// or a header when in LoRa modulation mode.
- /// 4. If no packet is received during the listen period defined by
- /// 2 x `rx_period` + `sleep_period`, the sleep mode is entered for a
- /// duration of `sleep_period`. At the end of the receive period,
- /// the sub-GHz radio takes some time to save the context before starting
- /// the sleep period.
- /// 5. After the sleep period, a new listening period is automatically
- /// started. The sub-GHz radio restores the sub-GHz radio configuration
- /// and continuous with step 2.
- ///
- /// The listening mode is terminated in one of the following cases:
- /// * if a packet is received during the listening period: the sub-GHz radio
- /// issues a [`RxDone`] interrupt and enters standby mode.
- /// * if [`set_standby`] is sent during the listening period or after the
- /// sub-GHz has been requested to exit sleep mode by sub-GHz radio SPI NSS
- ///
- /// # Erratum
- ///
- /// When a preamble is detected the radio should restart the RX timeout
- /// with a value of 2 × `rx_period` + `sleep_period`.
- /// Instead the radio erroneously uses `sleep_period`.
- ///
- /// To workaround this use [`restart_rtc`] and [`set_rtc_period`] to
- /// reprogram the radio timeout to 2 × `rx_period` + `sleep_period`.
- ///
- /// Use code similar to this in the [`PreambleDetected`] interrupt handler.
- ///
- /// ```no_run
- /// # let rx_period: Timeout = Timeout::from_millis_sat(100);
- /// # let sleep_period: Timeout = Timeout::from_millis_sat(100);
- /// # let mut sg = unsafe { stm32wlxx_hal::subghz::SubGhz::steal() };
- /// use stm32wlxx_hal::subghz::Timeout;
- ///
- /// let period: Timeout = rx_period
- /// .saturating_add(rx_period)
- /// .saturating_add(sleep_period);
- ///
- /// sg.set_rtc_period(period)?;
- /// sg.restart_rtc()?;
- /// # Ok::<(), stm32wlxx_hal::subghz::Error>(())
- /// ```
- ///
- /// Please read the erratum for more details.
- ///
- /// [`PreambleDetected`]: crate::subghz::Irq::PreambleDetected
- /// [`restart_rtc`]: crate::subghz::SubGhz::restart_rtc
- /// [`RxDone`]: crate::subghz::Irq::RxDone
- /// [`set_rf_frequency`]: crate::subghz::SubGhz::set_rf_frequency
- /// [`set_rtc_period`]: crate::subghz::SubGhz::set_rtc_period
- /// [`set_standby`]: crate::subghz::SubGhz::set_standby
- pub fn set_rx_duty_cycle(&mut self, rx_period: Timeout, sleep_period: Timeout) -> Result<(), Error> {
- let rx_period_bits: u32 = rx_period.into_bits();
- let sleep_period_bits: u32 = sleep_period.into_bits();
- self.write(&[
- OpCode::SetRxDutyCycle.into(),
- (rx_period_bits >> 16) as u8,
- (rx_period_bits >> 8) as u8,
- rx_period_bits as u8,
- (sleep_period_bits >> 16) as u8,
- (sleep_period_bits >> 8) as u8,
- sleep_period_bits as u8,
- ])
- }
-
- /// Channel Activity Detection (CAD) with LoRa packets.
- ///
- /// The channel activity detection (CAD) is a specific LoRa operation mode,
- /// where the sub-GHz radio searches for a LoRa radio signal.
- /// After the search is completed, the Standby mode is automatically
- /// entered, CAD is done and IRQ is generated.
- /// When a LoRa radio signal is detected, the CAD detected IRQ is also
- /// generated.
- ///
- /// The length of the search must be configured with [`set_cad_params`]
- /// prior to calling `set_cad`.
- ///
- /// [`set_cad_params`]: crate::subghz::SubGhz::set_cad_params
- pub fn set_cad(&mut self) -> Result<(), Error> {
- self.write(&[OpCode::SetCad.into()])
- }
-
- /// Generate a continuous transmit tone at the RF-PLL frequency.
- ///
- /// The sub-GHz radio remains in continuous transmit tone mode until a mode
- /// configuration command is received.
- pub fn set_tx_continuous_wave(&mut self) -> Result<(), Error> {
- self.write(&[OpCode::SetTxContinuousWave as u8])
- }
-
- /// Generate an infinite preamble at the RF-PLL frequency.
- ///
- /// The preamble is an alternating 0s and 1s sequence in generic (G)FSK and
- /// (G)MSK modulations.
- /// The preamble is symbol 0 in LoRa modulation.
- /// The sub-GHz radio remains in infinite preamble mode until a mode
- /// configuration command is received.
- pub fn set_tx_continuous_preamble(&mut self) -> Result<(), Error> {
- self.write(&[OpCode::SetTxContinuousPreamble as u8])
- }
-}
-
-// 5.8.4
-/// Radio configuration commands
-impl<'d> SubGhz<'d, NoDma, NoDma> {
- /// Set the packet type (modulation scheme).
- pub fn set_packet_type(&mut self, packet_type: PacketType) -> Result<(), Error> {
- self.write(&[OpCode::SetPacketType as u8, packet_type as u8])
- }
-
- /// Get the packet type.
- pub fn packet_type(&mut self) -> Result, Error> {
- let pkt_type: [u8; 2] = self.read_n(OpCode::GetPacketType)?;
- Ok(PacketType::from_raw(pkt_type[1]))
- }
-
- /// Set the radio carrier frequency.
- pub fn set_rf_frequency(&mut self, freq: &RfFreq) -> Result<(), Error> {
- self.write(freq.as_slice())
- }
-
- /// Set the transmit output power and the PA ramp-up time.
- pub fn set_tx_params(&mut self, params: &TxParams) -> Result<(), Error> {
- self.write(params.as_slice())
- }
-
- /// Power amplifier configuration.
- ///
- /// Used to customize the maximum output power and efficiency.
- pub fn set_pa_config(&mut self, pa_config: &PaConfig) -> Result<(), Error> {
- self.write(pa_config.as_slice())
- }
-
- /// Operating mode to enter after a successful packet transmission or
- /// packet reception.
- pub fn set_tx_rx_fallback_mode(&mut self, fm: FallbackMode) -> Result<(), Error> {
- self.write(&[OpCode::SetTxRxFallbackMode as u8, fm as u8])
- }
-
- /// Set channel activity detection (CAD) parameters.
- pub fn set_cad_params(&mut self, params: &CadParams) -> Result<(), Error> {
- self.write(params.as_slice())
- }
-
- /// Set the data buffer base address for the packet handling in TX and RX.
- ///
- /// There is a single buffer for both TX and RX.
- /// The buffer is not memory mapped, it is accessed via the
- /// [`read_buffer`](SubGhz::read_buffer) and
- /// [`write_buffer`](SubGhz::write_buffer) methods.
- pub fn set_buffer_base_address(&mut self, tx: u8, rx: u8) -> Result<(), Error> {
- self.write(&[OpCode::SetBufferBaseAddress as u8, tx, rx])
- }
-
- /// Set the (G)FSK modulation parameters.
- pub fn set_fsk_mod_params(&mut self, params: &FskModParams) -> Result<(), Error> {
- self.write(params.as_slice())
- }
-
- /// Set the LoRa modulation parameters.
- pub fn set_lora_mod_params(&mut self, params: &LoRaModParams) -> Result<(), Error> {
- self.write(params.as_slice())
- }
-
- /// Set the BPSK modulation parameters.
- pub fn set_bpsk_mod_params(&mut self, params: &BpskModParams) -> Result<(), Error> {
- self.write(params.as_slice())
- }
-
- /// Set the generic (FSK) packet parameters.
- pub fn set_packet_params(&mut self, params: &GenericPacketParams) -> Result<(), Error> {
- self.write(params.as_slice())
- }
-
- /// Set the BPSK packet parameters.
- pub fn set_bpsk_packet_params(&mut self, params: &BpskPacketParams) -> Result<(), Error> {
- self.write(params.as_slice())
- }
-
- /// Set the LoRa packet parameters.
- pub fn set_lora_packet_params(&mut self, params: &LoRaPacketParams) -> Result<(), Error> {
- self.write(params.as_slice())
- }
-
- /// Set the number of LoRa symbols to be received before starting the
- /// reception of a LoRa packet.
- ///
- /// Packet reception is started after `n` + 1 symbols are detected.
- pub fn set_lora_symb_timeout(&mut self, n: u8) -> Result<(), Error> {
- self.write(&[OpCode::SetLoRaSymbTimeout.into(), n])
- }
-}
-
-// 5.8.5
-/// Communication status and information commands
-impl<'d> SubGhz<'d, NoDma, NoDma> {
- /// Get the radio status.
- ///
- /// The hardware (or documentation) appears to have many bugs where this
- /// will return reserved values.
- /// See this thread in the ST community for details: [link]
- ///
- /// [link]: https://community.st.com/s/question/0D53W00000hR9GQSA0/stm32wl55-getstatus-command-returns-reserved-cmdstatus
- pub fn status(&mut self) -> Result {
- Ok(self.read_1(OpCode::GetStatus)?.into())
- }
-
- /// Get the RX buffer status.
- ///
- /// The return tuple is (status, payload_length, buffer_pointer).
- pub fn rx_buffer_status(&mut self) -> Result<(Status, u8, u8), Error> {
- let data: [u8; 3] = self.read_n(OpCode::GetRxBufferStatus)?;
- Ok((data[0].into(), data[1], data[2]))
- }
-
- /// Returns information on the last received (G)FSK packet.
- pub fn fsk_packet_status(&mut self) -> Result {
- Ok(FskPacketStatus::from(self.read_n(OpCode::GetPacketStatus)?))
- }
-
- /// Returns information on the last received LoRa packet.
- pub fn lora_packet_status(&mut self) -> Result {
- Ok(LoRaPacketStatus::from(self.read_n(OpCode::GetPacketStatus)?))
- }
-
- /// Get the instantaneous signal strength during packet reception.
- ///
- /// The units are in dbm.
- pub fn rssi_inst(&mut self) -> Result<(Status, Ratio), Error> {
- let data: [u8; 2] = self.read_n(OpCode::GetRssiInst)?;
- let status: Status = data[0].into();
- let rssi: Ratio = Ratio::new_raw(i16::from(data[1]), -2);
-
- Ok((status, rssi))
- }
-
- /// (G)FSK packet stats.
- pub fn fsk_stats(&mut self) -> Result, Error> {
- let data: [u8; 7] = self.read_n(OpCode::GetStats)?;
- Ok(Stats::from_raw_fsk(data))
- }
-
- /// LoRa packet stats.
- pub fn lora_stats(&mut self) -> Result, Error> {
- let data: [u8; 7] = self.read_n(OpCode::GetStats)?;
- Ok(Stats::from_raw_lora(data))
- }
-
- /// Reset the stats as reported in [`lora_stats`](SubGhz::lora_stats) and
- /// [`fsk_stats`](SubGhz::fsk_stats).
- pub fn reset_stats(&mut self) -> Result<(), Error> {
- const RESET_STATS: [u8; 7] = [0x00; 7];
- self.write(&RESET_STATS)
- }
-}
-
-// 5.8.6
-/// IRQ commands
-impl<'d> SubGhz<'d, NoDma, NoDma> {
- /// Set the interrupt configuration.
- pub fn set_irq_cfg(&mut self, cfg: &CfgIrq) -> Result<(), Error> {
- self.write(cfg.as_slice())
- }
-
- /// Get the IRQ status.
- pub fn irq_status(&mut self) -> Result<(Status, u16), Error> {
- let data: [u8; 3] = self.read_n(OpCode::GetIrqStatus)?;
- let irq_status: u16 = u16::from_be_bytes([data[1], data[2]]);
- Ok((data[0].into(), irq_status))
- }
-
- /// Clear the IRQ status.
- pub fn clear_irq_status(&mut self, mask: u16) -> Result<(), Error> {
- self.write(&[OpCode::ClrIrqStatus as u8, (mask >> 8) as u8, mask as u8])
- }
-}
-
-// 5.8.7
-/// Miscellaneous commands
-impl<'d> SubGhz<'d, NoDma, NoDma> {
- /// Calibrate one or several blocks at any time when in standby mode.
- pub fn calibrate(&mut self, cal: u8) -> Result<(), Error> {
- // bit 7 is reserved and must be kept at reset value.
- self.write(&[OpCode::Calibrate as u8, cal & 0x7F])
- }
-
- /// Calibrate the image at the given frequencies.
- ///
- /// Requires the radio to be in standby mode.
- pub fn calibrate_image(&mut self, cal: CalibrateImage) -> Result<(), Error> {
- self.write(&[OpCode::CalibrateImage as u8, cal.0, cal.1])
- }
-
- /// Set the radio power supply.
- pub fn set_regulator_mode(&mut self, reg_mode: RegMode) -> Result<(), Error> {
- self.write(&[OpCode::SetRegulatorMode as u8, reg_mode as u8])
- }
-
- /// Get the radio operational errors.
- pub fn op_error(&mut self) -> Result<(Status, u16), Error> {
- let data: [u8; 3] = self.read_n(OpCode::GetError)?;
- Ok((data[0].into(), u16::from_be_bytes([data[1], data[2]])))
- }
-
- /// Clear all errors as reported by [`op_error`](SubGhz::op_error).
- pub fn clear_error(&mut self) -> Result<(), Error> {
- self.write(&[OpCode::ClrError as u8, 0x00])
- }
-}
-
-// 5.8.8
-/// Set TCXO mode command
-impl<'d> SubGhz<'d, NoDma, NoDma> {
- /// Set the TCXO trim and HSE32 ready timeout.
- pub fn set_tcxo_mode(&mut self, tcxo_mode: &TcxoMode) -> Result<(), Error> {
- self.write(tcxo_mode.as_slice())
- }
-}
-
-/// sub-GHz radio opcodes.
-///
-/// See Table 41 "Sub-GHz radio SPI commands overview"
-#[repr(u8)]
-#[derive(Debug, Clone, Copy)]
-#[allow(dead_code)]
-pub(crate) enum OpCode {
- Calibrate = 0x89,
- CalibrateImage = 0x98,
- CfgDioIrq = 0x08,
- ClrError = 0x07,
- ClrIrqStatus = 0x02,
- GetError = 0x17,
- GetIrqStatus = 0x12,
- GetPacketStatus = 0x14,
- GetPacketType = 0x11,
- GetRssiInst = 0x15,
- GetRxBufferStatus = 0x13,
- GetStats = 0x10,
- GetStatus = 0xC0,
- ReadBuffer = 0x1E,
- RegRegister = 0x1D,
- ResetStats = 0x00,
- SetBufferBaseAddress = 0x8F,
- SetCad = 0xC5,
- SetCadParams = 0x88,
- SetFs = 0xC1,
- SetLoRaSymbTimeout = 0xA0,
- SetModulationParams = 0x8B,
- SetPacketParams = 0x8C,
- SetPacketType = 0x8A,
- SetPaConfig = 0x95,
- SetRegulatorMode = 0x96,
- SetRfFrequency = 0x86,
- SetRx = 0x82,
- SetRxDutyCycle = 0x94,
- SetSleep = 0x84,
- SetStandby = 0x80,
- SetStopRxTimerOnPreamble = 0x9F,
- SetTcxoMode = 0x97,
- SetTx = 0x83,
- SetTxContinuousPreamble = 0xD2,
- SetTxContinuousWave = 0xD1,
- SetTxParams = 0x8E,
- SetTxRxFallbackMode = 0x93,
- WriteBuffer = 0x0E,
- WriteRegister = 0x0D,
-}
-
-impl From for u8 {
- fn from(opcode: OpCode) -> Self {
- opcode as u8
- }
-}
-
-#[repr(u16)]
-#[allow(clippy::upper_case_acronyms)]
-pub(crate) enum Register {
- /// Generic bit synchronization.
- GBSYNC = 0x06AC,
- /// Generic packet control.
- GPKTCTL1A = 0x06B8,
- /// Generic whitening.
- GWHITEINIRL = 0x06B9,
- /// Generic CRC initial.
- GCRCINIRH = 0x06BC,
- /// Generic CRC polynomial.
- GCRCPOLRH = 0x06BE,
- /// Generic synchronization word 7.
- GSYNC7 = 0x06C0,
- /// Node address.
- NODE = 0x06CD,
- /// Broadcast address.
- BROADCAST = 0x06CE,
- /// LoRa synchronization word MSB.
- LSYNCH = 0x0740,
- /// LoRa synchronization word LSB.
- #[allow(dead_code)]
- LSYNCL = 0x0741,
- /// Receiver gain control.
- RXGAINC = 0x08AC,
- /// PA over current protection.
- PAOCP = 0x08E7,
- /// RTC control.
- RTCCTLR = 0x0902,
- /// RTC period MSB.
- RTCPRDR2 = 0x0906,
- /// RTC period mid-byte.
- #[allow(dead_code)]
- RTCPRDR1 = 0x0907,
- /// RTC period LSB.
- #[allow(dead_code)]
- RTCPRDR0 = 0x0908,
- /// HSE32 OSC_IN capacitor trim.
- HSEINTRIM = 0x0911,
- /// HSE32 OSC_OUT capacitor trim.
- HSEOUTTRIM = 0x0912,
- /// SMPS control 0.
- SMPSC0 = 0x0916,
- /// Power control.
- PC = 0x091A,
- /// SMPS control 2.
- SMPSC2 = 0x0923,
-}
-
-impl Register {
- pub const fn address(self) -> u16 {
- self as u16
- }
-}
diff --git a/embassy-stm32/src/subghz/mod_params.rs b/embassy-stm32/src/subghz/mod_params.rs
deleted file mode 100644
index d997ae11..00000000
--- a/embassy-stm32/src/subghz/mod_params.rs
+++ /dev/null
@@ -1,1045 +0,0 @@
-/// Bandwidth options for [`FskModParams`].
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum FskBandwidth {
- /// 4.8 kHz double-sideband
- Bw4 = 0x1F,
- /// 5.8 kHz double-sideband
- Bw5 = 0x17,
- /// 7.3 kHz double-sideband
- Bw7 = 0x0F,
- /// 9.7 kHz double-sideband
- Bw9 = 0x1E,
- /// 11.7 kHz double-sideband
- Bw11 = 0x16,
- /// 14.6 kHz double-sideband
- Bw14 = 0x0E,
- /// 19.5 kHz double-sideband
- Bw19 = 0x1D,
- /// 23.4 kHz double-sideband
- Bw23 = 0x15,
- /// 29.3 kHz double-sideband
- Bw29 = 0x0D,
- /// 39.0 kHz double-sideband
- Bw39 = 0x1C,
- /// 46.9 kHz double-sideband
- Bw46 = 0x14,
- /// 58.6 kHz double-sideband
- Bw58 = 0x0C,
- /// 78.2 kHz double-sideband
- Bw78 = 0x1B,
- /// 93.8 kHz double-sideband
- Bw93 = 0x13,
- /// 117.3 kHz double-sideband
- Bw117 = 0x0B,
- /// 156.2 kHz double-sideband
- Bw156 = 0x1A,
- /// 187.2 kHz double-sideband
- Bw187 = 0x12,
- /// 234.3 kHz double-sideband
- Bw234 = 0x0A,
- /// 312.0 kHz double-sideband
- Bw312 = 0x19,
- /// 373.6 kHz double-sideband
- Bw373 = 0x11,
- /// 467.0 kHz double-sideband
- Bw467 = 0x09,
-}
-
-impl FskBandwidth {
- /// Get the bandwidth in hertz.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::FskBandwidth;
- ///
- /// assert_eq!(FskBandwidth::Bw4.hertz(), 4_800);
- /// assert_eq!(FskBandwidth::Bw5.hertz(), 5_800);
- /// assert_eq!(FskBandwidth::Bw7.hertz(), 7_300);
- /// assert_eq!(FskBandwidth::Bw9.hertz(), 9_700);
- /// assert_eq!(FskBandwidth::Bw11.hertz(), 11_700);
- /// assert_eq!(FskBandwidth::Bw14.hertz(), 14_600);
- /// assert_eq!(FskBandwidth::Bw19.hertz(), 19_500);
- /// assert_eq!(FskBandwidth::Bw23.hertz(), 23_400);
- /// assert_eq!(FskBandwidth::Bw29.hertz(), 29_300);
- /// assert_eq!(FskBandwidth::Bw39.hertz(), 39_000);
- /// assert_eq!(FskBandwidth::Bw46.hertz(), 46_900);
- /// assert_eq!(FskBandwidth::Bw58.hertz(), 58_600);
- /// assert_eq!(FskBandwidth::Bw78.hertz(), 78_200);
- /// assert_eq!(FskBandwidth::Bw93.hertz(), 93_800);
- /// assert_eq!(FskBandwidth::Bw117.hertz(), 117_300);
- /// assert_eq!(FskBandwidth::Bw156.hertz(), 156_200);
- /// assert_eq!(FskBandwidth::Bw187.hertz(), 187_200);
- /// assert_eq!(FskBandwidth::Bw234.hertz(), 234_300);
- /// assert_eq!(FskBandwidth::Bw312.hertz(), 312_000);
- /// assert_eq!(FskBandwidth::Bw373.hertz(), 373_600);
- /// assert_eq!(FskBandwidth::Bw467.hertz(), 467_000);
- /// ```
- pub const fn hertz(&self) -> u32 {
- match self {
- FskBandwidth::Bw4 => 4_800,
- FskBandwidth::Bw5 => 5_800,
- FskBandwidth::Bw7 => 7_300,
- FskBandwidth::Bw9 => 9_700,
- FskBandwidth::Bw11 => 11_700,
- FskBandwidth::Bw14 => 14_600,
- FskBandwidth::Bw19 => 19_500,
- FskBandwidth::Bw23 => 23_400,
- FskBandwidth::Bw29 => 29_300,
- FskBandwidth::Bw39 => 39_000,
- FskBandwidth::Bw46 => 46_900,
- FskBandwidth::Bw58 => 58_600,
- FskBandwidth::Bw78 => 78_200,
- FskBandwidth::Bw93 => 93_800,
- FskBandwidth::Bw117 => 117_300,
- FskBandwidth::Bw156 => 156_200,
- FskBandwidth::Bw187 => 187_200,
- FskBandwidth::Bw234 => 234_300,
- FskBandwidth::Bw312 => 312_000,
- FskBandwidth::Bw373 => 373_600,
- FskBandwidth::Bw467 => 467_000,
- }
- }
-
- /// Convert from a raw bit value.
- ///
- /// Invalid values will be returned in the `Err` variant of the result.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::FskBandwidth;
- ///
- /// assert_eq!(FskBandwidth::from_bits(0x1F), Ok(FskBandwidth::Bw4));
- /// assert_eq!(FskBandwidth::from_bits(0x17), Ok(FskBandwidth::Bw5));
- /// assert_eq!(FskBandwidth::from_bits(0x0F), Ok(FskBandwidth::Bw7));
- /// assert_eq!(FskBandwidth::from_bits(0x1E), Ok(FskBandwidth::Bw9));
- /// assert_eq!(FskBandwidth::from_bits(0x16), Ok(FskBandwidth::Bw11));
- /// assert_eq!(FskBandwidth::from_bits(0x0E), Ok(FskBandwidth::Bw14));
- /// assert_eq!(FskBandwidth::from_bits(0x1D), Ok(FskBandwidth::Bw19));
- /// assert_eq!(FskBandwidth::from_bits(0x15), Ok(FskBandwidth::Bw23));
- /// assert_eq!(FskBandwidth::from_bits(0x0D), Ok(FskBandwidth::Bw29));
- /// assert_eq!(FskBandwidth::from_bits(0x1C), Ok(FskBandwidth::Bw39));
- /// assert_eq!(FskBandwidth::from_bits(0x14), Ok(FskBandwidth::Bw46));
- /// assert_eq!(FskBandwidth::from_bits(0x0C), Ok(FskBandwidth::Bw58));
- /// assert_eq!(FskBandwidth::from_bits(0x1B), Ok(FskBandwidth::Bw78));
- /// assert_eq!(FskBandwidth::from_bits(0x13), Ok(FskBandwidth::Bw93));
- /// assert_eq!(FskBandwidth::from_bits(0x0B), Ok(FskBandwidth::Bw117));
- /// assert_eq!(FskBandwidth::from_bits(0x1A), Ok(FskBandwidth::Bw156));
- /// assert_eq!(FskBandwidth::from_bits(0x12), Ok(FskBandwidth::Bw187));
- /// assert_eq!(FskBandwidth::from_bits(0x0A), Ok(FskBandwidth::Bw234));
- /// assert_eq!(FskBandwidth::from_bits(0x19), Ok(FskBandwidth::Bw312));
- /// assert_eq!(FskBandwidth::from_bits(0x11), Ok(FskBandwidth::Bw373));
- /// assert_eq!(FskBandwidth::from_bits(0x09), Ok(FskBandwidth::Bw467));
- /// assert_eq!(FskBandwidth::from_bits(0x00), Err(0x00));
- /// ```
- pub const fn from_bits(bits: u8) -> Result {
- match bits {
- 0x1F => Ok(Self::Bw4),
- 0x17 => Ok(Self::Bw5),
- 0x0F => Ok(Self::Bw7),
- 0x1E => Ok(Self::Bw9),
- 0x16 => Ok(Self::Bw11),
- 0x0E => Ok(Self::Bw14),
- 0x1D => Ok(Self::Bw19),
- 0x15 => Ok(Self::Bw23),
- 0x0D => Ok(Self::Bw29),
- 0x1C => Ok(Self::Bw39),
- 0x14 => Ok(Self::Bw46),
- 0x0C => Ok(Self::Bw58),
- 0x1B => Ok(Self::Bw78),
- 0x13 => Ok(Self::Bw93),
- 0x0B => Ok(Self::Bw117),
- 0x1A => Ok(Self::Bw156),
- 0x12 => Ok(Self::Bw187),
- 0x0A => Ok(Self::Bw234),
- 0x19 => Ok(Self::Bw312),
- 0x11 => Ok(Self::Bw373),
- 0x09 => Ok(Self::Bw467),
- x => Err(x),
- }
- }
-}
-
-impl Ord for FskBandwidth {
- fn cmp(&self, other: &Self) -> core::cmp::Ordering {
- self.hertz().cmp(&other.hertz())
- }
-}
-
-impl PartialOrd for FskBandwidth {
- fn partial_cmp(&self, other: &Self) -> Option {
- Some(self.hertz().cmp(&other.hertz()))
- }
-}
-
-/// Pulse shaping options for [`FskModParams`].
-#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum FskPulseShape {
- /// No filtering applied.
- None = 0b00,
- /// Gaussian BT 0.3
- Bt03 = 0x08,
- /// Gaussian BT 0.5
- Bt05 = 0x09,
- /// Gaussian BT 0.7
- Bt07 = 0x0A,
- /// Gaussian BT 1.0
- Bt10 = 0x0B,
-}
-
-/// Bitrate argument for [`FskModParams::set_bitrate`] and
-/// [`BpskModParams::set_bitrate`].
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-pub struct FskBitrate {
- bits: u32,
-}
-
-impl FskBitrate {
- /// Create a new `FskBitrate` from a bitrate in bits per second.
- ///
- /// This the resulting value will be rounded down, and will saturate if
- /// `bps` is outside of the theoretical limits.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::FskBitrate;
- ///
- /// const BITRATE: FskBitrate = FskBitrate::from_bps(9600);
- /// assert_eq!(BITRATE.as_bps(), 9600);
- /// ```
- pub const fn from_bps(bps: u32) -> Self {
- const MAX: u32 = 0x00FF_FFFF;
- if bps == 0 {
- Self { bits: MAX }
- } else {
- let bits: u32 = 32 * 32_000_000 / bps;
- if bits > MAX {
- Self { bits: MAX }
- } else {
- Self { bits }
- }
- }
- }
-
- /// Create a new `FskBitrate` from a raw bit value.
- ///
- /// bits = 32 × 32 MHz / bitrate
- ///
- /// **Note:** Only the first 24 bits of the `u32` are used, the `bits`
- /// argument will be masked.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::FskBitrate;
- ///
- /// const BITRATE: FskBitrate = FskBitrate::from_raw(0x7D00);
- /// assert_eq!(BITRATE.as_bps(), 32_000);
- /// ```
- pub const fn from_raw(bits: u32) -> Self {
- Self {
- bits: bits & 0x00FF_FFFF,
- }
- }
-
- /// Return the bitrate in bits per second, rounded down.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::FskBitrate;
- ///
- /// const BITS_PER_SEC: u32 = 9600;
- /// const BITRATE: FskBitrate = FskBitrate::from_bps(BITS_PER_SEC);
- /// assert_eq!(BITRATE.as_bps(), BITS_PER_SEC);
- /// ```
- pub const fn as_bps(&self) -> u32 {
- if self.bits == 0 {
- 0
- } else {
- 32 * 32_000_000 / self.bits
- }
- }
-
- pub(crate) const fn into_bits(self) -> u32 {
- self.bits
- }
-}
-
-impl Ord for FskBitrate {
- fn cmp(&self, other: &Self) -> core::cmp::Ordering {
- self.as_bps().cmp(&other.as_bps())
- }
-}
-
-impl PartialOrd for FskBitrate {
- fn partial_cmp(&self, other: &Self) -> Option {
- Some(self.as_bps().cmp(&other.as_bps()))
- }
-}
-
-/// Frequency deviation argument for [`FskModParams::set_fdev`]
-#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct FskFdev {
- bits: u32,
-}
-
-impl FskFdev {
- /// Create a new `FskFdev` from a frequency deviation in hertz, rounded
- /// down.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::FskFdev;
- ///
- /// const FDEV: FskFdev = FskFdev::from_hertz(31_250);
- /// assert_eq!(FDEV.as_hertz(), 31_250);
- /// ```
- pub const fn from_hertz(hz: u32) -> Self {
- Self {
- bits: ((hz as u64) * (1 << 25) / 32_000_000) as u32 & 0x00FF_FFFF,
- }
- }
-
- /// Create a new `FskFdev` from a raw bit value.
- ///
- /// bits = fdev × 225 / 32 MHz
- ///
- /// **Note:** Only the first 24 bits of the `u32` are used, the `bits`
- /// argument will be masked.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::FskFdev;
- ///
- /// const FDEV: FskFdev = FskFdev::from_raw(0x8000);
- /// assert_eq!(FDEV.as_hertz(), 31_250);
- /// ```
- pub const fn from_raw(bits: u32) -> Self {
- Self {
- bits: bits & 0x00FF_FFFF,
- }
- }
-
- /// Return the frequency deviation in hertz, rounded down.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::FskFdev;
- ///
- /// const HERTZ: u32 = 31_250;
- /// const FDEV: FskFdev = FskFdev::from_hertz(HERTZ);
- /// assert_eq!(FDEV.as_hertz(), HERTZ);
- /// ```
- pub const fn as_hertz(&self) -> u32 {
- ((self.bits as u64) * 32_000_000 / (1 << 25)) as u32
- }
-
- pub(crate) const fn into_bits(self) -> u32 {
- self.bits
- }
-}
-
-/// (G)FSK modulation parameters.
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct FskModParams {
- buf: [u8; 9],
-}
-
-impl FskModParams {
- /// Create a new `FskModParams` struct.
- ///
- /// This is the same as `default`, but in a `const` function.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::FskModParams;
- ///
- /// const MOD_PARAMS: FskModParams = FskModParams::new();
- /// ```
- pub const fn new() -> FskModParams {
- FskModParams {
- buf: [
- super::OpCode::SetModulationParams as u8,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- ],
- }
- .set_bitrate(FskBitrate::from_bps(50_000))
- .set_pulse_shape(FskPulseShape::None)
- .set_bandwidth(FskBandwidth::Bw58)
- .set_fdev(FskFdev::from_hertz(25_000))
- }
-
- /// Get the bitrate.
- ///
- /// # Example
- ///
- /// Setting the bitrate to 32,000 bits per second.
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{FskBitrate, FskModParams};
- ///
- /// const BITRATE: FskBitrate = FskBitrate::from_bps(32_000);
- /// const MOD_PARAMS: FskModParams = FskModParams::new().set_bitrate(BITRATE);
- /// assert_eq!(MOD_PARAMS.bitrate(), BITRATE);
- /// ```
- pub const fn bitrate(&self) -> FskBitrate {
- let raw: u32 = u32::from_be_bytes([0, self.buf[1], self.buf[2], self.buf[3]]);
- FskBitrate::from_raw(raw)
- }
-
- /// Set the bitrate.
- ///
- /// # Example
- ///
- /// Setting the bitrate to 32,000 bits per second.
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{FskBitrate, FskModParams};
- ///
- /// const BITRATE: FskBitrate = FskBitrate::from_bps(32_000);
- /// const MOD_PARAMS: FskModParams = FskModParams::new().set_bitrate(BITRATE);
- /// # assert_eq!(MOD_PARAMS.as_slice()[1], 0x00);
- /// # assert_eq!(MOD_PARAMS.as_slice()[2], 0x7D);
- /// # assert_eq!(MOD_PARAMS.as_slice()[3], 0x00);
- /// ```
- #[must_use = "set_bitrate returns a modified FskModParams"]
- pub const fn set_bitrate(mut self, bitrate: FskBitrate) -> FskModParams {
- let bits: u32 = bitrate.into_bits();
- self.buf[1] = ((bits >> 16) & 0xFF) as u8;
- self.buf[2] = ((bits >> 8) & 0xFF) as u8;
- self.buf[3] = (bits & 0xFF) as u8;
- self
- }
-
- /// Set the pulse shaping.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{FskModParams, FskPulseShape};
- ///
- /// const MOD_PARAMS: FskModParams = FskModParams::new().set_pulse_shape(FskPulseShape::Bt03);
- /// # assert_eq!(MOD_PARAMS.as_slice()[4], 0x08);
- /// ```
- #[must_use = "set_pulse_shape returns a modified FskModParams"]
- pub const fn set_pulse_shape(mut self, shape: FskPulseShape) -> FskModParams {
- self.buf[4] = shape as u8;
- self
- }
-
- /// Get the bandwidth.
- ///
- /// Values that do not correspond to a valid [`FskBandwidth`] will be
- /// returned in the `Err` variant of the result.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{FskBandwidth, FskModParams};
- ///
- /// const MOD_PARAMS: FskModParams = FskModParams::new().set_bandwidth(FskBandwidth::Bw9);
- /// assert_eq!(MOD_PARAMS.bandwidth(), Ok(FskBandwidth::Bw9));
- /// ```
- pub const fn bandwidth(&self) -> Result {
- FskBandwidth::from_bits(self.buf[5])
- }
-
- /// Set the bandwidth.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{FskBandwidth, FskModParams};
- ///
- /// const MOD_PARAMS: FskModParams = FskModParams::new().set_bandwidth(FskBandwidth::Bw9);
- /// # assert_eq!(MOD_PARAMS.as_slice()[5], 0x1E);
- /// ```
- #[must_use = "set_pulse_shape returns a modified FskModParams"]
- pub const fn set_bandwidth(mut self, bw: FskBandwidth) -> FskModParams {
- self.buf[5] = bw as u8;
- self
- }
-
- /// Get the frequency deviation.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{FskFdev, FskModParams};
- ///
- /// const FDEV: FskFdev = FskFdev::from_hertz(31_250);
- /// const MOD_PARAMS: FskModParams = FskModParams::new().set_fdev(FDEV);
- /// assert_eq!(MOD_PARAMS.fdev(), FDEV);
- /// ```
- pub const fn fdev(&self) -> FskFdev {
- let raw: u32 = u32::from_be_bytes([0, self.buf[6], self.buf[7], self.buf[8]]);
- FskFdev::from_raw(raw)
- }
-
- /// Set the frequency deviation.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{FskFdev, FskModParams};
- ///
- /// const FDEV: FskFdev = FskFdev::from_hertz(31_250);
- /// const MOD_PARAMS: FskModParams = FskModParams::new().set_fdev(FDEV);
- /// # assert_eq!(MOD_PARAMS.as_slice()[6], 0x00);
- /// # assert_eq!(MOD_PARAMS.as_slice()[7], 0x80);
- /// # assert_eq!(MOD_PARAMS.as_slice()[8], 0x00);
- /// ```
- #[must_use = "set_fdev returns a modified FskModParams"]
- pub const fn set_fdev(mut self, fdev: FskFdev) -> FskModParams {
- let bits: u32 = fdev.into_bits();
- self.buf[6] = ((bits >> 16) & 0xFF) as u8;
- self.buf[7] = ((bits >> 8) & 0xFF) as u8;
- self.buf[8] = (bits & 0xFF) as u8;
- self
- }
- /// Returns `true` if the modulation parameters are valid.
- ///
- /// The bandwidth must be chosen so that:
- ///
- /// [`FskBandwidth`] > [`FskBitrate`] + 2 × [`FskFdev`] + frequency error
- ///
- /// Where frequency error = 2 × HSE32FREQ error.
- ///
- /// The datasheet (DS13293 Rev 1) gives these requirements for the HSE32
- /// frequency tolerance:
- ///
- /// * Initial: ±10 ppm
- /// * Over temperature (-20 to 70 °C): ±10 ppm
- /// * Aging over 10 years: ±10 ppm
- ///
- /// # Example
- ///
- /// Checking valid parameters at compile-time
- ///
- /// ```
- /// extern crate static_assertions as sa;
- /// use stm32wlxx_hal::subghz::{FskBandwidth, FskBitrate, FskFdev, FskModParams, FskPulseShape};
- ///
- /// const MOD_PARAMS: FskModParams = FskModParams::new()
- /// .set_bitrate(FskBitrate::from_bps(20_000))
- /// .set_pulse_shape(FskPulseShape::Bt03)
- /// .set_bandwidth(FskBandwidth::Bw58)
- /// .set_fdev(FskFdev::from_hertz(10_000));
- ///
- /// // 30 PPM is wost case (if the HSE32 crystal meets requirements)
- /// sa::const_assert!(MOD_PARAMS.is_valid(30));
- /// ```
- #[must_use = "the return value indicates if the modulation parameters are valid"]
- pub const fn is_valid(&self, ppm: u8) -> bool {
- let bw: u32 = match self.bandwidth() {
- Ok(bw) => bw.hertz(),
- Err(_) => return false,
- };
- let br: u32 = self.bitrate().as_bps();
- let fdev: u32 = self.fdev().as_hertz();
- let hse_err: u32 = 32 * (ppm as u32);
- let freq_err: u32 = 2 * hse_err;
-
- bw > br + 2 * fdev + freq_err
- }
-
- /// Returns `true` if the modulation parameters are valid for a worst-case
- /// crystal tolerance.
- ///
- /// This is equivalent to [`is_valid`](Self::is_valid) with a `ppm` argument
- /// of 30.
- #[must_use = "the return value indicates if the modulation parameters are valid"]
- pub const fn is_valid_worst_case(&self) -> bool {
- self.is_valid(30)
- }
-
- /// Extracts a slice containing the packet.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{FskBandwidth, FskBitrate, FskFdev, FskModParams, FskPulseShape};
- ///
- /// const BITRATE: FskBitrate = FskBitrate::from_bps(20_000);
- /// const PULSE_SHAPE: FskPulseShape = FskPulseShape::Bt03;
- /// const BW: FskBandwidth = FskBandwidth::Bw58;
- /// const FDEV: FskFdev = FskFdev::from_hertz(10_000);
- ///
- /// const MOD_PARAMS: FskModParams = FskModParams::new()
- /// .set_bitrate(BITRATE)
- /// .set_pulse_shape(PULSE_SHAPE)
- /// .set_bandwidth(BW)
- /// .set_fdev(FDEV);
- ///
- /// assert_eq!(
- /// MOD_PARAMS.as_slice(),
- /// &[0x8B, 0x00, 0xC8, 0x00, 0x08, 0x0C, 0x00, 0x28, 0xF5]
- /// );
- /// ```
- pub const fn as_slice(&self) -> &[u8] {
- &self.buf
- }
-}
-
-impl Default for FskModParams {
- fn default() -> Self {
- Self::new()
- }
-}
-
-/// LoRa spreading factor.
-///
-/// Argument of [`LoRaModParams::set_sf`].
-///
-/// Higher spreading factors improve receiver sensitivity, but reduce bit rate
-/// and increase power consumption.
-#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-#[repr(u8)]
-pub enum SpreadingFactor {
- /// Spreading factor 5.
- Sf5 = 0x05,
- /// Spreading factor 6.
- Sf6 = 0x06,
- /// Spreading factor 7.
- Sf7 = 0x07,
- /// Spreading factor 8.
- Sf8 = 0x08,
- /// Spreading factor 9.
- Sf9 = 0x09,
- /// Spreading factor 10.
- Sf10 = 0x0A,
- /// Spreading factor 11.
- Sf11 = 0x0B,
- /// Spreading factor 12.
- Sf12 = 0x0C,
-}
-
-impl From for u8 {
- fn from(sf: SpreadingFactor) -> Self {
- sf as u8
- }
-}
-
-/// LoRa bandwidth.
-///
-/// Argument of [`LoRaModParams::set_bw`].
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-#[repr(u8)]
-pub enum LoRaBandwidth {
- /// 7.81 kHz
- Bw7 = 0x00,
- /// 10.42 kHz
- Bw10 = 0x08,
- /// 15.63 kHz
- Bw15 = 0x01,
- /// 20.83 kHz
- Bw20 = 0x09,
- /// 31.25 kHz
- Bw31 = 0x02,
- /// 41.67 kHz
- Bw41 = 0x0A,
- /// 62.50 kHz
- Bw62 = 0x03,
- /// 125 kHz
- Bw125 = 0x04,
- /// 250 kHz
- Bw250 = 0x05,
- /// 500 kHz
- Bw500 = 0x06,
-}
-
-impl LoRaBandwidth {
- /// Get the bandwidth in hertz.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::LoRaBandwidth;
- ///
- /// assert_eq!(LoRaBandwidth::Bw7.hertz(), 7_810);
- /// assert_eq!(LoRaBandwidth::Bw10.hertz(), 10_420);
- /// assert_eq!(LoRaBandwidth::Bw15.hertz(), 15_630);
- /// assert_eq!(LoRaBandwidth::Bw20.hertz(), 20_830);
- /// assert_eq!(LoRaBandwidth::Bw31.hertz(), 31_250);
- /// assert_eq!(LoRaBandwidth::Bw41.hertz(), 41_670);
- /// assert_eq!(LoRaBandwidth::Bw62.hertz(), 62_500);
- /// assert_eq!(LoRaBandwidth::Bw125.hertz(), 125_000);
- /// assert_eq!(LoRaBandwidth::Bw250.hertz(), 250_000);
- /// assert_eq!(LoRaBandwidth::Bw500.hertz(), 500_000);
- /// ```
- pub const fn hertz(&self) -> u32 {
- match self {
- LoRaBandwidth::Bw7 => 7_810,
- LoRaBandwidth::Bw10 => 10_420,
- LoRaBandwidth::Bw15 => 15_630,
- LoRaBandwidth::Bw20 => 20_830,
- LoRaBandwidth::Bw31 => 31_250,
- LoRaBandwidth::Bw41 => 41_670,
- LoRaBandwidth::Bw62 => 62_500,
- LoRaBandwidth::Bw125 => 125_000,
- LoRaBandwidth::Bw250 => 250_000,
- LoRaBandwidth::Bw500 => 500_000,
- }
- }
-}
-
-impl Ord for LoRaBandwidth {
- fn cmp(&self, other: &Self) -> core::cmp::Ordering {
- self.hertz().cmp(&other.hertz())
- }
-}
-
-impl PartialOrd for LoRaBandwidth {
- fn partial_cmp(&self, other: &Self) -> Option {
- Some(self.hertz().cmp(&other.hertz()))
- }
-}
-
-/// LoRa forward error correction coding rate.
-///
-/// Argument of [`LoRaModParams::set_cr`].
-///
-/// A higher coding rate provides better immunity to interference at the expense
-/// of longer transmission time.
-/// In normal conditions [`CodingRate::Cr45`] provides the best trade off.
-/// In case of strong interference, a higher coding rate may be used.
-#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-#[repr(u8)]
-pub enum CodingRate {
- /// No forward error correction coding rate 4/4
- ///
- /// Overhead ratio of 1
- Cr44 = 0x00,
- /// Forward error correction coding rate 4/5
- ///
- /// Overhead ratio of 1.25
- Cr45 = 0x1,
- /// Forward error correction coding rate 4/6
- ///
- /// Overhead ratio of 1.5
- Cr46 = 0x2,
- /// Forward error correction coding rate 4/7
- ///
- /// Overhead ratio of 1.75
- Cr47 = 0x3,
- /// Forward error correction coding rate 4/8
- ///
- /// Overhead ratio of 2
- Cr48 = 0x4,
-}
-
-/// LoRa modulation parameters.
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-
-pub struct LoRaModParams {
- buf: [u8; 5],
-}
-
-impl LoRaModParams {
- /// Create a new `LoRaModParams` struct.
- ///
- /// This is the same as `default`, but in a `const` function.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::LoRaModParams;
- ///
- /// const MOD_PARAMS: LoRaModParams = LoRaModParams::new();
- /// assert_eq!(MOD_PARAMS, LoRaModParams::default());
- /// ```
- pub const fn new() -> LoRaModParams {
- LoRaModParams {
- buf: [
- super::OpCode::SetModulationParams as u8,
- 0x05, // valid spreading factor
- 0x00,
- 0x00,
- 0x00,
- ],
- }
- }
-
- /// Set the spreading factor.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{LoRaModParams, SpreadingFactor};
- ///
- /// const MOD_PARAMS: LoRaModParams = LoRaModParams::new().set_sf(SpreadingFactor::Sf7);
- /// # assert_eq!(MOD_PARAMS.as_slice(), &[0x8B, 0x07, 0x00, 0x00, 0x00]);
- /// ```
- #[must_use = "set_sf returns a modified LoRaModParams"]
- pub const fn set_sf(mut self, sf: SpreadingFactor) -> Self {
- self.buf[1] = sf as u8;
- self
- }
-
- /// Set the bandwidth.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{LoRaBandwidth, LoRaModParams};
- ///
- /// const MOD_PARAMS: LoRaModParams = LoRaModParams::new().set_bw(LoRaBandwidth::Bw125);
- /// # assert_eq!(MOD_PARAMS.as_slice(), &[0x8B, 0x05, 0x04, 0x00, 0x00]);
- /// ```
- #[must_use = "set_bw returns a modified LoRaModParams"]
- pub const fn set_bw(mut self, bw: LoRaBandwidth) -> Self {
- self.buf[2] = bw as u8;
- self
- }
-
- /// Set the forward error correction coding rate.
- ///
- /// See [`CodingRate`] for more information.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{CodingRate, LoRaModParams};
- ///
- /// const MOD_PARAMS: LoRaModParams = LoRaModParams::new().set_cr(CodingRate::Cr45);
- /// # assert_eq!(MOD_PARAMS.as_slice(), &[0x8B, 0x05, 0x00, 0x01, 0x00]);
- /// ```
- #[must_use = "set_cr returns a modified LoRaModParams"]
- pub const fn set_cr(mut self, cr: CodingRate) -> Self {
- self.buf[3] = cr as u8;
- self
- }
-
- /// Set low data rate optimization enable.
- ///
- /// For low data rates (typically high SF or low BW) and very long payloads
- /// (may last several seconds), the low data rate optimization (LDRO) can be
- /// enabled.
- /// This reduces the number of bits per symbol to the given SF minus 2,
- /// to allow the receiver to have a better tracking of the LoRa receive
- /// signal.
- /// Depending on the payload length, the low data rate optimization is
- /// usually recommended when the LoRa symbol time is equal or above
- /// 16.38 ms.
- /// When using LoRa modulation, the total frequency drift over the packet
- /// time must be kept lower than Freq_drift_max:
- ///
- /// Freq_drift_max = BW / (3 × 2SF)
- ///
- /// When possible, enabling the low data rate optimization, relaxes the
- /// total frequency drift over the packet time by 16:
- ///
- /// Freq_drift_optimise_max = 16 × Freq_drift_max
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::LoRaModParams;
- ///
- /// const MOD_PARAMS: LoRaModParams = LoRaModParams::new().set_ldro_en(true);
- /// # assert_eq!(MOD_PARAMS.as_slice(), &[0x8B, 0x05, 0x00, 0x00, 0x01]);
- /// ```
- #[must_use = "set_ldro_en returns a modified LoRaModParams"]
- pub const fn set_ldro_en(mut self, en: bool) -> Self {
- self.buf[4] = en as u8;
- self
- }
-
- /// Extracts a slice containing the packet.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{CodingRate, LoRaBandwidth, LoRaModParams, SpreadingFactor};
- ///
- /// const MOD_PARAMS: LoRaModParams = LoRaModParams::new()
- /// .set_sf(SpreadingFactor::Sf7)
- /// .set_bw(LoRaBandwidth::Bw125)
- /// .set_cr(CodingRate::Cr45)
- /// .set_ldro_en(false);
- ///
- /// assert_eq!(MOD_PARAMS.as_slice(), &[0x8B, 0x07, 0x04, 0x01, 0x00]);
- /// ```
- pub const fn as_slice(&self) -> &[u8] {
- &self.buf
- }
-}
-
-impl Default for LoRaModParams {
- fn default() -> Self {
- Self::new()
- }
-}
-
-/// BPSK modulation parameters.
-///
-/// **Note:** There is no method to set the pulse shape because there is only
-/// one valid pulse shape (Gaussian BT 0.5).
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct BpskModParams {
- buf: [u8; 5],
-}
-
-impl BpskModParams {
- /// Create a new `BpskModParams` struct.
- ///
- /// This is the same as `default`, but in a `const` function.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::BpskModParams;
- ///
- /// const MOD_PARAMS: BpskModParams = BpskModParams::new();
- /// assert_eq!(MOD_PARAMS, BpskModParams::default());
- /// ```
- pub const fn new() -> BpskModParams {
- const OPCODE: u8 = super::OpCode::SetModulationParams as u8;
- BpskModParams {
- buf: [OPCODE, 0x1A, 0x0A, 0xAA, 0x16],
- }
- }
-
- /// Set the bitrate.
- ///
- /// # Example
- ///
- /// Setting the bitrate to 600 bits per second.
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{BpskModParams, FskBitrate};
- ///
- /// const BITRATE: FskBitrate = FskBitrate::from_bps(600);
- /// const MOD_PARAMS: BpskModParams = BpskModParams::new().set_bitrate(BITRATE);
- /// # assert_eq!(MOD_PARAMS.as_slice()[1], 0x1A);
- /// # assert_eq!(MOD_PARAMS.as_slice()[2], 0x0A);
- /// # assert_eq!(MOD_PARAMS.as_slice()[3], 0xAA);
- /// ```
- #[must_use = "set_bitrate returns a modified BpskModParams"]
- pub const fn set_bitrate(mut self, bitrate: FskBitrate) -> BpskModParams {
- let bits: u32 = bitrate.into_bits();
- self.buf[1] = ((bits >> 16) & 0xFF) as u8;
- self.buf[2] = ((bits >> 8) & 0xFF) as u8;
- self.buf[3] = (bits & 0xFF) as u8;
- self
- }
-
- /// Extracts a slice containing the packet.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{BpskModParams, FskBitrate};
- ///
- /// const BITRATE: FskBitrate = FskBitrate::from_bps(100);
- /// const MOD_PARAMS: BpskModParams = BpskModParams::new().set_bitrate(BITRATE);
- /// assert_eq!(MOD_PARAMS.as_slice(), [0x8B, 0x9C, 0x40, 0x00, 0x16]);
- /// ```
- pub const fn as_slice(&self) -> &[u8] {
- &self.buf
- }
-}
-
-impl Default for BpskModParams {
- fn default() -> Self {
- Self::new()
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::{FskBandwidth, FskBitrate, FskFdev, LoRaBandwidth};
-
- #[test]
- fn fsk_bw_ord() {
- assert!((FskBandwidth::Bw4 as u8) > (FskBandwidth::Bw5 as u8));
- assert!(FskBandwidth::Bw4 < FskBandwidth::Bw5);
- assert!(FskBandwidth::Bw5 > FskBandwidth::Bw4);
- }
-
- #[test]
- fn lora_bw_ord() {
- assert!((LoRaBandwidth::Bw10 as u8) > (LoRaBandwidth::Bw15 as u8));
- assert!(LoRaBandwidth::Bw10 < LoRaBandwidth::Bw15);
- assert!(LoRaBandwidth::Bw15 > LoRaBandwidth::Bw10);
- }
-
- #[test]
- fn fsk_bitrate_ord() {
- assert!(FskBitrate::from_bps(9600) > FskBitrate::from_bps(4800));
- assert!(FskBitrate::from_bps(4800) < FskBitrate::from_bps(9600));
- }
-
- #[test]
- fn fsk_bitrate_as_bps_limits() {
- const ZERO: FskBitrate = FskBitrate::from_raw(0);
- const ONE: FskBitrate = FskBitrate::from_raw(1);
- const MAX: FskBitrate = FskBitrate::from_raw(u32::MAX);
-
- assert_eq!(ZERO.as_bps(), 0);
- assert_eq!(ONE.as_bps(), 1_024_000_000);
- assert_eq!(MAX.as_bps(), 61);
- }
-
- #[test]
- fn fsk_bitrate_from_bps_limits() {
- const ZERO: FskBitrate = FskBitrate::from_bps(0);
- const ONE: FskBitrate = FskBitrate::from_bps(1);
- const MAX: FskBitrate = FskBitrate::from_bps(u32::MAX);
-
- assert_eq!(ZERO.as_bps(), 61);
- assert_eq!(ONE.as_bps(), 61);
- assert_eq!(MAX.as_bps(), 0);
- }
-
- #[test]
- fn fsk_fdev_ord() {
- assert!(FskFdev::from_hertz(30_000) > FskFdev::from_hertz(20_000));
- assert!(FskFdev::from_hertz(20_000) < FskFdev::from_hertz(30_000));
- }
-
- #[test]
- fn fsk_fdev_as_hertz_limits() {
- const ZERO: FskFdev = FskFdev::from_raw(0);
- const ONE: FskFdev = FskFdev::from_raw(1);
- const MAX: FskFdev = FskFdev::from_raw(u32::MAX);
-
- assert_eq!(ZERO.as_hertz(), 0);
- assert_eq!(ONE.as_hertz(), 0);
- assert_eq!(MAX.as_hertz(), 15_999_999);
- }
-
- #[test]
- fn fsk_fdev_from_hertz_limits() {
- const ZERO: FskFdev = FskFdev::from_hertz(0);
- const ONE: FskFdev = FskFdev::from_hertz(1);
- const MAX: FskFdev = FskFdev::from_hertz(u32::MAX);
-
- assert_eq!(ZERO.as_hertz(), 0);
- assert_eq!(ONE.as_hertz(), 0);
- assert_eq!(MAX.as_hertz(), 6_967_294);
- }
-}
diff --git a/embassy-stm32/src/subghz/ocp.rs b/embassy-stm32/src/subghz/ocp.rs
deleted file mode 100644
index 81e89c21..00000000
--- a/embassy-stm32/src/subghz/ocp.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-/// Power amplifier over current protection.
-///
-/// Used by [`set_pa_ocp`].
-///
-/// [`set_pa_ocp`]: super::SubGhz::set_pa_ocp
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-#[repr(u8)]
-pub enum Ocp {
- /// Maximum 60mA current for LP PA mode.
- Max60m = 0x18,
- /// Maximum 140mA for HP PA mode.
- Max140m = 0x38,
-}
diff --git a/embassy-stm32/src/subghz/op_error.rs b/embassy-stm32/src/subghz/op_error.rs
deleted file mode 100644
index b17b9920..00000000
--- a/embassy-stm32/src/subghz/op_error.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-/// Operation Errors.
-///
-/// Returned by [`op_error`].
-///
-/// [`op_error`]: super::SubGhz::op_error
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-#[repr(u8)]
-pub enum OpError {
- /// PA ramping failed
- PaRampError = 8,
- /// RF-PLL locking failed
- PllLockError = 6,
- /// HSE32 clock startup failed
- XoscStartError = 5,
- /// Image calibration failed
- ImageCalibrationError = 4,
- /// RF-ADC calibration failed
- AdcCalibrationError = 3,
- /// RF-PLL calibration failed
- PllCalibrationError = 2,
- /// Sub-GHz radio RC 13 MHz oscillator
- RC13MCalibrationError = 1,
- /// Sub-GHz radio RC 64 kHz oscillator
- RC64KCalibrationError = 0,
-}
-
-impl OpError {
- /// Get the bitmask for the error.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::OpError;
- ///
- /// assert_eq!(OpError::PaRampError.mask(), 0b1_0000_0000);
- /// assert_eq!(OpError::PllLockError.mask(), 0b0_0100_0000);
- /// assert_eq!(OpError::XoscStartError.mask(), 0b0_0010_0000);
- /// assert_eq!(OpError::ImageCalibrationError.mask(), 0b0_0001_0000);
- /// assert_eq!(OpError::AdcCalibrationError.mask(), 0b0_0000_1000);
- /// assert_eq!(OpError::PllCalibrationError.mask(), 0b0_0000_0100);
- /// assert_eq!(OpError::RC13MCalibrationError.mask(), 0b0_0000_0010);
- /// assert_eq!(OpError::RC64KCalibrationError.mask(), 0b0_0000_0001);
- /// ```
- pub const fn mask(self) -> u16 {
- 1 << (self as u8)
- }
-}
diff --git a/embassy-stm32/src/subghz/pa_config.rs b/embassy-stm32/src/subghz/pa_config.rs
deleted file mode 100644
index 875827bd..00000000
--- a/embassy-stm32/src/subghz/pa_config.rs
+++ /dev/null
@@ -1,196 +0,0 @@
-/// Power amplifier configuration parameters.
-///
-/// Argument of [`set_pa_config`].
-///
-/// [`set_pa_config`]: super::SubGhz::set_pa_config
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct PaConfig {
- buf: [u8; 5],
-}
-
-impl PaConfig {
- /// Optimal settings for +15dBm output power with the low-power PA.
- ///
- /// This must be used with [`TxParams::LP_15`](super::TxParams::LP_15).
- pub const LP_15: PaConfig = PaConfig::new().set_pa_duty_cycle(0x6).set_hp_max(0x0).set_pa(PaSel::Lp);
-
- /// Optimal settings for +14dBm output power with the low-power PA.
- ///
- /// This must be used with [`TxParams::LP_14`](super::TxParams::LP_14).
- pub const LP_14: PaConfig = PaConfig::new().set_pa_duty_cycle(0x4).set_hp_max(0x0).set_pa(PaSel::Lp);
-
- /// Optimal settings for +10dBm output power with the low-power PA.
- ///
- /// This must be used with [`TxParams::LP_10`](super::TxParams::LP_10).
- pub const LP_10: PaConfig = PaConfig::new().set_pa_duty_cycle(0x1).set_hp_max(0x0).set_pa(PaSel::Lp);
-
- /// Optimal settings for +22dBm output power with the high-power PA.
- ///
- /// This must be used with [`TxParams::HP`](super::TxParams::HP).
- pub const HP_22: PaConfig = PaConfig::new().set_pa_duty_cycle(0x4).set_hp_max(0x7).set_pa(PaSel::Hp);
-
- /// Optimal settings for +20dBm output power with the high-power PA.
- ///
- /// This must be used with [`TxParams::HP`](super::TxParams::HP).
- pub const HP_20: PaConfig = PaConfig::new().set_pa_duty_cycle(0x3).set_hp_max(0x5).set_pa(PaSel::Hp);
-
- /// Optimal settings for +17dBm output power with the high-power PA.
- ///
- /// This must be used with [`TxParams::HP`](super::TxParams::HP).
- pub const HP_17: PaConfig = PaConfig::new().set_pa_duty_cycle(0x2).set_hp_max(0x3).set_pa(PaSel::Hp);
-
- /// Optimal settings for +14dBm output power with the high-power PA.
- ///
- /// This must be used with [`TxParams::HP`](super::TxParams::HP).
- pub const HP_14: PaConfig = PaConfig::new().set_pa_duty_cycle(0x2).set_hp_max(0x2).set_pa(PaSel::Hp);
-
- /// Create a new `PaConfig` struct.
- ///
- /// This is the same as `default`, but in a `const` function.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::PaConfig;
- ///
- /// const PA_CONFIG: PaConfig = PaConfig::new();
- /// ```
- pub const fn new() -> PaConfig {
- PaConfig {
- buf: [super::OpCode::SetPaConfig as u8, 0x01, 0x00, 0x01, 0x01],
- }
- }
-
- /// Set the power amplifier duty cycle (conduit angle) control.
- ///
- /// **Note:** Only the first 3 bits of the `pa_duty_cycle` argument are used.
- ///
- /// Duty cycle = 0.2 + 0.04 × bits
- ///
- /// # Caution
- ///
- /// The following restrictions must be observed to avoid over-stress on the PA:
- /// * LP PA mode with synthesis frequency > 400 MHz, `pa_duty_cycle` must be < 0x7.
- /// * LP PA mode with synthesis frequency < 400 MHz, `pa_duty_cycle` must be < 0x4.
- /// * HP PA mode, `pa_duty_cycle` must be < 0x4
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{PaConfig, PaSel};
- ///
- /// const PA_CONFIG: PaConfig = PaConfig::new().set_pa(PaSel::Lp).set_pa_duty_cycle(0x4);
- /// # assert_eq!(PA_CONFIG.as_slice()[1], 0x04);
- /// ```
- #[must_use = "set_pa_duty_cycle returns a modified PaConfig"]
- pub const fn set_pa_duty_cycle(mut self, pa_duty_cycle: u8) -> PaConfig {
- self.buf[1] = pa_duty_cycle & 0b111;
- self
- }
-
- /// Set the high power amplifier output power.
- ///
- /// **Note:** Only the first 3 bits of the `hp_max` argument are used.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{PaConfig, PaSel};
- ///
- /// const PA_CONFIG: PaConfig = PaConfig::new().set_pa(PaSel::Hp).set_hp_max(0x2);
- /// # assert_eq!(PA_CONFIG.as_slice()[2], 0x02);
- /// ```
- #[must_use = "set_hp_max returns a modified PaConfig"]
- pub const fn set_hp_max(mut self, hp_max: u8) -> PaConfig {
- self.buf[2] = hp_max & 0b111;
- self
- }
-
- /// Set the power amplifier to use, low or high power.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{PaConfig, PaSel};
- ///
- /// const PA_CONFIG_HP: PaConfig = PaConfig::new().set_pa(PaSel::Hp);
- /// const PA_CONFIG_LP: PaConfig = PaConfig::new().set_pa(PaSel::Lp);
- /// # assert_eq!(PA_CONFIG_HP.as_slice()[3], 0x00);
- /// # assert_eq!(PA_CONFIG_LP.as_slice()[3], 0x01);
- /// ```
- #[must_use = "set_pa returns a modified PaConfig"]
- pub const fn set_pa(mut self, pa: PaSel) -> PaConfig {
- self.buf[3] = pa as u8;
- self
- }
-
- /// Extracts a slice containing the packet.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{PaConfig, PaSel};
- ///
- /// const PA_CONFIG: PaConfig = PaConfig::new()
- /// .set_pa(PaSel::Hp)
- /// .set_pa_duty_cycle(0x2)
- /// .set_hp_max(0x3);
- ///
- /// assert_eq!(PA_CONFIG.as_slice(), &[0x95, 0x2, 0x03, 0x00, 0x01]);
- /// ```
- pub const fn as_slice(&self) -> &[u8] {
- &self.buf
- }
-}
-
-impl Default for PaConfig {
- fn default() -> Self {
- Self::new()
- }
-}
-
-/// Power amplifier selection.
-///
-/// Argument of [`PaConfig::set_pa`].
-#[repr(u8)]
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-pub enum PaSel {
- /// High power amplifier.
- Hp = 0b0,
- /// Low power amplifier.
- Lp = 0b1,
-}
-
-impl PartialOrd for PaSel {
- fn partial_cmp(&self, other: &Self) -> Option {
- Some(self.cmp(other))
- }
-}
-
-impl Ord for PaSel {
- fn cmp(&self, other: &Self) -> core::cmp::Ordering {
- match (self, other) {
- (PaSel::Hp, PaSel::Hp) | (PaSel::Lp, PaSel::Lp) => core::cmp::Ordering::Equal,
- (PaSel::Hp, PaSel::Lp) => core::cmp::Ordering::Greater,
- (PaSel::Lp, PaSel::Hp) => core::cmp::Ordering::Less,
- }
- }
-}
-
-impl Default for PaSel {
- fn default() -> Self {
- PaSel::Lp
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::PaSel;
-
- #[test]
- fn pa_sel_ord() {
- assert!(PaSel::Lp < PaSel::Hp);
- assert!(PaSel::Hp > PaSel::Lp);
- }
-}
diff --git a/embassy-stm32/src/subghz/packet_params.rs b/embassy-stm32/src/subghz/packet_params.rs
deleted file mode 100644
index db1fb88d..00000000
--- a/embassy-stm32/src/subghz/packet_params.rs
+++ /dev/null
@@ -1,534 +0,0 @@
-/// Preamble detection length for [`GenericPacketParams`].
-#[repr(u8)]
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum PreambleDetection {
- /// Preamble detection disabled.
- Disabled = 0x0,
- /// 8-bit preamble detection.
- Bit8 = 0x4,
- /// 16-bit preamble detection.
- Bit16 = 0x5,
- /// 24-bit preamble detection.
- Bit24 = 0x6,
- /// 32-bit preamble detection.
- Bit32 = 0x7,
-}
-
-/// Address comparison/filtering for [`GenericPacketParams`].
-#[repr(u8)]
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum AddrComp {
- /// Address comparison/filtering disabled.
- Disabled = 0x0,
- /// Address comparison/filtering on node address.
- Node = 0x1,
- /// Address comparison/filtering on node and broadcast addresses.
- Broadcast = 0x2,
-}
-
-/// Packet header type.
-///
-/// Argument of [`GenericPacketParams::set_header_type`] and
-/// [`LoRaPacketParams::set_header_type`].
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum HeaderType {
- /// Fixed; payload length and header field not added to packet.
- Fixed,
- /// Variable; payload length and header field added to packet.
- Variable,
-}
-
-impl HeaderType {
- pub(crate) const fn to_bits_generic(self) -> u8 {
- match self {
- HeaderType::Fixed => 0,
- HeaderType::Variable => 1,
- }
- }
-
- pub(crate) const fn to_bits_lora(self) -> u8 {
- match self {
- HeaderType::Fixed => 1,
- HeaderType::Variable => 0,
- }
- }
-}
-
-/// CRC type definition for [`GenericPacketParams`].
-#[repr(u8)]
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum CrcType {
- /// 1-byte CRC.
- Byte1 = 0x0,
- /// CRC disabled.
- Disabled = 0x1,
- /// 2-byte CRC.
- Byte2 = 0x2,
- /// 1-byte inverted CRC.
- Byte1Inverted = 0x4,
- /// 2-byte inverted CRC.
- Byte2Inverted = 0x6,
-}
-
-/// Packet parameters for [`set_packet_params`].
-///
-/// [`set_packet_params`]: super::SubGhz::set_packet_params
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct GenericPacketParams {
- buf: [u8; 10],
-}
-
-impl GenericPacketParams {
- /// Create a new `GenericPacketParams`.
- ///
- /// This is the same as `default`, but in a `const` function.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::GenericPacketParams;
- ///
- /// const PKT_PARAMS: GenericPacketParams = GenericPacketParams::new();
- /// assert_eq!(PKT_PARAMS, GenericPacketParams::default());
- /// ```
- pub const fn new() -> GenericPacketParams {
- const OPCODE: u8 = super::OpCode::SetPacketParams as u8;
- // const variable ensure the compile always optimizes the methods
- const NEW: GenericPacketParams = GenericPacketParams {
- buf: [OPCODE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
- }
- .set_preamble_len(1)
- .set_preamble_detection(PreambleDetection::Disabled)
- .set_sync_word_len(0)
- .set_addr_comp(AddrComp::Disabled)
- .set_header_type(HeaderType::Fixed)
- .set_payload_len(1);
-
- NEW
- }
-
- /// Preamble length in number of symbols.
- ///
- /// Values of zero are invalid, and will automatically be set to 1.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::GenericPacketParams;
- ///
- /// const PKT_PARAMS: GenericPacketParams = GenericPacketParams::new().set_preamble_len(0x1234);
- /// # assert_eq!(PKT_PARAMS.as_slice()[1], 0x12);
- /// # assert_eq!(PKT_PARAMS.as_slice()[2], 0x34);
- /// ```
- #[must_use = "preamble_length returns a modified GenericPacketParams"]
- pub const fn set_preamble_len(mut self, mut len: u16) -> GenericPacketParams {
- if len == 0 {
- len = 1
- }
- self.buf[1] = ((len >> 8) & 0xFF) as u8;
- self.buf[2] = (len & 0xFF) as u8;
- self
- }
-
- /// Preamble detection length in number of bit symbols.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{GenericPacketParams, PreambleDetection};
- ///
- /// const PKT_PARAMS: GenericPacketParams =
- /// GenericPacketParams::new().set_preamble_detection(PreambleDetection::Bit8);
- /// # assert_eq!(PKT_PARAMS.as_slice()[3], 0x4);
- /// ```
- #[must_use = "set_preamble_detection returns a modified GenericPacketParams"]
- pub const fn set_preamble_detection(mut self, pb_det: PreambleDetection) -> GenericPacketParams {
- self.buf[3] = pb_det as u8;
- self
- }
-
- /// Sync word length in number of bit symbols.
- ///
- /// Valid values are `0x00` - `0x40` for 0 to 64-bits respectively.
- /// Values that exceed the maximum will saturate at `0x40`.
- ///
- /// # Example
- ///
- /// Set the sync word length to 4 bytes (16 bits).
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::GenericPacketParams;
- ///
- /// const PKT_PARAMS: GenericPacketParams = GenericPacketParams::new().set_sync_word_len(16);
- /// # assert_eq!(PKT_PARAMS.as_slice()[4], 0x10);
- /// ```
- #[must_use = "set_sync_word_len returns a modified GenericPacketParams"]
- pub const fn set_sync_word_len(mut self, len: u8) -> GenericPacketParams {
- const MAX: u8 = 0x40;
- if len > MAX {
- self.buf[4] = MAX;
- } else {
- self.buf[4] = len;
- }
- self
- }
-
- /// Address comparison/filtering.
- ///
- /// # Example
- ///
- /// Enable address on the node address.
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{AddrComp, GenericPacketParams};
- ///
- /// const PKT_PARAMS: GenericPacketParams =
- /// GenericPacketParams::new().set_addr_comp(AddrComp::Node);
- /// # assert_eq!(PKT_PARAMS.as_slice()[5], 0x01);
- /// ```
- #[must_use = "set_addr_comp returns a modified GenericPacketParams"]
- pub const fn set_addr_comp(mut self, addr_comp: AddrComp) -> GenericPacketParams {
- self.buf[5] = addr_comp as u8;
- self
- }
-
- /// Header type definition.
- ///
- /// **Note:** The reference manual calls this packet type, but that results
- /// in a conflicting variable name for the modulation scheme, which the
- /// reference manual also calls packet type.
- ///
- /// # Example
- ///
- /// Set the header type to a variable length.
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{GenericPacketParams, HeaderType};
- ///
- /// const PKT_PARAMS: GenericPacketParams =
- /// GenericPacketParams::new().set_header_type(HeaderType::Variable);
- /// # assert_eq!(PKT_PARAMS.as_slice()[6], 0x01);
- /// ```
- #[must_use = "set_header_type returns a modified GenericPacketParams"]
- pub const fn set_header_type(mut self, header_type: HeaderType) -> GenericPacketParams {
- self.buf[6] = header_type.to_bits_generic();
- self
- }
-
- /// Set the payload length in bytes.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::GenericPacketParams;
- ///
- /// const PKT_PARAMS: GenericPacketParams = GenericPacketParams::new().set_payload_len(12);
- /// # assert_eq!(PKT_PARAMS.as_slice()[7], 12);
- /// ```
- #[must_use = "set_payload_len returns a modified GenericPacketParams"]
- pub const fn set_payload_len(mut self, len: u8) -> GenericPacketParams {
- self.buf[7] = len;
- self
- }
-
- /// CRC type definition.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{CrcType, GenericPacketParams};
- ///
- /// const PKT_PARAMS: GenericPacketParams =
- /// GenericPacketParams::new().set_crc_type(CrcType::Byte2Inverted);
- /// # assert_eq!(PKT_PARAMS.as_slice()[8], 0x6);
- /// ```
- #[must_use = "set_payload_len returns a modified GenericPacketParams"]
- pub const fn set_crc_type(mut self, crc_type: CrcType) -> GenericPacketParams {
- self.buf[8] = crc_type as u8;
- self
- }
-
- /// Whitening enable.
- ///
- /// # Example
- ///
- /// Enable whitening.
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::GenericPacketParams;
- ///
- /// const PKT_PARAMS: GenericPacketParams = GenericPacketParams::new().set_whitening_enable(true);
- /// # assert_eq!(PKT_PARAMS.as_slice()[9], 1);
- /// ```
- #[must_use = "set_whitening_enable returns a modified GenericPacketParams"]
- pub const fn set_whitening_enable(mut self, en: bool) -> GenericPacketParams {
- self.buf[9] = en as u8;
- self
- }
-
- /// Extracts a slice containing the packet.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{
- /// AddrComp, CrcType, GenericPacketParams, HeaderType, PreambleDetection,
- /// };
- ///
- /// const PKT_PARAMS: GenericPacketParams = GenericPacketParams::new()
- /// .set_preamble_len(8)
- /// .set_preamble_detection(PreambleDetection::Disabled)
- /// .set_sync_word_len(2)
- /// .set_addr_comp(AddrComp::Disabled)
- /// .set_header_type(HeaderType::Fixed)
- /// .set_payload_len(128)
- /// .set_crc_type(CrcType::Byte2)
- /// .set_whitening_enable(true);
- ///
- /// assert_eq!(
- /// PKT_PARAMS.as_slice(),
- /// &[0x8C, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x80, 0x02, 0x01]
- /// );
- /// ```
- pub const fn as_slice(&self) -> &[u8] {
- &self.buf
- }
-}
-
-impl Default for GenericPacketParams {
- fn default() -> Self {
- Self::new()
- }
-}
-
-/// Packet parameters for [`set_lora_packet_params`].
-///
-/// [`set_lora_packet_params`]: super::SubGhz::set_lora_packet_params
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct LoRaPacketParams {
- buf: [u8; 7],
-}
-
-impl LoRaPacketParams {
- /// Create a new `LoRaPacketParams`.
- ///
- /// This is the same as `default`, but in a `const` function.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::LoRaPacketParams;
- ///
- /// const PKT_PARAMS: LoRaPacketParams = LoRaPacketParams::new();
- /// assert_eq!(PKT_PARAMS, LoRaPacketParams::default());
- /// ```
- pub const fn new() -> LoRaPacketParams {
- const OPCODE: u8 = super::OpCode::SetPacketParams as u8;
- // const variable ensure the compile always optimizes the methods
- const NEW: LoRaPacketParams = LoRaPacketParams {
- buf: [OPCODE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
- }
- .set_preamble_len(1)
- .set_header_type(HeaderType::Fixed)
- .set_payload_len(1)
- .set_crc_en(true)
- .set_invert_iq(false);
-
- NEW
- }
-
- /// Preamble length in number of symbols.
- ///
- /// Values of zero are invalid, and will automatically be set to 1.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::LoRaPacketParams;
- ///
- /// const PKT_PARAMS: LoRaPacketParams = LoRaPacketParams::new().set_preamble_len(0x1234);
- /// # assert_eq!(PKT_PARAMS.as_slice()[1], 0x12);
- /// # assert_eq!(PKT_PARAMS.as_slice()[2], 0x34);
- /// ```
- #[must_use = "preamble_length returns a modified LoRaPacketParams"]
- pub const fn set_preamble_len(mut self, mut len: u16) -> LoRaPacketParams {
- if len == 0 {
- len = 1
- }
- self.buf[1] = ((len >> 8) & 0xFF) as u8;
- self.buf[2] = (len & 0xFF) as u8;
- self
- }
-
- /// Header type (fixed or variable).
- ///
- /// # Example
- ///
- /// Set the payload type to a fixed length.
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{HeaderType, LoRaPacketParams};
- ///
- /// const PKT_PARAMS: LoRaPacketParams = LoRaPacketParams::new().set_header_type(HeaderType::Fixed);
- /// # assert_eq!(PKT_PARAMS.as_slice()[3], 0x01);
- /// ```
- #[must_use = "set_header_type returns a modified LoRaPacketParams"]
- pub const fn set_header_type(mut self, header_type: HeaderType) -> LoRaPacketParams {
- self.buf[3] = header_type.to_bits_lora();
- self
- }
-
- /// Set the payload length in bytes.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::LoRaPacketParams;
- ///
- /// const PKT_PARAMS: LoRaPacketParams = LoRaPacketParams::new().set_payload_len(12);
- /// # assert_eq!(PKT_PARAMS.as_slice()[4], 12);
- /// ```
- #[must_use = "set_payload_len returns a modified LoRaPacketParams"]
- pub const fn set_payload_len(mut self, len: u8) -> LoRaPacketParams {
- self.buf[4] = len;
- self
- }
-
- /// CRC enable.
- ///
- /// # Example
- ///
- /// Enable CRC.
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::LoRaPacketParams;
- ///
- /// const PKT_PARAMS: LoRaPacketParams = LoRaPacketParams::new().set_crc_en(true);
- /// # assert_eq!(PKT_PARAMS.as_slice()[5], 0x1);
- /// ```
- #[must_use = "set_crc_en returns a modified LoRaPacketParams"]
- pub const fn set_crc_en(mut self, en: bool) -> LoRaPacketParams {
- self.buf[5] = en as u8;
- self
- }
-
- /// IQ setup.
- ///
- /// # Example
- ///
- /// Use an inverted IQ setup.
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::LoRaPacketParams;
- ///
- /// const PKT_PARAMS: LoRaPacketParams = LoRaPacketParams::new().set_invert_iq(true);
- /// # assert_eq!(PKT_PARAMS.as_slice()[6], 0x1);
- /// ```
- #[must_use = "set_invert_iq returns a modified LoRaPacketParams"]
- pub const fn set_invert_iq(mut self, invert: bool) -> LoRaPacketParams {
- self.buf[6] = invert as u8;
- self
- }
-
- /// Extracts a slice containing the packet.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{HeaderType, LoRaPacketParams};
- ///
- /// const PKT_PARAMS: LoRaPacketParams = LoRaPacketParams::new()
- /// .set_preamble_len(5 * 8)
- /// .set_header_type(HeaderType::Fixed)
- /// .set_payload_len(64)
- /// .set_crc_en(true)
- /// .set_invert_iq(true);
- ///
- /// assert_eq!(
- /// PKT_PARAMS.as_slice(),
- /// &[0x8C, 0x00, 0x28, 0x01, 0x40, 0x01, 0x01]
- /// );
- /// ```
- pub const fn as_slice(&self) -> &[u8] {
- &self.buf
- }
-}
-
-impl Default for LoRaPacketParams {
- fn default() -> Self {
- Self::new()
- }
-}
-
-/// Packet parameters for [`set_bpsk_packet_params`].
-///
-/// [`set_bpsk_packet_params`]: super::SubGhz::set_bpsk_packet_params
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct BpskPacketParams {
- buf: [u8; 2],
-}
-
-impl BpskPacketParams {
- /// Create a new `BpskPacketParams`.
- ///
- /// This is the same as `default`, but in a `const` function.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::BpskPacketParams;
- ///
- /// const PKT_PARAMS: BpskPacketParams = BpskPacketParams::new();
- /// assert_eq!(PKT_PARAMS, BpskPacketParams::default());
- /// ```
- pub const fn new() -> BpskPacketParams {
- BpskPacketParams {
- buf: [super::OpCode::SetPacketParams as u8, 0x00],
- }
- }
-
- /// Set the payload length in bytes.
- ///
- /// The length includes preamble, sync word, device ID, and CRC.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::BpskPacketParams;
- ///
- /// const PKT_PARAMS: BpskPacketParams = BpskPacketParams::new().set_payload_len(12);
- /// # assert_eq!(PKT_PARAMS.as_slice()[1], 12);
- /// ```
- #[must_use = "set_payload_len returns a modified BpskPacketParams"]
- pub const fn set_payload_len(mut self, len: u8) -> BpskPacketParams {
- self.buf[1] = len;
- self
- }
-
- /// Extracts a slice containing the packet.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{BpskPacketParams, HeaderType};
- ///
- /// const PKT_PARAMS: BpskPacketParams = BpskPacketParams::new().set_payload_len(24);
- ///
- /// assert_eq!(PKT_PARAMS.as_slice(), &[0x8C, 24]);
- /// ```
- pub const fn as_slice(&self) -> &[u8] {
- &self.buf
- }
-}
-
-impl Default for BpskPacketParams {
- fn default() -> Self {
- Self::new()
- }
-}
diff --git a/embassy-stm32/src/subghz/packet_status.rs b/embassy-stm32/src/subghz/packet_status.rs
deleted file mode 100644
index b3acd73c..00000000
--- a/embassy-stm32/src/subghz/packet_status.rs
+++ /dev/null
@@ -1,282 +0,0 @@
-use super::{Ratio, Status};
-
-/// (G)FSK packet status.
-///
-/// Returned by [`fsk_packet_status`].
-///
-/// [`fsk_packet_status`]: super::SubGhz::fsk_packet_status
-#[derive(Clone, Copy, PartialEq, Eq)]
-pub struct FskPacketStatus {
- buf: [u8; 4],
-}
-
-impl From<[u8; 4]> for FskPacketStatus {
- fn from(buf: [u8; 4]) -> Self {
- FskPacketStatus { buf }
- }
-}
-
-impl FskPacketStatus {
- /// Get the status.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{CmdStatus, FskPacketStatus, Status, StatusMode};
- ///
- /// let example_data_from_radio: [u8; 4] = [0x54, 0, 0, 0];
- /// let pkt_status: FskPacketStatus = FskPacketStatus::from(example_data_from_radio);
- /// let status: Status = pkt_status.status();
- /// assert_eq!(status.mode(), Ok(StatusMode::Rx));
- /// assert_eq!(status.cmd(), Ok(CmdStatus::Avaliable));
- /// ```
- pub const fn status(&self) -> Status {
- Status::from_raw(self.buf[0])
- }
-
- /// Returns `true` if a preamble error occurred.
- pub const fn preamble_err(&self) -> bool {
- (self.buf[1] & (1 << 7)) != 0
- }
-
- /// Returns `true` if a synchronization error occurred.
- pub const fn sync_err(&self) -> bool {
- (self.buf[1] & (1 << 6)) != 0
- }
-
- /// Returns `true` if an address error occurred.
- pub const fn addr_err(&self) -> bool {
- (self.buf[1] & (1 << 5)) != 0
- }
-
- /// Returns `true` if an CRC error occurred.
- pub const fn crc_err(&self) -> bool {
- (self.buf[1] & (1 << 4)) != 0
- }
-
- /// Returns `true` if a length error occurred.
- pub const fn length_err(&self) -> bool {
- (self.buf[1] & (1 << 3)) != 0
- }
-
- /// Returns `true` if an abort error occurred.
- pub const fn abort_err(&self) -> bool {
- (self.buf[1] & (1 << 2)) != 0
- }
-
- /// Returns `true` if a packet is received.
- pub const fn pkt_received(&self) -> bool {
- (self.buf[1] & (1 << 1)) != 0
- }
-
- /// Returns `true` when a packet has been sent.
- pub const fn pkt_sent(&self) -> bool {
- (self.buf[1] & 1) != 0
- }
-
- /// Returns `true` if any error occurred.
- pub const fn any_err(&self) -> bool {
- (self.buf[1] & 0xFC) != 0
- }
-
- /// RSSI level when the synchronization address is detected.
- ///
- /// Units are in dBm.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::{subghz::FskPacketStatus, Ratio};
- ///
- /// let example_data_from_radio: [u8; 4] = [0, 0, 80, 0];
- /// let pkt_status: FskPacketStatus = FskPacketStatus::from(example_data_from_radio);
- /// assert_eq!(pkt_status.rssi_sync().to_integer(), -40);
- /// ```
- pub fn rssi_sync(&self) -> Ratio {
- Ratio::new_raw(i16::from(self.buf[2]), -2)
- }
-
- /// Return the RSSI level over the received packet.
- ///
- /// Units are in dBm.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::{subghz::FskPacketStatus, Ratio};
- ///
- /// let example_data_from_radio: [u8; 4] = [0, 0, 0, 100];
- /// let pkt_status: FskPacketStatus = FskPacketStatus::from(example_data_from_radio);
- /// assert_eq!(pkt_status.rssi_avg().to_integer(), -50);
- /// ```
- pub fn rssi_avg(&self) -> Ratio {
- Ratio::new_raw(i16::from(self.buf[3]), -2)
- }
-}
-
-#[cfg(feature = "defmt")]
-impl defmt::Format for FskPacketStatus {
- fn format(&self, fmt: defmt::Formatter) {
- defmt::write!(
- fmt,
- r#"FskPacketStatus {{
- status: {},
- preamble_err: {},
- sync_err: {},
- addr_err: {},
- crc_err: {},
- length_err: {},
- abort_err: {},
- pkt_received: {},
- pkt_sent: {},
- rssi_sync: {},
- rssi_avg: {},
-}}"#,
- self.status(),
- self.preamble_err(),
- self.sync_err(),
- self.addr_err(),
- self.crc_err(),
- self.length_err(),
- self.abort_err(),
- self.pkt_received(),
- self.pkt_sent(),
- self.rssi_sync().to_integer(),
- self.rssi_avg().to_integer()
- )
- }
-}
-
-impl core::fmt::Debug for FskPacketStatus {
- fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
- f.debug_struct("FskPacketStatus")
- .field("status", &self.status())
- .field("preamble_err", &self.preamble_err())
- .field("sync_err", &self.sync_err())
- .field("addr_err", &self.addr_err())
- .field("crc_err", &self.crc_err())
- .field("length_err", &self.length_err())
- .field("abort_err", &self.abort_err())
- .field("pkt_received", &self.pkt_received())
- .field("pkt_sent", &self.pkt_sent())
- .field("rssi_sync", &self.rssi_sync().to_integer())
- .field("rssi_avg", &self.rssi_avg().to_integer())
- .finish()
- }
-}
-
-/// (G)FSK packet status.
-///
-/// Returned by [`lora_packet_status`].
-///
-/// [`lora_packet_status`]: super::SubGhz::lora_packet_status
-#[derive(Clone, Copy, PartialEq, Eq)]
-pub struct LoRaPacketStatus {
- buf: [u8; 4],
-}
-
-impl From<[u8; 4]> for LoRaPacketStatus {
- fn from(buf: [u8; 4]) -> Self {
- LoRaPacketStatus { buf }
- }
-}
-
-impl LoRaPacketStatus {
- /// Get the status.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{CmdStatus, LoRaPacketStatus, Status, StatusMode};
- ///
- /// let example_data_from_radio: [u8; 4] = [0x54, 0, 0, 0];
- /// let pkt_status: LoRaPacketStatus = LoRaPacketStatus::from(example_data_from_radio);
- /// let status: Status = pkt_status.status();
- /// assert_eq!(status.mode(), Ok(StatusMode::Rx));
- /// assert_eq!(status.cmd(), Ok(CmdStatus::Avaliable));
- /// ```
- pub const fn status(&self) -> Status {
- Status::from_raw(self.buf[0])
- }
-
- /// Average RSSI level over the received packet.
- ///
- /// Units are in dBm.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::{subghz::LoRaPacketStatus, Ratio};
- ///
- /// let example_data_from_radio: [u8; 4] = [0, 80, 0, 0];
- /// let pkt_status: LoRaPacketStatus = LoRaPacketStatus::from(example_data_from_radio);
- /// assert_eq!(pkt_status.rssi_pkt().to_integer(), -40);
- /// ```
- pub fn rssi_pkt(&self) -> Ratio {
- Ratio::new_raw(i16::from(self.buf[1]), -2)
- }
-
- /// Estimation of SNR over the received packet.
- ///
- /// Units are in dB.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::{subghz::LoRaPacketStatus, Ratio};
- ///
- /// let example_data_from_radio: [u8; 4] = [0, 0, 40, 0];
- /// let pkt_status: LoRaPacketStatus = LoRaPacketStatus::from(example_data_from_radio);
- /// assert_eq!(pkt_status.snr_pkt().to_integer(), 10);
- /// ```
- pub fn snr_pkt(&self) -> Ratio {
- Ratio::new_raw(i16::from(self.buf[2]), 4)
- }
-
- /// Estimation of RSSI level of the LoRa signal after despreading.
- ///
- /// Units are in dBm.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::{subghz::LoRaPacketStatus, Ratio};
- ///
- /// let example_data_from_radio: [u8; 4] = [0, 0, 0, 80];
- /// let pkt_status: LoRaPacketStatus = LoRaPacketStatus::from(example_data_from_radio);
- /// assert_eq!(pkt_status.signal_rssi_pkt().to_integer(), -40);
- /// ```
- pub fn signal_rssi_pkt(&self) -> Ratio {
- Ratio::new_raw(i16::from(self.buf[3]), -2)
- }
-}
-
-#[cfg(feature = "defmt")]
-impl defmt::Format for LoRaPacketStatus {
- fn format(&self, fmt: defmt::Formatter) {
- defmt::write!(
- fmt,
- r#"LoRaPacketStatus {{
- status: {},
- rssi_pkt: {},
- snr_pkt: {},
- signal_rssi_pkt: {},
-}}"#,
- self.status(),
- self.rssi_pkt().to_integer(),
- self.snr_pkt().to_integer(),
- self.signal_rssi_pkt().to_integer(),
- )
- }
-}
-
-impl core::fmt::Debug for LoRaPacketStatus {
- fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
- f.debug_struct("LoRaPacketStatus")
- .field("status", &self.status())
- .field("rssi_pkt", &self.rssi_pkt().to_integer())
- .field("snr_pkt", &self.snr_pkt().to_integer())
- .field("signal_rssi_pkt", &self.signal_rssi_pkt().to_integer())
- .finish()
- }
-}
diff --git a/embassy-stm32/src/subghz/packet_type.rs b/embassy-stm32/src/subghz/packet_type.rs
deleted file mode 100644
index 88c62bb6..00000000
--- a/embassy-stm32/src/subghz/packet_type.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-/// Packet type definition.
-///
-/// Argument of [`set_packet_type`]
-///
-/// [`set_packet_type`]: super::SubGhz::set_packet_type
-#[repr(u8)]
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum PacketType {
- /// FSK (frequency shift keying) generic packet type.
- Fsk = 0,
- /// LoRa (long range) packet type.
- LoRa = 1,
- /// BPSK (binary phase shift keying) packet type.
- Bpsk = 2,
- /// MSK (minimum shift keying) generic packet type.
- Msk = 3,
-}
-
-impl PacketType {
- /// Create a new `PacketType` from bits.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::PacketType;
- ///
- /// assert_eq!(PacketType::from_raw(0), Ok(PacketType::Fsk));
- /// assert_eq!(PacketType::from_raw(1), Ok(PacketType::LoRa));
- /// assert_eq!(PacketType::from_raw(2), Ok(PacketType::Bpsk));
- /// assert_eq!(PacketType::from_raw(3), Ok(PacketType::Msk));
- /// // Other values are reserved
- /// assert_eq!(PacketType::from_raw(4), Err(4));
- /// ```
- pub const fn from_raw(bits: u8) -> Result {
- match bits {
- 0 => Ok(PacketType::Fsk),
- 1 => Ok(PacketType::LoRa),
- 2 => Ok(PacketType::Bpsk),
- 3 => Ok(PacketType::Msk),
- _ => Err(bits),
- }
- }
-}
diff --git a/embassy-stm32/src/subghz/pkt_ctrl.rs b/embassy-stm32/src/subghz/pkt_ctrl.rs
deleted file mode 100644
index 265833e3..00000000
--- a/embassy-stm32/src/subghz/pkt_ctrl.rs
+++ /dev/null
@@ -1,247 +0,0 @@
-/// Generic packet infinite sequence selection.
-///
-/// Argument of [`PktCtrl::set_inf_seq_sel`].
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum InfSeqSel {
- /// Preamble `0x5555`.
- Five = 0b00,
- /// Preamble `0x0000`.
- Zero = 0b01,
- /// Preamble `0xFFFF`.
- One = 0b10,
- /// PRBS9.
- Prbs9 = 0b11,
-}
-
-impl Default for InfSeqSel {
- fn default() -> Self {
- InfSeqSel::Five
- }
-}
-
-/// Generic packet control.
-///
-/// Argument of [`set_pkt_ctrl`](super::SubGhz::set_pkt_ctrl).
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct PktCtrl {
- val: u8,
-}
-
-impl PktCtrl {
- /// Reset value of the packet control register.
- pub const RESET: PktCtrl = PktCtrl { val: 0x21 };
-
- /// Create a new [`PktCtrl`] structure from a raw value.
- ///
- /// Reserved bits will be masked.
- pub const fn from_raw(raw: u8) -> Self {
- Self { val: raw & 0x3F }
- }
-
- /// Get the raw value of the [`PktCtrl`] register.
- pub const fn as_bits(&self) -> u8 {
- self.val
- }
-
- /// Generic packet synchronization word detection enable.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::PktCtrl;
- ///
- /// const PKT_CTRL: PktCtrl = PktCtrl::RESET.set_sync_det_en(true);
- /// ```
- #[must_use = "set_sync_det_en returns a modified PktCtrl"]
- pub const fn set_sync_det_en(mut self, en: bool) -> PktCtrl {
- if en {
- self.val |= 1 << 5;
- } else {
- self.val &= !(1 << 5);
- }
- self
- }
-
- /// Returns `true` if generic packet synchronization word detection is
- /// enabled.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::PktCtrl;
- ///
- /// let pc: PktCtrl = PktCtrl::RESET;
- /// assert_eq!(pc.sync_det_en(), true);
- /// let pc: PktCtrl = pc.set_sync_det_en(false);
- /// assert_eq!(pc.sync_det_en(), false);
- /// let pc: PktCtrl = pc.set_sync_det_en(true);
- /// assert_eq!(pc.sync_det_en(), true);
- /// ```
- pub const fn sync_det_en(&self) -> bool {
- self.val & (1 << 5) != 0
- }
-
- /// Generic packet continuous transmit enable.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::PktCtrl;
- ///
- /// const PKT_CTRL: PktCtrl = PktCtrl::RESET.set_cont_tx_en(true);
- /// ```
- #[must_use = "set_cont_tx_en returns a modified PktCtrl"]
- pub const fn set_cont_tx_en(mut self, en: bool) -> PktCtrl {
- if en {
- self.val |= 1 << 4;
- } else {
- self.val &= !(1 << 4);
- }
- self
- }
-
- /// Returns `true` if generic packet continuous transmit is enabled.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::PktCtrl;
- ///
- /// let pc: PktCtrl = PktCtrl::RESET;
- /// assert_eq!(pc.cont_tx_en(), false);
- /// let pc: PktCtrl = pc.set_cont_tx_en(true);
- /// assert_eq!(pc.cont_tx_en(), true);
- /// let pc: PktCtrl = pc.set_cont_tx_en(false);
- /// assert_eq!(pc.cont_tx_en(), false);
- /// ```
- pub const fn cont_tx_en(&self) -> bool {
- self.val & (1 << 4) != 0
- }
-
- /// Set the continuous sequence type.
- #[must_use = "set_inf_seq_sel returns a modified PktCtrl"]
- pub const fn set_inf_seq_sel(mut self, sel: InfSeqSel) -> PktCtrl {
- self.val &= !(0b11 << 2);
- self.val |= (sel as u8) << 2;
- self
- }
-
- /// Get the continuous sequence type.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{InfSeqSel, PktCtrl};
- ///
- /// let pc: PktCtrl = PktCtrl::RESET;
- /// assert_eq!(pc.inf_seq_sel(), InfSeqSel::Five);
- ///
- /// let pc: PktCtrl = pc.set_inf_seq_sel(InfSeqSel::Zero);
- /// assert_eq!(pc.inf_seq_sel(), InfSeqSel::Zero);
- ///
- /// let pc: PktCtrl = pc.set_inf_seq_sel(InfSeqSel::One);
- /// assert_eq!(pc.inf_seq_sel(), InfSeqSel::One);
- ///
- /// let pc: PktCtrl = pc.set_inf_seq_sel(InfSeqSel::Prbs9);
- /// assert_eq!(pc.inf_seq_sel(), InfSeqSel::Prbs9);
- ///
- /// let pc: PktCtrl = pc.set_inf_seq_sel(InfSeqSel::Five);
- /// assert_eq!(pc.inf_seq_sel(), InfSeqSel::Five);
- /// ```
- pub const fn inf_seq_sel(&self) -> InfSeqSel {
- match (self.val >> 2) & 0b11 {
- 0b00 => InfSeqSel::Five,
- 0b01 => InfSeqSel::Zero,
- 0b10 => InfSeqSel::One,
- _ => InfSeqSel::Prbs9,
- }
- }
-
- /// Enable infinite sequence generation.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::PktCtrl;
- ///
- /// const PKT_CTRL: PktCtrl = PktCtrl::RESET.set_inf_seq_en(true);
- /// ```
- #[must_use = "set_inf_seq_en returns a modified PktCtrl"]
- pub const fn set_inf_seq_en(mut self, en: bool) -> PktCtrl {
- if en {
- self.val |= 1 << 1;
- } else {
- self.val &= !(1 << 1);
- }
- self
- }
-
- /// Returns `true` if infinite sequence generation is enabled.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::PktCtrl;
- ///
- /// let pc: PktCtrl = PktCtrl::RESET;
- /// assert_eq!(pc.inf_seq_en(), false);
- /// let pc: PktCtrl = pc.set_inf_seq_en(true);
- /// assert_eq!(pc.inf_seq_en(), true);
- /// let pc: PktCtrl = pc.set_inf_seq_en(false);
- /// assert_eq!(pc.inf_seq_en(), false);
- /// ```
- pub const fn inf_seq_en(&self) -> bool {
- self.val & (1 << 1) != 0
- }
-
- /// Set the value of bit-8 (9th bit) for generic packet whitening.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::PktCtrl;
- ///
- /// const PKT_CTRL: PktCtrl = PktCtrl::RESET.set_whitening_init(true);
- /// ```
- #[must_use = "set_whitening_init returns a modified PktCtrl"]
- pub const fn set_whitening_init(mut self, val: bool) -> PktCtrl {
- if val {
- self.val |= 1;
- } else {
- self.val &= !1;
- }
- self
- }
-
- /// Returns `true` if bit-8 of the generic packet whitening is set.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::PktCtrl;
- ///
- /// let pc: PktCtrl = PktCtrl::RESET;
- /// assert_eq!(pc.whitening_init(), true);
- /// let pc: PktCtrl = pc.set_whitening_init(false);
- /// assert_eq!(pc.whitening_init(), false);
- /// let pc: PktCtrl = pc.set_whitening_init(true);
- /// assert_eq!(pc.whitening_init(), true);
- /// ```
- pub const fn whitening_init(&self) -> bool {
- self.val & 0b1 != 0
- }
-}
-
-impl From for u8 {
- fn from(pc: PktCtrl) -> Self {
- pc.val
- }
-}
-
-impl Default for PktCtrl {
- fn default() -> Self {
- Self::RESET
- }
-}
diff --git a/embassy-stm32/src/subghz/pmode.rs b/embassy-stm32/src/subghz/pmode.rs
deleted file mode 100644
index 0c07f319..00000000
--- a/embassy-stm32/src/subghz/pmode.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-/// RX gain power modes.
-///
-/// Argument of [`set_rx_gain`].
-///
-/// [`set_rx_gain`]: super::SubGhz::set_rx_gain
-#[repr(u8)]
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum PMode {
- /// Power saving mode.
- ///
- /// Reduces sensitivity.
- #[allow(clippy::identity_op)]
- PowerSaving = (0x25 << 2) | 0b00,
- /// Boost mode level 1.
- ///
- /// Improves sensitivity at detriment of power consumption.
- Boost1 = (0x25 << 2) | 0b01,
- /// Boost mode level 2.
- ///
- /// Improves a set further sensitivity at detriment of power consumption.
- Boost2 = (0x25 << 2) | 0b10,
- /// Boost mode.
- ///
- /// Best receiver sensitivity.
- Boost = (0x25 << 2) | 0b11,
-}
diff --git a/embassy-stm32/src/subghz/pwr_ctrl.rs b/embassy-stm32/src/subghz/pwr_ctrl.rs
deleted file mode 100644
index 974bddeb..00000000
--- a/embassy-stm32/src/subghz/pwr_ctrl.rs
+++ /dev/null
@@ -1,160 +0,0 @@
-/// Power-supply current limit.
-///
-/// Argument of [`PwrCtrl::set_current_lim`].
-#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-#[repr(u8)]
-pub enum CurrentLim {
- /// 25 mA
- Milli25 = 0x0,
- /// 50 mA (default)
- Milli50 = 0x1,
- /// 100 mA
- Milli100 = 0x2,
- /// 200 mA
- Milli200 = 0x3,
-}
-
-impl CurrentLim {
- /// Get the SMPS drive value as milliamps.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::CurrentLim;
- ///
- /// assert_eq!(CurrentLim::Milli25.as_milliamps(), 25);
- /// assert_eq!(CurrentLim::Milli50.as_milliamps(), 50);
- /// assert_eq!(CurrentLim::Milli100.as_milliamps(), 100);
- /// assert_eq!(CurrentLim::Milli200.as_milliamps(), 200);
- /// ```
- pub const fn as_milliamps(&self) -> u8 {
- match self {
- CurrentLim::Milli25 => 25,
- CurrentLim::Milli50 => 50,
- CurrentLim::Milli100 => 100,
- CurrentLim::Milli200 => 200,
- }
- }
-}
-
-impl Default for CurrentLim {
- fn default() -> Self {
- CurrentLim::Milli50
- }
-}
-
-/// Power control.
-///
-/// Argument of [`set_bit_sync`](super::SubGhz::set_bit_sync).
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct PwrCtrl {
- val: u8,
-}
-
-impl PwrCtrl {
- /// Power control register reset value.
- pub const RESET: PwrCtrl = PwrCtrl { val: 0x50 };
-
- /// Create a new [`PwrCtrl`] structure from a raw value.
- ///
- /// Reserved bits will be masked.
- pub const fn from_raw(raw: u8) -> Self {
- Self { val: raw & 0x70 }
- }
-
- /// Get the raw value of the [`PwrCtrl`] register.
- pub const fn as_bits(&self) -> u8 {
- self.val
- }
-
- /// Set the current limiter enable.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::PwrCtrl;
- ///
- /// const PWR_CTRL: PwrCtrl = PwrCtrl::RESET.set_current_lim_en(true);
- /// # assert_eq!(u8::from(PWR_CTRL), 0x50u8);
- /// ```
- #[must_use = "set_current_lim_en returns a modified PwrCtrl"]
- pub const fn set_current_lim_en(mut self, en: bool) -> PwrCtrl {
- if en {
- self.val |= 1 << 6;
- } else {
- self.val &= !(1 << 6);
- }
- self
- }
-
- /// Returns `true` if current limiting is enabled
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::PwrCtrl;
- ///
- /// let pc: PwrCtrl = PwrCtrl::RESET;
- /// assert_eq!(pc.current_limit_en(), true);
- /// let pc: PwrCtrl = pc.set_current_lim_en(false);
- /// assert_eq!(pc.current_limit_en(), false);
- /// let pc: PwrCtrl = pc.set_current_lim_en(true);
- /// assert_eq!(pc.current_limit_en(), true);
- /// ```
- pub const fn current_limit_en(&self) -> bool {
- self.val & (1 << 6) != 0
- }
-
- /// Set the current limit.
- #[must_use = "set_current_lim returns a modified PwrCtrl"]
- pub const fn set_current_lim(mut self, lim: CurrentLim) -> PwrCtrl {
- self.val &= !(0x30);
- self.val |= (lim as u8) << 4;
- self
- }
-
- /// Get the current limit.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{CurrentLim, PwrCtrl};
- ///
- /// let pc: PwrCtrl = PwrCtrl::RESET;
- /// assert_eq!(pc.current_lim(), CurrentLim::Milli50);
- ///
- /// let pc: PwrCtrl = pc.set_current_lim(CurrentLim::Milli25);
- /// assert_eq!(pc.current_lim(), CurrentLim::Milli25);
- ///
- /// let pc: PwrCtrl = pc.set_current_lim(CurrentLim::Milli50);
- /// assert_eq!(pc.current_lim(), CurrentLim::Milli50);
- ///
- /// let pc: PwrCtrl = pc.set_current_lim(CurrentLim::Milli100);
- /// assert_eq!(pc.current_lim(), CurrentLim::Milli100);
- ///
- /// let pc: PwrCtrl = pc.set_current_lim(CurrentLim::Milli200);
- /// assert_eq!(pc.current_lim(), CurrentLim::Milli200);
- /// ```
- pub const fn current_lim(&self) -> CurrentLim {
- match (self.val >> 4) & 0b11 {
- 0x0 => CurrentLim::Milli25,
- 0x1 => CurrentLim::Milli50,
- 0x2 => CurrentLim::Milli100,
- _ => CurrentLim::Milli200,
- }
- }
-}
-
-impl From for u8 {
- fn from(bs: PwrCtrl) -> Self {
- bs.val
- }
-}
-
-impl Default for PwrCtrl {
- fn default() -> Self {
- Self::RESET
- }
-}
diff --git a/embassy-stm32/src/subghz/reg_mode.rs b/embassy-stm32/src/subghz/reg_mode.rs
deleted file mode 100644
index b8322695..00000000
--- a/embassy-stm32/src/subghz/reg_mode.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-/// Radio power supply selection.
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-#[repr(u8)]
-pub enum RegMode {
- /// Linear dropout regulator
- Ldo = 0b0,
- /// Switch mode power supply.
- ///
- /// Used in standby with HSE32, FS, RX, and TX modes.
- Smps = 0b1,
-}
-
-impl Default for RegMode {
- fn default() -> Self {
- RegMode::Ldo
- }
-}
diff --git a/embassy-stm32/src/subghz/rf_frequency.rs b/embassy-stm32/src/subghz/rf_frequency.rs
deleted file mode 100644
index 3de2f50c..00000000
--- a/embassy-stm32/src/subghz/rf_frequency.rs
+++ /dev/null
@@ -1,135 +0,0 @@
-/// RF frequency structure.
-///
-/// Argument of [`set_rf_frequency`].
-///
-/// [`set_rf_frequency`]: super::SubGhz::set_rf_frequency
-#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct RfFreq {
- buf: [u8; 5],
-}
-
-impl RfFreq {
- /// 915MHz, often used in Australia and North America.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::RfFreq;
- ///
- /// assert_eq!(RfFreq::F915.freq(), 915_000_000);
- /// ```
- pub const F915: RfFreq = RfFreq::from_raw(0x39_30_00_00);
-
- /// 868MHz, often used in Europe.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::RfFreq;
- ///
- /// assert_eq!(RfFreq::F868.freq(), 868_000_000);
- /// ```
- pub const F868: RfFreq = RfFreq::from_raw(0x36_40_00_00);
-
- /// 433MHz, often used in Europe.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::RfFreq;
- ///
- /// assert_eq!(RfFreq::F433.freq(), 433_000_000);
- /// ```
- pub const F433: RfFreq = RfFreq::from_raw(0x1B_10_00_00);
-
- /// Create a new `RfFreq` from a raw bit value.
- ///
- /// The equation used to get the PLL frequency from the raw bits is:
- ///
- /// RFPLL = 32e6 × bits / 225
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::RfFreq;
- ///
- /// const FREQ: RfFreq = RfFreq::from_raw(0x39300000);
- /// assert_eq!(FREQ, RfFreq::F915);
- /// ```
- pub const fn from_raw(bits: u32) -> RfFreq {
- RfFreq {
- buf: [
- super::OpCode::SetRfFrequency as u8,
- ((bits >> 24) & 0xFF) as u8,
- ((bits >> 16) & 0xFF) as u8,
- ((bits >> 8) & 0xFF) as u8,
- (bits & 0xFF) as u8,
- ],
- }
- }
-
- /// Create a new `RfFreq` from a PLL frequency.
- ///
- /// The equation used to get the raw bits from the PLL frequency is:
- ///
- /// bits = RFPLL * 225 / 32e6
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::RfFreq;
- ///
- /// const FREQ: RfFreq = RfFreq::from_frequency(915_000_000);
- /// assert_eq!(FREQ, RfFreq::F915);
- /// ```
- pub const fn from_frequency(freq: u32) -> RfFreq {
- Self::from_raw((((freq as u64) * (1 << 25)) / 32_000_000) as u32)
- }
-
- // Get the frequency bit value.
- const fn as_bits(&self) -> u32 {
- ((self.buf[1] as u32) << 24) | ((self.buf[2] as u32) << 16) | ((self.buf[3] as u32) << 8) | (self.buf[4] as u32)
- }
-
- /// Get the actual frequency.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::RfFreq;
- ///
- /// assert_eq!(RfFreq::from_raw(0x39300000).freq(), 915_000_000);
- /// ```
- pub fn freq(&self) -> u32 {
- (32_000_000 * (self.as_bits() as u64) / (1 << 25)) as u32
- }
-
- /// Extracts a slice containing the packet.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::RfFreq;
- ///
- /// assert_eq!(RfFreq::F915.as_slice(), &[0x86, 0x39, 0x30, 0x00, 0x00]);
- /// ```
- pub const fn as_slice(&self) -> &[u8] {
- &self.buf
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::RfFreq;
-
- #[test]
- fn max() {
- assert_eq!(RfFreq::from_raw(u32::MAX).freq(), 4_095_999_999);
- }
-
- #[test]
- fn min() {
- assert_eq!(RfFreq::from_raw(u32::MIN).freq(), 0);
- }
-}
diff --git a/embassy-stm32/src/subghz/rx_timeout_stop.rs b/embassy-stm32/src/subghz/rx_timeout_stop.rs
deleted file mode 100644
index 1d4aaece..00000000
--- a/embassy-stm32/src/subghz/rx_timeout_stop.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-/// Receiver event which stops the RX timeout timer.
-///
-/// Used by [`set_rx_timeout_stop`].
-///
-/// [`set_rx_timeout_stop`]: super::SubGhz::set_rx_timeout_stop
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-#[repr(u8)]
-pub enum RxTimeoutStop {
- /// Receive timeout stopped on synchronization word detection in generic
- /// packet mode or header detection in LoRa packet mode.
- Sync = 0b0,
- /// Receive timeout stopped on preamble detection.
- Preamble = 0b1,
-}
-
-impl From for u8 {
- fn from(rx_ts: RxTimeoutStop) -> Self {
- rx_ts as u8
- }
-}
diff --git a/embassy-stm32/src/subghz/sleep_cfg.rs b/embassy-stm32/src/subghz/sleep_cfg.rs
deleted file mode 100644
index 0a50e970..00000000
--- a/embassy-stm32/src/subghz/sleep_cfg.rs
+++ /dev/null
@@ -1,107 +0,0 @@
-/// Startup configurations when exiting sleep mode.
-///
-/// Argument of [`SleepCfg::set_startup`].
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-#[repr(u8)]
-pub enum Startup {
- /// Cold startup when exiting Sleep mode, configuration registers reset.
- Cold = 0,
- /// Warm startup when exiting Sleep mode,
- /// configuration registers kept in retention.
- ///
- /// **Note:** Only the configuration of the activated modem,
- /// before going to sleep mode, is retained.
- /// The configuration of the other modes is lost and must be re-configured
- /// when exiting sleep mode.
- Warm = 1,
-}
-
-impl Default for Startup {
- fn default() -> Self {
- Startup::Warm
- }
-}
-
-/// Sleep configuration.
-///
-/// Argument of [`set_sleep`].
-///
-/// [`set_sleep`]: super::SubGhz::set_sleep
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct SleepCfg(u8);
-
-impl SleepCfg {
- /// Create a new `SleepCfg` structure.
- ///
- /// This is the same as `default`, but in a `const` function.
- ///
- /// The defaults are a warm startup, with RTC wakeup enabled.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::SleepCfg;
- ///
- /// const SLEEP_CFG: SleepCfg = SleepCfg::new();
- /// assert_eq!(SLEEP_CFG, SleepCfg::default());
- /// # assert_eq!(u8::from(SLEEP_CFG), 0b101);
- /// ```
- pub const fn new() -> SleepCfg {
- SleepCfg(0).set_startup(Startup::Warm).set_rtc_wakeup_en(true)
- }
-
- /// Set the startup mode.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{SleepCfg, Startup};
- ///
- /// const SLEEP_CFG: SleepCfg = SleepCfg::new().set_startup(Startup::Cold);
- /// # assert_eq!(u8::from(SLEEP_CFG), 0b001);
- /// # assert_eq!(u8::from(SLEEP_CFG.set_startup(Startup::Warm)), 0b101);
- /// ```
- pub const fn set_startup(mut self, startup: Startup) -> SleepCfg {
- if startup as u8 == 1 {
- self.0 |= 1 << 2
- } else {
- self.0 &= !(1 << 2)
- }
- self
- }
-
- /// Set the RTC wakeup enable.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::SleepCfg;
- ///
- /// const SLEEP_CFG: SleepCfg = SleepCfg::new().set_rtc_wakeup_en(false);
- /// # assert_eq!(u8::from(SLEEP_CFG), 0b100);
- /// # assert_eq!(u8::from(SLEEP_CFG.set_rtc_wakeup_en(true)), 0b101);
- /// ```
- #[must_use = "set_rtc_wakeup_en returns a modified SleepCfg"]
- pub const fn set_rtc_wakeup_en(mut self, en: bool) -> SleepCfg {
- if en {
- self.0 |= 0b1
- } else {
- self.0 &= !0b1
- }
- self
- }
-}
-
-impl From for u8 {
- fn from(sc: SleepCfg) -> Self {
- sc.0
- }
-}
-
-impl Default for SleepCfg {
- fn default() -> Self {
- Self::new()
- }
-}
diff --git a/embassy-stm32/src/subghz/smps.rs b/embassy-stm32/src/subghz/smps.rs
deleted file mode 100644
index 81615ea7..00000000
--- a/embassy-stm32/src/subghz/smps.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-/// SMPS maximum drive capability.
-///
-/// Argument of [`set_smps_drv`](super::SubGhz::set_smps_drv).
-#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-#[repr(u8)]
-pub enum SmpsDrv {
- /// 20 mA
- Milli20 = 0x0,
- /// 40 mA
- Milli40 = 0x1,
- /// 60 mA
- Milli60 = 0x2,
- /// 100 mA (default)
- Milli100 = 0x3,
-}
-
-impl SmpsDrv {
- /// Get the SMPS drive value as milliamps.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::SmpsDrv;
- ///
- /// assert_eq!(SmpsDrv::Milli20.as_milliamps(), 20);
- /// assert_eq!(SmpsDrv::Milli40.as_milliamps(), 40);
- /// assert_eq!(SmpsDrv::Milli60.as_milliamps(), 60);
- /// assert_eq!(SmpsDrv::Milli100.as_milliamps(), 100);
- /// ```
- pub const fn as_milliamps(&self) -> u8 {
- match self {
- SmpsDrv::Milli20 => 20,
- SmpsDrv::Milli40 => 40,
- SmpsDrv::Milli60 => 60,
- SmpsDrv::Milli100 => 100,
- }
- }
-}
-
-impl Default for SmpsDrv {
- fn default() -> Self {
- SmpsDrv::Milli100
- }
-}
diff --git a/embassy-stm32/src/subghz/standby_clk.rs b/embassy-stm32/src/subghz/standby_clk.rs
deleted file mode 100644
index c130bbee..00000000
--- a/embassy-stm32/src/subghz/standby_clk.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-/// Clock in standby mode.
-///
-/// Used by [`set_standby`].
-///
-/// [`set_standby`]: super::SubGhz::set_standby
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-#[repr(u8)]
-pub enum StandbyClk {
- /// RC 13 MHz used in standby mode.
- Rc = 0b0,
- /// HSE32 used in standby mode.
- Hse = 0b1,
-}
-
-impl From for u8 {
- fn from(sc: StandbyClk) -> Self {
- sc as u8
- }
-}
diff --git a/embassy-stm32/src/subghz/stats.rs b/embassy-stm32/src/subghz/stats.rs
deleted file mode 100644
index 41b7a200..00000000
--- a/embassy-stm32/src/subghz/stats.rs
+++ /dev/null
@@ -1,184 +0,0 @@
-use super::Status;
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct LoRaStats;
-
-impl LoRaStats {
- pub const fn new() -> Self {
- Self {}
- }
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct FskStats;
-
-impl FskStats {
- pub const fn new() -> Self {
- Self {}
- }
-}
-
-/// Packet statistics.
-///
-/// Returned by [`fsk_stats`] and [`lora_stats`].
-///
-/// [`fsk_stats`]: super::SubGhz::fsk_stats
-/// [`lora_stats`]: super::SubGhz::lora_stats
-#[derive(Eq, PartialEq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct Stats {
- status: Status,
- pkt_rx: u16,
- pkt_crc: u16,
- pkt_len_or_hdr_err: u16,
- ty: ModType,
-}
-
-impl Stats {
- const fn from_buf(buf: [u8; 7], ty: ModType) -> Stats {
- Stats {
- status: Status::from_raw(buf[0]),
- pkt_rx: u16::from_be_bytes([buf[1], buf[2]]),
- pkt_crc: u16::from_be_bytes([buf[3], buf[4]]),
- pkt_len_or_hdr_err: u16::from_be_bytes([buf[5], buf[6]]),
- ty,
- }
- }
-
- /// Get the radio status returned with the packet statistics.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{CmdStatus, FskStats, Stats, StatusMode};
- ///
- /// let example_data_from_radio: [u8; 7] = [0x54, 0, 0, 0, 0, 0, 0];
- /// let stats: Stats = Stats::from_raw_fsk(example_data_from_radio);
- /// assert_eq!(stats.status().mode(), Ok(StatusMode::Rx));
- /// assert_eq!(stats.status().cmd(), Ok(CmdStatus::Avaliable));
- /// ```
- pub const fn status(&self) -> Status {
- self.status
- }
-
- /// Number of packets received.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{FskStats, Stats};
- ///
- /// let example_data_from_radio: [u8; 7] = [0x54, 0, 3, 0, 0, 0, 0];
- /// let stats: Stats = Stats::from_raw_fsk(example_data_from_radio);
- /// assert_eq!(stats.pkt_rx(), 3);
- /// ```
- pub const fn pkt_rx(&self) -> u16 {
- self.pkt_rx
- }
-
- /// Number of packets received with a payload CRC error
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{LoRaStats, Stats};
- ///
- /// let example_data_from_radio: [u8; 7] = [0x54, 0, 0, 0, 1, 0, 0];
- /// let stats: Stats = Stats::from_raw_lora(example_data_from_radio);
- /// assert_eq!(stats.pkt_crc(), 1);
- /// ```
- pub const fn pkt_crc(&self) -> u16 {
- self.pkt_crc
- }
-}
-
-impl Stats {
- /// Create a new FSK packet statistics structure from a raw buffer.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{FskStats, Stats};
- ///
- /// let example_data_from_radio: [u8; 7] = [0x54, 0, 0, 0, 0, 0, 0];
- /// let stats: Stats = Stats::from_raw_fsk(example_data_from_radio);
- /// ```
- pub const fn from_raw_fsk(buf: [u8; 7]) -> Stats {
- Self::from_buf(buf, FskStats::new())
- }
-
- /// Number of packets received with a payload length error.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{FskStats, Stats};
- ///
- /// let example_data_from_radio: [u8; 7] = [0x54, 0, 0, 0, 0, 0, 1];
- /// let stats: Stats = Stats::from_raw_fsk(example_data_from_radio);
- /// assert_eq!(stats.pkt_len_err(), 1);
- /// ```
- pub const fn pkt_len_err(&self) -> u16 {
- self.pkt_len_or_hdr_err
- }
-}
-
-impl Stats {
- /// Create a new LoRa packet statistics structure from a raw buffer.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{LoRaStats, Stats};
- ///
- /// let example_data_from_radio: [u8; 7] = [0x54, 0, 0, 0, 0, 0, 0];
- /// let stats: Stats = Stats::from_raw_lora(example_data_from_radio);
- /// ```
- pub const fn from_raw_lora(buf: [u8; 7]) -> Stats {
- Self::from_buf(buf, LoRaStats::new())
- }
-
- /// Number of packets received with a header CRC error.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{LoRaStats, Stats};
- ///
- /// let example_data_from_radio: [u8; 7] = [0x54, 0, 0, 0, 0, 0, 1];
- /// let stats: Stats = Stats::from_raw_lora(example_data_from_radio);
- /// assert_eq!(stats.pkt_hdr_err(), 1);
- /// ```
- pub const fn pkt_hdr_err(&self) -> u16 {
- self.pkt_len_or_hdr_err
- }
-}
-
-impl core::fmt::Debug for Stats {
- fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
- f.debug_struct("Stats")
- .field("status", &self.status())
- .field("pkt_rx", &self.pkt_rx())
- .field("pkt_crc", &self.pkt_crc())
- .field("pkt_len_err", &self.pkt_len_err())
- .finish()
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::super::{CmdStatus, LoRaStats, Stats, StatusMode};
-
- #[test]
- fn mixed() {
- let example_data_from_radio: [u8; 7] = [0x54, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06];
- let stats: Stats = Stats::from_raw_lora(example_data_from_radio);
- assert_eq!(stats.status().mode(), Ok(StatusMode::Rx));
- assert_eq!(stats.status().cmd(), Ok(CmdStatus::Avaliable));
- assert_eq!(stats.pkt_rx(), 0x0102);
- assert_eq!(stats.pkt_crc(), 0x0304);
- assert_eq!(stats.pkt_hdr_err(), 0x0506);
- }
-}
diff --git a/embassy-stm32/src/subghz/status.rs b/embassy-stm32/src/subghz/status.rs
deleted file mode 100644
index b84034f6..00000000
--- a/embassy-stm32/src/subghz/status.rs
+++ /dev/null
@@ -1,197 +0,0 @@
-/// sub-GHz radio operating mode.
-///
-/// See `Get_Status` under section 5.8.5 "Communication status information commands"
-/// in the reference manual.
-///
-/// This is returned by [`Status::mode`].
-#[repr(u8)]
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum StatusMode {
- /// Standby mode with RC 13MHz.
- StandbyRc = 0x2,
- /// Standby mode with HSE32.
- StandbyHse = 0x3,
- /// Frequency Synthesis mode.
- Fs = 0x4,
- /// Receive mode.
- Rx = 0x5,
- /// Transmit mode.
- Tx = 0x6,
-}
-
-impl StatusMode {
- /// Create a new `StatusMode` from bits.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::StatusMode;
- ///
- /// assert_eq!(StatusMode::from_raw(0x2), Ok(StatusMode::StandbyRc));
- /// assert_eq!(StatusMode::from_raw(0x3), Ok(StatusMode::StandbyHse));
- /// assert_eq!(StatusMode::from_raw(0x4), Ok(StatusMode::Fs));
- /// assert_eq!(StatusMode::from_raw(0x5), Ok(StatusMode::Rx));
- /// assert_eq!(StatusMode::from_raw(0x6), Ok(StatusMode::Tx));
- /// // Other values are reserved
- /// assert_eq!(StatusMode::from_raw(0), Err(0));
- /// ```
- pub const fn from_raw(bits: u8) -> Result {
- match bits {
- 0x2 => Ok(StatusMode::StandbyRc),
- 0x3 => Ok(StatusMode::StandbyHse),
- 0x4 => Ok(StatusMode::Fs),
- 0x5 => Ok(StatusMode::Rx),
- 0x6 => Ok(StatusMode::Tx),
- _ => Err(bits),
- }
- }
-}
-
-/// Command status.
-///
-/// See `Get_Status` under section 5.8.5 "Communication status information commands"
-/// in the reference manual.
-///
-/// This is returned by [`Status::cmd`].
-#[repr(u8)]
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum CmdStatus {
- /// Data available to host.
- ///
- /// Packet received successfully and data can be retrieved.
- Avaliable = 0x2,
- /// Command time out.
- ///
- /// Command took too long to complete triggering a sub-GHz radio watchdog
- /// timeout.
- Timeout = 0x3,
- /// Command processing error.
- ///
- /// Invalid opcode or incorrect number of parameters.
- ProcessingError = 0x4,
- /// Command execution failure.
- ///
- /// Command successfully received but cannot be executed at this time,
- /// requested operating mode cannot be entered or requested data cannot be
- /// sent.
- ExecutionFailure = 0x5,
- /// Transmit command completed.
- ///
- /// Current packet transmission completed.
- Complete = 0x6,
-}
-
-impl CmdStatus {
- /// Create a new `CmdStatus` from bits.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::CmdStatus;
- ///
- /// assert_eq!(CmdStatus::from_raw(0x2), Ok(CmdStatus::Avaliable));
- /// assert_eq!(CmdStatus::from_raw(0x3), Ok(CmdStatus::Timeout));
- /// assert_eq!(CmdStatus::from_raw(0x4), Ok(CmdStatus::ProcessingError));
- /// assert_eq!(CmdStatus::from_raw(0x5), Ok(CmdStatus::ExecutionFailure));
- /// assert_eq!(CmdStatus::from_raw(0x6), Ok(CmdStatus::Complete));
- /// // Other values are reserved
- /// assert_eq!(CmdStatus::from_raw(0), Err(0));
- /// ```
- pub const fn from_raw(bits: u8) -> Result {
- match bits {
- 0x2 => Ok(CmdStatus::Avaliable),
- 0x3 => Ok(CmdStatus::Timeout),
- 0x4 => Ok(CmdStatus::ProcessingError),
- 0x5 => Ok(CmdStatus::ExecutionFailure),
- 0x6 => Ok(CmdStatus::Complete),
- _ => Err(bits),
- }
- }
-}
-
-/// Radio status.
-///
-/// This is returned by [`status`].
-///
-/// [`status`]: super::SubGhz::status
-#[derive(PartialEq, Eq, Clone, Copy)]
-pub struct Status(u8);
-
-impl From for Status {
- fn from(x: u8) -> Self {
- Status(x)
- }
-}
-impl From for u8 {
- fn from(x: Status) -> Self {
- x.0
- }
-}
-
-impl Status {
- /// Create a new `Status` from a raw `u8` value.
- ///
- /// This is the same as `Status::from(u8)`, but in a `const` function.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{CmdStatus, Status, StatusMode};
- ///
- /// const STATUS: Status = Status::from_raw(0x54_u8);
- /// assert_eq!(STATUS.mode(), Ok(StatusMode::Rx));
- /// assert_eq!(STATUS.cmd(), Ok(CmdStatus::Avaliable));
- /// ```
- pub const fn from_raw(value: u8) -> Status {
- Status(value)
- }
-
- /// sub-GHz radio operating mode.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{Status, StatusMode};
- ///
- /// let status: Status = 0xACu8.into();
- /// assert_eq!(status.mode(), Ok(StatusMode::StandbyRc));
- /// ```
- pub const fn mode(&self) -> Result {
- StatusMode::from_raw((self.0 >> 4) & 0b111)
- }
-
- /// Command status.
- ///
- /// This method frequently returns reserved values such as `Err(1)`.
- /// ST support has confirmed that this is normal and should be ignored.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{CmdStatus, Status};
- ///
- /// let status: Status = 0xACu8.into();
- /// assert_eq!(status.cmd(), Ok(CmdStatus::Complete));
- /// ```
- pub const fn cmd(&self) -> Result {
- CmdStatus::from_raw((self.0 >> 1) & 0b111)
- }
-}
-
-impl core::fmt::Debug for Status {
- fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
- f.debug_struct("Status")
- .field("mode", &self.mode())
- .field("cmd", &self.cmd())
- .finish()
- }
-}
-
-#[cfg(feature = "defmt")]
-impl defmt::Format for Status {
- fn format(&self, fmt: defmt::Formatter) {
- defmt::write!(fmt, "Status {{ mode: {}, cmd: {} }}", self.mode(), self.cmd())
- }
-}
diff --git a/embassy-stm32/src/subghz/tcxo_mode.rs b/embassy-stm32/src/subghz/tcxo_mode.rs
deleted file mode 100644
index 698dee0a..00000000
--- a/embassy-stm32/src/subghz/tcxo_mode.rs
+++ /dev/null
@@ -1,170 +0,0 @@
-use super::Timeout;
-
-/// TCXO trim.
-///
-/// **Note:** To use VDDTCXO, the VDDRF supply must be at
-/// least + 200 mV higher than the selected `TcxoTrim` voltage level.
-///
-/// Used by [`TcxoMode`].
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-#[repr(u8)]
-pub enum TcxoTrim {
- /// 1.6V
- Volts1pt6 = 0x0,
- /// 1.7V
- Volts1pt7 = 0x1,
- /// 1.8V
- Volts1pt8 = 0x2,
- /// 2.2V
- Volts2pt2 = 0x3,
- /// 2.4V
- Volts2pt4 = 0x4,
- /// 2.7V
- Volts2pt7 = 0x5,
- /// 3.0V
- Volts3pt0 = 0x6,
- /// 3.3V
- Volts3pt3 = 0x7,
-}
-
-impl core::fmt::Display for TcxoTrim {
- fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
- match self {
- TcxoTrim::Volts1pt6 => write!(f, "1.6V"),
- TcxoTrim::Volts1pt7 => write!(f, "1.7V"),
- TcxoTrim::Volts1pt8 => write!(f, "1.8V"),
- TcxoTrim::Volts2pt2 => write!(f, "2.2V"),
- TcxoTrim::Volts2pt4 => write!(f, "2.4V"),
- TcxoTrim::Volts2pt7 => write!(f, "2.7V"),
- TcxoTrim::Volts3pt0 => write!(f, "3.0V"),
- TcxoTrim::Volts3pt3 => write!(f, "3.3V"),
- }
- }
-}
-
-impl TcxoTrim {
- /// Get the value of the TXCO trim in millivolts.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::TcxoTrim;
- ///
- /// assert_eq!(TcxoTrim::Volts1pt6.as_millivolts(), 1600);
- /// assert_eq!(TcxoTrim::Volts1pt7.as_millivolts(), 1700);
- /// assert_eq!(TcxoTrim::Volts1pt8.as_millivolts(), 1800);
- /// assert_eq!(TcxoTrim::Volts2pt2.as_millivolts(), 2200);
- /// assert_eq!(TcxoTrim::Volts2pt4.as_millivolts(), 2400);
- /// assert_eq!(TcxoTrim::Volts2pt7.as_millivolts(), 2700);
- /// assert_eq!(TcxoTrim::Volts3pt0.as_millivolts(), 3000);
- /// assert_eq!(TcxoTrim::Volts3pt3.as_millivolts(), 3300);
- /// ```
- pub const fn as_millivolts(&self) -> u16 {
- match self {
- TcxoTrim::Volts1pt6 => 1600,
- TcxoTrim::Volts1pt7 => 1700,
- TcxoTrim::Volts1pt8 => 1800,
- TcxoTrim::Volts2pt2 => 2200,
- TcxoTrim::Volts2pt4 => 2400,
- TcxoTrim::Volts2pt7 => 2700,
- TcxoTrim::Volts3pt0 => 3000,
- TcxoTrim::Volts3pt3 => 3300,
- }
- }
-}
-
-/// TCXO trim and HSE32 ready timeout.
-///
-/// Argument of [`set_tcxo_mode`].
-///
-/// [`set_tcxo_mode`]: super::SubGhz::set_tcxo_mode
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct TcxoMode {
- buf: [u8; 5],
-}
-
-impl TcxoMode {
- /// Create a new `TcxoMode` struct.
- ///
- /// This is the same as `default`, but in a `const` function.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::TcxoMode;
- ///
- /// const TCXO_MODE: TcxoMode = TcxoMode::new();
- /// ```
- pub const fn new() -> TcxoMode {
- TcxoMode {
- buf: [super::OpCode::SetTcxoMode as u8, 0x00, 0x00, 0x00, 0x00],
- }
- }
-
- /// Set the TCXO trim.
- ///
- /// **Note:** To use VDDTCXO, the VDDRF supply must be
- /// at least + 200 mV higher than the selected `TcxoTrim` voltage level.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{TcxoMode, TcxoTrim};
- ///
- /// const TCXO_MODE: TcxoMode = TcxoMode::new().set_txco_trim(TcxoTrim::Volts1pt6);
- /// # assert_eq!(TCXO_MODE.as_slice()[1], 0x00);
- /// ```
- #[must_use = "set_txco_trim returns a modified TcxoMode"]
- pub const fn set_txco_trim(mut self, tcxo_trim: TcxoTrim) -> TcxoMode {
- self.buf[1] = tcxo_trim as u8;
- self
- }
-
- /// Set the ready timeout duration.
- ///
- /// # Example
- ///
- /// ```
- /// use core::time::Duration;
- /// use stm32wlxx_hal::subghz::{TcxoMode, Timeout};
- ///
- /// // 15.625 ms timeout
- /// const TIMEOUT: Timeout = Timeout::from_duration_sat(Duration::from_millis(15_625));
- /// const TCXO_MODE: TcxoMode = TcxoMode::new().set_timeout(TIMEOUT);
- /// # assert_eq!(TCXO_MODE.as_slice()[2], 0x0F);
- /// # assert_eq!(TCXO_MODE.as_slice()[3], 0x42);
- /// # assert_eq!(TCXO_MODE.as_slice()[4], 0x40);
- /// ```
- #[must_use = "set_timeout returns a modified TcxoMode"]
- pub const fn set_timeout(mut self, timeout: Timeout) -> TcxoMode {
- let timeout_bits: u32 = timeout.into_bits();
- self.buf[2] = ((timeout_bits >> 16) & 0xFF) as u8;
- self.buf[3] = ((timeout_bits >> 8) & 0xFF) as u8;
- self.buf[4] = (timeout_bits & 0xFF) as u8;
- self
- }
-
- /// Extracts a slice containing the packet.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{TcxoMode, TcxoTrim, Timeout};
- ///
- /// const TCXO_MODE: TcxoMode = TcxoMode::new()
- /// .set_txco_trim(TcxoTrim::Volts1pt7)
- /// .set_timeout(Timeout::from_raw(0x123456));
- /// assert_eq!(TCXO_MODE.as_slice(), &[0x97, 0x1, 0x12, 0x34, 0x56]);
- /// ```
- pub const fn as_slice(&self) -> &[u8] {
- &self.buf
- }
-}
-
-impl Default for TcxoMode {
- fn default() -> Self {
- Self::new()
- }
-}
diff --git a/embassy-stm32/src/subghz/timeout.rs b/embassy-stm32/src/subghz/timeout.rs
deleted file mode 100644
index 0ae49dd9..00000000
--- a/embassy-stm32/src/subghz/timeout.rs
+++ /dev/null
@@ -1,492 +0,0 @@
-use core::time::Duration;
-
-use super::ValueError;
-
-const fn abs_diff(a: u64, b: u64) -> u64 {
- if a > b {
- a - b
- } else {
- b - a
- }
-}
-
-/// Timeout argument.
-///
-/// This is used by:
-/// * [`set_rx`]
-/// * [`set_tx`]
-/// * [`TcxoMode`]
-///
-/// Each timeout has 3 bytes, with a resolution of 15.625µs per bit, giving a
-/// range of 0s to 262.143984375s.
-///
-/// [`set_rx`]: super::SubGhz::set_rx
-/// [`set_tx`]: super::SubGhz::set_tx
-/// [`TcxoMode`]: super::TcxoMode
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct Timeout {
- bits: u32,
-}
-
-impl Timeout {
- const BITS_PER_MILLI: u32 = 64; // 1e-3 / 15.625e-6
- const BITS_PER_SEC: u32 = 64_000; // 1 / 15.625e-6
-
- /// Disable the timeout (0s timeout).
- ///
- /// # Example
- ///
- /// ```
- /// use core::time::Duration;
- /// use stm32wlxx_hal::subghz::Timeout;
- ///
- /// const TIMEOUT: Timeout = Timeout::DISABLED;
- /// assert_eq!(TIMEOUT.as_duration(), Duration::from_secs(0));
- /// ```
- pub const DISABLED: Timeout = Timeout { bits: 0x0 };
-
- /// Minimum timeout, 15.625µs.
- ///
- /// # Example
- ///
- /// ```
- /// use core::time::Duration;
- /// use stm32wlxx_hal::subghz::Timeout;
- ///
- /// const TIMEOUT: Timeout = Timeout::MIN;
- /// assert_eq!(TIMEOUT.into_bits(), 1);
- /// ```
- pub const MIN: Timeout = Timeout { bits: 1 };
-
- /// Maximum timeout, 262.143984375s.
- ///
- /// # Example
- ///
- /// ```
- /// use core::time::Duration;
- /// use stm32wlxx_hal::subghz::Timeout;
- ///
- /// const TIMEOUT: Timeout = Timeout::MAX;
- /// assert_eq!(TIMEOUT.as_duration(), Duration::from_nanos(262_143_984_375));
- /// ```
- pub const MAX: Timeout = Timeout { bits: 0x00FF_FFFF };
-
- /// Timeout resolution in nanoseconds, 15.625µs.
- pub const RESOLUTION_NANOS: u16 = 15_625;
-
- /// Timeout resolution, 15.625µs.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::Timeout;
- ///
- /// assert_eq!(
- /// Timeout::RESOLUTION.as_nanos(),
- /// Timeout::RESOLUTION_NANOS as u128
- /// );
- /// ```
- pub const RESOLUTION: Duration = Duration::from_nanos(Self::RESOLUTION_NANOS as u64);
-
- /// Create a new timeout from a [`Duration`].
- ///
- /// This will return the nearest timeout value possible, or a
- /// [`ValueError`] if the value is out of bounds.
- ///
- /// Use [`from_millis_sat`](Self::from_millis_sat) for runtime timeout
- /// construction.
- /// This is not _that_ useful right now, it is simply future proofing for a
- /// time when `Result::unwrap` is available for `const fn`.
- ///
- /// # Example
- ///
- /// Value within bounds:
- ///
- /// ```
- /// use core::time::Duration;
- /// use stm32wlxx_hal::subghz::{Timeout, ValueError};
- ///
- /// const MIN: Duration = Timeout::RESOLUTION;
- /// assert_eq!(Timeout::from_duration(MIN).unwrap(), Timeout::MIN);
- /// ```
- ///
- /// Value too low:
- ///
- /// ```
- /// use core::time::Duration;
- /// use stm32wlxx_hal::subghz::{Timeout, ValueError};
- ///
- /// const LOWER_LIMIT_NANOS: u128 = 7813;
- /// const TOO_LOW_NANOS: u128 = LOWER_LIMIT_NANOS - 1;
- /// const TOO_LOW_DURATION: Duration = Duration::from_nanos(TOO_LOW_NANOS as u64);
- /// assert_eq!(
- /// Timeout::from_duration(TOO_LOW_DURATION),
- /// Err(ValueError::too_low(TOO_LOW_NANOS, LOWER_LIMIT_NANOS))
- /// );
- /// ```
- ///
- /// Value too high:
- ///
- /// ```
- /// use core::time::Duration;
- /// use stm32wlxx_hal::subghz::{Timeout, ValueError};
- ///
- /// const UPPER_LIMIT_NANOS: u128 = Timeout::MAX.as_nanos() as u128 + 7812;
- /// const TOO_HIGH_NANOS: u128 = UPPER_LIMIT_NANOS + 1;
- /// const TOO_HIGH_DURATION: Duration = Duration::from_nanos(TOO_HIGH_NANOS as u64);
- /// assert_eq!(
- /// Timeout::from_duration(TOO_HIGH_DURATION),
- /// Err(ValueError::too_high(TOO_HIGH_NANOS, UPPER_LIMIT_NANOS))
- /// );
- /// ```
- pub const fn from_duration(duration: Duration) -> Result> {
- // at the time of development many methods in
- // `core::Duration` were not `const fn`, which leads to the hacks
- // you see here.
- let nanos: u128 = duration.as_nanos();
- const UPPER_LIMIT: u128 = Timeout::MAX.as_nanos() as u128 + (Timeout::RESOLUTION_NANOS as u128) / 2;
- const LOWER_LIMIT: u128 = (((Timeout::RESOLUTION_NANOS as u128) + 1) / 2) as u128;
-
- if nanos > UPPER_LIMIT {
- Err(ValueError::too_high(nanos, UPPER_LIMIT))
- } else if nanos < LOWER_LIMIT {
- Err(ValueError::too_low(nanos, LOWER_LIMIT))
- } else {
- // safe to truncate here because of previous bounds check.
- let duration_nanos: u64 = nanos as u64;
-
- let div_floor: u64 = duration_nanos / (Self::RESOLUTION_NANOS as u64);
- let div_ceil: u64 = 1 + (duration_nanos - 1) / (Self::RESOLUTION_NANOS as u64);
-
- let timeout_ceil: Timeout = Timeout::from_raw(div_ceil as u32);
- let timeout_floor: Timeout = Timeout::from_raw(div_floor as u32);
-
- let error_ceil: u64 = abs_diff(timeout_ceil.as_nanos(), duration_nanos);
- let error_floor: u64 = abs_diff(timeout_floor.as_nanos(), duration_nanos);
-
- if error_ceil < error_floor {
- Ok(timeout_ceil)
- } else {
- Ok(timeout_floor)
- }
- }
- }
-
- /// Create a new timeout from a [`Duration`].
- ///
- /// This will return the nearest timeout value possible, saturating at the
- /// limits.
- ///
- /// This is an expensive function to call outside of `const` contexts.
- /// Use [`from_millis_sat`](Self::from_millis_sat) for runtime timeout
- /// construction.
- ///
- /// # Example
- ///
- /// ```
- /// use core::time::Duration;
- /// use stm32wlxx_hal::subghz::Timeout;
- ///
- /// const DURATION_MAX_NS: u64 = 262_143_984_376;
- ///
- /// assert_eq!(
- /// Timeout::from_duration_sat(Duration::from_millis(0)),
- /// Timeout::MIN
- /// );
- /// assert_eq!(
- /// Timeout::from_duration_sat(Duration::from_nanos(DURATION_MAX_NS)),
- /// Timeout::MAX
- /// );
- /// assert_eq!(
- /// Timeout::from_duration_sat(Timeout::RESOLUTION).into_bits(),
- /// 1
- /// );
- /// ```
- pub const fn from_duration_sat(duration: Duration) -> Timeout {
- // at the time of development many methods in
- // `core::Duration` were not `const fn`, which leads to the hacks
- // you see here.
- let nanos: u128 = duration.as_nanos();
- const UPPER_LIMIT: u128 = Timeout::MAX.as_nanos() as u128;
-
- if nanos > UPPER_LIMIT {
- Timeout::MAX
- } else if nanos < (Timeout::RESOLUTION_NANOS as u128) {
- Timeout::from_raw(1)
- } else {
- // safe to truncate here because of previous bounds check.
- let duration_nanos: u64 = duration.as_nanos() as u64;
-
- let div_floor: u64 = duration_nanos / (Self::RESOLUTION_NANOS as u64);
- let div_ceil: u64 = 1 + (duration_nanos - 1) / (Self::RESOLUTION_NANOS as u64);
-
- let timeout_ceil: Timeout = Timeout::from_raw(div_ceil as u32);
- let timeout_floor: Timeout = Timeout::from_raw(div_floor as u32);
-
- let error_ceil: u64 = abs_diff(timeout_ceil.as_nanos(), duration_nanos);
- let error_floor: u64 = abs_diff(timeout_floor.as_nanos(), duration_nanos);
-
- if error_ceil < error_floor {
- timeout_ceil
- } else {
- timeout_floor
- }
- }
- }
-
- /// Create a new timeout from a milliseconds value.
- ///
- /// This will round towards zero and saturate at the limits.
- ///
- /// This is the preferred method to call when you need to generate a
- /// timeout value at runtime.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::Timeout;
- ///
- /// assert_eq!(Timeout::from_millis_sat(0), Timeout::MIN);
- /// assert_eq!(Timeout::from_millis_sat(262_144), Timeout::MAX);
- /// assert_eq!(Timeout::from_millis_sat(1).into_bits(), 64);
- /// ```
- pub const fn from_millis_sat(millis: u32) -> Timeout {
- if millis == 0 {
- Timeout::MIN
- } else if millis >= 262_144 {
- Timeout::MAX
- } else {
- Timeout::from_raw(millis * Self::BITS_PER_MILLI)
- }
- }
-
- /// Create a timeout from raw bits, where each bit has the resolution of
- /// [`Timeout::RESOLUTION`].
- ///
- /// **Note:** Only the first 24 bits of the `u32` are used, the `bits`
- /// argument will be masked.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::Timeout;
- ///
- /// assert_eq!(Timeout::from_raw(u32::MAX), Timeout::MAX);
- /// assert_eq!(Timeout::from_raw(0x00_FF_FF_FF), Timeout::MAX);
- /// assert_eq!(Timeout::from_raw(1).as_duration(), Timeout::RESOLUTION);
- /// assert_eq!(Timeout::from_raw(0), Timeout::DISABLED);
- /// ```
- pub const fn from_raw(bits: u32) -> Timeout {
- Timeout {
- bits: bits & 0x00FF_FFFF,
- }
- }
-
- /// Get the timeout as nanoseconds.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::Timeout;
- ///
- /// assert_eq!(Timeout::MAX.as_nanos(), 262_143_984_375);
- /// assert_eq!(Timeout::DISABLED.as_nanos(), 0);
- /// assert_eq!(Timeout::from_raw(1).as_nanos(), 15_625);
- /// assert_eq!(Timeout::from_raw(64_000).as_nanos(), 1_000_000_000);
- /// ```
- pub const fn as_nanos(&self) -> u64 {
- (self.bits as u64) * (Timeout::RESOLUTION_NANOS as u64)
- }
-
- /// Get the timeout as microseconds, rounding towards zero.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::Timeout;
- ///
- /// assert_eq!(Timeout::MAX.as_micros(), 262_143_984);
- /// assert_eq!(Timeout::DISABLED.as_micros(), 0);
- /// assert_eq!(Timeout::from_raw(1).as_micros(), 15);
- /// assert_eq!(Timeout::from_raw(64_000).as_micros(), 1_000_000);
- /// ```
- pub const fn as_micros(&self) -> u32 {
- (self.as_nanos() / 1_000) as u32
- }
-
- /// Get the timeout as milliseconds, rounding towards zero.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::Timeout;
- ///
- /// assert_eq!(Timeout::MAX.as_millis(), 262_143);
- /// assert_eq!(Timeout::DISABLED.as_millis(), 0);
- /// assert_eq!(Timeout::from_raw(1).as_millis(), 0);
- /// assert_eq!(Timeout::from_raw(64_000).as_millis(), 1_000);
- /// ```
- pub const fn as_millis(&self) -> u32 {
- self.into_bits() / Self::BITS_PER_MILLI
- }
-
- /// Get the timeout as seconds, rounding towards zero.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::Timeout;
- ///
- /// assert_eq!(Timeout::MAX.as_secs(), 262);
- /// assert_eq!(Timeout::DISABLED.as_secs(), 0);
- /// assert_eq!(Timeout::from_raw(1).as_secs(), 0);
- /// assert_eq!(Timeout::from_raw(64_000).as_secs(), 1);
- /// ```
- pub const fn as_secs(&self) -> u16 {
- (self.into_bits() / Self::BITS_PER_SEC) as u16
- }
-
- /// Get the timeout as a [`Duration`].
- ///
- /// # Example
- ///
- /// ```
- /// use core::time::Duration;
- /// use stm32wlxx_hal::subghz::Timeout;
- ///
- /// assert_eq!(
- /// Timeout::MAX.as_duration(),
- /// Duration::from_nanos(262_143_984_375)
- /// );
- /// assert_eq!(Timeout::DISABLED.as_duration(), Duration::from_nanos(0));
- /// assert_eq!(Timeout::from_raw(1).as_duration(), Timeout::RESOLUTION);
- /// ```
- pub const fn as_duration(&self) -> Duration {
- Duration::from_nanos((self.bits as u64) * (Timeout::RESOLUTION_NANOS as u64))
- }
-
- /// Get the bit value for the timeout.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::Timeout;
- ///
- /// assert_eq!(Timeout::from_raw(u32::MAX).into_bits(), 0x00FF_FFFF);
- /// assert_eq!(Timeout::from_raw(1).into_bits(), 1);
- /// ```
- pub const fn into_bits(self) -> u32 {
- self.bits
- }
-
- /// Get the byte value for the timeout.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::Timeout;
- ///
- /// assert_eq!(Timeout::from_raw(u32::MAX).as_bytes(), [0xFF, 0xFF, 0xFF]);
- /// assert_eq!(Timeout::from_raw(1).as_bytes(), [0, 0, 1]);
- /// ```
- pub const fn as_bytes(self) -> [u8; 3] {
- [
- ((self.bits >> 16) & 0xFF) as u8,
- ((self.bits >> 8) & 0xFF) as u8,
- (self.bits & 0xFF) as u8,
- ]
- }
-
- /// Saturating timeout addition. Computes `self + rhs`, saturating at the
- /// numeric bounds instead of overflowing.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::Timeout;
- ///
- /// assert_eq!(
- /// Timeout::from_raw(0xFF_FF_F0).saturating_add(Timeout::from_raw(0xFF)),
- /// Timeout::from_raw(0xFF_FF_FF)
- /// );
- /// assert_eq!(
- /// Timeout::from_raw(100).saturating_add(Timeout::from_raw(23)),
- /// Timeout::from_raw(123)
- /// );
- /// ```
- #[must_use = "saturating_add returns a new Timeout"]
- pub const fn saturating_add(self, rhs: Self) -> Self {
- // TODO: use core::cmp::min when it is const
- let bits: u32 = self.bits.saturating_add(rhs.bits);
- if bits > Self::MAX.bits {
- Self::MAX
- } else {
- Self { bits }
- }
- }
-}
-
-impl From for Duration {
- fn from(to: Timeout) -> Self {
- to.as_duration()
- }
-}
-
-impl From for [u8; 3] {
- fn from(to: Timeout) -> Self {
- to.as_bytes()
- }
-}
-
-#[cfg(feature = "time")]
-impl From for embassy_time::Duration {
- fn from(to: Timeout) -> Self {
- embassy_time::Duration::from_micros(to.as_micros().into())
- }
-}
-
-#[cfg(test)]
-mod tests {
- use core::time::Duration;
-
- use super::{Timeout, ValueError};
-
- #[test]
- fn saturate() {
- assert_eq!(Timeout::from_duration_sat(Duration::from_secs(u64::MAX)), Timeout::MAX);
- }
-
- #[test]
- fn rounding() {
- const NANO1: Duration = Duration::from_nanos(1);
- let res_sub_1_ns: Duration = Timeout::RESOLUTION - NANO1;
- let res_add_1_ns: Duration = Timeout::RESOLUTION + NANO1;
- assert_eq!(Timeout::from_duration_sat(res_sub_1_ns).into_bits(), 1);
- assert_eq!(Timeout::from_duration_sat(res_add_1_ns).into_bits(), 1);
- }
-
- #[test]
- fn lower_limit() {
- let low: Duration = (Timeout::RESOLUTION + Duration::from_nanos(1)) / 2;
- assert_eq!(Timeout::from_duration(low), Ok(Timeout::from_raw(1)));
-
- let too_low: Duration = low - Duration::from_nanos(1);
- assert_eq!(
- Timeout::from_duration(too_low),
- Err(ValueError::too_low(too_low.as_nanos(), low.as_nanos()))
- );
- }
-
- #[test]
- fn upper_limit() {
- let high: Duration = Timeout::MAX.as_duration() + Timeout::RESOLUTION / 2;
- assert_eq!(Timeout::from_duration(high), Ok(Timeout::from_raw(0xFFFFFF)));
-
- let too_high: Duration = high + Duration::from_nanos(1);
- assert_eq!(
- Timeout::from_duration(too_high),
- Err(ValueError::too_high(too_high.as_nanos(), high.as_nanos()))
- );
- }
-}
diff --git a/embassy-stm32/src/subghz/tx_params.rs b/embassy-stm32/src/subghz/tx_params.rs
deleted file mode 100644
index 03bdb1ea..00000000
--- a/embassy-stm32/src/subghz/tx_params.rs
+++ /dev/null
@@ -1,192 +0,0 @@
-/// Power amplifier ramp time for FSK, MSK, and LoRa modulation.
-///
-/// Argument of [`set_ramp_time`][`super::TxParams::set_ramp_time`].
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-#[repr(u8)]
-pub enum RampTime {
- /// 10µs
- Micros10 = 0x00,
- /// 20µs
- Micros20 = 0x01,
- /// 40µs
- Micros40 = 0x02,
- /// 80µs
- Micros80 = 0x03,
- /// 200µs
- Micros200 = 0x04,
- /// 800µs
- Micros800 = 0x05,
- /// 1.7ms
- Micros1700 = 0x06,
- /// 3.4ms
- Micros3400 = 0x07,
-}
-
-impl From for u8 {
- fn from(rt: RampTime) -> Self {
- rt as u8
- }
-}
-
-impl From for core::time::Duration {
- fn from(rt: RampTime) -> Self {
- match rt {
- RampTime::Micros10 => core::time::Duration::from_micros(10),
- RampTime::Micros20 => core::time::Duration::from_micros(20),
- RampTime::Micros40 => core::time::Duration::from_micros(40),
- RampTime::Micros80 => core::time::Duration::from_micros(80),
- RampTime::Micros200 => core::time::Duration::from_micros(200),
- RampTime::Micros800 => core::time::Duration::from_micros(800),
- RampTime::Micros1700 => core::time::Duration::from_micros(1700),
- RampTime::Micros3400 => core::time::Duration::from_micros(3400),
- }
- }
-}
-
-#[cfg(feature = "time")]
-impl From for embassy_time::Duration {
- fn from(rt: RampTime) -> Self {
- match rt {
- RampTime::Micros10 => embassy_time::Duration::from_micros(10),
- RampTime::Micros20 => embassy_time::Duration::from_micros(20),
- RampTime::Micros40 => embassy_time::Duration::from_micros(40),
- RampTime::Micros80 => embassy_time::Duration::from_micros(80),
- RampTime::Micros200 => embassy_time::Duration::from_micros(200),
- RampTime::Micros800 => embassy_time::Duration::from_micros(800),
- RampTime::Micros1700 => embassy_time::Duration::from_micros(1700),
- RampTime::Micros3400 => embassy_time::Duration::from_micros(3400),
- }
- }
-}
-/// Transmit parameters, output power and power amplifier ramp up time.
-///
-/// Argument of [`set_tx_params`][`super::SubGhz::set_tx_params`].
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct TxParams {
- buf: [u8; 3],
-}
-
-impl TxParams {
- /// Optimal power setting for +15dBm output power with the low-power PA.
- ///
- /// This must be used with [`PaConfig::LP_15`](super::PaConfig::LP_15).
- pub const LP_15: TxParams = TxParams::new().set_power(0x0E);
-
- /// Optimal power setting for +14dBm output power with the low-power PA.
- ///
- /// This must be used with [`PaConfig::LP_14`](super::PaConfig::LP_14).
- pub const LP_14: TxParams = TxParams::new().set_power(0x0E);
-
- /// Optimal power setting for +10dBm output power with the low-power PA.
- ///
- /// This must be used with [`PaConfig::LP_10`](super::PaConfig::LP_10).
- pub const LP_10: TxParams = TxParams::new().set_power(0x0D);
-
- /// Optimal power setting for the high-power PA.
- ///
- /// This must be used with one of:
- ///
- /// * [`PaConfig::HP_22`](super::PaConfig::HP_22)
- /// * [`PaConfig::HP_20`](super::PaConfig::HP_20)
- /// * [`PaConfig::HP_17`](super::PaConfig::HP_17)
- /// * [`PaConfig::HP_14`](super::PaConfig::HP_14)
- pub const HP: TxParams = TxParams::new().set_power(0x16);
-
- /// Create a new `TxParams` struct.
- ///
- /// This is the same as `default`, but in a `const` function.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::TxParams;
- ///
- /// const TX_PARAMS: TxParams = TxParams::new();
- /// assert_eq!(TX_PARAMS, TxParams::default());
- /// ```
- pub const fn new() -> TxParams {
- TxParams {
- buf: [super::OpCode::SetTxParams as u8, 0x00, 0x00],
- }
- }
-
- /// Set the output power.
- ///
- /// For low power selected in [`set_pa_config`]:
- ///
- /// * 0x0E: +14 dB
- /// * ...
- /// * 0x00: 0 dB
- /// * ...
- /// * 0xEF: -17 dB
- /// * Others: reserved
- ///
- /// For high power selected in [`set_pa_config`]:
- ///
- /// * 0x16: +22 dB
- /// * ...
- /// * 0x00: 0 dB
- /// * ...
- /// * 0xF7: -9 dB
- /// * Others: reserved
- ///
- /// # Example
- ///
- /// Set the output power to 0 dB.
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{RampTime, TxParams};
- ///
- /// const TX_PARAMS: TxParams = TxParams::new().set_power(0x00);
- /// # assert_eq!(TX_PARAMS.as_slice()[1], 0x00);
- /// ```
- ///
- /// [`set_pa_config`]: super::SubGhz::set_pa_config
- #[must_use = "set_power returns a modified TxParams"]
- pub const fn set_power(mut self, power: u8) -> TxParams {
- self.buf[1] = power;
- self
- }
-
- /// Set the Power amplifier ramp time for FSK, MSK, and LoRa modulation.
- ///
- /// # Example
- ///
- /// Set the ramp time to 200 microseconds.
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{RampTime, TxParams};
- ///
- /// const TX_PARAMS: TxParams = TxParams::new().set_ramp_time(RampTime::Micros200);
- /// # assert_eq!(TX_PARAMS.as_slice()[2], 0x04);
- /// ```
- #[must_use = "set_ramp_time returns a modified TxParams"]
- pub const fn set_ramp_time(mut self, rt: RampTime) -> TxParams {
- self.buf[2] = rt as u8;
- self
- }
-
- /// Extracts a slice containing the packet.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::{RampTime, TxParams};
- ///
- /// const TX_PARAMS: TxParams = TxParams::new()
- /// .set_ramp_time(RampTime::Micros80)
- /// .set_power(0x0E);
- /// assert_eq!(TX_PARAMS.as_slice(), &[0x8E, 0x0E, 0x03]);
- /// ```
- pub const fn as_slice(&self) -> &[u8] {
- &self.buf
- }
-}
-
-impl Default for TxParams {
- fn default() -> Self {
- Self::new()
- }
-}
diff --git a/embassy-stm32/src/subghz/value_error.rs b/embassy-stm32/src/subghz/value_error.rs
deleted file mode 100644
index 6a0b489a..00000000
--- a/embassy-stm32/src/subghz/value_error.rs
+++ /dev/null
@@ -1,129 +0,0 @@
-/// Error for a value that is out-of-bounds.
-///
-/// Used by [`Timeout::from_duration`].
-///
-/// [`Timeout::from_duration`]: super::Timeout::from_duration
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct ValueError {
- value: T,
- limit: T,
- over: bool,
-}
-
-impl ValueError {
- /// Create a new `ValueError` for a value that exceeded an upper bound.
- ///
- /// Unfortunately panic is not available in `const fn`, so there are no
- /// guarantees on the value being greater than the limit.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::ValueError;
- ///
- /// const ERROR: ValueError = ValueError::too_high(101u8, 100u8);
- /// assert!(ERROR.over());
- /// assert!(!ERROR.under());
- /// ```
- pub const fn too_high(value: T, limit: T) -> ValueError {
- ValueError {
- value,
- limit,
- over: true,
- }
- }
-
- /// Create a new `ValueError` for a value that exceeded a lower bound.
- ///
- /// Unfortunately panic is not available in `const fn`, so there are no
- /// guarantees on the value being less than the limit.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::ValueError;
- ///
- /// const ERROR: ValueError = ValueError::too_low(200u8, 201u8);
- /// assert!(ERROR.under());
- /// assert!(!ERROR.over());
- /// ```
- pub const fn too_low(value: T, limit: T) -> ValueError {
- ValueError {
- value,
- limit,
- over: false,
- }
- }
-
- /// Get the value that caused the error.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::ValueError;
- ///
- /// const ERROR: ValueError = ValueError::too_high(101u8, 100u8);
- /// assert_eq!(ERROR.value(), &101u8);
- /// ```
- pub const fn value(&self) -> &T {
- &self.value
- }
-
- /// Get the limit for the value.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::ValueError;
- ///
- /// const ERROR: ValueError = ValueError::too_high(101u8, 100u8);
- /// assert_eq!(ERROR.limit(), &100u8);
- /// ```
- pub const fn limit(&self) -> &T {
- &self.limit
- }
-
- /// Returns `true` if the value was over the limit.
- ///
- /// # Example
- ///
- /// ```
- /// use stm32wlxx_hal::subghz::ValueError;
- ///
- /// const ERROR: ValueError