Some more unifying, documentation

This commit is contained in:
Erik Bånvik 2024-03-05 01:03:10 +01:00
parent 0c4c996339
commit c00f014f18
3 changed files with 61 additions and 90 deletions

View File

@ -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

View File

@ -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 {
RadioState::DISABLED => false,
RadioState::RX_DISABLE => true,
RadioState::TX_DISABLE => true,
RadioState::RX_IDLE => self.needs_enable,
// 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
RadioState::TX_IDLE => true,
_ => unreachable!(),
let disable = match self.state() {
RadioState::DISABLED => false,
RadioState::RX_IDLE => self.needs_enable,
_ => 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();

View File

@ -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"),
}
}