From 53dff0f0afbfa01d7401b40c995e1aec0f0d0786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= Date: Mon, 6 Sep 2021 02:08:49 +0200 Subject: [PATCH 1/5] Initial, very unsafe implementation of polling 802.15.4 RX --- nrf-hal-common/src/ieee802154.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/nrf-hal-common/src/ieee802154.rs b/nrf-hal-common/src/ieee802154.rs index 0066d773..f7ea203d 100644 --- a/nrf-hal-common/src/ieee802154.rs +++ b/nrf-hal-common/src/ieee802154.rs @@ -326,6 +326,29 @@ impl<'c> Radio<'c> { } } + pub fn recv_async_start(&mut self, packet: &mut Packet) -> () { + unsafe { + self.start_recv(packet); + } + } + + pub fn recv_async_poll(&mut self) -> bool { + self.radio.events_end.read().events_end().bit_is_set() + //self.radio.events_end.reset(); + } + + pub fn recv_async_sync(&mut self) -> Result { + self.wait_for_event(Event::End); + dma_end_fence(); + + let crc = self.radio.rxcrc.read().rxcrc().bits() as u16; + if self.radio.crcstatus.read().crcstatus().bit_is_set() { + Ok(crc) + } else { + Err(crc) + } + } + /// Listens for a packet for no longer than the specified amount of microseconds /// and copies its contents into the given `packet` buffer /// From aa56ff6fbba47e74344f45fbec94b95e09731f97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= Date: Sat, 11 Sep 2021 23:41:42 +0200 Subject: [PATCH 2/5] Implement nb::WouldBlock --- nrf-hal-common/Cargo.toml | 2 + nrf-hal-common/src/ieee802154.rs | 93 +++++++++++++++++++++++++------- 2 files changed, 75 insertions(+), 20 deletions(-) diff --git a/nrf-hal-common/Cargo.toml b/nrf-hal-common/Cargo.toml index 7f9a07fe..3bbe3582 100644 --- a/nrf-hal-common/Cargo.toml +++ b/nrf-hal-common/Cargo.toml @@ -28,6 +28,8 @@ cfg-if = "1.0.0" embedded-dma = "0.1.1" embedded-storage = "0.1.0" +#log = "0.4.14" + [dependencies.void] default-features = false version = "1.0.2" diff --git a/nrf-hal-common/src/ieee802154.rs b/nrf-hal-common/src/ieee802154.rs index f7ea203d..318981c3 100644 --- a/nrf-hal-common/src/ieee802154.rs +++ b/nrf-hal-common/src/ieee802154.rs @@ -25,6 +25,8 @@ pub struct Radio<'c> { needs_enable: bool, // used to freeze `Clocks` _clocks: PhantomData<&'c ()>, + rxbuffer: Packet, + receiving: bool, } /// Default Clear Channel Assessment method = Carrier sense @@ -155,6 +157,8 @@ impl<'c> Radio<'c> { needs_enable: false, radio, _clocks: PhantomData, + rxbuffer: Packet::new(), + receiving: false, }; // shortcuts will be kept off by default and only be temporarily enabled within blocking @@ -326,26 +330,45 @@ impl<'c> Radio<'c> { } } - pub fn recv_async_start(&mut self, packet: &mut Packet) -> () { - unsafe { - self.start_recv(packet); + pub fn recv_async(&mut self) -> nb::Result { + if !self.receiving { + unsafe { + // TODO: Ensure the following assumption still holds true! + // NOTE we do NOT check the address of `packet` because the mutable reference ensures it's + // allocated in RAM + let ptr = self.rxbuffer.buffer.as_mut_ptr() as u32; + self.start_recv_ptr(ptr); + self.receiving = true; + } } - } + if self.radio.events_end.read().events_end().bit_is_set() { + self.wait_for_event(Event::End); + dma_end_fence(); + self.receiving = false; - pub fn recv_async_poll(&mut self) -> bool { - self.radio.events_end.read().events_end().bit_is_set() - //self.radio.events_end.reset(); - } - - pub fn recv_async_sync(&mut self) -> Result { - self.wait_for_event(Event::End); - dma_end_fence(); - - let crc = self.radio.rxcrc.read().rxcrc().bits() as u16; - if self.radio.crcstatus.read().crcstatus().bit_is_set() { - Ok(crc) + let crc = self.radio.rxcrc.read().rxcrc().bits() as u16; + let crcstatus = self.radio.crcstatus.read().crcstatus().bit_is_set(); + + let packet = self.rxbuffer.clone(); + /* + unsafe { + // Data is captured into a new Packet object, re-start rx for the next one + // start transfer + dma_start_fence(); + self.radio.tasks_start.write(|w| w.tasks_start().set_bit()); + self.receiving = true; + }*/ + + //log::trace!("Received crc: {}, crcstatus: {}", crc, crcstatus); + //log::trace!("Data: {}", str::from_utf8(&*packet).expect("msg is not valid UTF-8 data")); + + if crcstatus { + Ok(packet) + } else { + Err(nb::Error::Other(Error::AsyncCrc(packet, crc))) + } } else { - Err(crc) + Err(nb::Error::WouldBlock) } } @@ -410,7 +433,8 @@ impl<'c> Radio<'c> { } } - unsafe fn start_recv(&mut self, packet: &mut Packet) { + unsafe fn start_recv_ptr(&mut self, ptr: u32) { + //log::trace!("start_recv_ptr({})", ptr); // NOTE we do NOT check the address of `packet` because the mutable reference ensures it's // allocated in RAM @@ -424,13 +448,17 @@ impl<'c> Radio<'c> { // set up RX buffer self.radio .packetptr - .write(|w| w.packetptr().bits(packet.buffer.as_mut_ptr() as u32)); + .write(|w| w.packetptr().bits(ptr)); // start transfer dma_start_fence(); self.radio.tasks_start.write(|w| w.tasks_start().set_bit()); } + unsafe fn start_recv(&mut self, packet: &mut Packet) { + self.start_recv_ptr(packet.buffer.as_mut_ptr() as u32) + } + fn cancel_recv(&mut self) { self.radio.tasks_stop.write(|w| w.tasks_stop().set_bit()); self.wait_for_state_a(STATE_A::RXIDLE); @@ -638,6 +666,11 @@ impl<'c> Radio<'c> { /// Moves the radio to the RXIDLE state fn put_in_rx_mode(&mut self) { + if self.receiving { + self.cancel_recv(); + self.receiving = false; + } + let state = self.state(); let (disable, enable) = match state { @@ -645,6 +678,8 @@ impl<'c> Radio<'c> { State::RxIdle => (false, self.needs_enable), // NOTE to avoid errata 204 (see rev1 v1.4) we do TXIDLE -> DISABLED -> RXIDLE State::TxIdle => (true, true), + // cancel_recv above puts us in RxIdle + State::Rx => unreachable!(), }; if disable { @@ -663,6 +698,10 @@ impl<'c> Radio<'c> { /// Moves the radio to the TXIDLE state fn put_in_tx_mode(&mut self) { + if self.receiving { + self.cancel_recv(); + self.receiving = false; + } let state = self.state(); if state != State::TxIdle || self.needs_enable { @@ -678,6 +717,7 @@ impl<'c> Radio<'c> { STATE_A::DISABLED => State::Disabled, STATE_A::TXIDLE => State::TxIdle, STATE_A::RXIDLE => State::RxIdle, + STATE_A::RX => State::Rx, _ => unreachable!(), } } else { @@ -711,12 +751,14 @@ impl<'c> Radio<'c> { } /// Error -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub enum Error { /// Incorrect CRC Crc(u16), /// Timeout Timeout, + /// Incorrect CRC + AsyncCrc(Packet, u16), } /// Driver state @@ -728,6 +770,7 @@ enum State { Disabled, RxIdle, TxIdle, + Rx, } /// NOTE must be followed by a volatile write operation @@ -756,6 +799,7 @@ enum Event { /// `copy_from_slice` methods. These methods will automatically update the PHR. /// /// See figure 119 in the Product Specification of the nRF52840 for more details +#[derive(Debug, PartialEq)] pub struct Packet { buffer: [u8; Self::SIZE], } @@ -822,6 +866,15 @@ impl Packet { } } +impl Clone for Packet { + fn clone(&self) -> Self { + let mut res = Self::new(); + res.buffer.clone_from_slice(&self.buffer); + //log::trace!("Packet.clone {} {}", self.len(), res.len()); + res + } +} + impl ops::Deref for Packet { type Target = [u8]; From 148ab0f78f235bf65108d604bb792e87d26d50ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= Date: Mon, 13 Sep 2021 01:10:51 +0200 Subject: [PATCH 3/5] ieee802154: Implement Debug for Radio --- nrf-hal-common/src/ieee802154.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/nrf-hal-common/src/ieee802154.rs b/nrf-hal-common/src/ieee802154.rs index 318981c3..4c1fe4d9 100644 --- a/nrf-hal-common/src/ieee802154.rs +++ b/nrf-hal-common/src/ieee802154.rs @@ -1,6 +1,7 @@ //! IEEE 802.15.4 radio use core::{ + fmt, marker::PhantomData, ops::{self, RangeFrom}, sync::atomic::{self, Ordering}, @@ -29,6 +30,13 @@ pub struct Radio<'c> { receiving: bool, } +impl fmt::Debug for Radio<'_> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let channel = self.radio.frequency.read().frequency().bits() / 5 + 10; + write!(f, "Radio(ch={})", channel) + } +} + /// Default Clear Channel Assessment method = Carrier sense pub const DEFAULT_CCA: Cca = Cca::CarrierSense; From 5a772a4169a8fb3775ab5c359c40d91da8b0c564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= Date: Mon, 13 Sep 2021 15:47:25 +0200 Subject: [PATCH 4/5] Add function to get data with crc included --- nrf-hal-common/src/ieee802154.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nrf-hal-common/src/ieee802154.rs b/nrf-hal-common/src/ieee802154.rs index 4c1fe4d9..1bf7550c 100644 --- a/nrf-hal-common/src/ieee802154.rs +++ b/nrf-hal-common/src/ieee802154.rs @@ -860,6 +860,11 @@ impl Packet { self.buffer[Self::PHY_HDR] = len + Self::CRC; } + pub fn get_data_crc_included(&self) -> &[u8] { + let full_len = self.buffer[Self::PHY_HDR] as usize; + &self.buffer[Self::DATA][..full_len] + } + /// Returns the LQI (Link Quality Indicator) of the received packet /// /// Note that the LQI is stored in the `Packet`'s internal buffer by the hardware so the value From 0fd4b08e9b521884ee56f7a8b55ec2f01f39e25c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= Date: Mon, 13 Sep 2021 16:18:41 +0200 Subject: [PATCH 5/5] get_data_crc_included_mut --- nrf-hal-common/src/ieee802154.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nrf-hal-common/src/ieee802154.rs b/nrf-hal-common/src/ieee802154.rs index 1bf7550c..47a0c3ec 100644 --- a/nrf-hal-common/src/ieee802154.rs +++ b/nrf-hal-common/src/ieee802154.rs @@ -865,6 +865,11 @@ impl Packet { &self.buffer[Self::DATA][..full_len] } + pub fn get_data_crc_included_mut(&mut self) -> &mut [u8] { + let full_len = self.buffer[Self::PHY_HDR] as usize; + &mut self.buffer[Self::DATA][..full_len] + } + /// Returns the LQI (Link Quality Indicator) of the received packet /// /// Note that the LQI is stored in the `Packet`'s internal buffer by the hardware so the value