isotp_rs/
lib.rs

1pub mod constant;
2pub mod error;
3pub mod can;
4pub mod device;
5
6use std::fmt::{Debug, Display, Formatter};
7use std::sync::atomic::{AtomicU8, Ordering};
8use bitflags::bitflags;
9use crate::error::Error;
10
11bitflags! {
12    /// ISO-TP state.
13    #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
14    pub struct IsoTpState: u8 {
15        const Idle = 0b0000_0000;
16        #[deprecated]
17        const WaitSingle = 0b0000_0001;
18        #[deprecated]
19        const WaitFirst = 0b0000_0010;
20        const WaitFlowCtrl = 0b0000_0100;
21        #[deprecated]
22        const WaitData = 0b0000_1000;
23        const WaitBusy = 0b0001_0000;
24        #[deprecated]
25        const ResponsePending = 0b0010_0000;
26        const Sending = 0b0100_0000;
27        const Error = 0b1000_0000;
28    }
29}
30
31impl Display for IsoTpState {
32    #[allow(deprecated)]
33    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
34        let mut idle = true;
35        let mut first = true;
36        if self.contains(IsoTpState::WaitSingle) {
37            write!(f, "WaitSingle")?;
38            idle = false;
39            first = false;
40        }
41        if self.contains(IsoTpState::WaitFirst) {
42            write!(f, "{}", format!("{}WaitFirst", if first { "" } else { " | " }))?;
43            idle = false;
44            first = false;
45        }
46        if self.contains(IsoTpState::WaitFlowCtrl) {
47            write!(f, "{}", format!("{}WaitFlowCtrl", if first { "" } else { " | " }))?;
48            idle = false;
49            first = false;
50        }
51        if self.contains(IsoTpState::WaitData) {
52            write!(f, "{}", format!("{}WaitData", if first { "" } else { " | " }))?;
53            idle = false;
54            first = false;
55        }
56        if self.contains(IsoTpState::WaitBusy) {
57            write!(f, "{}", format!("{}WaitBusy", if first { "" } else { " | " }))?;
58            idle = false;
59            first = false;
60        }
61        if self.contains(IsoTpState::ResponsePending) {
62            write!(f, "{}", format!("{}ResponsePending", if first { "" } else { " | " }))?;
63            idle = false;
64            first = false;
65        }
66        if self.contains(IsoTpState::Sending) {
67            write!(f, "{}", format!("{}Sending", if first { "" } else { " | " }))?;
68            idle = false;
69            first = false;
70        }
71        if self.contains(IsoTpState::Error) {
72            write!(f, "{}", format!("{}Error", if first { "" } else { " | " }))?;
73            idle = false;
74        }
75        if idle {
76            write!(f, "Idle")?;
77        }
78
79        Ok(())
80    }
81}
82
83/// A wrapper around `AtomicU8` for `IsoTpState` with atomic operations.
84#[derive(Debug)]
85pub struct AtomicState(AtomicU8);
86
87impl Default for AtomicState {
88    fn default() -> Self {
89        Self(AtomicU8::from(IsoTpState::Idle.bits()))
90    }
91}
92
93impl AtomicState {
94    /// Creates a new `AtomicState` with the initial state.
95    pub fn new(state: IsoTpState) -> Self {
96        Self(AtomicU8::new(state.bits()))
97    }
98
99    /// Loads the current state.
100    #[inline]
101    pub fn load(&self, order: Ordering) -> IsoTpState {
102        IsoTpState::from_bits_truncate(self.0.load(order))
103    }
104
105    /// Stores a new state.
106    #[inline]
107    pub fn store(&self, state: IsoTpState, order: Ordering) {
108        self.0.store(state.bits(), order);
109    }
110
111    /// Updates the state using the provided function.
112    pub fn fetch_update(&self,
113                        set_order: Ordering,
114                        fetch_order: Ordering,
115                        mut f: impl FnMut(IsoTpState) -> Option<IsoTpState>,
116    ) -> Result<IsoTpState, IsoTpState> {
117        let mut prev = self.load(fetch_order);
118        while let Some(next) = f(prev) {
119            match self.0.compare_exchange_weak(prev.bits(), next.bits(), set_order, fetch_order) {
120                Ok(_) => return Ok(next),
121                Err(next_prev) => prev = IsoTpState::from_bits_truncate(next_prev),
122            }
123        }
124        Err(prev)
125    }
126
127    /// Performs an atomic addition of flags to the current state.
128    #[inline]
129    pub fn fetch_add(&self,
130                     flags: IsoTpState,
131                     success: Ordering,
132                     failure: Ordering,
133    ) -> Result<IsoTpState, IsoTpState> {
134        self.fetch_update(success, failure, |state| Some(state | flags))
135    }
136
137    /// Performs an atomic removal of flags from the current state.
138    #[inline]
139    pub fn fetch_remove(&self,
140                        flags: IsoTpState,
141                        success: Ordering,
142                        failure: Ordering,
143    ) -> Result<IsoTpState, IsoTpState> {
144        self.fetch_update(success, failure, |state| Some(state & !flags))
145    }
146}
147
148#[derive(Debug, Clone)]
149pub enum IsoTpEvent {
150    Wait,
151    FirstFrameReceived,
152    DataReceived(Vec<u8>),
153    ErrorOccurred(Error),
154}
155
156pub trait IsoTpEventListener {
157    fn from_buffer(&mut self) -> Option<IsoTpEvent>;
158    fn clear_buffer(&mut self);
159    fn on_iso_tp_event(&mut self, event: IsoTpEvent);
160}
161
162/// ISO-TP timeout type define.
163/// The unit of value is ms.
164#[derive(Debug, Copy, Clone)]
165pub enum IsoTpTimeout {
166    TimeoutAr { timeout_ms: u32 },
167    TimeoutAs { timeout_ms: u32 },
168    TimeoutBr { timeout_ms: u32 },
169    TimeoutBs { timeout_ms: u32 },
170    TimeoutCr { timeout_ms: u32 },
171    TimeoutCs { timeout_ms: u32 },
172}
173
174/// ISO-TP frame type define.
175#[repr(u8)]
176#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
177pub enum FrameType {
178    /// | - data length -| - N_PCI bytes - | - note - |
179    ///
180    /// | -     le 8   - | -  bit0(3~0) = length  - | - std2004 - |
181    ///
182    /// | -     gt 8    - | -  bit0(3~0) = 0; bit1(7~0) = length  - | - std2016 - |
183    Single = 0x00,
184    /// | - data length -| - N_PCI bytes - | - note - |
185    ///
186    /// | -  le 4095   - | - bit0(3~0) + bit1(7~0) = length - | - std2004 - |
187    ///
188    /// | -  gt 4095   - | - bit0(3~0) + bit1(7~0) = 0; byte2~5(7~0) = length - | - std2016 - |
189    First = 0x10,
190    Consecutive = 0x20,
191    FlowControl = 0x30,
192}
193
194impl Into<u8> for FrameType {
195    #[inline]
196    fn into(self) -> u8 {
197        self as u8
198    }
199}
200
201impl TryFrom<u8> for FrameType {
202    type Error = Error;
203    #[inline]
204    fn try_from(value: u8) -> Result<Self, Self::Error> {
205        match value & 0xF0 {
206            0x00 => Ok(Self::Single),
207            0x10 => Ok(Self::First),
208            0x20 => Ok(Self::Consecutive),
209            0x30 => Ok(Self::FlowControl),
210            v => Err(Error::InvalidParam(format!("`frame type`({})", v))),
211        }
212    }
213}
214
215/// Flow control type define.
216#[repr(u8)]
217#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
218pub enum FlowControlState {
219    #[default]
220    Continues = 0x00,
221    Wait = 0x01,
222    Overload = 0x02,
223}
224
225impl TryFrom<u8> for FlowControlState {
226    type Error = Error;
227    fn try_from(value: u8) -> Result<Self, Self::Error> {
228        match value {
229            0x00 => Ok(Self::Continues),
230            0x01 => Ok(Self::Wait),
231            0x02 => Ok(Self::Overload),
232            v => Err(Error::InvalidParam(format!("`state` ({})", v))),
233        }
234    }
235}
236
237impl Into<u8> for FlowControlState {
238    #[inline]
239    fn into(self) -> u8 {
240        self as u8
241    }
242}
243
244/// Flow control frame context.
245#[derive(Debug, Default, Copy, Clone)]
246pub struct FlowControlContext {
247    state: FlowControlState,
248    block_size: u8,
249    /// Use milliseconds (ms) for values in the range 00 to 7F (0 ms to 127 ms).
250    /// If st_min is 0, set to default value. See [`constant::ST_MIN_ISO15765_2`]
251    /// and [`constant::ST_MIN_ISO15765_4`]
252    ///
253    /// Use microseconds (μs) for values in the range F1 to F9 (100 μs to 900 μs).
254    ///
255    /// Values in the ranges 80 to F0 and FA to FF are reserved.
256    st_min: u8,
257}
258
259impl FlowControlContext {
260    #[inline]
261    pub fn new(
262        state: FlowControlState,
263        block_size: u8,
264        st_min: u8,
265    ) -> Result<Self, Error> {
266        match st_min {
267            0x80..=0xF0 |
268            0xFA..=0xFF => Err(Error::InvalidStMin(st_min)),
269            v => Ok(Self { state, block_size, st_min: v }),
270        }
271    }
272    #[inline]
273    pub fn state(&self) -> FlowControlState {
274        self.state
275    }
276    #[inline]
277    pub fn block_size(&self) -> u8 {
278        self.block_size
279    }
280    #[inline]
281    pub fn st_min(&self) -> u8 {
282        self.st_min
283    }
284    #[inline]
285    pub fn st_min_us(&self) -> u32 {
286        match self.st_min {
287            // 0x00 => 1000 * 10,
288            ..=0x7F => 1000 * (self.st_min as u32),
289            0x80..=0xF0 |
290            0xFA..=0xFF => {
291                // should not enter
292                let message = format!("ISO-TP: got an invalid st_min: {}", self.st_min);
293                log::error!("{}" ,message);
294                panic!("{}", message)   // panic is dangerous
295            },
296            0xF1..=0xF9 => 100 * (self.st_min & 0x0F) as u32,
297        }
298    }
299}
300
301/// byte order define.
302#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
303pub enum ByteOrder {
304    /// Motorola byte order
305    Big,
306    /// Intel byte order
307    #[default]
308    Little,
309    /// The native byte order depends on your CPU
310    Native,
311}
312
313/// ISO-TP frame trait define.
314pub trait IsoTpFrame: Send {
315    /// Decode frame from origin data like `02 10 01`.
316    ///
317    /// # Parameters
318    ///
319    /// * `data` - the source data.
320    ///
321    /// # Return
322    ///
323    /// A struct that implements [`IsoTpFrame`] if parameters are valid.
324    fn decode<T: AsRef<[u8]>>(data: T) -> Result<Self, Error>
325    where
326        Self: Sized;
327    /// Encode frame to data.
328    ///
329    /// # Parameters
330    ///
331    /// * `padding` - the padding value when the length of return value is insufficient.
332    ///
333    /// # Returns
334    ///
335    /// The encoded data.
336    fn encode(self, padding: Option<u8>) -> Vec<u8>;
337    /// Encoding full multi-frame from original data.
338    ///
339    /// # Parameters
340    ///
341    /// * `data` - original data
342    ///
343    /// * `flow_ctrl` - the flow control context(added one default)
344    ///
345    /// # Returns
346    ///
347    /// The frames contain either a `SingleFrame` or a multi-frame sequence starting
348    ///
349    /// with a `FirstFrame` and followed by at least one `FlowControlFrame`.
350    fn from_data<T: AsRef<[u8]>>(data: T) -> Result<Vec<Self>, Error>
351    where
352        Self: Sized;
353
354    /// New single frame from data.
355    ///
356    /// * `data` - the single frame data
357    ///
358    /// # Returns
359    ///
360    /// A new `SingleFrame` if parameters are valid.
361    fn single_frame<T: AsRef<[u8]>>(data: T) -> Result<Self, Error>
362    where
363        Self: Sized;
364    /// New flow control frame from data.
365    ///
366    /// # Parameters
367    ///
368    /// * `state` - [`FlowControlState`]
369    /// * `block_size` - the block size
370    /// * `st_min` - separation time minimum
371    ///
372    /// # Returns
373    ///
374    /// A new `FlowControlFrame` if parameters are valid.
375    fn flow_ctrl_frame(state: FlowControlState, block_size: u8, st_min: u8) -> Result<Self, Error>
376    where
377        Self: Sized;
378
379    #[inline]
380    fn default_flow_ctrl_frame() -> Self
381    where
382        Self: Sized
383    {
384        Self::flow_ctrl_frame(FlowControlState::Continues, 0x00, 10)
385            .unwrap()
386    }
387}