rf24/
types.rs

1//! This module defines types used by various traits.
2//! These types are meant to be agnostic of the trait implementation.
3
4use core::{
5    fmt::{Display, Formatter, Result},
6    write,
7};
8
9use bitfield_struct::bitfield;
10
11/// Power Amplifier level. The units dBm (decibel-milliwatts or dB<sub>mW</sub>)
12/// represents a logarithmic signal loss.
13#[derive(Clone, Copy, Debug, PartialEq)]
14pub enum PaLevel {
15    /// | nRF24L01 | Si24R1 with<br>LNA Enabled | Si24R1 with<br>LNA Disabled |
16    /// | :-------:|:--------------------------:|:---------------------------:|
17    /// | -18 dBm | -6 dBm | -12 dBm |
18    Min,
19    /// | nRF24L01 | Si24R1 with<br>LNA Enabled | Si24R1 with<br>LNA Disabled |
20    /// | :-------:|:--------------------------:|:---------------------------:|
21    /// | -12 dBm | 0 dBm | -4 dBm |
22    Low,
23    /// | nRF24L01 | Si24R1 with<br>LNA Enabled | Si24R1 with<br>LNA Disabled |
24    /// | :-------:|:--------------------------:|:---------------------------:|
25    /// | -6 dBm | 3 dBm | 1 dBm |
26    High,
27    /// | nRF24L01 | Si24R1 with<br>LNA Enabled | Si24R1 with<br>LNA Disabled |
28    /// | :-------:|:--------------------------:|:---------------------------:|
29    /// | 0 dBm | 7 dBm | 4 dBm |
30    Max,
31}
32
33#[cfg(feature = "defmt")]
34#[cfg(target_os = "none")]
35impl defmt::Format for PaLevel {
36    fn format(&self, fmt: defmt::Formatter) {
37        match self {
38            PaLevel::Min => defmt::write!(fmt, "Min"),
39            PaLevel::Low => defmt::write!(fmt, "Low"),
40            PaLevel::High => defmt::write!(fmt, "High"),
41            PaLevel::Max => defmt::write!(fmt, "Max"),
42        }
43    }
44}
45
46impl PaLevel {
47    pub(crate) const MASK: u8 = 6;
48
49    pub(crate) const fn into_bits(self) -> u8 {
50        match self {
51            PaLevel::Min => 0,
52            PaLevel::Low => 2,
53            PaLevel::High => 4,
54            PaLevel::Max => 6,
55        }
56    }
57    pub(crate) const fn from_bits(value: u8) -> Self {
58        match value {
59            0 => PaLevel::Min,
60            2 => PaLevel::Low,
61            4 => PaLevel::High,
62            _ => PaLevel::Max,
63        }
64    }
65}
66
67impl Display for PaLevel {
68    fn fmt(&self, f: &mut Formatter) -> Result {
69        match self {
70            PaLevel::Min => write!(f, "Min"),
71            PaLevel::Low => write!(f, "Low"),
72            PaLevel::High => write!(f, "High"),
73            PaLevel::Max => write!(f, "Max"),
74        }
75    }
76}
77
78/// How fast data moves through the air. Units are in bits per second (bps).
79#[derive(Clone, Copy, Debug, PartialEq)]
80pub enum DataRate {
81    /// represents 1 Mbps
82    Mbps1,
83    /// represents 2 Mbps
84    Mbps2,
85    /// represents 250 Kbps
86    Kbps250,
87}
88
89impl DataRate {
90    pub(crate) const MASK: u8 = 0x28;
91
92    pub(crate) const fn into_bits(self) -> u8 {
93        match self {
94            DataRate::Mbps1 => 0,
95            DataRate::Mbps2 => 0x8,
96            DataRate::Kbps250 => 0x20,
97        }
98    }
99    pub(crate) const fn from_bits(value: u8) -> Self {
100        match value {
101            0x8 => DataRate::Mbps2,
102            0x20 => DataRate::Kbps250,
103            _ => DataRate::Mbps1,
104        }
105    }
106}
107
108#[cfg(feature = "defmt")]
109#[cfg(target_os = "none")]
110impl defmt::Format for DataRate {
111    fn format(&self, fmt: defmt::Formatter) {
112        match self {
113            DataRate::Mbps1 => defmt::write!(fmt, "1 Mbps"),
114            DataRate::Mbps2 => defmt::write!(fmt, "2 Mbps"),
115            DataRate::Kbps250 => defmt::write!(fmt, "250 Kbps"),
116        }
117    }
118}
119
120impl Display for DataRate {
121    fn fmt(&self, f: &mut Formatter) -> Result {
122        match self {
123            DataRate::Mbps1 => write!(f, "1 Mbps"),
124            DataRate::Mbps2 => write!(f, "2 Mbps"),
125            DataRate::Kbps250 => write!(f, "250 Kbps"),
126        }
127    }
128}
129
130/// The length of a CRC checksum that is used (if any).
131///
132/// Cyclical Redundancy Checking (CRC) is commonly used to ensure data integrity.
133#[derive(Clone, Copy, Debug, PartialEq)]
134pub enum CrcLength {
135    /// represents no CRC checksum is used
136    Disabled,
137    /// represents CRC 8 bit checksum is used
138    Bit8,
139    /// represents CRC 16 bit checksum is used
140    Bit16,
141}
142
143impl CrcLength {
144    pub(crate) const fn into_bits(self) -> u8 {
145        match self {
146            CrcLength::Disabled => 0,
147            CrcLength::Bit8 => 8,
148            CrcLength::Bit16 => 12,
149        }
150    }
151    pub(crate) const fn from_bits(value: u8) -> Self {
152        match value {
153            0 => CrcLength::Disabled,
154            8 => CrcLength::Bit8,
155            _ => CrcLength::Bit16,
156        }
157    }
158}
159
160#[cfg(feature = "defmt")]
161#[cfg(target_os = "none")]
162impl defmt::Format for CrcLength {
163    fn format(&self, fmt: defmt::Formatter) {
164        match self {
165            CrcLength::Disabled => defmt::write!(fmt, "disabled"),
166            CrcLength::Bit8 => defmt::write!(fmt, "8 bit"),
167            CrcLength::Bit16 => defmt::write!(fmt, "16 bit"),
168        }
169    }
170}
171
172impl Display for CrcLength {
173    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
174        match self {
175            CrcLength::Disabled => write!(f, "disabled"),
176            CrcLength::Bit8 => write!(f, "8 bit"),
177            CrcLength::Bit16 => write!(f, "16 bit"),
178        }
179    }
180}
181
182/// The possible states of a FIFO.
183#[derive(Clone, Copy, Debug, PartialEq)]
184pub enum FifoState {
185    /// Represent the state of a FIFO when it is full.
186    Full,
187    /// Represent the state of a FIFO when it is empty.
188    Empty,
189    /// Represent the state of a FIFO when it is not full but not empty either.
190    Occupied,
191}
192
193#[cfg(feature = "defmt")]
194#[cfg(target_os = "none")]
195impl defmt::Format for FifoState {
196    #[cfg(feature = "defmt")]
197    fn format(&self, fmt: defmt::Formatter) {
198        match self {
199            FifoState::Empty => defmt::write!(fmt, "Empty"),
200            FifoState::Full => defmt::write!(fmt, "Full"),
201            FifoState::Occupied => defmt::write!(fmt, "Occupied"),
202        }
203    }
204}
205
206impl Display for FifoState {
207    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
208        match self {
209            FifoState::Empty => write!(f, "Empty"),
210            FifoState::Full => write!(f, "Full"),
211            FifoState::Occupied => write!(f, "Occupied"),
212        }
213    }
214}
215
216/// A struct used to describe the different interrupt events.
217///
218/// To instantiate an object with flags that have different values:
219/// ```
220/// let flags = StatusFlags::default() // all flags are false
221///     .with_rx_dr(true); // assert only `rx_dr` flags
222/// ```
223/// Use [`StatusFlags::default`] to instantiate all flags set to false.
224/// Use [`StatusFlags::new`] to instantiate all flags set to true.
225#[bitfield(u8, new = false, order = Msb)]
226pub struct StatusFlags {
227    #[bits(1)]
228    _padding: u8,
229
230    /// A flag to describe if RX Data Ready to read.
231    #[bits(1, access = RO)]
232    pub rx_dr: bool,
233
234    /// A flag to describe if TX Data Sent.
235    #[bits(1, access = RO)]
236    pub tx_ds: bool,
237
238    /// A flag to describe if TX Data Failed.
239    #[bits(1, access = RO)]
240    pub tx_df: bool,
241
242    #[bits(3, access = RO)]
243    pub(crate) rx_pipe: u8,
244
245    #[bits(1, access = RO)]
246    pub(crate) tx_full: bool,
247}
248
249#[cfg(feature = "defmt")]
250impl defmt::Format for StatusFlags {
251    fn format(&self, fmt: defmt::Formatter) {
252        defmt::write!(
253            fmt,
254            "StatusFlags rx_dr: {}, tx_ds: {}, tx_df: {}",
255            self.rx_dr,
256            self.tx_ds,
257            self.tx_df
258        )
259    }
260}
261
262impl StatusFlags {
263    /// A mask to isolate only the IRQ flags. Useful for STATUS and CONFIG registers.
264    pub(crate) const IRQ_MASK: u8 = 0x70;
265
266    /// A convenience constructor similar to [`StatusFlags::default`] except
267    /// all fields are set to `true`.
268    pub fn new() -> Self {
269        Self::from_bits(0x70)
270    }
271
272    /// A flag to describe if RX Data Ready to read.
273    pub fn with_rx_dr(self, flag: bool) -> Self {
274        let new_val = self.into_bits() & !(1 << Self::RX_DR_OFFSET);
275        if flag {
276            Self::from_bits(new_val | (1 << Self::RX_DR_OFFSET))
277        } else {
278            Self::from_bits(new_val)
279        }
280    }
281
282    /// A flag to describe if TX Data Sent.
283    pub fn with_tx_ds(self, flag: bool) -> Self {
284        let new_val = self.into_bits() & !(1 << Self::TX_DS_OFFSET);
285        if flag {
286            Self::from_bits(new_val | (1 << Self::TX_DS_OFFSET))
287        } else {
288            Self::from_bits(new_val)
289        }
290    }
291
292    /// A flag to describe if TX Data Failed.
293    pub fn with_tx_df(self, flag: bool) -> Self {
294        let new_val = self.into_bits() & !(1 << Self::TX_DF_OFFSET);
295        if flag {
296            Self::from_bits(new_val | (1 << Self::TX_DF_OFFSET))
297        } else {
298            Self::from_bits(new_val)
299        }
300    }
301}
302
303impl Display for StatusFlags {
304    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
305        write!(
306            f,
307            "StatusFlags rx_dr: {}, tx_ds: {}, tx_df: {}",
308            self.rx_dr(),
309            self.tx_ds(),
310            self.tx_df()
311        )
312    }
313}
314
315#[cfg(test)]
316mod test {
317    use crate::StatusFlags;
318
319    use super::{CrcLength, DataRate, FifoState, PaLevel};
320    extern crate std;
321    use std::{format, string::String};
322
323    fn display_crc(param: CrcLength, expected: String) -> bool {
324        format!("{param}") == expected
325    }
326
327    #[test]
328    fn crc_8bit() {
329        assert!(display_crc(CrcLength::Bit8, String::from("8 bit")));
330    }
331
332    #[test]
333    fn crc_16bit() {
334        assert!(display_crc(CrcLength::Bit16, String::from("16 bit")));
335    }
336
337    #[test]
338    fn crc_disable() {
339        assert!(display_crc(CrcLength::Disabled, String::from("disabled")));
340    }
341
342    fn display_fifo_state(param: FifoState, expected: String) -> bool {
343        format!("{param}") == expected
344    }
345
346    #[test]
347    fn fifo_state_empty() {
348        assert!(display_fifo_state(FifoState::Empty, String::from("Empty")));
349    }
350
351    #[test]
352    fn fifo_state_full() {
353        assert!(display_fifo_state(FifoState::Full, String::from("Full")));
354    }
355
356    #[test]
357    fn fifo_state_occupied() {
358        assert!(display_fifo_state(
359            FifoState::Occupied,
360            String::from("Occupied")
361        ));
362    }
363
364    fn display_data_rate(param: DataRate, expected: String) -> bool {
365        format!("{param}") == expected
366    }
367
368    #[test]
369    fn data_rate_1mbps() {
370        assert!(display_data_rate(DataRate::Mbps1, String::from("1 Mbps")));
371    }
372
373    #[test]
374    fn data_rate_2mbps() {
375        assert!(display_data_rate(DataRate::Mbps2, String::from("2 Mbps")));
376    }
377
378    #[test]
379    fn data_rate_250kbps() {
380        assert!(display_data_rate(
381            DataRate::Kbps250,
382            String::from("250 Kbps")
383        ));
384    }
385
386    fn display_pa_level(param: PaLevel, expected: String) -> bool {
387        format!("{param}") == expected
388    }
389
390    #[test]
391    fn pa_level_min() {
392        assert!(display_pa_level(PaLevel::Min, String::from("Min")));
393    }
394
395    #[test]
396    fn pa_level_low() {
397        assert!(display_pa_level(PaLevel::Low, String::from("Low")));
398    }
399
400    #[test]
401    fn pa_level_high() {
402        assert!(display_pa_level(PaLevel::High, String::from("High")));
403    }
404
405    #[test]
406    fn pa_level_max() {
407        assert!(display_pa_level(PaLevel::Max, String::from("Max")));
408    }
409
410    #[test]
411    fn display_flags() {
412        assert_eq!(
413            format!("{}", StatusFlags::default()),
414            String::from("StatusFlags rx_dr: false, tx_ds: false, tx_df: false")
415        );
416    }
417
418    fn set_flags(rx_dr: bool, tx_ds: bool, tx_df: bool) {
419        let flags = StatusFlags::default()
420            .with_rx_dr(rx_dr)
421            .with_tx_ds(tx_ds)
422            .with_tx_df(tx_df);
423        assert_eq!(flags.rx_dr(), rx_dr);
424        assert_eq!(flags.tx_ds(), tx_ds);
425        assert_eq!(flags.tx_df(), tx_df);
426    }
427
428    #[test]
429    fn flags_0x50() {
430        set_flags(true, false, true);
431    }
432
433    #[test]
434    fn flags_0x20() {
435        set_flags(false, true, false);
436    }
437}