/// 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() } }