1mod backend;
2pub mod dbc;
3
4use crate::sim::types::SimCanFrame;
5use crate::sim::types::{
6 CAN_FLAG_BRS, CAN_FLAG_ESI, CAN_FLAG_EXTENDED, CAN_FLAG_FD, CAN_FLAG_RESERVED_MASK,
7 CAN_FLAG_RTR,
8};
9
10#[derive(Debug)]
11pub struct CanSocket {
12 inner: backend::PlatformCanSocket,
13}
14
15impl CanSocket {
16 pub fn open(
17 iface: &str,
18 bitrate: u32,
19 bitrate_data: u32,
20 fd_capable: bool,
21 ) -> Result<Self, String> {
22 Ok(Self {
23 inner: backend::PlatformCanSocket::open(iface, bitrate, bitrate_data, fd_capable)?,
24 })
25 }
26
27 pub fn iface(&self) -> &str {
28 self.inner.iface()
29 }
30
31 pub fn recv_all(&self) -> Result<Vec<SimCanFrame>, String> {
32 self.inner.recv_all()
33 }
34
35 pub fn send(&self, frame: &SimCanFrame) -> Result<(), String> {
36 self.inner.send(frame)
37 }
38}
39
40pub fn parse_data_hex(raw: &str) -> Result<Vec<u8>, String> {
41 let compact = raw
42 .chars()
43 .filter(|ch| !ch.is_whitespace() && *ch != '_')
44 .collect::<String>();
45 if compact.len() % 2 != 0 {
46 return Err(format!(
47 "invalid CAN payload hex '{raw}': expected an even number of hex characters"
48 ));
49 }
50 if compact.len() / 2 > 64 {
51 return Err(format!(
52 "invalid CAN payload hex '{raw}': payload exceeds 64 bytes"
53 ));
54 }
55 let mut payload = Vec::with_capacity(compact.len() / 2);
56 let bytes = compact.as_bytes();
57 let mut idx = 0;
58 while idx < bytes.len() {
59 let pair = format!("{}{}", bytes[idx] as char, bytes[idx + 1] as char);
60 let value = u8::from_str_radix(&pair, 16)
61 .map_err(|_| format!("invalid CAN payload hex '{raw}': bad byte '{pair}'"))?;
62 payload.push(value);
63 idx += 2;
64 }
65 Ok(payload)
66}
67
68pub fn validate_frame(bus_name: &str, fd_capable: bool, frame: &SimCanFrame) -> Result<(), String> {
69 if (frame.flags & CAN_FLAG_RESERVED_MASK) != 0 {
70 return Err(format!(
71 "CAN frame for bus '{}' has reserved flag bits set",
72 bus_name
73 ));
74 }
75 if (frame.flags & CAN_FLAG_EXTENDED) != 0 {
76 if frame.arb_id > 0x1FFF_FFFF {
77 return Err(format!(
78 "CAN frame for bus '{}' has invalid extended arbitration id 0x{:X}",
79 bus_name, frame.arb_id
80 ));
81 }
82 } else if frame.arb_id > 0x7FF {
83 return Err(format!(
84 "CAN frame for bus '{}' has invalid standard arbitration id 0x{:X}",
85 bus_name, frame.arb_id
86 ));
87 }
88 if frame.len > 64 {
89 return Err(format!(
90 "CAN frame for bus '{}' has invalid payload length {}",
91 bus_name, frame.len
92 ));
93 }
94
95 let fd_requested =
96 (frame.flags & CAN_FLAG_FD) != 0 || (frame.flags & (CAN_FLAG_BRS | CAN_FLAG_ESI)) != 0;
97 if fd_requested {
98 if !fd_capable {
99 return Err(format!(
100 "CAN bus '{}' is classic-only and cannot carry FD frames",
101 bus_name
102 ));
103 }
104 if !matches!(frame.len, 0..=8 | 12 | 16 | 20 | 24 | 32 | 48 | 64) {
105 return Err(format!(
106 "CAN FD frame for bus '{}' has invalid length {}; valid lengths are 0-8,12,16,20,24,32,48,64",
107 bus_name, frame.len
108 ));
109 }
110 if (frame.flags & CAN_FLAG_RTR) != 0 {
111 return Err(format!(
112 "CAN FD frame for bus '{}' cannot set RTR flag",
113 bus_name
114 ));
115 }
116 } else if frame.len > 8 {
117 return Err(format!(
118 "classic CAN frame for bus '{}' has invalid length {}",
119 bus_name, frame.len
120 ));
121 }
122
123 Ok(())
124}