#![no_std]
pub mod config;
mod consts;
pub mod error;
mod internal_radio;
mod internal_state;
pub(crate) mod state;
use core::{convert::Infallible, fmt::Debug};
use embedded_hal::{
blocking::{delay::DelayUs, spi::Transfer},
digital::v2::OutputPin,
};
use consts::*;
use error::{RfError, SpiErrorToOtherError, TransferError};
use internal_state::InternalState;
use state::State;
use crate::internal_radio::InternalRadio;
pub struct Rf4463<const PACKET_LEN: usize, Spi, SdnPin, CsPin, Delay> {
radio: InternalRadio<Spi, SdnPin, CsPin, Delay>,
state: InternalState<PACKET_LEN>,
rx_forever: bool,
}
impl<
const PACKET_LEN: usize,
Spi: Transfer<u8>,
SdnPin: OutputPin<Error = Infallible>,
CsPin: OutputPin<Error = Infallible>,
Delay: DelayUs<u16>,
> Rf4463<PACKET_LEN, Spi, SdnPin, CsPin, Delay>
where
Spi::Error: Debug,
{
pub fn new(
spi: Spi,
sdn: SdnPin,
mut cs: CsPin,
delay: Delay,
config: &mut [u8],
) -> Result<Self, RfError<Spi::Error>> {
assert!(
PACKET_LEN < 8192,
"Packet length cannot be above 8191 bytes"
);
cs.set_high().unwrap();
Ok(Self {
radio: InternalRadio::new(spi, sdn, cs, delay, config)?,
state: InternalState::Idle,
rx_forever: false,
})
}
pub fn get_temp(&mut self) -> Result<f32, Spi::Error> {
self.radio.get_temp()
}
pub fn get_rssi(&mut self) -> Result<f64, Spi::Error> {
self.radio.get_rssi()
}
pub fn is_idle(&mut self) -> bool {
matches!(self.state, InternalState::Idle)
}
pub fn start_rx(&mut self, rx_forever: bool) -> Result<(), Spi::Error> {
self.radio.clear_fifo()?;
self.radio.clear_ph_and_modem_interrupts()?;
self.state = InternalState::Rx {
data: [0; PACKET_LEN],
i: 0,
received: false,
rssi: None,
};
self.radio.send_command::<0>(&mut [
START_RX,
0,
0,
(PACKET_LEN >> 8).try_into().unwrap(),
(PACKET_LEN & 0xff).try_into().unwrap(),
State::Rx.into(),
if rx_forever {
State::Rx.into()
} else {
State::Sleep.into()
},
State::Rx.into(),
])?;
self.rx_forever = rx_forever;
Ok(())
}
pub fn finish_rx(&mut self) -> Result<Option<([u8; PACKET_LEN], f64)>, Spi::Error> {
let pkt = match self.state {
InternalState::Rx {
data,
received,
i,
rssi,
} if i == PACKET_LEN && received => {
let rssi = match rssi {
Some(x) => x,
None => self.get_rssi()?,
};
let ret = Some((data, rssi));
if self.rx_forever {
self.radio.clear_ph_and_modem_interrupts()?;
self.state = InternalState::Rx {
data: [0; PACKET_LEN],
i: 0,
received: false,
rssi: None,
};
} else {
self.state = InternalState::Idle;
}
ret
}
_ => None,
};
Ok(pkt)
}
pub fn start_tx(&mut self, mut data: [u8; PACKET_LEN]) -> Result<(), Spi::Error> {
self.radio.clear_fifo()?;
self.radio.clear_ph_and_modem_interrupts()?;
let i = data.len().min(128);
self.radio.with_cs(|s| {
s.spi_transfer_byte(WRITE_TX_FIFO)?;
s.spi.transfer(&mut data[0..i])?;
Ok(())
})?;
self.radio.send_command::<0>(&mut [
START_TX,
0,
u8::from(State::Sleep) << 4,
(PACKET_LEN >> 8).try_into().unwrap(),
(PACKET_LEN & 0xff).try_into().unwrap(),
0,
0,
])?;
self.state = InternalState::Tx { data, i };
Ok(())
}
pub fn interrupt(&mut self) -> Result<(), TransferError<Spi::Error>> {
if self.radio.fifo_underflow_pending().te()? {
return Err(TransferError::FifoOverflow);
}
match &mut self.state {
InternalState::Idle => {
}
InternalState::Rx { received, .. } => {
if self.radio.packet_received_pending().te()? {
*received = true;
}
if let Err(e) = self.rx_step() {
self.state = InternalState::Idle;
let _ = self.radio.sleep();
return Err(e);
}
}
InternalState::Tx { .. } => {
if self.radio.packet_sent_pending().te()? {
self.state = InternalState::Idle;
}
if let Err(e) = self.tx_step() {
self.state = InternalState::Idle;
let _ = self.radio.sleep();
return Err(e);
}
}
}
Ok(())
}
fn rx_step(&mut self) -> Result<(), TransferError<Spi::Error>> {
let (data, i, rssi) = match &mut self.state {
InternalState::Rx { data, i, rssi, .. } => (data, i, rssi),
_ => return Ok(()),
};
let len: usize = self.radio.rx_fifo_len().te()?.into();
if len == 0 {
return Ok(());
}
if len + *i > PACKET_LEN {
return Err(TransferError::TooMuchData);
}
if self.radio.fifo_underflow_pending().te()? {
return Err(TransferError::FifoOverflow);
}
let data = &mut data[*i..(*i + len)];
self.radio
.with_cs(|s| {
s.spi_transfer_byte(READ_RX_FIFO)?;
s.spi.transfer(data)?;
Ok(())
})
.te()?;
if rssi.is_none() {
*rssi = Some(self.radio.get_rssi().te()?)
}
*i += len;
Ok(())
}
fn tx_step(&mut self) -> Result<(), TransferError<Spi::Error>> {
let (data, i) = match &mut self.state {
InternalState::Tx { data, i, .. } => (data, i),
_ => return Ok(()),
};
let data = &mut data[*i..];
let len: usize = self.radio.tx_fifo_space().te()?.into();
let len = len.min(data.len());
if len == 0 {
return Ok(());
}
if self.radio.fifo_underflow_pending().te()? {
return Err(TransferError::FifoOverflow);
}
self.radio.with_cs(|s| {
s.spi_transfer_byte(WRITE_TX_FIFO).te()?;
s.spi.transfer(&mut data[0..len]).te()?;
Ok(())
})?;
*i += len;
Ok(())
}
}