#![no_std]
use embassy_time::{Duration, Instant};
pub use rylr998_core::RadioError;
use rylr998_core::{Command, Driver, Event, Poll, Response, RfParams};
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(1);
const FACTORY_RESET_TIMEOUT: Duration = Duration::from_secs(2);
#[derive(Debug)]
pub enum Error<E> {
Core(rylr998_core::Error),
Io(E),
Timeout,
Radio(u8),
}
impl<E> From<rylr998_core::Error> for Error<E> {
fn from(e: rylr998_core::Error) -> Self {
Self::Core(e)
}
}
pub struct Radio<UART> {
driver: Driver,
uart: UART,
}
fn wait_ok<E>(r: Response<'_>) -> Option<Result<(), Error<E>>> {
match r {
Response::Ok => Some(Ok(())),
Response::Err(n) => Some(Err(Error::Radio(n))),
_ => None,
}
}
fn log_event(e: Event<'_>) {
match e {
Event::Recv {
from,
data,
rssi,
snr,
} => {
defmt::info!(
"recv from={} len={} rssi={} snr={}",
from,
data.len(),
rssi,
snr,
);
}
Event::Ready => defmt::info!("event: ready"),
}
}
impl<UART> Radio<UART>
where
UART: embedded_io_async::Read + embedded_io_async::Write,
{
pub fn new(uart: UART) -> Self {
let driver = Driver::new();
Self { uart, driver }
}
fn deadline(d: Duration) -> Instant {
Instant::now() + d
}
pub async fn ping(&mut self) -> Result<(), Error<UART::Error>> {
self.driver.submit(Command::Ping)?;
self.pump_until(Self::deadline(DEFAULT_TIMEOUT), wait_ok)
.await
}
pub async fn set_address(&mut self, n: u16) -> Result<(), Error<UART::Error>> {
self.driver.submit(Command::SetAddress(n))?;
self.pump_until(Self::deadline(DEFAULT_TIMEOUT), wait_ok)
.await
}
pub async fn address(&mut self) -> Result<u16, Error<UART::Error>> {
self.driver.submit(Command::GetAddress)?;
self.pump_until(Self::deadline(DEFAULT_TIMEOUT), |r| match r {
Response::Address(n) => Some(Ok(n)),
Response::Err(n) => Some(Err(Error::Radio(n))),
_ => None,
})
.await
}
pub async fn set_network_id(&mut self, n: u8) -> Result<(), Error<UART::Error>> {
self.driver.submit(Command::SetNetworkId(n))?;
self.pump_until(Self::deadline(DEFAULT_TIMEOUT), wait_ok)
.await
}
pub async fn network_id(&mut self) -> Result<u8, Error<UART::Error>> {
self.driver.submit(Command::GetNetworkId)?;
self.pump_until(Self::deadline(DEFAULT_TIMEOUT), |r| match r {
Response::NetworkId(n) => Some(Ok(n)),
Response::Err(n) => Some(Err(Error::Radio(n))),
_ => None,
})
.await
}
pub async fn set_band(&mut self, hz: u32) -> Result<(), Error<UART::Error>> {
self.driver.submit(Command::SetBand(hz))?;
self.pump_until(Self::deadline(DEFAULT_TIMEOUT), wait_ok)
.await
}
pub async fn band(&mut self) -> Result<u32, Error<UART::Error>> {
self.driver.submit(Command::GetBand)?;
self.pump_until(Self::deadline(DEFAULT_TIMEOUT), |r| match r {
Response::Band(n) => Some(Ok(n)),
Response::Err(n) => Some(Err(Error::Radio(n))),
_ => None,
})
.await
}
pub async fn cpin(&mut self) -> Result<heapless::String<8>, Error<UART::Error>> {
self.driver.submit(Command::GetCpin)?;
self.pump_until(Self::deadline(DEFAULT_TIMEOUT), |r| match r {
Response::Cpin(s) => {
let mut out = heapless::String::new();
match out.push_str(s) {
Ok(()) => Some(Ok(out)),
Err(_) => Some(Err(Error::Core(rylr998_core::Error::Parse))),
}
}
Response::Err(n) => Some(Err(Error::Radio(n))),
_ => None,
})
.await
}
pub async fn set_cpin(&mut self, password: &[u8]) -> Result<(), Error<UART::Error>> {
self.driver.submit(Command::SetCpin(password))?;
self.pump_until(Self::deadline(DEFAULT_TIMEOUT), wait_ok)
.await
}
pub async fn set_parameters(&mut self, p: RfParams) -> Result<(), Error<UART::Error>> {
self.driver.submit(Command::SetParameters(p))?;
self.pump_until(Self::deadline(DEFAULT_TIMEOUT), wait_ok)
.await
}
pub async fn parameters(&mut self) -> Result<RfParams, Error<UART::Error>> {
self.driver.submit(Command::GetParameters)?;
self.pump_until(Self::deadline(DEFAULT_TIMEOUT), |r| match r {
Response::Parameters(p) => Some(Ok(p)),
Response::Err(n) => Some(Err(Error::Radio(n))),
_ => None,
})
.await
}
pub async fn crfop(&mut self) -> Result<u8, Error<UART::Error>> {
self.driver.submit(Command::GetCrfop)?;
self.pump_until(Self::deadline(DEFAULT_TIMEOUT), |r| match r {
Response::Crfop(n) => Some(Ok(n)),
Response::Err(n) => Some(Err(Error::Radio(n))),
_ => None,
})
.await
}
pub async fn factory_reset(&mut self) -> Result<(), Error<UART::Error>> {
self.driver.submit(Command::FactoryReset)?;
self.pump_until(Self::deadline(FACTORY_RESET_TIMEOUT), wait_ok)
.await
}
pub async fn send(&mut self, to: u16, data: &[u8]) -> Result<(), Error<UART::Error>> {
self.driver.submit(Command::Send { to, data })?;
self.pump_until(Self::deadline(DEFAULT_TIMEOUT), wait_ok)
.await
}
pub async fn next_event<F, R>(
&mut self,
timeout: Duration,
mut handler: F,
) -> Result<R, Error<UART::Error>>
where
F: FnMut(Event<'_>) -> Option<R>,
{
let deadline = Self::deadline(timeout);
loop {
loop {
match self.driver.poll() {
Poll::NeedTx(bytes) => {
let n = bytes.len();
self.uart.write_all(bytes).await.map_err(Error::Io)?;
self.driver.ack_tx(n);
}
Poll::Event(e) => {
if let Some(r) = handler(e) {
return Ok(r);
}
}
Poll::Response(_) => {} Poll::Idle => break,
}
}
let mut buf = [0u8; 256];
let remaining = deadline.saturating_duration_since(Instant::now());
if remaining.as_ticks() == 0 {
return Err(Error::Timeout);
}
match embassy_time::with_timeout(remaining, self.uart.read(&mut buf)).await {
Ok(Ok(n)) => {
self.driver.push_rx(&buf[..n])?;
}
Ok(Err(e)) => return Err(Error::Io(e)),
Err(_) => {} }
}
}
pub(crate) async fn pump_until<R, F>(
&mut self,
deadline: Instant,
mut want: F,
) -> Result<R, Error<UART::Error>>
where
F: FnMut(Response<'_>) -> Option<Result<R, Error<UART::Error>>>,
{
loop {
loop {
match self.driver.poll() {
Poll::NeedTx(bytes) => {
let n = bytes.len();
self.uart.write_all(bytes).await.map_err(Error::Io)?;
self.driver.ack_tx(n);
}
Poll::Response(r) => {
if let Some(out) = want(r) {
return out;
}
}
Poll::Event(e) => log_event(e),
Poll::Idle => break,
}
}
let mut buf = [0u8; 256];
let remaining = deadline.saturating_duration_since(Instant::now());
if remaining.as_ticks() == 0 {
return Err(Error::Timeout);
}
match embassy_time::with_timeout(remaining, self.uart.read(&mut buf)).await {
Ok(Ok(n)) => {
self.driver.push_rx(&buf[..n])?;
}
Ok(Err(e)) => return Err(Error::Io(e)),
Err(_) => {} }
}
}
}