Skip to main content

agent_sim/can/
mod.rs

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}