pub mod constant;
pub mod error;
use std::fmt::{Debug, Display, Formatter};
use std::sync::atomic::{AtomicU8, Ordering};
use bitflags::bitflags;
use crate::error::Error;
bitflags! {
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub struct IsoTpState: u8 {
const Idle = 0b0000_0000;
const WaitSingle = 0b0000_0001;
const WaitFirst = 0b0000_0010;
const WaitFlowCtrl = 0b0000_0100;
const WaitData = 0b0000_1000;
const ResponsePending = 0b0001_0000;
const Sending = 0b0010_0000;
const Error = 0b1000_0000;
}
}
impl Display for IsoTpState {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:08b}", self.bits())
}
}
#[derive(Debug)]
pub struct AtomicState(AtomicU8);
impl Default for AtomicState {
fn default() -> Self {
Self(AtomicU8::from(IsoTpState::Idle.bits()))
}
}
impl AtomicState {
pub fn new(state: IsoTpState) -> Self {
Self(AtomicU8::new(state.bits()))
}
#[inline]
pub fn load(&self, order: Ordering) -> IsoTpState {
IsoTpState::from_bits_truncate(self.0.load(order))
}
#[inline]
pub fn store(&self, state: IsoTpState, order: Ordering) {
self.0.store(state.bits(), order);
}
pub fn fetch_update(&self,
set_order: Ordering,
fetch_order: Ordering,
mut f: impl FnMut(IsoTpState) -> Option<IsoTpState>,
) -> Result<IsoTpState, IsoTpState> {
let mut prev = self.load(fetch_order);
while let Some(next) = f(prev) {
match self.0.compare_exchange_weak(prev.bits(), next.bits(), set_order, fetch_order) {
Ok(_) => return Ok(next),
Err(next_prev) => prev = IsoTpState::from_bits_truncate(next_prev),
}
}
Err(prev)
}
#[inline]
pub fn fetch_add(&self,
flags: IsoTpState,
success: Ordering,
failure: Ordering,
) -> Result<IsoTpState, IsoTpState> {
self.fetch_update(success, failure, |state| Some(state | flags))
}
#[inline]
pub fn fetch_remove(&self,
flags: IsoTpState,
success: Ordering,
failure: Ordering,
) -> Result<IsoTpState, IsoTpState> {
self.fetch_update(success, failure, |state| Some(state & !flags))
}
}
#[derive(Debug, Clone)]
pub enum IsoTpEvent<'a> {
DataReceived(&'a [u8]),
ErrorOccurred(Error),
}
pub trait IsoTpEventListener: Debug {
type Channel;
fn on_iso_tp_event(&self, channel: Self::Channel, event: IsoTpEvent);
}
#[derive(Debug, Copy, Clone)]
pub enum IsoTpTimeout {
TimeoutAr { timeout_us: u32 },
TimeoutAs { timeout_us: u32 },
TimeoutBr { timeout_us: u32 },
TimeoutBs { timeout_us: u32 },
TimeoutCr { timeout_us: u32 },
TimeoutCs { timeout_us: u32 },
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum FrameType {
Single = 0x00,
First = 0x10,
Consecutive = 0x20,
FlowControl = 0x30,
}
impl std::ops::BitOr<u8> for FrameType {
type Output = u8;
#[inline]
fn bitor(self, rhs: u8) -> Self::Output {
let result: u8 = self.into();
result | rhs
}
}
impl Into<u8> for FrameType {
#[inline]
fn into(self) -> u8 {
self as u8
}
}
impl TryFrom<u8> for FrameType {
type Error = Error;
#[inline]
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value & 0xF0 {
0x00 => Ok(Self::Single),
0x10 => Ok(Self::First),
0x20 => Ok(Self::Consecutive),
0x30 => Ok(Self::FlowControl),
v => Err(Error::InvalidParam(format!("`frame type`({})", v))),
}
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum FlowControlState {
Continues = 0x00,
Wait = 0x01,
Overload = 0x02,
}
impl TryFrom<u8> for FlowControlState {
type Error = Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0x00 => Ok(Self::Continues),
0x01 => Ok(Self::Wait),
0x02 => Ok(Self::Overload),
v => Err(Error::InvalidParam(format!("`state` ({})", v))),
}
}
}
#[derive(Debug, Copy, Clone)]
pub struct FlowControlContext {
state: FlowControlState,
st_min: u8,
suppress_positive: bool,
}
impl FlowControlContext {
#[inline]
pub fn new(
state: FlowControlState,
st_min: u8,
suppress_positive: bool,
) -> Result<Self, Error> {
match st_min {
0x80..=0xF0 |
0xFA..=0xFF => Err(Error::InvalidParam(format!("`st_min` value({})", st_min))),
v => Ok(Self { state, st_min: v, suppress_positive, })
}
}
#[inline]
pub fn state(&self) -> FlowControlState {
self.state
}
#[inline]
pub fn suppress_positive(&self) -> bool {
self.suppress_positive
}
#[inline]
pub fn st_min(&self) -> u8 {
self.st_min
}
#[inline]
pub fn st_min_us(&self) -> u32 {
match self.st_min {
..=0x7F => 1000 * (self.st_min as u32),
0x80..=0xF0 |
0xFA..=0xFF => {
let message = format!("ISO-TP: got an invalid st_min: {}", self.st_min);
log::error!("{}" ,message);
panic!("{}", message) },
0xF1..=0xF9 => 100 * (self.st_min & 0x0F) as u32,
}
}
}
pub trait IsoTpFrame: Sized + Send {
fn decode<T: AsRef<[u8]>>(data: T) -> Result<Self, Error>;
fn encode(self, padding: Option<u8>) -> Vec<u8>;
fn from_data<T: AsRef<[u8]>>(
data: T,
flow_ctrl: Vec<FlowControlContext>,
) -> Result<Vec<Self>, Error>;
fn single_frame<T: AsRef<[u8]>>(data: T) -> Result<Self, Error>;
fn flow_ctrl_frame(
state: FlowControlState,
suppress_positive: bool,
st_min: u8,
) -> Result<Self, Error>;
#[inline]
fn default_flow_ctrl_frame() -> Self {
Self::flow_ctrl_frame(FlowControlState::Continues, true, 0)
.expect("ISO-TP: method `flow_ctrl_frame` is invalid")
}
}