2022-06-14 16:27:42 +02:00

293 lines
7.9 KiB
Rust

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