diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs
index 93c701de0..846ac98af 100644
--- a/embassy-nrf/src/radio/ble.rs
+++ b/embassy-nrf/src/radio/ble.rs
@@ -8,8 +8,6 @@ use embassy_hal_internal::drop::OnDrop;
use embassy_hal_internal::{into_ref, PeripheralRef};
pub use pac::radio::mode::MODE_A as Mode;
use pac::radio::pcnf0::PLEN_A as PreambleLength;
-use pac::radio::state::STATE_A as RadioState;
-pub use pac::radio::txpower::TXPOWER_A as TxPower;
use crate::interrupt::typelevel::Interrupt;
pub use crate::radio::Error;
@@ -111,17 +109,7 @@ impl<'d, T: Instance> Radio<'d, T> {
#[allow(dead_code)]
fn trace_state(&self) {
- match self.state() {
- RadioState::DISABLED => trace!("radio:state:DISABLED"),
- RadioState::RX_RU => trace!("radio:state:RX_RU"),
- RadioState::RX_IDLE => trace!("radio:state:RX_IDLE"),
- RadioState::RX => trace!("radio:state:RX"),
- RadioState::RX_DISABLE => trace!("radio:state:RX_DISABLE"),
- RadioState::TX_RU => trace!("radio:state:TX_RU"),
- RadioState::TX_IDLE => trace!("radio:state:TX_IDLE"),
- RadioState::TX => trace!("radio:state:TX"),
- RadioState::TX_DISABLE => trace!("radio:state:TX_DISABLE"),
- }
+ super::trace_state(T::regs())
}
/// Set the radio mode
diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs
index 91c6dbd3b..2de53b392 100644
--- a/embassy-nrf/src/radio/ieee802154.rs
+++ b/embassy-nrf/src/radio/ieee802154.rs
@@ -1,19 +1,17 @@
-//! IEEE 802.15.4 radio
+//! IEEE 802.15.4 radio driver
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll;
use embassy_hal_internal::drop::OnDrop;
use embassy_hal_internal::{into_ref, PeripheralRef};
-use pac::radio::state::STATE_A as RadioState;
-use pac::radio::txpower::TXPOWER_A as TxPower;
-use super::{Error, Instance, InterruptHandler};
+use super::{state, Error, Instance, InterruptHandler, RadioState, TxPower};
use crate::interrupt::typelevel::Interrupt;
use crate::interrupt::{self};
-use crate::{pac, Peripheral};
+use crate::Peripheral;
-/// Default Start of Frame Delimiter = `0xA7` (IEEE compliant)
+/// Default (IEEE compliant) Start of Frame Delimiter
pub const DEFAULT_SFD: u8 = 0xA7;
// TODO expose the other variants in `pac::CCAMODE_A`
@@ -32,35 +30,14 @@ pub enum Cca {
},
}
-fn get_state(radio: &pac::radio::RegisterBlock) -> RadioState {
- match radio.state.read().state().variant() {
- Some(state) => state,
- None => unreachable!(),
- }
-}
-
-fn trace_state(state: RadioState) {
- match state {
- RadioState::DISABLED => trace!("radio:state:DISABLED"),
- RadioState::RX_RU => trace!("radio:state:RX_RU"),
- RadioState::RX_IDLE => trace!("radio:state:RX_IDLE"),
- RadioState::RX => trace!("radio:state:RX"),
- RadioState::RX_DISABLE => trace!("radio:state:RX_DISABLE"),
- RadioState::TX_RU => trace!("radio:state:TX_RU"),
- RadioState::TX_IDLE => trace!("radio:state:TX_IDLE"),
- RadioState::TX => trace!("radio:state:TX"),
- RadioState::TX_DISABLE => trace!("radio:state:TX_DISABLE"),
- }
-}
-
-/// Radio driver.
+/// IEEE 802.15.4 radio driver.
pub struct Radio<'d, T: Instance> {
_p: PeripheralRef<'d, T>,
needs_enable: bool,
}
impl<'d, T: Instance> Radio<'d, T> {
- /// Create a new radio driver.
+ /// Create a new IEEE 802.15.4 radio driver.
pub fn new(
radio: impl Peripheral
+ 'd,
_irq: impl interrupt::typelevel::Binding> + 'd,
@@ -81,40 +58,43 @@ impl<'d, T: Instance> Radio<'d, T> {
// Configure CRC polynomial and init
r.crcpoly.write(|w| w.crcpoly().bits(0x0001_1021));
r.crcinit.write(|w| w.crcinit().bits(0));
- // Configure packet layout
- // 8-bit on air length
- // S0 length, zero bytes
- // S1 length, zero bytes
- // S1 included in RAM if S1 length > 0, No.
- // Code Indicator length, 0
- // Preamble length 32-bit zero
- // Exclude CRC
- // No TERM field
r.pcnf0.write(|w| {
+ // 8-bit on air length
w.lflen()
.bits(8)
+ // Zero bytes S0 field length
.s0len()
.clear_bit()
+ // Zero bytes S1 field length
.s1len()
.bits(0)
+ // Do not include S1 field in RAM if S1 length > 0
.s1incl()
.clear_bit()
+ // Zero code Indicator length
.cilen()
.bits(0)
+ // 32-bit zero preamble
.plen()
._32bit_zero()
+ // Include CRC in length
.crcinc()
.include()
});
r.pcnf1.write(|w| {
+ // Maximum packet length
w.maxlen()
.bits(Packet::MAX_PSDU_LEN)
+ // Zero static length
.statlen()
.bits(0)
+ // Zero base address length
.balen()
.bits(0)
+ // Little-endian
.endian()
.clear_bit()
+ // Disable packet whitening
.whiteen()
.clear_bit()
});
@@ -208,16 +188,9 @@ impl<'d, T: Instance> Radio<'d, T> {
while self.state() != state {}
}
+ /// Get the current radio state
fn state(&self) -> RadioState {
- let r = T::regs();
- match r.state.read().state().variant() {
- Some(state) => state,
- None => unreachable!(),
- }
- }
-
- fn trace_state(&self) {
- trace_state(self.state());
+ state(T::regs())
}
/// Moves the radio from any state to the DISABLED state
@@ -227,20 +200,17 @@ impl<'d, T: Instance> Radio<'d, T> {
loop {
match self.state() {
RadioState::DISABLED => return,
-
+ // idle or ramping up
RadioState::RX_RU | RadioState::RX_IDLE | RadioState::TX_RU | RadioState::TX_IDLE => {
r.tasks_disable.write(|w| w.tasks_disable().set_bit());
-
self.wait_for_radio_state(RadioState::DISABLED);
return;
}
-
// ramping down
RadioState::RX_DISABLE | RadioState::TX_DISABLE => {
self.wait_for_radio_state(RadioState::DISABLED);
return;
}
-
// cancel ongoing transfer or ongoing CCA
RadioState::RX => {
r.tasks_ccastop.write(|w| w.tasks_ccastop().set_bit());
@@ -262,35 +232,27 @@ impl<'d, T: Instance> Radio<'d, T> {
/// Moves the radio to the RXIDLE state
fn receive_prepare(&mut self) {
- let state = self.state();
-
- let disable = match state {
+ // clear related events
+ T::regs().events_ccabusy.reset();
+ T::regs().events_phyend.reset();
+ // NOTE to avoid errata 204 (see rev1 v1.4) we do TX_IDLE -> DISABLED -> RX_IDLE
+ let disable = match self.state() {
RadioState::DISABLED => false,
- RadioState::RX_DISABLE => true,
- RadioState::TX_DISABLE => true,
RadioState::RX_IDLE => self.needs_enable,
- // NOTE to avoid errata 204 (see rev1 v1.4) we do TX_IDLE -> DISABLED -> RX_IDLE
- RadioState::TX_IDLE => true,
- _ => unreachable!(),
+ _ => true,
};
if disable {
- trace!("Receive Setup");
- self.trace_state();
self.disable();
}
self.needs_enable = false;
}
+ /// Prepare radio for receiving a packet
fn receive_start(&mut self, packet: &mut Packet) {
// NOTE we do NOT check the address of `packet` because the mutable reference ensures it's
// allocated in RAM
let r = T::regs();
- // clear related events
- r.events_framestart.reset();
- r.events_ccabusy.reset();
- r.events_phyend.reset();
-
self.receive_prepare();
// Configure shortcuts
@@ -314,15 +276,13 @@ impl<'d, T: Instance> Radio<'d, T> {
}
}
+ /// Cancel receiving packet
fn receive_cancel() {
let r = T::regs();
r.shorts.reset();
- if r.events_framestart.read().events_framestart().bit_is_set() {
- // TODO: Is there a way to finish receiving this frame
- }
r.tasks_stop.write(|w| w.tasks_stop().set_bit());
loop {
- match get_state(r) {
+ match state(r) {
RadioState::DISABLED | RadioState::RX_IDLE => break,
_ => (),
}
@@ -336,7 +296,7 @@ impl<'d, T: Instance> Radio<'d, T> {
/// This methods returns the `Ok` variant if the CRC included the packet was successfully
/// validated by the hardware; otherwise it returns the `Err` variant. In either case, `packet`
/// will be updated with the received packet's data
- pub async fn receive(&mut self, packet: &mut Packet) -> Result<(), u16> {
+ pub async fn receive(&mut self, packet: &mut Packet) -> Result<(), Error> {
let s = T::state();
let r = T::regs();
@@ -369,7 +329,7 @@ impl<'d, T: Instance> Radio<'d, T> {
if r.crcstatus.read().crcstatus().bit_is_set() {
Ok(())
} else {
- Err(crc)
+ Err(Error::CrcFailed(crc))
}
}
@@ -387,11 +347,6 @@ impl<'d, T: Instance> Radio<'d, T> {
let s = T::state();
let r = T::regs();
- // clear related events
- r.events_framestart.reset();
- r.events_ccabusy.reset();
- r.events_phyend.reset();
-
// enable radio to perform cca
self.receive_prepare();
diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs
index 9b3a6cf49..333dfb33d 100644
--- a/embassy-nrf/src/radio/mod.rs
+++ b/embassy-nrf/src/radio/mod.rs
@@ -15,6 +15,9 @@ use core::marker::PhantomData;
use crate::{interrupt, pac, Peripheral};
+use pac::radio::state::STATE_A as RadioState;
+use pac::radio::txpower::TXPOWER_A as TxPower;
+
/// RADIO error.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -28,6 +31,8 @@ pub enum Error {
BufferNotInRAM,
/// Clear channel assessment reported channel in use
ChannelInUse,
+ /// CRC check failed
+ CrcFailed(u16),
}
/// Interrupt handler
@@ -89,3 +94,26 @@ pub trait Instance: Peripheral + sealed::Instance + 'static + Send {
/// Interrupt for this peripheral.
type Interrupt: interrupt::typelevel::Interrupt;
}
+
+/// Get the state of the radio
+pub(crate) fn state(radio: &pac::radio::RegisterBlock) -> RadioState {
+ match radio.state.read().state().variant() {
+ Some(state) => state,
+ None => unreachable!(),
+ }
+}
+
+#[allow(dead_code)]
+pub(crate) fn trace_state(radio: &pac::radio::RegisterBlock) {
+ match state(radio) {
+ RadioState::DISABLED => trace!("radio:state:DISABLED"),
+ RadioState::RX_RU => trace!("radio:state:RX_RU"),
+ RadioState::RX_IDLE => trace!("radio:state:RX_IDLE"),
+ RadioState::RX => trace!("radio:state:RX"),
+ RadioState::RX_DISABLE => trace!("radio:state:RX_DISABLE"),
+ RadioState::TX_RU => trace!("radio:state:TX_RU"),
+ RadioState::TX_IDLE => trace!("radio:state:TX_IDLE"),
+ RadioState::TX => trace!("radio:state:TX"),
+ RadioState::TX_DISABLE => trace!("radio:state:TX_DISABLE"),
+ }
+}