pub(crate) mod identifier;
use self::identifier::{CanFdFlags, Id};
use crate::utils;
use crate::CanResult;
use std::fmt::{Display, Formatter, Write};
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum TimestampSource {
System,
Hardware,
#[default]
Unknown,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct Timestamp {
pub nanos: u128,
pub source: TimestampSource,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum FrameFormat {
#[default]
Data,
Remote,
Error,
}
#[repr(C)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Kind {
#[default]
Classical,
FD,
XL,
}
#[repr(C)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Direction {
#[default]
Transmit,
Receive,
}
impl Display for Direction {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Transmit => f.write_str("Tx"),
Self::Receive => f.write_str("Rx"),
}
}
}
pub trait Frame: Send + Sync {
type Channel: Display;
fn new_can(id: Id, data: &[u8]) -> CanResult<Self>
where
Self: Sized;
fn new_remote(id: Id, dlc: u8) -> CanResult<Self>
where
Self: Sized;
fn new_can_fd(id: Id, data: &[u8], flags: CanFdFlags) -> CanResult<Self>
where
Self: Sized;
fn id(&self) -> Id;
fn channel(&self) -> Self::Channel;
fn set_channel(&mut self, v: Self::Channel) -> &mut Self
where
Self: Sized;
fn kind(&self) -> Kind;
fn format(&self) -> FrameFormat;
fn data(&self) -> &[u8];
fn len(&self) -> usize;
fn dlc(&self) -> CanResult<u8> {
utils::can_dlc(self.len(), self.kind())
}
fn direction(&self) -> Direction;
fn set_direction(&mut self, d: Direction) -> &mut Self
where
Self: Sized;
fn timestamp(&self) -> Option<Timestamp>;
fn set_timestamp(&mut self, ts: Option<Timestamp>) -> &mut Self
where
Self: Sized;
fn is_bitrate_switch(&self) -> bool;
fn set_bitrate_switch(&mut self, v: bool) -> &mut Self
where
Self: Sized;
fn is_remote(&self) -> bool {
matches!(self.format(), FrameFormat::Remote)
}
fn is_error_frame(&self) -> bool {
matches!(self.format(), FrameFormat::Error)
}
fn is_extended(&self) -> bool {
matches!(self.id(), Id::Extended(_))
}
fn is_esi(&self) -> bool;
fn set_esi(&mut self, v: bool) -> &mut Self
where
Self: Sized;
}
impl<T: Display> Display for dyn Frame<Channel = T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let data_str = if self.is_remote() {
" ".to_owned()
} else {
self.data().iter().fold(String::new(), |mut out, &b| {
let _ = write!(out, "{b:02x} ");
out
})
};
match self.kind() {
Kind::Classical => {
let timestamp_secs = self
.timestamp()
.map(|ts| ts.nanos as f64 / 1_000_000_000.)
.unwrap_or_default();
write!(
f,
"{:.3} {} {}{: <4} {} {} {} {}",
timestamp_secs,
self.channel(),
format!("{: >8x}", self.id().as_raw()),
if self.is_extended() { "x" } else { "" },
self.direction(),
if self.is_remote() { "r" } else { "d" },
format!("{: >2}", self.len()),
data_str,
)
}
Kind::FD => {
let timestamp_secs = self
.timestamp()
.map(|ts| ts.nanos as f64 / 1_000_000_000.)
.unwrap_or_default();
let dlc = self.dlc().map_err(|_| std::fmt::Error)?;
let mut flags = 1 << 12;
write!(
f,
"{:.3} CANFD {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}",
timestamp_secs,
self.channel(),
self.direction(),
format!("{: >8x}", self.id().as_raw()),
if self.is_bitrate_switch() {
flags |= 1 << 13;
1
} else {
0
},
if self.is_esi() {
flags |= 1 << 14;
1
} else {
0
},
format!("{: >2}", dlc),
format!("{: >2}", self.len()),
data_str,
format!("{: >8}", 0), format!("{: <4}", 0), format!("{: >8x}", flags),
format!("{: >8}", 0), format!("{: >8}", 0), format!("{: >8}", 0), format!("{: >8}", 0), format!("{: >8}", 0), )
}
Kind::XL => {
write!(f, "CANXL Frame")
}
}
}
}