1use crate::{
2 data_manipulation::{crc24_ble, reverse_bits, whiten},
3 services::BlePayload,
4};
5use embedded_hal::{
6 delay::DelayNs,
7 digital::{ErrorKind as OutputPinError, OutputPin},
8 spi::{ErrorKind as SpiError, SpiDevice},
9};
10use rf24::{
11 radio::{
12 prelude::{EsbChannel, EsbPaLevel, EsbRadio},
13 Nrf24Error, RadioConfig, RF24,
14 },
15 CrcLength, PaLevel,
16};
17
18pub const BLE_CHANNEL: [u8; 3] = [2, 26, 80];
20
21pub struct BleChannels;
23
24impl BleChannels {
25 pub fn index_of(channel: u8) -> Option<usize> {
29 for (index, ch) in BLE_CHANNEL.iter().enumerate() {
30 if *ch == channel {
31 return Some(index);
32 }
33 }
34 None
35 }
36
37 pub fn increment(current: u8) -> Option<u8> {
41 if let Some(index) = Self::index_of(current) {
42 if index < (BLE_CHANNEL.len() - 1) {
43 return Some(BLE_CHANNEL[index + 1]);
44 } else {
45 return Some(BLE_CHANNEL[0]);
46 }
47 }
48 None
49 }
50}
51
52const BLE_ADDRESS: [u8; 4] = [0x71, 0x91, 0x7d, 0x6b];
54
55pub fn ble_config() -> RadioConfig {
60 RadioConfig::default()
61 .with_channel(BLE_CHANNEL[0])
62 .with_crc_length(CrcLength::Disabled)
63 .with_auto_ack(0)
64 .with_auto_retries(0, 0)
65 .with_address_length(4)
66 .with_rx_address(1, &BLE_ADDRESS)
67 .with_tx_address(&BLE_ADDRESS)
68}
69
70pub struct FakeBle {
88 pub(crate) name: [u8; 12],
89 pub show_pa_level: bool,
94 pub mac_address: [u8; 6],
99}
100
101impl Default for FakeBle {
102 fn default() -> Self {
103 Self::new()
104 }
105}
106
107impl FakeBle {
108 const DEVICE_FLAGS: u8 = 0x42;
109 const PROFILE_FLAGS: [u8; 3] = [2, 1, 5];
110
111 pub fn new() -> Self {
116 let mut mac_address = [0u8; 6];
117
118 mac_address.copy_from_slice(b"nRF24L");
120
121 Self {
122 name: [0u8; 12],
123 show_pa_level: false,
124 mac_address,
125 }
126 }
127
128 pub fn set_name(&mut self, name: &str) {
137 let len = name.len().min(10);
138 self.name[2..len + 2].copy_from_slice(&name.as_bytes()[0..len]);
139 self.name[0] = len as u8 + 1;
140 self.name[1] = 0x08;
141 }
142
143 pub fn get_name(&self, name: &mut [u8]) -> u8 {
152 let len = self.name[0];
153 if len > 1 {
154 let len = (len as usize - 1).min(name.len());
155 name[0..len].copy_from_slice(&self.name[2..len + 2]);
156 return len as u8;
157 }
158 0
159 }
160
161 pub fn len_available(&self, hypothetical: &[u8]) -> i8 {
172 let mut result = 18 - hypothetical.len() as i8;
173 let name_len = self.name[0];
174 if name_len > 1 {
175 result -= name_len as i8 + 1;
176 }
177 if self.show_pa_level {
178 result -= 3;
179 }
180 result
181 }
182
183 pub fn hop_channel<SPI, DO, DELAY>(
188 &self,
189 radio: &mut RF24<SPI, DO, DELAY>,
190 ) -> Result<(), Nrf24Error<SpiError, OutputPinError>>
191 where
192 SPI: SpiDevice,
193 DO: OutputPin,
194 DELAY: DelayNs,
195 {
196 let channel = radio.get_channel()?;
197 if let Some(channel) = BleChannels::increment(channel) {
198 radio.set_channel(channel)?;
199 }
200 Ok(())
202 }
203
204 pub fn make_payload(
211 &self,
212 buf: &[u8],
213 pa_level: Option<PaLevel>,
214 channel: u8,
215 ) -> Option<[u8; 32]> {
216 let mut payload_length = buf.len() + 9;
217
218 let mut tx_queue = [0; 32];
219 tx_queue[0] = Self::DEVICE_FLAGS;
221 tx_queue[2..8].copy_from_slice(&self.mac_address);
226 tx_queue[8..11].copy_from_slice(&Self::PROFILE_FLAGS);
228 let mut offset = 11;
229
230 if let Some(pa_level) = pa_level {
231 let pa_level: i8 = match pa_level {
232 rf24::PaLevel::Min => -18,
233 rf24::PaLevel::Low => -12,
234 rf24::PaLevel::High => -6,
235 rf24::PaLevel::Max => 0,
236 };
237 payload_length += 3;
238 offset += 3;
239 tx_queue[11..offset].copy_from_slice(&[2, 0x0A, pa_level as u8]);
240 }
241
242 if self.name[0] > 1 {
243 let len = self.name[0] as usize + 1;
244 payload_length += len;
245 tx_queue[offset..offset + len].copy_from_slice(&self.name[0..len]);
246 offset += len;
247 }
248
249 if payload_length > BlePayload::MAX_BLE_PAYLOAD_SIZE as usize {
250 return None;
251 }
252
253 tx_queue[1] = payload_length as u8;
254 for byte in buf {
255 tx_queue[offset] = *byte;
256 offset += 1;
257 }
258 let crc = crc24_ble(&tx_queue[0..offset]);
259 tx_queue[offset..offset + 3].copy_from_slice(&crc);
260 offset += 3;
261
262 let coefficient = (BleChannels::index_of(channel).unwrap_or_default() + 37) | 0x40;
263 whiten(&mut tx_queue[0..offset], coefficient as u8);
264
265 reverse_bits(&mut tx_queue[0..offset]);
266 Some(tx_queue)
267 }
268
269 pub fn send<SPI, DO, DELAY>(
288 &self,
289 radio: &mut RF24<SPI, DO, DELAY>,
290 buf: &[u8],
291 ) -> Result<bool, Nrf24Error<SpiError, OutputPinError>>
292 where
293 SPI: SpiDevice,
294 DO: OutputPin,
295 DELAY: DelayNs,
296 {
297 if let Some(tx_queue) = self.make_payload(
298 buf,
299 if self.show_pa_level {
300 Some(radio.get_pa_level()?)
301 } else {
302 None
303 },
304 radio.get_channel()?,
305 ) {
306 return radio.send(&tx_queue, false);
309 }
310 Ok(false)
311 }
312
313 pub fn read<SPI, DO, DELAY>(
330 &self,
331 radio: &mut RF24<SPI, DO, DELAY>,
332 ) -> Result<Option<BlePayload>, Nrf24Error<SpiError, OutputPinError>>
333 where
334 SPI: SpiDevice,
335 DO: OutputPin,
336 DELAY: DelayNs,
337 {
338 let mut buf = [0u8; 32];
339 radio.read(&mut buf, Some(32))?;
340 let channel = radio.get_channel()?;
341 Ok(BlePayload::from_bytes(&mut buf, channel))
342 }
343}
344
345#[cfg(test)]
348mod test {
349 extern crate std;
350 use super::{ble_config, FakeBle, BLE_ADDRESS, BLE_CHANNEL};
351 use crate::{spi_test_expects, test::mk_radio};
352 use embedded_hal_mock::eh1::{
353 digital::{State, Transaction as PinTransaction},
354 spi::Transaction as SpiTransaction,
355 };
356 use rf24::{CrcLength, PaLevel};
357 use std::vec;
358
359 #[test]
360 fn name() {
361 let mut ble = FakeBle::default();
362 let mut expected = [0u8; 10];
363 assert_eq!(0, ble.get_name(&mut expected));
364 ble.set_name("nRF24L");
365 assert_eq!(6, ble.get_name(&mut expected));
366 assert!(expected.starts_with(b"nRF24L"));
367 assert_eq!(ble.len_available(b""), 10);
368 }
369
370 #[test]
371 fn mac() {
372 let mut mac = [0u8; 6];
373 mac.copy_from_slice(b"nRF24L");
374 let mut ble = FakeBle::default();
375 ble.mac_address.copy_from_slice(&mac);
376 assert_eq!(ble.len_available(b""), 18);
377 }
378
379 #[test]
380 fn pa_level() {
381 let mut ble = FakeBle::default();
382 assert_eq!(ble.len_available(b""), 18);
383 ble.show_pa_level = true;
384 assert_eq!(ble.len_available(b""), 15);
385 }
386
387 #[test]
388 fn config() {
389 let config = ble_config();
390 assert_eq!(config.channel(), BLE_CHANNEL[0]);
391 assert_eq!(config.crc_length(), CrcLength::Disabled);
392 assert_eq!(config.auto_ack(), 0);
393 assert_eq!(config.auto_retry_count(), 0);
394 assert_eq!(config.auto_retry_delay(), 0);
395 assert_eq!(config.address_length(), 4);
396 let mut address = [0u8; 4];
397 config.tx_address(&mut address);
398 assert_eq!(address, BLE_ADDRESS);
399 config.rx_address(1, &mut address);
400 assert_eq!(address, BLE_ADDRESS);
401 for pipe in 0..5 {
402 let enabled = config.is_rx_pipe_enabled(pipe);
403 assert_eq!(enabled, pipe == 1);
404 }
405 }
406
407 const RF_CH: u8 = 5;
409 const W_REGISTER: u8 = 0x20;
411
412 #[test]
413 fn channel_hop() {
414 let expectations = spi_test_expects![
415 (vec![RF_CH, 0], vec![0xEu8, BLE_CHANNEL[0]]),
416 (vec![RF_CH | W_REGISTER, BLE_CHANNEL[1]], vec![0xEu8, 0]),
417 (vec![RF_CH, 0], vec![0xEu8, BLE_CHANNEL[1]]),
418 (vec![RF_CH | W_REGISTER, BLE_CHANNEL[2]], vec![0xEu8, 0]),
419 (vec![RF_CH, 0], vec![0xEu8, BLE_CHANNEL[2]]),
420 (vec![RF_CH | W_REGISTER, BLE_CHANNEL[0]], vec![0xEu8, 0]),
421 (vec![RF_CH, 0], vec![0xEu8, 0]),
422 ];
423 let mocks = mk_radio(&[], &expectations);
424 let (mut radio, mut spi, mut ce_pin) = (mocks.0, mocks.1, mocks.2);
425 let ble = FakeBle::default();
426 for _ in 0..4 {
427 ble.hop_channel(&mut radio).unwrap();
428 }
429 spi.done();
430 ce_pin.done();
431 }
432
433 const R_RX_PAYLOAD: u8 = 0x61;
434 const STATUS: u8 = 7;
435 const MASK_RX_DR: u8 = 1 << 6;
436
437 #[test]
438 fn read() {
439 let ble = FakeBle::default();
440 let channel = BLE_CHANNEL[0];
441 let payload = ble.make_payload(&[], None, channel).unwrap();
442 let mut buf = [0; 33];
443 buf[1..].copy_from_slice(&payload);
444 buf[0] = 0xE;
445 let mut expected = [0; 33];
446 expected[0] = R_RX_PAYLOAD;
447
448 let spi_expectations = spi_test_expects![
449 (expected.to_vec(), buf.to_vec()),
450 (vec![STATUS | W_REGISTER, MASK_RX_DR], vec![0xEu8, 0]),
451 (vec![RF_CH, 0], vec![0xEu8, BLE_CHANNEL[0]]),
452 ];
453 let mocks = mk_radio(&[], &spi_expectations);
454 let (mut radio, mut spi, mut ce_pin) = (mocks.0, mocks.1, mocks.2);
455
456 let ble_payload = ble.read(&mut radio).unwrap().unwrap();
457 assert_eq!(&ble.mac_address, &ble_payload.mac_address);
458 spi.done();
459 ce_pin.done();
460 }
461
462 const MASK_TX_DS: u8 = 1 << 5;
463 const MASK_MAX_RT: u8 = 1 << 4;
464 const W_TX_PAYLOAD: u8 = 0xA0;
465 const FLUSH_TX: u8 = 0xE1;
466 const NOP: u8 = 0xFF;
467 const RF_SETUP: u8 = 0x06;
468
469 fn send_ce_expects() -> vec::Vec<PinTransaction> {
470 vec![
471 PinTransaction::set(State::Low),
472 PinTransaction::set(State::High),
473 ]
474 }
475
476 fn send_spi_expects(
477 ble: &FakeBle,
478 pa_level: Option<PaLevel>,
479 big_buf: bool,
480 ) -> vec::Vec<SpiTransaction<u8>> {
481 let channel = BLE_CHANNEL[0];
482 let payload = ble.make_payload(&[], pa_level, channel).unwrap();
483 let mut buf = [0; 33];
484 buf[0] = 0xE;
485 let mut expected = [0; 33];
486 expected[0] = W_TX_PAYLOAD;
487 expected[1..].copy_from_slice(&payload);
488
489 let mut expectations = vec![];
490 let bin_pa_level = pa_level.map(|lvl| match lvl {
491 PaLevel::High => 4,
495 _ => 6,
496 });
497 if let Some(lvl) = bin_pa_level {
498 expectations
499 .append(&mut spi_test_expects![(vec![RF_SETUP, 0], vec![0xEu8, lvl]),].to_vec());
500 }
501 expectations.append(
502 &mut spi_test_expects![(
503 vec![RF_CH, bin_pa_level.unwrap_or_default()],
504 vec![0xEu8, BLE_CHANNEL[0]]
505 ),]
506 .to_vec(),
507 );
508 if !big_buf {
509 expectations.append(
510 &mut spi_test_expects![
511 (vec![FLUSH_TX], vec![0xEu8]),
512 (
513 vec![STATUS | W_REGISTER, MASK_TX_DS | MASK_MAX_RT],
514 vec![0xEu8, 0]
515 ),
516 (expected.to_vec(), buf.to_vec()),
517 (vec![NOP], vec![0xE | MASK_TX_DS]),
518 ]
519 .to_vec(),
520 );
521 }
522 expectations
523 }
524
525 #[test]
526 fn send() {
527 let ble = FakeBle::default();
528
529 let spi_expectations = send_spi_expects(&ble, None, false);
530 let ce_expectations = send_ce_expects();
531 let mocks = mk_radio(&ce_expectations, &spi_expectations);
532 let (mut radio, mut spi, mut ce_pin) = (mocks.0, mocks.1, mocks.2);
533
534 assert!(ble.send(&mut radio, &[]).unwrap());
535 spi.done();
536 ce_pin.done();
537 }
538
539 #[test]
540 fn send_pa_level() {
541 let mut ble = FakeBle::new();
542 ble.show_pa_level = true;
543
544 let spi_expectations = send_spi_expects(&ble, Some(PaLevel::Max), false);
545 let ce_expectations = send_ce_expects();
546 let mocks = mk_radio(&ce_expectations, &spi_expectations);
547 let (mut radio, mut spi, mut ce_pin) = (mocks.0, mocks.1, mocks.2);
548
549 assert!(ble.send(&mut radio, &[]).unwrap());
550 spi.done();
551 ce_pin.done();
552 }
553
554 #[test]
555 fn send_big_buf() {
556 let mut ble = FakeBle::new();
557 ble.show_pa_level = true;
558
559 let spi_expectations = send_spi_expects(&ble, Some(PaLevel::High), true);
560 let ce_expectations = [];
561 let mocks = mk_radio(&ce_expectations, &spi_expectations);
562 let (mut radio, mut spi, mut ce_pin) = (mocks.0, mocks.1, mocks.2);
563
564 assert!(!ble.send(&mut radio, &[0u8; 20]).unwrap());
565 spi.done();
566 ce_pin.done();
567 }
568}