#![no_std]
#![allow(async_fn_in_trait)]
use core::time::Duration;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RxFlowControl {
pub block_size: u8,
pub st_min: Duration,
}
pub trait IsoTpRxFlowControlConfig {
type Error;
fn set_rx_flow_control(&mut self, fc: RxFlowControl) -> Result<(), Self::Error>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RecvStatus {
TimedOut,
DeliveredOne,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RecvControl {
Continue,
Stop,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RecvMeta {
pub reply_to: u8,
}
#[derive(Debug)]
pub enum SendError<E> {
Timeout,
Backend(E),
}
#[derive(Debug)]
pub enum RecvError<E> {
BufferTooSmall {
needed: usize,
got: usize,
},
Backend(E),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RecvMetaIntoStatus {
TimedOut,
DeliveredOne {
meta: RecvMeta,
len: usize,
},
}
pub trait IsoTpEndpoint {
type Error;
fn send_to(
&mut self,
to: u8,
payload: &[u8],
timeout: Duration,
) -> Result<(), SendError<Self::Error>>;
fn send_functional_to(
&mut self,
functional_to: u8,
payload: &[u8],
timeout: Duration,
) -> Result<(), SendError<Self::Error>>;
fn recv_one<Cb>(
&mut self,
timeout: Duration,
on_payload: Cb,
) -> Result<RecvStatus, RecvError<Self::Error>>
where
Cb: FnMut(RecvMeta, &[u8]) -> Result<RecvControl, Self::Error>;
}
pub trait IsoTpAsyncEndpoint {
type Error;
async fn send_to(
&mut self,
to: u8,
payload: &[u8],
timeout: Duration,
) -> Result<(), SendError<Self::Error>>;
async fn send_functional_to(
&mut self,
functional_to: u8,
payload: &[u8],
timeout: Duration,
) -> Result<(), SendError<Self::Error>>;
async fn recv_one<Cb>(
&mut self,
timeout: Duration,
on_payload: Cb,
) -> Result<RecvStatus, RecvError<Self::Error>>
where
Cb: FnMut(RecvMeta, &[u8]) -> Result<RecvControl, Self::Error>;
}
pub trait IsoTpAsyncEndpointRecvInto {
type Error;
async fn recv_one_into(
&mut self,
timeout: Duration,
out: &mut [u8],
) -> Result<RecvMetaIntoStatus, RecvError<Self::Error>>;
}
pub trait IsoTpEndpointMeta: IsoTpEndpoint {}
impl<T> IsoTpEndpointMeta for T where T: IsoTpEndpoint {}
pub trait IsoTpAsyncEndpointMeta: IsoTpAsyncEndpoint {}
impl<T> IsoTpAsyncEndpointMeta for T where T: IsoTpAsyncEndpoint {}
pub trait IsoTpAsyncEndpointMetaRecvInto: IsoTpAsyncEndpointRecvInto {}
impl<T> IsoTpAsyncEndpointMetaRecvInto for T where T: IsoTpAsyncEndpointRecvInto {}
#[cfg(test)]
mod tests {
extern crate std;
use super::*;
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
use std::vec;
use std::vec::Vec;
fn block_on<F: Future>(mut fut: F) -> F::Output {
fn raw_waker() -> RawWaker {
fn clone(_: *const ()) -> RawWaker {
raw_waker()
}
fn wake(_: *const ()) {}
fn wake_by_ref(_: *const ()) {}
fn drop(_: *const ()) {}
let vtable = &RawWakerVTable::new(clone, wake, wake_by_ref, drop);
RawWaker::new(core::ptr::null(), vtable)
}
let waker = unsafe { Waker::from_raw(raw_waker()) };
let mut cx = Context::from_waker(&waker);
let mut fut = unsafe { Pin::new_unchecked(&mut fut) };
loop {
match fut.as_mut().poll(&mut cx) {
Poll::Ready(v) => return v,
Poll::Pending => {}
}
}
}
#[derive(Default)]
struct Dummy {
sent_to: Vec<u8>,
sent_payloads: Vec<Vec<u8>>,
inbox: Vec<(u8, Vec<u8>)>,
}
impl IsoTpEndpoint for Dummy {
type Error = ();
fn send_to(
&mut self,
to: u8,
payload: &[u8],
_timeout: Duration,
) -> Result<(), SendError<Self::Error>> {
self.sent_to.push(to);
self.sent_payloads.push(payload.to_vec());
Ok(())
}
fn send_functional_to(
&mut self,
functional_to: u8,
payload: &[u8],
timeout: Duration,
) -> Result<(), SendError<Self::Error>> {
IsoTpEndpoint::send_to(self, functional_to, payload, timeout)
}
fn recv_one<Cb>(
&mut self,
_timeout: Duration,
mut on_payload: Cb,
) -> Result<RecvStatus, RecvError<Self::Error>>
where
Cb: FnMut(RecvMeta, &[u8]) -> Result<RecvControl, Self::Error>,
{
if let Some((reply_to, data)) = self.inbox.pop() {
let _ = on_payload(RecvMeta { reply_to }, &data).map_err(RecvError::Backend)?;
return Ok(RecvStatus::DeliveredOne);
}
Ok(RecvStatus::TimedOut)
}
}
impl IsoTpAsyncEndpoint for Dummy {
type Error = ();
async fn send_to(
&mut self,
to: u8,
payload: &[u8],
timeout: Duration,
) -> Result<(), SendError<Self::Error>> {
IsoTpEndpoint::send_to(self, to, payload, timeout)
}
async fn send_functional_to(
&mut self,
functional_to: u8,
payload: &[u8],
timeout: Duration,
) -> Result<(), SendError<Self::Error>> {
IsoTpEndpoint::send_functional_to(self, functional_to, payload, timeout)
}
async fn recv_one<Cb>(
&mut self,
timeout: Duration,
on_payload: Cb,
) -> Result<RecvStatus, RecvError<Self::Error>>
where
Cb: FnMut(RecvMeta, &[u8]) -> Result<RecvControl, Self::Error>,
{
IsoTpEndpoint::recv_one(self, timeout, on_payload)
}
}
impl IsoTpAsyncEndpointRecvInto for Dummy {
type Error = ();
async fn recv_one_into(
&mut self,
_timeout: Duration,
out: &mut [u8],
) -> Result<RecvMetaIntoStatus, RecvError<Self::Error>> {
if let Some((reply_to, data)) = self.inbox.pop() {
if data.len() > out.len() {
return Err(RecvError::BufferTooSmall {
needed: data.len(),
got: out.len(),
});
}
out[..data.len()].copy_from_slice(&data);
return Ok(RecvMetaIntoStatus::DeliveredOne {
meta: RecvMeta { reply_to },
len: data.len(),
});
}
Ok(RecvMetaIntoStatus::TimedOut)
}
}
#[test]
fn sync_trait_is_addressed() {
let mut d = Dummy::default();
IsoTpEndpoint::send_to(&mut d, 0x33, b"abc", Duration::from_millis(1)).unwrap();
assert_eq!(d.sent_to, vec![0x33]);
assert_eq!(d.sent_payloads, vec![b"abc".to_vec()]);
}
#[test]
fn async_trait_is_addressed() {
let mut d = Dummy::default();
block_on(IsoTpAsyncEndpoint::send_to(
&mut d,
0x44,
b"xyz",
Duration::from_millis(1),
))
.unwrap();
assert_eq!(d.sent_to, vec![0x44]);
assert_eq!(d.sent_payloads, vec![b"xyz".to_vec()]);
}
}