Skip to main content

pamoja_radios/sx126x/
irq.rs

1//! The SX126x interrupt bits.
2//!
3//! The chip logs each interrupt source in a 16-bit IRQ register, laid out in Table 13-29
4//! of the SX1261/2 datasheet. The same layout masks which interrupts are enabled and
5//! routes each one to DIO1, DIO2, or DIO3 through SetDioIrqParams, and clears them through
6//! ClearIrqStatus.
7
8use core::ops::{BitAnd, BitOr, BitOrAssign};
9
10/// A set of SX126x interrupts, in the layout of the IRQ register.
11///
12/// # Examples
13///
14/// ```
15/// use pamoja_radios::sx126x::irq::Irq;
16///
17/// // GetIrqStatus answered 0x0202: a timeout and a received packet.
18/// let pending = Irq::from_bytes([0x02, 0x02]);
19/// assert!(pending.contains(Irq::RX_DONE | Irq::TIMEOUT));
20/// assert!(!pending.contains(Irq::CRC_ERROR));
21/// ```
22#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
23pub struct Irq(u16);
24
25impl Irq {
26    /// No interrupt.
27    pub const NONE: Irq = Irq(0);
28    /// Bit 0: the packet transmission completed.
29    pub const TX_DONE: Irq = Irq(1 << 0);
30    /// Bit 1: a packet was received.
31    pub const RX_DONE: Irq = Irq(1 << 1);
32    /// Bit 2: a preamble was detected.
33    pub const PREAMBLE_DETECTED: Irq = Irq(1 << 2);
34    /// Bit 3: a valid sync word was detected, in FSK.
35    pub const SYNC_WORD_VALID: Irq = Irq(1 << 3);
36    /// Bit 4: a valid LoRa header was received.
37    pub const HEADER_VALID: Irq = Irq(1 << 4);
38    /// Bit 5: a LoRa header failed its CRC.
39    pub const HEADER_ERROR: Irq = Irq(1 << 5);
40    /// Bit 6: a packet failed its CRC.
41    pub const CRC_ERROR: Irq = Irq(1 << 6);
42    /// Bit 7: channel activity detection finished, in LoRa.
43    pub const CAD_DONE: Irq = Irq(1 << 7);
44    /// Bit 8: channel activity was detected, in LoRa.
45    pub const CAD_DETECTED: Irq = Irq(1 << 8);
46    /// Bit 9: a receive or transmit timeout.
47    pub const TIMEOUT: Irq = Irq(1 << 9);
48    /// Bit 14: a hop in LR-FHSS, after the power amplifier ramped up again.
49    pub const LR_FHSS_HOP: Irq = Irq(1 << 14);
50    /// Every interrupt the datasheet defines: bits 0 to 9 and bit 14.
51    pub const ALL: Irq = Irq(0x43FF);
52
53    /// Creates a set from the register's bits.
54    ///
55    /// # Arguments
56    ///
57    /// * `bits` - the 16-bit register value.
58    ///
59    /// # Returns
60    ///
61    /// The set, keeping reserved bits as they came.
62    pub const fn from_bits(bits: u16) -> Irq {
63        Irq(bits)
64    }
65
66    /// Creates a set from the two bytes the chip answers with, most significant first.
67    ///
68    /// # Arguments
69    ///
70    /// * `bytes` - the IrqStatus bytes of a GetIrqStatus answer.
71    ///
72    /// # Returns
73    ///
74    /// The set.
75    pub const fn from_bytes(bytes: [u8; 2]) -> Irq {
76        Irq(u16::from_be_bytes(bytes))
77    }
78
79    /// Returns the register's bits.
80    ///
81    /// # Returns
82    ///
83    /// The 16-bit register value.
84    pub const fn bits(self) -> u16 {
85        self.0
86    }
87
88    /// Returns the two bytes a command carries for this set, most significant first.
89    ///
90    /// # Returns
91    ///
92    /// The mask as it goes on the wire.
93    pub const fn to_bytes(self) -> [u8; 2] {
94        self.0.to_be_bytes()
95    }
96
97    /// Reports whether every interrupt of another set is in this one.
98    ///
99    /// # Arguments
100    ///
101    /// * `other` - the interrupts to look for.
102    ///
103    /// # Returns
104    ///
105    /// `true` when all of them are set.
106    pub const fn contains(self, other: Irq) -> bool {
107        self.0 & other.0 == other.0
108    }
109
110    /// Reports whether any interrupt of another set is in this one.
111    ///
112    /// # Arguments
113    ///
114    /// * `other` - the interrupts to look for.
115    ///
116    /// # Returns
117    ///
118    /// `true` when at least one of them is set.
119    pub const fn intersects(self, other: Irq) -> bool {
120        self.0 & other.0 != 0
121    }
122
123    /// Reports whether the set holds no interrupt.
124    ///
125    /// # Returns
126    ///
127    /// `true` when no bit is set.
128    pub const fn is_empty(self) -> bool {
129        self.0 == 0
130    }
131}
132
133impl BitOr for Irq {
134    type Output = Irq;
135
136    fn bitor(self, rhs: Irq) -> Irq {
137        Irq(self.0 | rhs.0)
138    }
139}
140
141impl BitOrAssign for Irq {
142    fn bitor_assign(&mut self, rhs: Irq) {
143        self.0 |= rhs.0;
144    }
145}
146
147impl BitAnd for Irq {
148    type Output = Irq;
149
150    fn bitand(self, rhs: Irq) -> Irq {
151        Irq(self.0 & rhs.0)
152    }
153}
154
155#[cfg(test)]
156mod tests {
157    use super::*;
158
159    #[test]
160    fn the_bits_follow_table_13_29() {
161        let table = [
162            (Irq::TX_DONE, 0),
163            (Irq::RX_DONE, 1),
164            (Irq::PREAMBLE_DETECTED, 2),
165            (Irq::SYNC_WORD_VALID, 3),
166            (Irq::HEADER_VALID, 4),
167            (Irq::HEADER_ERROR, 5),
168            (Irq::CRC_ERROR, 6),
169            (Irq::CAD_DONE, 7),
170            (Irq::CAD_DETECTED, 8),
171            (Irq::TIMEOUT, 9),
172            (Irq::LR_FHSS_HOP, 14),
173        ];
174        let mut all = Irq::NONE;
175        for (irq, bit) in table {
176            assert_eq!(irq.bits(), 1 << bit);
177            all |= irq;
178        }
179        assert_eq!(all, Irq::ALL);
180    }
181
182    #[test]
183    fn the_register_travels_most_significant_byte_first() {
184        let irq = Irq::TIMEOUT | Irq::TX_DONE;
185        assert_eq!(irq.to_bytes(), [0x02, 0x01]);
186        assert_eq!(Irq::from_bytes([0x02, 0x01]), irq);
187    }
188
189    #[test]
190    fn a_set_answers_for_its_members() {
191        let pending = Irq::RX_DONE | Irq::CRC_ERROR;
192        assert!(pending.contains(Irq::RX_DONE));
193        assert!(!pending.contains(Irq::RX_DONE | Irq::TIMEOUT));
194        assert!(pending.intersects(Irq::CRC_ERROR | Irq::HEADER_ERROR));
195        assert_eq!(pending & Irq::CRC_ERROR, Irq::CRC_ERROR);
196        assert!(Irq::NONE.is_empty());
197    }
198}