nrf24_rs/
config.rs

1//! Different structs and values for configuration of the chip.
2//!
3//! To construct a representation of your config, see [`NrfConfig`].
4//!
5//! # Default values
6//! All these options have a default value:
7//!
8//! * `addr_width`:             address width of 5 bytes.
9//! * `ack_payloads_enabled`:   false: acknowledgement payloads are disabled by default.
10//! * `auto_retry`:             enabled, will wait 1586µs on ack, and will retry 15 times.
11//! * `channel`:                channel 76.
12//! * `crc_encoding_scheme`:    encoding scheme with 2 bytes.
13//! * `data_rate`:              1Mbps.
14//! * `payload_size`:           static payload size of [`MAX_PAYLOAD_SIZE`] bytes.
15//! * `pa_level`:               min amplification level.
16//!
17use crate::register_acces::Register;
18use crate::MAX_PAYLOAD_SIZE;
19#[cfg(feature = "micro-fmt")]
20use ufmt::{uDebug, uWrite, uwrite, Formatter};
21
22const MAX_CHANNEL: u8 = 125;
23
24/// Configuration builder struct for NRF chip.
25///
26/// Always created with the `default()` method and modified through
27/// the builder pattern.
28///
29/// # Example: default
30/// ```rust
31/// use nrf24::Nrf24l01;
32/// use nrf24::config::NrfConfig;
33///
34/// let config = NrfConfig::default();
35///
36/// let mut chip = Nrf24l01::new(spi, ce, ncs, delay, config)?;
37/// ```
38///
39/// # Example: custom configuration
40/// ```rust
41/// use nrf24::Nrf24l01;
42/// use nrf24::config::{PALevel, DataRate, NrfConfig, PayloadSize};
43///
44/// let config = NrfConfig::default()
45///     .payload_size(PayloadSize::Dynamic) // set dynamic payload size
46///     .channel(7)
47///     .addr_width(3),
48///     .data_rate(DataRate::R2Mbps)
49///     .pa_level(PALevel::Max)
50///     .crc_encoding_scheme(None) // disable crc
51///     .ack_payloads_enabled(true)
52///     .auto_retry((15, 15));
53///
54/// let mut chip = Nrf24l01::new(spi, ce, ncs, delay, config)?;
55/// ```
56#[derive(Copy, Debug, Clone)]
57pub struct NrfConfig {
58    pub(crate) payload_size: PayloadSize,
59    pub(crate) channel: u8,
60    pub(crate) addr_width: AddressWidth,
61    pub(crate) data_rate: DataRate,
62    pub(crate) pa_level: PALevel,
63    pub(crate) crc_encoding_scheme: Option<EncodingScheme>,
64    pub(crate) ack_payloads_enabled: bool,
65    pub(crate) auto_retry: AutoRetransmission,
66}
67
68impl NrfConfig {
69    /// Set Payload Size
70    /// A value of 0 means dynamic payloads will be enabled.
71    /// Values greater than [`MAX_PAYLOAD_SIZE`] will be floored.
72    pub fn payload_size<T: Into<PayloadSize>>(mut self, payload_size: T) -> Self {
73        self.payload_size = payload_size.into();
74        self
75    }
76    /// Set RF channel
77    /// Must be a number in [0..125], values outside will be clipped
78    pub fn channel(mut self, channel: u8) -> Self {
79        self.channel = core::cmp::min(channel, MAX_CHANNEL);
80        self
81    }
82    /// Set the Address Width
83    /// If using a number, it must be in [3..5], values outside will be clipped
84    pub fn addr_width<T: Into<AddressWidth>>(mut self, addr_width: T) -> Self {
85        self.addr_width = addr_width.into();
86        self
87    }
88    /// Set the Data Rate
89    pub fn data_rate(mut self, data_rate: DataRate) -> Self {
90        self.data_rate = data_rate;
91        self
92    }
93    /// Set the Power Amplification Level
94    pub fn pa_level(mut self, pa_level: PALevel) -> Self {
95        self.pa_level = pa_level;
96        self
97    }
98    /// Set the Cyclic Redundancy Check Encodign Scheme
99    /// None will disable the CRC.
100    pub fn crc_encoding_scheme(mut self, crc_encoding_scheme: Option<EncodingScheme>) -> Self {
101        self.crc_encoding_scheme = crc_encoding_scheme;
102        self
103    }
104    /// Configure if auto acknowledgements are enabled
105    pub fn ack_payloads_enabled(mut self, ack_payloads_enabled: bool) -> Self {
106        self.ack_payloads_enabled = ack_payloads_enabled;
107        self
108    }
109    /// Set the automatic retransmission config
110    pub fn auto_retry<T: Into<AutoRetransmission>>(mut self, auto_retry: T) -> Self {
111        self.auto_retry = auto_retry.into();
112        self
113    }
114}
115
116impl Default for NrfConfig {
117    fn default() -> Self {
118        Self {
119            channel: 76,
120            payload_size: PayloadSize::default(),
121            addr_width: AddressWidth::default(),
122            crc_encoding_scheme: Some(EncodingScheme::R2Bytes),
123            pa_level: PALevel::default(),
124            data_rate: DataRate::default(),
125            ack_payloads_enabled: false,
126            auto_retry: AutoRetransmission::default(),
127        }
128    }
129}
130
131#[cfg(feature = "micro-fmt")]
132impl uDebug for NrfConfig {
133    fn fmt<W: ?Sized>(&self, f: &mut Formatter<'_, W>) -> core::result::Result<(), W::Error>
134    where
135        W: uWrite,
136    {
137        f.debug_struct("nRF configuration")?
138            .field("channel", &self.channel)?
139            .field("payload size", &self.payload_size)?
140            .field("power amplification level", &self.pa_level)?
141            .field("data rate", &self.data_rate)?
142            .field("auto retransmission", &self.auto_retry)?
143            .field(
144                "acknowledgement payloads enabled",
145                &self.ack_payloads_enabled,
146            )?
147            .field("address width", &self.addr_width)?
148            .field("crc encoding scheme", &self.crc_encoding_scheme)?
149            .finish()
150    }
151}
152
153/// Different RF power levels. The higher the level the bigger range, but the more the current
154/// consumption.
155///
156/// Defaults to Min.
157#[derive(Debug, PartialEq, Eq, Copy, Clone)]
158pub enum PALevel {
159    /// -18 dBm, 7 mA current consumption.
160    Min = 0b0000_0000,
161    /// -12 dBm, 7.5 mA current consumption.
162    Low = 0b0000_0010,
163    /// -6 dBm, 9.0 mA current consumption.
164    High = 0b0000_0100,
165    /// -0 dBm, 11.3 mA current consumption.
166    Max = 0b0000_0110,
167}
168
169impl PALevel {
170    pub(crate) fn bitmask() -> u8 {
171        0b0000_0110
172    }
173    pub(crate) fn level(&self) -> u8 {
174        *self as u8
175    }
176}
177
178impl Default for PALevel {
179    fn default() -> Self {
180        PALevel::Min
181    }
182}
183
184impl From<u8> for PALevel {
185    fn from(t: u8) -> Self {
186        match t & Self::bitmask() {
187            0b0000_0000 => Self::Min,
188            0b0000_0010 => Self::Low,
189            0b0000_0100 => Self::High,
190            0b0000_0110 => Self::Max,
191            _ => unreachable!(),
192        }
193    }
194}
195
196#[cfg(feature = "micro-fmt")]
197impl uDebug for PALevel {
198    fn fmt<W: ?Sized>(&self, f: &mut Formatter<'_, W>) -> core::result::Result<(), W::Error>
199    where
200        W: uWrite,
201    {
202        match *self {
203            PALevel::Min => f.write_str("min (-18 dBm)"),
204            PALevel::Low => f.write_str("low (-12 dBm)"),
205            PALevel::High => f.write_str("high (-6 dBm)"),
206            PALevel::Max => f.write_str("max (0 dBm)"),
207        }
208    }
209}
210
211/// Enum representing the payload size.
212#[derive(Debug, Copy, Clone, PartialEq, Eq)]
213pub enum PayloadSize {
214    /// The chip will dynamically set the payload size, depending on the message size.
215    Dynamic,
216    /// Static payload size. Maximum value of 127.
217    Static(u8),
218}
219
220impl PayloadSize {
221    /// Truncates the payload size to be max [`MAX_PAYLOAD_SIZE`].
222    pub(crate) fn truncate(self) -> Self {
223        match self {
224            Self::Dynamic => Self::Dynamic,
225            Self::Static(n) => Self::Static(core::cmp::min(n, MAX_PAYLOAD_SIZE)),
226        }
227    }
228}
229
230impl Default for PayloadSize {
231    fn default() -> Self {
232        Self::Static(MAX_PAYLOAD_SIZE)
233    }
234}
235
236impl From<u8> for PayloadSize {
237    fn from(size: u8) -> Self {
238        match size {
239            0 => Self::Dynamic,
240            n => Self::Static(core::cmp::min(n, MAX_PAYLOAD_SIZE)),
241        }
242    }
243}
244
245#[cfg(feature = "micro-fmt")]
246impl uDebug for PayloadSize {
247    fn fmt<W: ?Sized>(&self, f: &mut Formatter<'_, W>) -> core::result::Result<(), W::Error>
248    where
249        W: uWrite,
250    {
251        match *self {
252            Self::Dynamic => f.write_str("dynamic payloads"),
253            Self::Static(n) => uwrite!(f, "{:?} byte static payloads", n),
254        }
255    }
256}
257
258/// Configured speed at which data will be sent.
259///
260/// Defaults to 2Mpbs.
261#[derive(Debug, PartialEq, Eq, Copy, Clone)]
262pub enum DataRate {
263    /// 1 Mbps
264    R1Mbps = 0b0000_0000,
265    /// 2 Mbps
266    R2Mbps = 0b0000_0001,
267}
268
269impl DataRate {
270    pub(crate) fn bitmask() -> u8 {
271        0b1111_1110
272    }
273    pub(crate) fn rate(&self) -> u8 {
274        *self as u8
275    }
276}
277
278impl Default for DataRate {
279    fn default() -> Self {
280        DataRate::R1Mbps
281    }
282}
283
284impl From<u8> for DataRate {
285    fn from(t: u8) -> Self {
286        match t & Self::bitmask() {
287            0 => Self::R1Mbps,
288            1 => Self::R2Mbps,
289            _ => unreachable!(),
290        }
291    }
292}
293
294#[cfg(feature = "micro-fmt")]
295impl uDebug for DataRate {
296    fn fmt<W: ?Sized>(&self, f: &mut Formatter<'_, W>) -> core::result::Result<(), W::Error>
297    where
298        W: uWrite,
299    {
300        match *self {
301            DataRate::R1Mbps => f.write_str("1 Mbps"),
302            DataRate::R2Mbps => f.write_str("2 Mbps"),
303        }
304    }
305}
306
307/// Cyclic Redundancy Check encoding scheme.
308#[derive(Debug, PartialEq, Eq, Copy, Clone)]
309pub enum EncodingScheme {
310    /// 1 byte
311    R1Byte = 0,
312    /// 2 bytes
313    R2Bytes = 1,
314}
315
316impl EncodingScheme {
317    pub(crate) fn scheme(&self) -> u8 {
318        *self as u8
319    }
320}
321
322#[cfg(feature = "micro-fmt")]
323impl uDebug for EncodingScheme {
324    fn fmt<W: ?Sized>(&self, f: &mut Formatter<'_, W>) -> core::result::Result<(), W::Error>
325    where
326        W: uWrite,
327    {
328        match *self {
329            Self::R1Byte => f.write_str("1 byte"),
330            Self::R2Bytes => f.write_str("2 bytes"),
331        }
332    }
333}
334
335/// Address width for the reading and writing pipes.
336#[derive(Debug, PartialEq, Eq, Copy, Clone)]
337pub enum AddressWidth {
338    /// 3 bytes
339    R3Bytes = 1,
340    /// 4 bytes
341    R4Bytes = 2,
342    /// 5 bytes
343    R5Bytes = 3,
344}
345
346impl AddressWidth {
347    pub(crate) fn value(&self) -> u8 {
348        *self as u8
349    }
350}
351impl Default for AddressWidth {
352    fn default() -> Self {
353        Self::R5Bytes
354    }
355}
356
357impl From<u8> for AddressWidth {
358    fn from(t: u8) -> Self {
359        match t {
360            0..=3 => Self::R3Bytes,
361            4 => Self::R4Bytes,
362            5..=u8::MAX => Self::R5Bytes,
363        }
364    }
365}
366
367#[cfg(feature = "micro-fmt")]
368impl uDebug for AddressWidth {
369    fn fmt<W: ?Sized>(&self, f: &mut Formatter<'_, W>) -> core::result::Result<(), W::Error>
370    where
371        W: uWrite,
372    {
373        match *self {
374            Self::R3Bytes => f.write_str("3 bytes"),
375            Self::R4Bytes => f.write_str("4 bytes"),
376            Self::R5Bytes => f.write_str("5 bytes"),
377        }
378    }
379}
380
381/// Configuration of automatic retransmission consisting of a retransmit delay
382/// and a retransmission count.
383///
384/// The delay before a retransmit is initiated, is calculated according to the following formula:
385/// > ((**delay** + 1) * 250) + 86 µs
386///
387/// # Default
388///
389/// * Auto retransmission delay has a default value of 5, which means `1586 µs`.
390/// * The chip will try to resend a failed message 15 times by default.
391#[derive(Debug, PartialEq, Eq, Copy, Clone)]
392pub struct AutoRetransmission {
393    delay: u8,
394    count: u8,
395}
396
397impl Default for AutoRetransmission {
398    fn default() -> Self {
399        Self {
400            delay: 5,
401            count: 15,
402        }
403    }
404}
405
406impl AutoRetransmission {
407    pub(crate) fn from_register(reg: u8) -> Self {
408        Self {
409            delay: reg >> 4,
410            count: reg & 0b0000_1111,
411        }
412    }
413    /// The auto retransmit delay value.
414    /// Values can be between 0 and 15.
415    /// The delay before a retransmit is initiated, is calculated according to the following formula:
416    /// > ((**delay** + 1) * 250) + 86 µs
417    pub fn raw_delay(&self) -> u8 {
418        self.delay
419    }
420
421    /// Returns the delay between auto retransmissions in ms.
422    pub fn delay(&self) -> u32 {
423        ((self.delay as u32 + 1) * 250) + 86
424    }
425    /// The number of times there will be an auto retransmission.
426    /// Guarantueed to be a value between 0 and 15.
427    pub fn count(&self) -> u8 {
428        self.count
429    }
430}
431
432impl From<(u8, u8)> for AutoRetransmission {
433    fn from((d, c): (u8, u8)) -> Self {
434        Self {
435            delay: core::cmp::min(d, 15),
436            count: core::cmp::min(c, 15),
437        }
438    }
439}
440
441#[cfg(feature = "micro-fmt")]
442impl uDebug for AutoRetransmission {
443    fn fmt<W: ?Sized>(&self, f: &mut Formatter<'_, W>) -> core::result::Result<(), W::Error>
444    where
445        W: uWrite,
446    {
447        f.debug_struct("AutoRetransmission")?
448            .field("delay", &self.delay)?
449            .field("count", &self.count)?
450            .finish()
451    }
452}
453/// Representation of the different data pipes through which data can be received.
454///
455/// An nRF24L01 configured as primary RX (PRX) will be able to receive data trough 6 different data
456/// pipes.
457/// One data pipe will have a unique address but share the same frequency channel.
458/// This means that up to 6 different nRF24L01 configured as primary TX (PTX) can communicate with
459/// one nRF24L01 configured as PRX, and the nRF24L01 configured as PRX will be able to distinguish
460/// between them.
461///
462/// The default assumed data pipe is 0.
463///
464/// Data pipe 0 has a unique 40 bit configurable address. Each of data pipe 1-5 has an 8 bit unique
465/// address and shares the 32 most significant address bits.
466///
467/// # Notes
468/// In the PTX device data pipe 0 is used to received the acknowledgement, and therefore the
469/// receive address for data pipe 0 has to be equal to the transmit address to be able to receive
470/// the acknowledgement.
471#[derive(Debug, PartialEq, Eq, Copy, Clone)]
472#[repr(u8)]
473pub enum DataPipe {
474    /// Data pipe 0.
475    /// Default pipe with a 40 bit configurable address.
476    /// This pipe is used in TX mode when auto acknowledgement is enabled. On this channel the ACK
477    /// messages are received.
478    DP0 = 0,
479    /// Data pipe 1.
480    DP1 = 1,
481    /// Data pipe 2.
482    DP2 = 2,
483    /// Data pipe 3.
484    DP3 = 3,
485    /// Data pipe 4.
486    DP4 = 4,
487    /// Data pipe 5.
488    DP5 = 5,
489}
490
491impl DataPipe {
492    pub(crate) fn pipe(&self) -> u8 {
493        *self as u8
494    }
495}
496
497impl Default for DataPipe {
498    fn default() -> Self {
499        DataPipe::DP0
500    }
501}
502
503impl From<u8> for DataPipe {
504    fn from(t: u8) -> Self {
505        match t {
506            0 => DataPipe::DP0,
507            1 => DataPipe::DP1,
508            2 => DataPipe::DP2,
509            3 => DataPipe::DP3,
510            4 => DataPipe::DP4,
511            5 => DataPipe::DP5,
512            _ => DataPipe::DP0,
513        }
514    }
515}
516
517impl Into<Register> for DataPipe {
518    fn into(self) -> Register {
519        match self {
520            DataPipe::DP0 => Register::RX_ADDR_P0,
521            DataPipe::DP1 => Register::RX_ADDR_P1,
522            DataPipe::DP2 => Register::RX_ADDR_P2,
523            DataPipe::DP3 => Register::RX_ADDR_P3,
524            DataPipe::DP4 => Register::RX_ADDR_P4,
525            DataPipe::DP5 => Register::RX_ADDR_P5,
526        }
527    }
528}
529
530#[cfg(feature = "micro-fmt")]
531impl uDebug for DataPipe {
532    fn fmt<W: ?Sized>(&self, f: &mut Formatter<'_, W>) -> core::result::Result<(), W::Error>
533    where
534        W: uWrite,
535    {
536        match *self {
537            DataPipe::DP0 => f.write_str("data pipe 0"),
538            DataPipe::DP1 => f.write_str("data pipe 1"),
539            DataPipe::DP2 => f.write_str("data pipe 2"),
540            DataPipe::DP3 => f.write_str("data pipe 3"),
541            DataPipe::DP4 => f.write_str("data pipe 4"),
542            DataPipe::DP5 => f.write_str("data pipe 5"),
543        }
544    }
545}