use core::fmt::Debug;
use core::future::Future;
use core::marker::PhantomData;
use core::pin::Pin;
use core::task::{Context, Poll};
use core::time::Duration;
use crate::{Power, Receive, ReceiveInfo, Transmit};
pub struct AsyncOptions {
pub power: Option<i8>,
#[deprecated(note = "Timeouts must (currently) be implemented outside this module")]
pub timeout: Option<Duration>,
pub poll_period: Duration,
pub wake_fn: Option<&'static fn(cx: &mut Context, d: Duration)>,
}
impl Default for AsyncOptions {
#[allow(deprecated)]
fn default() -> Self {
Self {
power: None,
timeout: None,
poll_period: Duration::from_millis(10),
wake_fn: None,
}
}
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "thiserror", derive(thiserror::Error))]
pub enum AsyncError<E> {
#[cfg_attr(feature = "thiserror", error("Inner: {0}"))]
Inner(E),
#[cfg_attr(feature = "thiserror", error("Timeout"))]
Timeout,
}
impl<E> From<E> for AsyncError<E> {
fn from(e: E) -> Self {
AsyncError::Inner(e)
}
}
#[cfg_attr(
feature = "mock",
doc = r##"
```
extern crate async_std;
use async_std::task;
# use radio::*;
# use radio::mock::*;
use radio::nonblocking::{AsyncTransmit, AsyncOptions};
# let mut radio = MockRadio::new(&[
# Transaction::start_transmit(vec![0xaa, 0xbb], None),
# Transaction::check_transmit(Ok(false)),
# Transaction::check_transmit(Ok(true)),
# ]);
#
let res = task::block_on(async {
// Transmit using a future
radio.async_transmit(&[0xaa, 0xbb], AsyncOptions::default())?.await
});
assert_eq!(res, Ok(()));
# radio.done();
```
"##
)]
pub trait AsyncTransmit<'a, E> {
type Output: Future<Output = Result<(), AsyncError<E>>>;
fn async_transmit(
&'a mut self,
data: &'a [u8],
tx_options: AsyncOptions,
) -> Result<Self::Output, E>;
}
pub struct TransmitFuture<'a, T, E> {
radio: &'a mut T,
options: AsyncOptions,
_err: PhantomData<E>,
}
impl<'a, T, E> AsyncTransmit<'a, E> for T
where
T: Transmit<Error = E> + Power<Error = E> + 'a,
E: Debug + Unpin,
{
type Output = TransmitFuture<'a, T, E>;
fn async_transmit(
&'a mut self,
data: &'a [u8],
tx_options: AsyncOptions,
) -> Result<Self::Output, E> {
if let Some(p) = tx_options.power {
self.set_power(p)?;
}
self.start_transmit(data)?;
let f: TransmitFuture<_, E> = TransmitFuture {
radio: self,
options: tx_options,
_err: PhantomData,
};
Ok(f)
}
}
impl<'a, T, E> Future for TransmitFuture<'a, T, E>
where
T: Transmit<Error = E> + Power<Error = E>,
E: Debug + Unpin,
{
type Output = Result<(), AsyncError<E>>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let s = self.get_mut();
let period = s.options.poll_period.clone();
if s.radio.check_transmit()? {
return Poll::Ready(Ok(()));
};
if let Some(w) = s.options.wake_fn {
w(cx, period);
} else {
cx.waker().clone().wake();
}
Poll::Pending
}
}
#[cfg_attr(
feature = "mock",
doc = r##"
```
extern crate async_std;
use async_std::task;
# use radio::*;
# use radio::mock::*;
use radio::nonblocking::{AsyncReceive, AsyncOptions};
let data = [0xaa, 0xbb];
let info = BasicInfo::new(-81, 0);
# let mut radio = MockRadio::new(&[
# Transaction::start_receive(None),
# Transaction::check_receive(true, Ok(false)),
# Transaction::check_receive(true, Ok(true)),
# Transaction::get_received(Ok((data.to_vec(), info.clone()))),
# ]);
#
// Setup buffer and receive info
let mut buff = [0u8; 128];
let mut i = BasicInfo::new(0, 0);
let (n, i) = task::block_on(async {
// Receive using a future
radio.async_receive(&mut buff, AsyncOptions::default())?.await
})?;
assert_eq!(n, data.len());
assert_eq!(&buff[..data.len()], &data);
# radio.done();
Ok::<(), anyhow::Error>(())
```
"##
)]
pub trait AsyncReceive<'a, I, E> {
type Output: Future<Output = Result<(usize, I), AsyncError<E>>>;
fn async_receive(
&'a mut self,
buff: &'a mut [u8],
rx_options: AsyncOptions,
) -> Result<Self::Output, E>;
}
pub struct ReceiveFuture<'a, T, I, E> {
radio: &'a mut T,
buff: &'a mut [u8],
options: AsyncOptions,
_inf: PhantomData<I>,
_err: PhantomData<E>,
}
impl<'a, T, I, E> AsyncReceive<'a, I, E> for T
where
T: Receive<Error = E, Info = I> + 'a,
I: ReceiveInfo + Unpin + 'a,
E: Debug + Unpin,
{
type Output = ReceiveFuture<'a, T, I, E>;
fn async_receive(
&'a mut self,
buff: &'a mut [u8],
rx_options: AsyncOptions,
) -> Result<Self::Output, E> {
self.start_receive()?;
let f: ReceiveFuture<_, I, E> = ReceiveFuture {
radio: self,
buff,
options: rx_options,
_inf: PhantomData,
_err: PhantomData,
};
Ok(f)
}
}
impl<'a, T, I, E> Future for ReceiveFuture<'a, T, I, E>
where
T: Receive<Error = E, Info = I>,
I: ReceiveInfo + Unpin,
E: Debug + Unpin,
{
type Output = Result<(usize, I), AsyncError<E>>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let s = self.get_mut();
if s.radio.check_receive(true)? {
let (n, i) = s.radio.get_received(s.buff)?;
return Poll::Ready(Ok((n, i)));
}
if let Some(w) = s.options.wake_fn {
w(cx, s.options.poll_period)
} else {
cx.waker().clone().wake();
}
Poll::Pending
}
}
#[cfg(feature = "async-std")]
pub fn async_std_task_waker(cx: &mut Context, period: Duration) {
let waker = cx.waker().clone();
async_std::task::spawn(async move {
async_std::task::sleep(period).await;
waker.wake();
});
}