1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct CanBpfFilter {
14 pub can_id: u32,
16 pub mask: u32,
18 pub is_extended: bool,
20 pub inverted: bool,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct CanFrameDto {
27 pub timestamp: f64,
28 pub channel: String,
29 pub can_id: u32,
30 pub is_extended: bool,
31 pub is_fd: bool,
32 pub brs: bool,
33 pub esi: bool,
34 pub dlc: u8,
35 pub data: Vec<u8>,
36}
37
38impl CanFrameDto {
39 #[cfg(target_os = "linux")]
41 fn id_to_u32(id: embedded_can::Id) -> u32 {
42 match id {
43 embedded_can::Id::Standard(id) => id.as_raw() as u32,
44 embedded_can::Id::Extended(id) => id.as_raw(),
45 }
46 }
47
48 #[cfg(target_os = "linux")]
52 pub fn from_any_frame(
53 frame: &socketcan::CanAnyFrame,
54 timestamp: f64,
55 channel: &str,
56 ) -> Option<Self> {
57 use embedded_can::Frame;
59 match frame {
62 socketcan::CanAnyFrame::Normal(data_frame) => Some(Self {
63 timestamp,
64 channel: channel.to_string(),
65 can_id: Self::id_to_u32(data_frame.id()),
66 is_extended: data_frame.is_extended(),
67 is_fd: false,
68 brs: false,
69 esi: false,
70 dlc: data_frame.dlc() as u8,
71 data: data_frame.data().to_vec(),
72 }),
73 socketcan::CanAnyFrame::Remote(_) => None, socketcan::CanAnyFrame::Fd(fd_frame) => Some(Self {
75 timestamp,
76 channel: channel.to_string(),
77 can_id: Self::id_to_u32(fd_frame.id()),
78 is_extended: fd_frame.is_extended(),
79 is_fd: true,
80 brs: fd_frame.is_brs(),
81 esi: fd_frame.is_esi(),
82 dlc: fd_frame.dlc() as u8,
83 data: fd_frame.data().to_vec(),
84 }),
85 socketcan::CanAnyFrame::Error(_) => None, }
87 }
88
89 pub fn from_mdf4(timestamp: f64, channel: String, can_id: u32, dlc: u8, data: Vec<u8>) -> Self {
91 let is_fd = data.len() > 8 || dlc > 8;
92 Self {
93 timestamp,
94 channel,
95 can_id,
96 is_extended: can_id > 0x7FF,
97 is_fd,
98 brs: false, esi: false,
100 dlc,
101 data,
102 }
103 }
104
105 #[allow(dead_code)]
107 pub fn from_mdf4_fd(
108 timestamp: f64,
109 channel: String,
110 can_id: u32,
111 dlc: u8,
112 data: Vec<u8>,
113 brs: bool,
114 esi: bool,
115 ) -> Self {
116 Self {
117 timestamp,
118 channel,
119 can_id,
120 is_extended: can_id > 0x7FF,
121 is_fd: true,
122 brs,
123 esi,
124 dlc,
125 data,
126 }
127 }
128}
129
130#[derive(Debug, Clone, Serialize, Deserialize)]
132pub struct DecodedSignalDto {
133 pub timestamp: f64,
134 pub message_name: String,
135 pub signal_name: String,
136 pub value: f64,
137 pub raw_value: i64,
138 pub unit: String,
139 #[serde(skip_serializing_if = "Option::is_none")]
140 pub description: Option<String>,
141}
142
143impl DecodedSignalDto {
144 pub fn from_dbc_signal(
146 sig: &dbc_rs::DecodedSignal<'_>,
147 timestamp: f64,
148 message_name: &str,
149 ) -> Self {
150 Self {
151 timestamp,
152 message_name: message_name.to_string(),
153 signal_name: sig.name.to_string(),
154 value: sig.value,
155 raw_value: sig.raw_value,
156 unit: sig.unit.unwrap_or("").to_string(),
157 description: sig.description.map(|s| s.to_string()),
158 }
159 }
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize)]
164pub struct DecodeResponse {
165 pub signals: Vec<DecodedSignalDto>,
166 pub errors: Vec<String>,
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize)]
171pub struct CanErrorDto {
172 pub timestamp: f64,
173 pub channel: String,
174 pub error_type: String,
175 pub details: String,
176}
177
178#[cfg(target_os = "linux")]
179impl CanErrorDto {
180 pub fn from_error_frame(
182 frame: socketcan::CanErrorFrame,
183 timestamp: f64,
184 channel: &str,
185 ) -> Self {
186 use socketcan::CanError;
187
188 let error: CanError = frame.into();
190
191 let (error_type, details) = match error {
192 CanError::TransmitTimeout => ("TX Timeout", "Transmit timeout".to_string()),
193 CanError::LostArbitration(bit) => ("Lost Arbitration", format!("at bit {}", bit)),
194 CanError::ControllerProblem(err) => ("Controller", format!("{:?}", err)),
195 CanError::ProtocolViolation { vtype, location } => (
196 "Protocol Violation",
197 format!("{:?} at {:?}", vtype, location),
198 ),
199 CanError::TransceiverError => ("Transceiver", "Transceiver error".to_string()),
200 CanError::NoAck => ("No ACK", "No acknowledgment received".to_string()),
201 CanError::BusOff => ("Bus Off", "Controller is bus-off".to_string()),
202 CanError::BusError => ("Bus Error", "Bus error occurred".to_string()),
203 CanError::Restarted => ("Restarted", "Controller restarted".to_string()),
204 CanError::DecodingFailure(msg) => ("Decode Error", msg.to_string()),
205 CanError::Unknown(code) => ("Unknown", format!("Error code: 0x{:08X}", code)),
206 };
207
208 Self {
209 timestamp,
210 channel: channel.to_string(),
211 error_type: error_type.to_string(),
212 details,
213 }
214 }
215}
216
217#[derive(Debug, Clone, Serialize, Deserialize)]
223pub struct CaptureStatsDto {
224 pub frame_count: u64,
225 pub message_count: u32,
226 pub signal_count: u32,
227 pub frame_rate: f64,
228 pub elapsed_secs: f64,
229 pub capture_file: Option<String>,
230}
231
232#[derive(Debug, Clone, Serialize, Deserialize)]
234pub struct StatsHtml {
235 pub message_count: String,
236 pub frame_count: String,
237 pub frame_rate: String,
238 pub elapsed: String,
239}
240
241#[derive(Debug, Clone, Serialize, Deserialize)]
243pub struct LiveCaptureUpdate {
244 pub stats: CaptureStatsDto,
245 pub messages_html: String,
247 pub signals_html: String,
249 pub frames_html: String,
251 pub errors_html: String,
253 pub stats_html: StatsHtml,
255 pub message_count: u32,
257 pub signal_count: u32,
258 pub frame_count: usize,
259 pub error_count: u32,
260}