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<P = T> + 'd, _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + '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<P = Self> + 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"), + } +}