pub mod constant;
pub mod error;
pub mod can;
pub mod device;
use std::fmt::{Debug, Display, Formatter};
use std::sync::atomic::{AtomicU8, Ordering};
use bitflags::bitflags;
use crate::constant::MAX_ST_MIN;
use crate::error::Error;
bitflags! {
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub struct IsoTpState: u8 {
const Idle = 0b0000_0000;
#[deprecated]
const WaitSingle = 0b0000_0001;
#[deprecated]
const WaitFirst = 0b0000_0010;
const WaitFlowCtrl = 0b0000_0100;
#[deprecated]
const WaitData = 0b0000_1000;
const WaitBusy = 0b0001_0000;
#[deprecated]
const ResponsePending = 0b0010_0000;
const Sending = 0b0100_0000;
const Error = 0b1000_0000;
}
}
impl Display for IsoTpState {
#[allow(deprecated)]
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut idle = true;
let mut first = true;
if self.contains(IsoTpState::WaitSingle) {
write!(f, "WaitSingle")?;
idle = false;
first = false;
}
if self.contains(IsoTpState::WaitFirst) {
write!(f, "{}", format!("{}WaitFirst", if first { "" } else { " | " }))?;
idle = false;
first = false;
}
if self.contains(IsoTpState::WaitFlowCtrl) {
write!(f, "{}", format!("{}WaitFlowCtrl", if first { "" } else { " | " }))?;
idle = false;
first = false;
}
if self.contains(IsoTpState::WaitData) {
write!(f, "{}", format!("{}WaitData", if first { "" } else { " | " }))?;
idle = false;
first = false;
}
if self.contains(IsoTpState::WaitBusy) {
write!(f, "{}", format!("{}WaitBusy", if first { "" } else { " | " }))?;
idle = false;
first = false;
}
if self.contains(IsoTpState::ResponsePending) {
write!(f, "{}", format!("{}ResponsePending", if first { "" } else { " | " }))?;
idle = false;
first = false;
}
if self.contains(IsoTpState::Sending) {
write!(f, "{}", format!("{}Sending", if first { "" } else { " | " }))?;
idle = false;
first = false;
}
if self.contains(IsoTpState::Error) {
write!(f, "{}", format!("{}Error", if first { "" } else { " | " }))?;
idle = false;
}
if idle {
write!(f, "Idle")?;
}
Ok(())
}
}
#[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 {
Wait,
FirstFrameReceived,
DataReceived(Vec<u8>),
ErrorOccurred(Error),
}
pub trait IsoTpEventListener {
fn clear_buffer(&mut self);
fn on_iso_tp_event(&mut self, event: IsoTpEvent);
}
#[derive(Debug, Copy, Clone)]
pub enum IsoTpTimeout {
TimeoutAr { timeout_ms: u32 },
TimeoutAs { timeout_ms: u32 },
TimeoutBr { timeout_ms: u32 },
TimeoutBs { timeout_ms: u32 },
TimeoutCr { timeout_ms: u32 },
TimeoutCs { timeout_ms: u32 },
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum FrameType {
Single = 0x00,
First = 0x10,
Consecutive = 0x20,
FlowControl = 0x30,
}
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, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum FlowControlState {
#[default]
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))),
}
}
}
impl Into<u8> for FlowControlState {
#[inline]
fn into(self) -> u8 {
self as u8
}
}
#[derive(Debug, Default, Copy, Clone)]
pub struct FlowControlContext {
state: FlowControlState,
block_size: u8,
st_min: u8,
}
impl FlowControlContext {
#[inline]
pub fn new(
state: FlowControlState,
block_size: u8,
st_min: u8,
) -> Self {
match st_min {
0x80..=0xF0 |
0xFA..=0xFF => {
log::warn!("ISO-TP - invalid st_min: {}, set to default 127ms", st_min);
Self { state, block_size, st_min: MAX_ST_MIN }
},
v => Self { state, block_size, st_min: v }
}
}
#[inline]
pub fn state(&self) -> FlowControlState {
self.state
}
#[inline]
pub fn block_size(&self) -> u8 {
self.block_size
}
#[inline]
pub fn st_min(&self) -> u8 {
self.st_min
}
#[inline]
pub fn st_min_us(&self) -> u32 {
match self.st_min {
0x00 => 1000 * 10,
..=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,
}
}
}
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
pub enum ByteOrder {
Big,
#[default]
Little,
Native,
}
pub trait IsoTpFrame: Send {
fn decode<T: AsRef<[u8]>>(data: T) -> Result<Self, Error>
where
Self: Sized;
fn encode(self, padding: Option<u8>) -> Vec<u8>;
fn from_data<T: AsRef<[u8]>>(data: T) -> Result<Vec<Self>, Error>
where
Self: Sized;
fn single_frame<T: AsRef<[u8]>>(data: T) -> Result<Self, Error>
where
Self: Sized;
fn flow_ctrl_frame(state: FlowControlState, block_size: u8, st_min: u8) -> Self
where
Self: Sized;
#[inline]
fn default_flow_ctrl_frame() -> Self
where
Self: Sized
{
Self::flow_ctrl_frame(FlowControlState::Continues, 0x00, 10)
}
}