#![no_std]
pub mod status;
pub mod system;
pub mod fifo;
pub mod cmd;
pub mod radio;
pub mod lora;
pub mod ble;
pub mod flrc;
pub mod ook;
pub mod fsk;
pub mod zigbee;
pub mod zwave;
pub mod lrfhss;
pub mod wmbus;
pub mod wisun;
pub mod bpsk_tx;
mod constants;
use core::marker::PhantomData;
use embassy_time::{with_timeout, Duration, Instant, Timer};
use embedded_hal::digital::{OutputPin, InputPin};
use embedded_hal_async::{digital::Wait, spi::SpiBus};
use status::{CmdStatus, Intr, Status};
pub use cmd::{RxBw, PulseShape};
trait Sealed{}
#[allow(private_bounds)]
pub trait BusyPin: Sealed {
type Pin: InputPin;
#[allow(async_fn_in_trait)]
async fn wait_ready(pin: &mut Self::Pin, timeout: Duration) -> Result<(), Lr2021Error>;
}
pub struct BusyBlocking<I> {
_marker: PhantomData<I>
}
pub struct BusyAsync<I> {
_marker: PhantomData<I>
}
impl<I> Sealed for BusyBlocking<I> {}
impl<I> Sealed for BusyAsync<I> {}
impl<I: InputPin> BusyPin for BusyBlocking<I> {
type Pin = I;
async fn wait_ready(pin: &mut I, timeout: Duration) -> Result<(), Lr2021Error> {
let start = Instant::now();
while pin.is_high().map_err(|_| Lr2021Error::Pin)? {
if start.elapsed() >= timeout {
return Err(Lr2021Error::BusyTimeout);
}
}
Ok(())
}
}
impl<I: InputPin + Wait> BusyPin for BusyAsync<I> {
type Pin = I;
async fn wait_ready(pin: &mut I, timeout: Duration) -> Result<(), Lr2021Error> {
if pin.is_high().map_err(|_| Lr2021Error::Pin)? {
match with_timeout(timeout, pin.wait_for_low()).await {
Ok(_) => Ok(()),
Err(_) => Err(Lr2021Error::BusyTimeout),
}
} else {
Ok(())
}
}
}
const BUFFER_SIZE: usize = 256;
pub struct CmdBuffer ([u8;BUFFER_SIZE+2]);
impl CmdBuffer {
pub fn new() -> Self {
CmdBuffer([0;BUFFER_SIZE+2])
}
pub fn nop(&mut self) {
self.0[0] = 0;
self.0[1] = 0;
}
pub fn status(&self) -> Status {
Status::from_array([self.0[0],self.0[1]])
}
pub fn updt_status(&mut self, bytes: &[u8]) {
self.0.iter_mut()
.zip(bytes)
.take(2)
.for_each(|(s,&b)| *s = b);
}
pub fn cmd_status(&self) -> CmdStatus {
let bits_cmd = (self.0[0] >> 1) & 7;
bits_cmd.into()
}
pub fn data(&self) -> &[u8] {
&self.0[2..]
}
pub fn data_mut(&mut self) -> &mut [u8] {
&mut self.0[2..]
}
}
impl Default for CmdBuffer {
fn default() -> Self {
Self::new()
}
}
impl AsMut<[u8]> for CmdBuffer {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0[2..]
}
}
pub struct Lr2021<O,SPI, M: BusyPin> {
nreset: O,
busy: M::Pin,
spi: SPI,
nss: O,
buffer: CmdBuffer,
}
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Lr2021Error {
Pin,
Spi,
CmdFail,
CmdErr,
BusyTimeout,
InvalidSize,
Unknown,
}
impl<I,O,SPI> Lr2021<O,SPI, BusyBlocking<I>> where
I: InputPin, O: OutputPin, SPI: SpiBus<u8>
{
pub fn new_blocking(nreset: O, busy: I, spi: SPI, nss: O) -> Self {
Self { nreset, busy, spi, nss, buffer: CmdBuffer::new()}
}
}
impl<I,O,SPI> Lr2021<O,SPI, BusyAsync<I>> where
I: InputPin + Wait, O: OutputPin, SPI: SpiBus<u8>
{
pub fn new(nreset: O, busy: I, spi: SPI, nss: O) -> Self {
Self { nreset, busy, spi, nss, buffer: CmdBuffer::new()}
}
}
impl<O,SPI, M> Lr2021<O,SPI, M> where
O: OutputPin, SPI: SpiBus<u8>, M: BusyPin
{
pub async fn reset(&mut self) -> Result<(), Lr2021Error> {
self.nreset.set_low().map_err(|_| Lr2021Error::Pin)?;
Timer::after_millis(10).await;
self.nreset.set_high().map_err(|_| Lr2021Error::Pin)?;
Timer::after_millis(10).await;
Ok(())
}
pub fn is_busy(&mut self) -> bool {
self.busy.is_high().unwrap_or(false)
}
pub fn status(&self) -> Status {
self.buffer.status()
}
pub fn buffer(&self) -> &[u8] {
self.buffer.data()
}
pub fn buffer_mut(&mut self) -> &mut [u8] {
self.buffer.data_mut()
}
pub fn last_intr(&self) -> Intr {
Intr::from_slice(&self.buffer.data()[2..6])
}
pub async fn wait_ready(&mut self, timeout: Duration) -> Result<(), Lr2021Error> {
M::wait_ready(&mut self.busy, timeout).await
}
pub async fn cmd_wr_begin(&mut self, req: &[u8]) -> Result<(), Lr2021Error> {
if req.len() > BUFFER_SIZE {
return Err(Lr2021Error::InvalidSize);
}
self.wait_ready(Duration::from_millis(100)).await?;
self.nss.set_low().map_err(|_| Lr2021Error::Pin)?;
let rsp_buf = &mut self.buffer.0[..req.len()];
self.spi
.transfer(rsp_buf, req).await
.map_err(|_| Lr2021Error::Spi)?;
self.buffer.cmd_status().check()
}
pub async fn cmd_wr(&mut self, req: &[u8]) -> Result<(), Lr2021Error> {
self.cmd_wr_begin(req).await?;
self.nss.set_high().map_err(|_| Lr2021Error::Pin)
}
pub async fn cmd_rd(&mut self, req: &[u8], rsp: &mut [u8]) -> Result<(), Lr2021Error> {
self.cmd_wr(req).await?;
self.wait_ready(Duration::from_millis(1)).await?;
self.nss.set_low().map_err(|_| Lr2021Error::Pin)?;
self.spi
.transfer_in_place(rsp).await
.map_err(|_| Lr2021Error::Spi)?;
self.nss.set_high().map_err(|_| Lr2021Error::Pin)?;
self.buffer.updt_status(rsp);
self.buffer.cmd_status().check()
}
pub async fn cmd_data_wr(&mut self, opcode: &[u8], data: &[u8]) -> Result<(), Lr2021Error> {
self.cmd_wr_begin(opcode).await?;
let rsp = &mut self.buffer.data_mut()[..data.len()];
self.spi
.transfer(rsp, data).await
.map_err(|_| Lr2021Error::Spi)?;
self.nss.set_high().map_err(|_| Lr2021Error::Pin)
}
pub async fn cmd_data_rw(&mut self, opcode: &[u8], data: &mut [u8]) -> Result<(), Lr2021Error> {
self.cmd_wr_begin(opcode).await?;
self.spi
.transfer_in_place(data).await
.map_err(|_| Lr2021Error::Spi)?;
self.nss.set_high().map_err(|_| Lr2021Error::Pin)
}
pub async fn cmd_buf_wr(&mut self, len: usize) -> Result<(), Lr2021Error> {
self.wait_ready(Duration::from_millis(100)).await?;
self.nss.set_low().map_err(|_| Lr2021Error::Pin)?;
self.spi
.transfer_in_place(&mut self.buffer.as_mut()[..len]).await
.map_err(|_| Lr2021Error::Spi)?;
self.nss.set_high().map_err(|_| Lr2021Error::Pin)
}
pub async fn cmd_buf_rd(&mut self, len: usize, rsp: &mut [u8]) -> Result<(), Lr2021Error> {
self.cmd_buf_wr(len).await?;
self.wait_ready(Duration::from_millis(1)).await?;
self.nss.set_low().map_err(|_| Lr2021Error::Pin)?;
self.spi
.transfer_in_place(rsp).await
.map_err(|_| Lr2021Error::Spi)?;
self.nss.set_high().map_err(|_| Lr2021Error::Pin)?;
self.buffer.updt_status(rsp);
self.buffer.cmd_status().check()
}
pub async fn wake_up(&mut self) -> Result<(), Lr2021Error> {
self.nss.set_low().map_err(|_| Lr2021Error::Pin)?;
self.wait_ready(Duration::from_millis(100)).await?;
self.nss.set_high().map_err(|_| Lr2021Error::Pin)
}
}