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