1pub(crate) mod identifier;
2
3use self::identifier::{CanFdFlags, Id};
4use crate::utils;
5use crate::CanResult;
6use std::fmt::{Display, Formatter, Write};
7
8#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
9pub enum TimestampSource {
10 System,
11 Hardware,
12 #[default]
13 Unknown,
14}
15
16#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
17pub struct Timestamp {
18 pub nanos: u128,
19 pub source: TimestampSource,
20}
21
22#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
23pub enum FrameFormat {
24 #[default]
25 Data,
26 Remote,
27 Error,
28}
29
30#[repr(C)]
31#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
32pub enum Kind {
33 #[default]
34 Classical,
35 FD,
36 XL,
37}
38
39#[repr(C)]
40#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
41pub enum Direction {
42 #[default]
43 Transmit,
44 Receive,
45}
46
47impl Display for Direction {
48 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
49 match self {
50 Self::Transmit => f.write_str("Tx"),
51 Self::Receive => f.write_str("Rx"),
52 }
53 }
54}
55
56pub trait Frame: Send + Sync {
58 type Channel: Display;
59
60 fn new_can(id: Id, data: &[u8]) -> CanResult<Self>
61 where
62 Self: Sized;
63
64 fn new_remote(id: Id, dlc: u8) -> CanResult<Self>
65 where
66 Self: Sized;
67
68 fn new_can_fd(id: Id, data: &[u8], flags: CanFdFlags) -> CanResult<Self>
69 where
70 Self: Sized;
71
72 fn id(&self) -> Id;
73 fn channel(&self) -> Self::Channel;
74 fn set_channel(&mut self, v: Self::Channel) -> &mut Self
75 where
76 Self: Sized;
77
78 fn kind(&self) -> Kind;
79 fn format(&self) -> FrameFormat;
80
81 fn data(&self) -> &[u8];
82 fn len(&self) -> usize;
83 fn dlc(&self) -> CanResult<u8> {
84 utils::can_dlc(self.len(), self.kind())
85 }
86
87 fn direction(&self) -> Direction;
88 fn set_direction(&mut self, d: Direction) -> &mut Self
89 where
90 Self: Sized;
91
92 fn timestamp(&self) -> Option<Timestamp>;
93 fn set_timestamp(&mut self, ts: Option<Timestamp>) -> &mut Self
94 where
95 Self: Sized;
96
97 fn is_bitrate_switch(&self) -> bool;
98 fn set_bitrate_switch(&mut self, v: bool) -> &mut Self
99 where
100 Self: Sized;
101
102 fn is_remote(&self) -> bool {
103 matches!(self.format(), FrameFormat::Remote)
104 }
105
106 fn is_error_frame(&self) -> bool {
107 matches!(self.format(), FrameFormat::Error)
108 }
109
110 fn is_extended(&self) -> bool {
111 matches!(self.id(), Id::Extended(_))
112 }
113
114 fn is_esi(&self) -> bool;
115 fn set_esi(&mut self, v: bool) -> &mut Self
116 where
117 Self: Sized;
118}
119
120impl<T: Display> Display for dyn Frame<Channel = T> {
121 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
123 let data_str = if self.is_remote() {
124 " ".to_owned()
125 } else {
126 self.data().iter().fold(String::new(), |mut out, &b| {
127 let _ = write!(out, "{b:02x} ");
128 out
129 })
130 };
131
132 match self.kind() {
133 Kind::Classical => {
134 let timestamp_secs = self
135 .timestamp()
136 .map(|ts| ts.nanos as f64 / 1_000_000_000.)
137 .unwrap_or_default();
138 write!(
139 f,
140 "{:.3} {} {}{: <4} {} {} {} {}",
141 timestamp_secs,
142 self.channel(),
143 format!("{: >8x}", self.id().as_raw()),
144 if self.is_extended() { "x" } else { "" },
145 self.direction(),
146 if self.is_remote() { "r" } else { "d" },
148 format!("{: >2}", self.len()),
149 data_str,
150 )
151 }
152 Kind::FD => {
153 let timestamp_secs = self
154 .timestamp()
155 .map(|ts| ts.nanos as f64 / 1_000_000_000.)
156 .unwrap_or_default();
157 let dlc = self.dlc().map_err(|_| std::fmt::Error)?;
158 let mut flags = 1 << 12;
159 write!(
160 f,
161 "{:.3} CANFD {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}",
162 timestamp_secs,
163 self.channel(),
164 self.direction(),
165 format!("{: >8x}", self.id().as_raw()),
167 if self.is_bitrate_switch() {
168 flags |= 1 << 13;
169 1
170 } else {
171 0
172 },
173 if self.is_esi() {
174 flags |= 1 << 14;
175 1
176 } else {
177 0
178 },
179 format!("{: >2}", dlc),
180 format!("{: >2}", self.len()),
181 data_str,
182 format!("{: >8}", 0), format!("{: <4}", 0), format!("{: >8x}", flags),
185 format!("{: >8}", 0), format!("{: >8}", 0), format!("{: >8}", 0), format!("{: >8}", 0), format!("{: >8}", 0), )
191 }
192 Kind::XL => {
193 write!(f, "CANXL Frame")
195 }
196 }
197 }
198}