Skip to content

Commit 8798adc

Browse files
committed
Added non-blocking radio receive
1 parent 04cd0c8 commit 8798adc

File tree

1 file changed

+76
-44
lines changed

1 file changed

+76
-44
lines changed

nrf-hal-common/src/ieee802154.rs

+76-44
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use core::{
66
sync::atomic::{self, Ordering},
77
};
88

9+
use nb::block;
10+
911
use crate::{
1012
clocks::{Clocks, ExternalOscillator},
1113
pac::{
@@ -15,6 +17,47 @@ use crate::{
1517
timer::{self, Timer},
1618
};
1719

20+
/// Non-blocking receive
21+
pub struct Recv<'a, 'c> {
22+
radio: &'a mut Radio<'c>,
23+
}
24+
25+
impl<'a, 'c> Recv<'a, 'c> {
26+
fn new(radio: &'a mut Radio<'c>) -> Self {
27+
Self { radio }
28+
}
29+
30+
/// Check if receive is done
31+
///
32+
/// This methods returns the `Ok` variant if the CRC included the
33+
/// packet was successfully validated by the hardware. It returns
34+
/// `Err(nb::Error::WouldBlock)` if a packet hasn't been received
35+
/// yet, and `Err(nb::Error::Other)` if the CRC check failed.
36+
pub fn is_done(&mut self) -> nb::Result<u16, u16> {
37+
if self.radio.radio.events_end.read().events_end().bit_is_set() {
38+
self.radio.radio.events_end.reset();
39+
40+
dma_end_fence();
41+
42+
let crc = self.radio.radio.rxcrc.read().rxcrc().bits() as u16;
43+
44+
if self.radio.radio.crcstatus.read().crcstatus().bit_is_set() {
45+
Ok(crc)
46+
} else {
47+
Err(nb::Error::Other(crc))
48+
}
49+
} else {
50+
Err(nb::Error::WouldBlock)
51+
}
52+
}
53+
}
54+
55+
impl<'a, 'c> Drop for Recv<'a, 'c> {
56+
fn drop(&mut self) {
57+
self.radio.cancel_recv();
58+
}
59+
}
60+
1861
/// IEEE 802.15.4 radio
1962
pub struct Radio<'c> {
2063
radio: RADIO,
@@ -305,22 +348,24 @@ impl<'c> Radio<'c> {
305348
/// validated by the hardware; otherwise it returns the `Err` variant. In either case, `packet`
306349
/// will be updated with the received packet's data
307350
pub fn recv(&mut self, packet: &mut Packet) -> Result<u16, u16> {
351+
// Start non-blocking receive
352+
let mut recv = self.recv_non_blocking(packet);
353+
354+
// Block untill receive is done
355+
block!(recv.is_done())
356+
}
357+
358+
/// Receives one radio packet and copies its contents into the given `packet` buffer
359+
///
360+
/// This method is non-blocking
361+
pub fn recv_non_blocking(&mut self, packet: &mut Packet) -> Recv<'_, 'c> {
308362
// Start the read
309363
// NOTE(unsafe) We block until reception completes or errors
310364
unsafe {
311365
self.start_recv(packet);
312366
}
313367

314-
// wait until we have received something
315-
self.wait_for_event(Event::End);
316-
dma_end_fence();
317-
318-
let crc = self.radio.rxcrc.read().rxcrc().bits() as u16;
319-
if self.radio.crcstatus.read().crcstatus().bit_is_set() {
320-
Ok(crc)
321-
} else {
322-
Err(crc)
323-
}
368+
Recv::new(self)
324369
}
325370

326371
/// Listens for a packet for no longer than the specified amount of microseconds
@@ -347,40 +392,32 @@ impl<'c> Radio<'c> {
347392
// Start the timeout timer
348393
timer.start(microseconds);
349394

350-
// Start the read
351-
// NOTE(unsafe) We block until reception completes or errors
352-
unsafe {
353-
self.start_recv(packet);
354-
}
355-
356-
// Wait for transmission to end
357-
let mut recv_completed = false;
395+
let result = {
396+
// Start non-blocking receive
397+
let mut recv = self.recv_non_blocking(packet);
358398

359-
loop {
360-
if self.radio.events_end.read().bits() != 0 {
361-
// transfer complete
362-
dma_end_fence();
363-
recv_completed = true;
364-
break;
365-
}
399+
// Check if either receive is done, or timeout occurs
400+
loop {
401+
match recv.is_done() {
402+
Ok(crc) => break Some(Ok(crc)),
403+
Err(err) => match err {
404+
nb::Error::Other(crc) => break Some(Err(Error::Crc(crc))),
405+
nb::Error::WouldBlock => (),
406+
},
407+
}
366408

367-
if timer.reset_if_finished() {
368-
// timeout
369-
break;
409+
if timer.reset_if_finished() {
410+
// Break loop in case of timeout. Receive is
411+
// cancelled when `recv` is dropped.
412+
break None;
413+
}
370414
}
371-
}
415+
};
372416

373-
if !recv_completed {
374-
// Cancel the reception if it did not complete until now
375-
self.cancel_recv();
376-
Err(Error::Timeout)
417+
if let Some(result) = result {
418+
result
377419
} else {
378-
let crc = self.radio.rxcrc.read().rxcrc().bits() as u16;
379-
if self.radio.crcstatus.read().crcstatus().bit_is_set() {
380-
Ok(crc)
381-
} else {
382-
Err(Error::Crc(crc))
383-
}
420+
Err(Error::Timeout)
384421
}
385422
}
386423

@@ -674,10 +711,6 @@ impl<'c> Radio<'c> {
674711

675712
fn wait_for_event(&self, event: Event) {
676713
match event {
677-
Event::End => {
678-
while self.radio.events_end.read().events_end().bit_is_clear() {}
679-
self.radio.events_end.reset();
680-
}
681714
Event::PhyEnd => {
682715
while self
683716
.radio
@@ -728,7 +761,6 @@ fn dma_end_fence() {
728761
}
729762

730763
enum Event {
731-
End,
732764
PhyEnd,
733765
}
734766

0 commit comments

Comments
 (0)