Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9ac3659

Browse files
committedAug 18, 2024·
Added non-blocking radio receive
1 parent 04cd0c8 commit 9ac3659

File tree

1 file changed

+74
-44
lines changed

1 file changed

+74
-44
lines changed
 

‎nrf-hal-common/src/ieee802154.rs

+74-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,51 @@ 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+
_packet: &'a mut Packet,
24+
}
25+
26+
impl<'a, 'c> Recv<'a, 'c> {
27+
fn new(radio: &'a mut Radio<'c>, packet: &'a mut Packet) -> Self {
28+
Self {
29+
radio,
30+
_packet: packet,
31+
}
32+
}
33+
34+
/// Check if receive is done
35+
///
36+
/// This methods returns the `Ok` variant if the CRC included the
37+
/// packet was successfully validated by the hardware. It returns
38+
/// `Err(nb::Error::WouldBlock)` if a packet hasn't been received
39+
/// yet, and `Err(nb::Error::Other)` if the CRC check failed.
40+
pub fn is_done(&mut self) -> nb::Result<u16, u16> {
41+
if self.radio.radio.events_end.read().events_end().bit_is_set() {
42+
self.radio.radio.events_end.reset();
43+
44+
dma_end_fence();
45+
46+
let crc = self.radio.radio.rxcrc.read().rxcrc().bits() as u16;
47+
48+
if self.radio.radio.crcstatus.read().crcstatus().bit_is_set() {
49+
Ok(crc)
50+
} else {
51+
Err(nb::Error::Other(crc))
52+
}
53+
} else {
54+
Err(nb::Error::WouldBlock)
55+
}
56+
}
57+
}
58+
59+
impl<'a, 'c> Drop for Recv<'a, 'c> {
60+
fn drop(&mut self) {
61+
self.radio.cancel_recv();
62+
}
63+
}
64+
1865
/// IEEE 802.15.4 radio
1966
pub struct Radio<'c> {
2067
radio: RADIO,
@@ -305,22 +352,26 @@ impl<'c> Radio<'c> {
305352
/// validated by the hardware; otherwise it returns the `Err` variant. In either case, `packet`
306353
/// will be updated with the received packet's data
307354
pub fn recv(&mut self, packet: &mut Packet) -> Result<u16, u16> {
355+
// Start non-blocking receive
356+
let mut recv = self.recv_non_blocking(packet);
357+
358+
// Block untill receive is done
359+
block!(recv.is_done())
360+
}
361+
362+
/// Receives one radio packet and copies its contents into the given `packet` buffer
363+
///
364+
/// This method is non-blocking
365+
pub fn recv_non_blocking<'a>(&'a mut self, packet: &'a mut Packet) -> Recv<'a, 'c> {
308366
// Start the read
309-
// NOTE(unsafe) We block until reception completes or errors
367+
// NOTE(unsafe)
368+
// The packet must live until the transfer is done. Recv takes
369+
// a mutable reference to the packet to enforce this.
310370
unsafe {
311371
self.start_recv(packet);
312372
}
313373

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-
}
374+
Recv::new(self, packet)
324375
}
325376

326377
/// Listens for a packet for no longer than the specified amount of microseconds
@@ -347,39 +398,23 @@ impl<'c> Radio<'c> {
347398
// Start the timeout timer
348399
timer.start(microseconds);
349400

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;
401+
// Start non-blocking receive
402+
let mut recv = self.recv_non_blocking(packet);
358403

404+
// Check if either receive is done or timeout occured
359405
loop {
360-
if self.radio.events_end.read().bits() != 0 {
361-
// transfer complete
362-
dma_end_fence();
363-
recv_completed = true;
364-
break;
406+
match recv.is_done() {
407+
Ok(crc) => break Ok(crc),
408+
Err(err) => match err {
409+
nb::Error::Other(crc) => break Err(Error::Crc(crc)),
410+
nb::Error::WouldBlock => (),
411+
},
365412
}
366413

367414
if timer.reset_if_finished() {
368-
// timeout
369-
break;
370-
}
371-
}
372-
373-
if !recv_completed {
374-
// Cancel the reception if it did not complete until now
375-
self.cancel_recv();
376-
Err(Error::Timeout)
377-
} 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))
415+
// Break loop in case of timeout. Receive is
416+
// cancelled when `recv` is dropped.
417+
break Err(Error::Timeout);
383418
}
384419
}
385420
}
@@ -674,10 +709,6 @@ impl<'c> Radio<'c> {
674709

675710
fn wait_for_event(&self, event: Event) {
676711
match event {
677-
Event::End => {
678-
while self.radio.events_end.read().events_end().bit_is_clear() {}
679-
self.radio.events_end.reset();
680-
}
681712
Event::PhyEnd => {
682713
while self
683714
.radio
@@ -728,7 +759,6 @@ fn dma_end_fence() {
728759
}
729760

730761
enum Event {
731-
End,
732762
PhyEnd,
733763
}
734764

0 commit comments

Comments
 (0)
Please sign in to comment.