1use embedded_hal::{delay::DelayNs, digital::OutputPin, spi::SpiDevice};
2
3use crate::radio::{prelude::EsbAutoAck, Nrf24Error, RF24};
4
5use super::{commands, registers, Feature};
6
7impl<SPI, DO, DELAY> EsbAutoAck for RF24<SPI, DO, DELAY>
8where
9 SPI: SpiDevice,
10 DO: OutputPin,
11 DELAY: DelayNs,
12{
13 type AutoAckErrorType = Nrf24Error<SPI::Error, DO::Error>;
14
15 fn set_ack_payloads(&mut self, enable: bool) -> Result<(), Self::AutoAckErrorType> {
16 if self._feature.ack_payloads() != enable {
17 self.spi_read(1, registers::FEATURE)?;
18 self._feature =
19 Feature::from_bits(self._feature.into_bits() & !Feature::REG_MASK | self._buf[1])
20 .with_ack_payloads(enable);
21 self.spi_write_byte(
22 registers::FEATURE,
23 self._feature.into_bits() & Feature::REG_MASK,
24 )?;
25
26 if enable {
27 self.spi_write_byte(registers::DYNPD, 0x3F)?;
29 }
30 }
32 Ok(())
33 }
34
35 fn get_ack_payloads(&self) -> bool {
36 self._feature.ack_payloads()
37 }
38
39 fn set_auto_ack(&mut self, enable: bool) -> Result<(), Self::AutoAckErrorType> {
40 self.spi_write_byte(registers::EN_AA, 0x3F * enable as u8)?;
41 if !enable && self._feature.ack_payloads() {
43 self.set_ack_payloads(false)?;
44 }
45 Ok(())
46 }
47
48 fn set_auto_ack_pipe(&mut self, enable: bool, pipe: u8) -> Result<(), Self::AutoAckErrorType> {
49 if pipe > 5 {
50 return Ok(());
51 }
52 self.spi_read(1, registers::EN_AA)?;
53 let mask = 1 << pipe;
54 let reg_val = self._buf[1];
55 if !enable && self._feature.ack_payloads() && pipe == 0 {
56 self.set_ack_payloads(enable)?;
57 }
58 self.spi_write_byte(registers::EN_AA, reg_val & !mask | (mask * enable as u8))
59 }
60
61 fn allow_ask_no_ack(&mut self, enable: bool) -> Result<(), Self::AutoAckErrorType> {
62 self.spi_read(1, registers::FEATURE)?;
63 self.spi_write_byte(registers::FEATURE, self._buf[1] & !1 | enable as u8)
64 }
65
66 fn write_ack_payload(&mut self, pipe: u8, buf: &[u8]) -> Result<bool, Self::AutoAckErrorType> {
67 if self._feature.ack_payloads() && pipe <= 5 {
68 let len = buf.len().min(32);
69 self.spi_write_buf(commands::W_ACK_PAYLOAD | pipe, &buf[..len])?;
70 return Ok(!self._status.tx_full());
71 }
72 Ok(false)
73 }
74
75 fn set_auto_retries(&mut self, delay: u8, count: u8) -> Result<(), Self::AutoAckErrorType> {
76 self.spi_write_byte(registers::SETUP_RETR, count.min(15) | (delay.min(15) << 4))
77 }
78}
79
80#[cfg(test)]
83mod test {
84 extern crate std;
85 use crate::radio::prelude::{EsbAutoAck, EsbPayloadLength};
86 use crate::spi_test_expects;
87
88 use super::{commands, registers, RF24};
89 use embedded_hal_mock::eh1::delay::NoopDelay;
90 use embedded_hal_mock::eh1::digital::Mock as PinMock;
91 use embedded_hal_mock::eh1::spi::{Mock as SpiMock, Transaction as SpiTransaction};
92 use std::vec;
93
94 const EN_ACK_PAY: u8 = 1 << 1;
95 const EN_DPL: u8 = 1 << 2;
96
97 #[test]
98 pub fn allow_ack_payloads() {
99 let pin_expectations = [];
101 let mut pin_mock = PinMock::new(&pin_expectations);
102
103 let delay_mock = NoopDelay::new();
105 let mut ack_buf = [0x55; 3];
106 let valid_pipe = 2;
107 ack_buf[0] = commands::W_ACK_PAYLOAD | valid_pipe;
108
109 let spi_expectations = spi_test_expects![
110 (vec![registers::FEATURE, 0u8], vec![0xEu8, 0u8]),
113 (
114 vec![
115 registers::FEATURE | commands::W_REGISTER,
116 EN_ACK_PAY | EN_DPL,
117 ],
118 vec![0xEu8, 0u8],
119 ),
120 (
122 vec![registers::DYNPD | commands::W_REGISTER, 0x3Fu8],
123 vec![0xEu8, 0u8],
124 ),
125 (ack_buf.to_vec(), vec![0u8; 3]),
127 (ack_buf.to_vec(), vec![1u8; 3]),
129 (vec![registers::EN_AA, 1u8], vec![0u8, 0x3Fu8]),
131 (
133 vec![registers::FEATURE, 0x3Fu8],
134 vec![0u8, EN_ACK_PAY | EN_DPL | 1]
135 ),
136 (
137 vec![registers::FEATURE | commands::W_REGISTER, EN_DPL | 1],
138 vec![0xEu8, 0u8],
139 ),
140 (
142 vec![registers::EN_AA | commands::W_REGISTER, 0x3Eu8],
143 vec![0xEu8, 0u8],
144 ),
145 (vec![registers::EN_AA, 0u8], vec![0u8, 0x3Eu8]),
147 (
149 vec![registers::EN_AA | commands::W_REGISTER, 0x3Cu8],
150 vec![0xEu8, 0u8],
151 ),
152 ];
153 let mut spi_mock = SpiMock::new(&spi_expectations);
154 let mut radio = RF24::new(pin_mock.clone(), spi_mock.clone(), delay_mock);
155 radio.set_ack_payloads(true).unwrap();
156 radio.set_ack_payloads(true).unwrap();
158 let buf = &ack_buf[1..3];
159 assert!(!radio.write_ack_payload(9, buf).unwrap());
161 assert!(radio.write_ack_payload(valid_pipe, buf).unwrap());
163 assert!(!radio.write_ack_payload(valid_pipe, buf).unwrap());
165 radio.set_auto_ack_pipe(false, 9).unwrap();
167 radio.set_auto_ack_pipe(false, 0).unwrap();
169 radio.set_auto_ack_pipe(false, 1).unwrap();
171 spi_mock.done();
172 pin_mock.done();
173 }
174
175 #[test]
176 pub fn set_auto_ack() {
177 let pin_expectations = [];
179 let mut pin_mock = PinMock::new(&pin_expectations);
180
181 let delay_mock = NoopDelay::new();
183
184 let spi_expectations = spi_test_expects![
185 (vec![registers::FEATURE, 0u8], vec![0xEu8, 0u8]),
188 (
189 vec![
190 registers::FEATURE | commands::W_REGISTER,
191 EN_ACK_PAY | EN_DPL,
192 ],
193 vec![0xEu8, 0u8],
194 ),
195 (
197 vec![registers::DYNPD | commands::W_REGISTER, 0x3Fu8],
198 vec![0xEu8, 0u8],
199 ),
200 (
202 vec![registers::EN_AA | commands::W_REGISTER, 0u8],
203 vec![0xEu8, 0u8],
204 ),
205 (
207 vec![registers::FEATURE, 0u8],
208 vec![0u8, EN_ACK_PAY | EN_DPL]
209 ),
210 (
211 vec![registers::FEATURE | commands::W_REGISTER, EN_DPL],
212 vec![0xEu8, 0u8],
213 ),
214 (vec![commands::R_RX_PL_WID, 0u8], vec![0xEu8, 32]),
216 ];
217 let mut spi_mock = SpiMock::new(&spi_expectations);
218 let mut radio = RF24::new(pin_mock.clone(), spi_mock.clone(), delay_mock);
219 radio.set_ack_payloads(true).unwrap();
220 assert!(radio.get_ack_payloads());
221 radio.set_auto_ack(false).unwrap();
222 assert_eq!(radio.get_dynamic_payload_length().unwrap(), 32u8);
223 spi_mock.done();
224 pin_mock.done();
225 }
226
227 #[test]
228 pub fn allow_ask_no_ack() {
229 let pin_expectations = [];
231 let mut pin_mock = PinMock::new(&pin_expectations);
232
233 let delay_mock = NoopDelay::new();
235
236 let spi_expectations = spi_test_expects![
237 (vec![registers::FEATURE, 0u8], vec![0u8, EN_ACK_PAY]),
239 (
240 vec![registers::FEATURE | commands::W_REGISTER, EN_ACK_PAY | 1],
241 vec![0xEu8, 0u8],
242 ),
243 ];
244 let mut spi_mock = SpiMock::new(&spi_expectations);
245 let mut radio = RF24::new(pin_mock.clone(), spi_mock.clone(), delay_mock);
246 radio.allow_ask_no_ack(true).unwrap();
247 spi_mock.done();
248 pin_mock.done();
249 }
250}