Skip to content

Polling 802.15.4 API #355

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions nrf-hal-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
100 changes: 97 additions & 3 deletions nrf-hal-common/src/ieee802154.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! IEEE 802.15.4 radio

use core::{
fmt,
marker::PhantomData,
ops::{self, RangeFrom},
sync::atomic::{self, Ordering},
Expand All @@ -25,6 +26,15 @@ pub struct Radio<'c> {
needs_enable: bool,
// used to freeze `Clocks`
_clocks: PhantomData<&'c ()>,
rxbuffer: Packet,
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
Expand Down Expand Up @@ -155,6 +165,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
Expand Down Expand Up @@ -326,6 +338,48 @@ impl<'c> Radio<'c> {
}
}

pub fn recv_async(&mut self) -> nb::Result<Packet, Error> {
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;

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(nb::Error::WouldBlock)
}
}

/// Listens for a packet for no longer than the specified amount of microseconds
/// and copies its contents into the given `packet` buffer
///
Expand Down Expand Up @@ -387,7 +441,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

Expand All @@ -401,13 +456,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);
Expand Down Expand Up @@ -615,13 +674,20 @@ 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 {
State::Disabled => (false, true),
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 {
Expand All @@ -640,6 +706,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 {
Expand All @@ -655,6 +725,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 {
Expand Down Expand Up @@ -688,12 +759,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
Expand All @@ -705,6 +778,7 @@ enum State {
Disabled,
RxIdle,
TxIdle,
Rx,
}

/// NOTE must be followed by a volatile write operation
Expand Down Expand Up @@ -733,6 +807,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],
}
Expand Down Expand Up @@ -785,6 +860,16 @@ 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]
}

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
Expand All @@ -799,6 +884,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];

Expand Down