rf24/radio/rf24/
power.rs

1use embedded_hal::{delay::DelayNs, digital::OutputPin, spi::SpiDevice};
2
3use crate::radio::{prelude::EsbPower, Nrf24Error, RF24};
4
5use super::registers;
6
7impl<SPI, DO, DELAY> EsbPower for RF24<SPI, DO, DELAY>
8where
9    SPI: SpiDevice,
10    DO: OutputPin,
11    DELAY: DelayNs,
12{
13    type PowerErrorType = Nrf24Error<SPI::Error, DO::Error>;
14
15    /// After calling [`EsbRadio::as_rx()`](fn@crate::radio::prelude::EsbRadio::as_rx),
16    /// a non-PA/LNA radio will consume about
17    /// 13.5mA at [`PaLevel::MAX`](type@crate::types::PaLevel::Max).
18    /// During active transmission (including RX role when transmitting an auto-ACK
19    /// packet), a non-PA/LNA radio will consume about 11.5mA.
20    /// In power standby mode (when not receiving nor transmitting), a non-PA/LNA radio
21    /// will consume about 26uA (.026mA).
22    /// In full power down mode (a sleep state), the radio will consume approximately
23    /// 900nA (.0009mA).
24    fn power_down(&mut self) -> Result<(), Self::PowerErrorType> {
25        self.ce_pin.set_low().map_err(Nrf24Error::Gpo)?; // Guarantee CE is low on powerDown
26        self._config_reg = self._config_reg.with_power(false);
27        self.spi_write_byte(registers::CONFIG, self._config_reg.into_bits())?;
28        Ok(())
29    }
30
31    fn power_up(&mut self, delay: Option<u32>) -> Result<(), Self::PowerErrorType> {
32        // if not powered up then power up and wait for the radio to initialize
33        if self._config_reg.power() {
34            return Ok(());
35        }
36        self._config_reg = self._config_reg.with_power(true);
37        self.spi_write_byte(registers::CONFIG, self._config_reg.into_bits())?;
38
39        // For nRF24L01+ to go from power down mode to TX or RX mode it must first pass through stand-by mode.
40        // There must be a delay of Tpd2standby (see Table 16.) after the nRF24L01+ leaves power down mode before
41        // the CE is set high. Tpd2standby can be up to 5ms per the 1.0 datasheet
42        if delay.is_some_and(|val| val > 0) || delay.is_none() {
43            self._delay_impl.delay_ns(delay.unwrap_or(5000000));
44        }
45        Ok(())
46    }
47
48    /// Is the radio powered up?
49    fn is_powered(&self) -> bool {
50        self._config_reg.power()
51    }
52}
53
54/////////////////////////////////////////////////////////////////////////////////
55/// unit tests
56#[cfg(test)]
57mod test {
58    extern crate std;
59    use crate::radio::prelude::EsbPower;
60    use crate::radio::rf24::commands;
61    use crate::spi_test_expects;
62
63    use super::{registers, RF24};
64    use embedded_hal_mock::eh1::delay::NoopDelay;
65    use embedded_hal_mock::eh1::digital::Mock as PinMock;
66    use embedded_hal_mock::eh1::spi::{Mock as SpiMock, Transaction as SpiTransaction};
67    use std::vec;
68
69    #[test]
70    pub fn power_up() {
71        // Create pin
72        let pin_expectations = [];
73        let mut pin_mock = PinMock::new(&pin_expectations);
74
75        // create delay fn
76        let delay_mock = NoopDelay::new();
77
78        let spi_expectations = spi_test_expects![
79            // get the RF_SETUP register value for each possible result
80            (
81                vec![registers::CONFIG | commands::W_REGISTER, 0xEu8],
82                vec![0xEu8, 0u8],
83            ),
84        ];
85        let mut spi_mock = SpiMock::new(&spi_expectations);
86        let mut radio = RF24::new(pin_mock.clone(), spi_mock.clone(), delay_mock);
87        radio.power_up(None).unwrap();
88        radio.power_up(None).unwrap();
89        // radio.power_up(Some(0)).unwrap();
90        spi_mock.done();
91        pin_mock.done();
92    }
93
94    #[test]
95    pub fn power_up_no_blocking() {
96        // Create pin
97        let pin_expectations = [];
98        let mut pin_mock = PinMock::new(&pin_expectations);
99
100        // create delay fn
101        let delay_mock = NoopDelay::new();
102
103        let spi_expectations = spi_test_expects![
104            // get the RF_SETUP register value for each possible result
105            (
106                vec![registers::CONFIG | commands::W_REGISTER, 0xEu8],
107                vec![0xEu8, 0u8],
108            ),
109        ];
110        let mut spi_mock = SpiMock::new(&spi_expectations);
111        let mut radio = RF24::new(pin_mock.clone(), spi_mock.clone(), delay_mock);
112        radio.power_up(Some(0)).unwrap();
113        assert!(radio.is_powered());
114        spi_mock.done();
115        pin_mock.done();
116    }
117
118    #[test]
119    pub fn power_getter() {
120        // Create pin
121        let pin_expectations = [];
122        let mut pin_mock = PinMock::new(&pin_expectations);
123
124        // create delay fn
125        let delay_mock = NoopDelay::new();
126
127        let spi_expectations = vec![];
128        let mut spi_mock = SpiMock::new(&spi_expectations);
129        let radio = RF24::new(pin_mock.clone(), spi_mock.clone(), delay_mock);
130        // without calling `RF24::init()`, the lib _assumes_ the radio is powered down.
131        assert!(!radio.is_powered());
132        spi_mock.done();
133        pin_mock.done();
134    }
135}