rf24/radio/rf24/
payload_length.rs

1use crate::radio::{prelude::EsbPayloadLength, Nrf24Error, RF24};
2use embedded_hal::{delay::DelayNs, digital::OutputPin, spi::SpiDevice};
3
4use super::{commands, registers, Feature};
5
6impl<SPI, DO, DELAY> EsbPayloadLength for RF24<SPI, DO, DELAY>
7where
8    SPI: SpiDevice,
9    DO: OutputPin,
10    DELAY: DelayNs,
11{
12    type PayloadLengthErrorType = Nrf24Error<SPI::Error, DO::Error>;
13
14    fn set_payload_length(&mut self, length: u8) -> Result<(), Self::PayloadLengthErrorType> {
15        let len = length.clamp(1, 32);
16        for i in 0..6 {
17            self.spi_write_byte(registers::RX_PW_P0 + i, len)?;
18        }
19        self._payload_length = len;
20        Ok(())
21    }
22
23    fn get_payload_length(&mut self) -> Result<u8, Self::PayloadLengthErrorType> {
24        self.spi_read(1, registers::RX_PW_P0)?;
25        Ok(self._buf[1])
26    }
27
28    fn set_dynamic_payloads(&mut self, enable: bool) -> Result<(), Self::PayloadLengthErrorType> {
29        self.spi_read(1, registers::FEATURE)?;
30        self._feature =
31            Feature::from_bits(self._feature.into_bits() & !Feature::REG_MASK | self._buf[1])
32                .with_dynamic_payloads(enable);
33        self.spi_write_byte(
34            registers::FEATURE,
35            self._feature.into_bits() & Feature::REG_MASK,
36        )?;
37        self.spi_write_byte(registers::DYNPD, 0x3F * enable as u8)?;
38        Ok(())
39    }
40
41    fn get_dynamic_payloads(&self) -> bool {
42        self._feature.dynamic_payloads()
43    }
44
45    fn get_dynamic_payload_length(&mut self) -> Result<u8, Self::PayloadLengthErrorType> {
46        self.spi_read(1, commands::R_RX_PL_WID)?;
47        if self._buf[1] > 32 {
48            return Err(Nrf24Error::BinaryCorruption);
49        }
50        Ok(self._buf[1])
51    }
52}
53
54/////////////////////////////////////////////////////////////////////////////////
55/// unit tests
56#[cfg(test)]
57mod test {
58    extern crate std;
59    use crate::radio::prelude::{EsbAutoAck, EsbPayloadLength};
60    use crate::radio::Nrf24Error;
61    use crate::spi_test_expects;
62
63    use super::{commands, 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    const EN_ACK_PAY: u8 = 1 << 1;
70    const EN_DPL: u8 = 1 << 2;
71
72    #[test]
73    fn dynamic_payloads() {
74        let pin_expectations = [];
75        let mut pin_mock = PinMock::new(&pin_expectations);
76
77        // create delay fn
78        let delay_mock = NoopDelay::new();
79
80        let spi_expectations = spi_test_expects![
81            // set_dynamic_payloads(true)
82            (vec![registers::FEATURE, 0u8], vec![0xEu8, 0u8],),
83            (
84                vec![registers::FEATURE | commands::W_REGISTER, EN_DPL],
85                vec![0xEu8, 0u8],
86            ),
87            (
88                vec![registers::DYNPD | commands::W_REGISTER, 0x3Fu8],
89                vec![0xEu8, 0],
90            ),
91            // read dynamic payload length invalid value
92            (vec![commands::R_RX_PL_WID, 0u8], vec![0xEu8, 0xFFu8]),
93            // read dynamic payload length valid value
94            (vec![commands::R_RX_PL_WID, 0xFFu8], vec![0xEu8, 32u8]),
95            // set_dynamic_payloads(false)
96            (
97                vec![registers::FEATURE, 32u8],
98                vec![0xEu8, EN_ACK_PAY | EN_DPL],
99            ),
100            (
101                vec![registers::FEATURE | commands::W_REGISTER, 0u8],
102                vec![0xEu8, 0u8],
103            ),
104            (
105                vec![registers::DYNPD | commands::W_REGISTER, 0u8],
106                vec![0xEu8, 0],
107            ),
108        ];
109        let mut spi_mock = SpiMock::new(&spi_expectations);
110        let mut radio = RF24::new(pin_mock.clone(), spi_mock.clone(), delay_mock);
111        radio.set_dynamic_payloads(true).unwrap();
112        assert!(radio.get_dynamic_payloads());
113        assert_eq!(
114            radio.get_dynamic_payload_length(),
115            Err(Nrf24Error::BinaryCorruption)
116        );
117        assert_eq!(radio.get_dynamic_payload_length().unwrap(), 32u8);
118        radio.set_dynamic_payloads(false).unwrap();
119        assert!(!radio.get_dynamic_payloads());
120        assert!(!radio.get_ack_payloads());
121        spi_mock.done();
122        pin_mock.done();
123    }
124
125    #[test]
126    pub fn set_payload_length() {
127        // Create pin
128        let pin_expectations = [];
129        let mut pin_mock = PinMock::new(&pin_expectations);
130
131        // create delay fn
132        let delay_mock = NoopDelay::new();
133
134        let spi_expectations = spi_test_expects![
135            // set payload length to 32 bytes on all pipes
136            (
137                vec![registers::RX_PW_P0 | commands::W_REGISTER, 32u8],
138                vec![0xEu8, 0u8]
139            ),
140            (
141                vec![(registers::RX_PW_P0 + 1) | commands::W_REGISTER, 32u8],
142                vec![0xEu8, 0u8]
143            ),
144            (
145                vec![(registers::RX_PW_P0 + 2) | commands::W_REGISTER, 32u8],
146                vec![0xEu8, 0u8]
147            ),
148            (
149                vec![(registers::RX_PW_P0 + 3) | commands::W_REGISTER, 32u8],
150                vec![0xEu8, 0u8]
151            ),
152            (
153                vec![(registers::RX_PW_P0 + 4) | commands::W_REGISTER, 32u8],
154                vec![0xEu8, 0u8]
155            ),
156            (
157                vec![(registers::RX_PW_P0 + 5) | commands::W_REGISTER, 32u8],
158                vec![0xEu8, 0u8]
159            ),
160            // get payload length for all pipe 0 (because all pipes will use the same static length)
161            (vec![registers::RX_PW_P0, 0u8], vec![0xEu8, 32u8]),
162        ];
163        let mut spi_mock = SpiMock::new(&spi_expectations);
164        let mut radio = RF24::new(pin_mock.clone(), spi_mock.clone(), delay_mock);
165        radio.set_payload_length(76).unwrap();
166        assert_eq!(radio.get_payload_length().unwrap(), 32u8);
167        spi_mock.done();
168        pin_mock.done();
169    }
170}