1#![no_std]
7#![allow(async_fn_in_trait)]
8
9use core::time::Duration;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub struct RxFlowControl {
14 pub block_size: u8,
16 pub st_min: Duration,
18}
19
20pub trait IsoTpRxFlowControlConfig {
22 type Error;
24
25 fn set_rx_flow_control(&mut self, fc: RxFlowControl) -> Result<(), Self::Error>;
27}
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub enum RecvStatus {
32 TimedOut,
34 DeliveredOne,
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub enum RecvControl {
41 Continue,
43 Stop,
45}
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub struct RecvMeta {
50 pub reply_to: u8,
52}
53
54#[derive(Debug)]
56pub enum SendError<E> {
57 Timeout,
59 Backend(E),
61}
62
63#[derive(Debug)]
65pub enum RecvError<E> {
66 BufferTooSmall {
68 needed: usize,
70 got: usize,
72 },
73 Backend(E),
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79pub enum RecvMetaIntoStatus {
80 TimedOut,
82 DeliveredOne {
84 meta: RecvMeta,
86 len: usize,
88 },
89}
90
91pub trait IsoTpEndpoint {
95 type Error;
97
98 fn send_to(
100 &mut self,
101 to: u8,
102 payload: &[u8],
103 timeout: Duration,
104 ) -> Result<(), SendError<Self::Error>>;
105
106 fn send_functional_to(
108 &mut self,
109 functional_to: u8,
110 payload: &[u8],
111 timeout: Duration,
112 ) -> Result<(), SendError<Self::Error>>;
113
114 fn recv_one<Cb>(
116 &mut self,
117 timeout: Duration,
118 on_payload: Cb,
119 ) -> Result<RecvStatus, RecvError<Self::Error>>
120 where
121 Cb: FnMut(RecvMeta, &[u8]) -> Result<RecvControl, Self::Error>;
122}
123
124pub trait IsoTpAsyncEndpoint {
126 type Error;
128
129 async fn send_to(
131 &mut self,
132 to: u8,
133 payload: &[u8],
134 timeout: Duration,
135 ) -> Result<(), SendError<Self::Error>>;
136
137 async fn send_functional_to(
139 &mut self,
140 functional_to: u8,
141 payload: &[u8],
142 timeout: Duration,
143 ) -> Result<(), SendError<Self::Error>>;
144
145 async fn recv_one<Cb>(
147 &mut self,
148 timeout: Duration,
149 on_payload: Cb,
150 ) -> Result<RecvStatus, RecvError<Self::Error>>
151 where
152 Cb: FnMut(RecvMeta, &[u8]) -> Result<RecvControl, Self::Error>;
153}
154
155pub trait IsoTpAsyncEndpointRecvInto {
157 type Error;
159
160 async fn recv_one_into(
162 &mut self,
163 timeout: Duration,
164 out: &mut [u8],
165 ) -> Result<RecvMetaIntoStatus, RecvError<Self::Error>>;
166}
167
168pub trait IsoTpEndpointMeta: IsoTpEndpoint {}
170
171impl<T> IsoTpEndpointMeta for T where T: IsoTpEndpoint {}
172
173pub trait IsoTpAsyncEndpointMeta: IsoTpAsyncEndpoint {}
175
176impl<T> IsoTpAsyncEndpointMeta for T where T: IsoTpAsyncEndpoint {}
177
178pub trait IsoTpAsyncEndpointMetaRecvInto: IsoTpAsyncEndpointRecvInto {}
180
181impl<T> IsoTpAsyncEndpointMetaRecvInto for T where T: IsoTpAsyncEndpointRecvInto {}
182
183#[cfg(test)]
184mod tests {
185 extern crate std;
186
187 use super::*;
188 use core::future::Future;
189 use core::pin::Pin;
190 use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
191 use std::vec;
192 use std::vec::Vec;
193
194 fn block_on<F: Future>(mut fut: F) -> F::Output {
195 fn raw_waker() -> RawWaker {
196 fn clone(_: *const ()) -> RawWaker {
197 raw_waker()
198 }
199 fn wake(_: *const ()) {}
200 fn wake_by_ref(_: *const ()) {}
201 fn drop(_: *const ()) {}
202 let vtable = &RawWakerVTable::new(clone, wake, wake_by_ref, drop);
203 RawWaker::new(core::ptr::null(), vtable)
204 }
205
206 let waker = unsafe { Waker::from_raw(raw_waker()) };
208 let mut cx = Context::from_waker(&waker);
209 let mut fut = unsafe { Pin::new_unchecked(&mut fut) };
211 loop {
212 match fut.as_mut().poll(&mut cx) {
213 Poll::Ready(v) => return v,
214 Poll::Pending => {}
215 }
216 }
217 }
218
219 #[derive(Default)]
220 struct Dummy {
221 sent_to: Vec<u8>,
222 sent_payloads: Vec<Vec<u8>>,
223 inbox: Vec<(u8, Vec<u8>)>,
224 }
225
226 impl IsoTpEndpoint for Dummy {
227 type Error = ();
228
229 fn send_to(
230 &mut self,
231 to: u8,
232 payload: &[u8],
233 _timeout: Duration,
234 ) -> Result<(), SendError<Self::Error>> {
235 self.sent_to.push(to);
236 self.sent_payloads.push(payload.to_vec());
237 Ok(())
238 }
239
240 fn send_functional_to(
241 &mut self,
242 functional_to: u8,
243 payload: &[u8],
244 timeout: Duration,
245 ) -> Result<(), SendError<Self::Error>> {
246 IsoTpEndpoint::send_to(self, functional_to, payload, timeout)
247 }
248
249 fn recv_one<Cb>(
250 &mut self,
251 _timeout: Duration,
252 mut on_payload: Cb,
253 ) -> Result<RecvStatus, RecvError<Self::Error>>
254 where
255 Cb: FnMut(RecvMeta, &[u8]) -> Result<RecvControl, Self::Error>,
256 {
257 if let Some((reply_to, data)) = self.inbox.pop() {
258 let _ = on_payload(RecvMeta { reply_to }, &data).map_err(RecvError::Backend)?;
259 return Ok(RecvStatus::DeliveredOne);
260 }
261 Ok(RecvStatus::TimedOut)
262 }
263 }
264
265 impl IsoTpAsyncEndpoint for Dummy {
266 type Error = ();
267
268 async fn send_to(
269 &mut self,
270 to: u8,
271 payload: &[u8],
272 timeout: Duration,
273 ) -> Result<(), SendError<Self::Error>> {
274 IsoTpEndpoint::send_to(self, to, payload, timeout)
275 }
276
277 async fn send_functional_to(
278 &mut self,
279 functional_to: u8,
280 payload: &[u8],
281 timeout: Duration,
282 ) -> Result<(), SendError<Self::Error>> {
283 IsoTpEndpoint::send_functional_to(self, functional_to, payload, timeout)
284 }
285
286 async fn recv_one<Cb>(
287 &mut self,
288 timeout: Duration,
289 on_payload: Cb,
290 ) -> Result<RecvStatus, RecvError<Self::Error>>
291 where
292 Cb: FnMut(RecvMeta, &[u8]) -> Result<RecvControl, Self::Error>,
293 {
294 IsoTpEndpoint::recv_one(self, timeout, on_payload)
295 }
296 }
297
298 impl IsoTpAsyncEndpointRecvInto for Dummy {
299 type Error = ();
300
301 async fn recv_one_into(
302 &mut self,
303 _timeout: Duration,
304 out: &mut [u8],
305 ) -> Result<RecvMetaIntoStatus, RecvError<Self::Error>> {
306 if let Some((reply_to, data)) = self.inbox.pop() {
307 if data.len() > out.len() {
308 return Err(RecvError::BufferTooSmall {
309 needed: data.len(),
310 got: out.len(),
311 });
312 }
313 out[..data.len()].copy_from_slice(&data);
314 return Ok(RecvMetaIntoStatus::DeliveredOne {
315 meta: RecvMeta { reply_to },
316 len: data.len(),
317 });
318 }
319 Ok(RecvMetaIntoStatus::TimedOut)
320 }
321 }
322
323 #[test]
324 fn sync_trait_is_addressed() {
325 let mut d = Dummy::default();
326 IsoTpEndpoint::send_to(&mut d, 0x33, b"abc", Duration::from_millis(1)).unwrap();
327 assert_eq!(d.sent_to, vec![0x33]);
328 assert_eq!(d.sent_payloads, vec![b"abc".to_vec()]);
329 }
330
331 #[test]
332 fn async_trait_is_addressed() {
333 let mut d = Dummy::default();
334 block_on(IsoTpAsyncEndpoint::send_to(
335 &mut d,
336 0x44,
337 b"xyz",
338 Duration::from_millis(1),
339 ))
340 .unwrap();
341 assert_eq!(d.sent_to, vec![0x44]);
342 assert_eq!(d.sent_payloads, vec![b"xyz".to_vec()]);
343 }
344}