1#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
19pub enum Toggle {
20 #[default]
22 Default,
23 ForceOff,
25 ForceOn,
27}
28
29impl core::fmt::Display for Toggle {
30 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
31 match self {
32 Toggle::Default => write!(f, "default"),
33 Toggle::ForceOff => write!(f, "off"),
34 Toggle::ForceOn => write!(f, "on"),
35 }
36 }
37}
38
39#[non_exhaustive]
46#[derive(Clone, PartialEq)]
47pub struct CanFdFrame {
48 pub channel: Option<usize>,
51 pub arbitration_id: u32,
53 pub data: [u8; 64],
55 pub size: u8,
57
58 pub brs: Toggle,
60 pub fdcan_frame: Toggle,
62}
63
64impl Default for CanFdFrame {
65 fn default() -> Self {
66 Self::new()
67 }
68}
69
70impl CanFdFrame {
71 pub const fn new() -> Self {
73 CanFdFrame {
74 channel: None,
75 arbitration_id: 0,
76 data: [0u8; 64],
77 size: 0,
78 brs: Toggle::Default,
79 fdcan_frame: Toggle::Default,
80 }
81 }
82
83 pub fn payload(&self) -> &[u8] {
85 &self.data[..self.size as usize]
86 }
87
88 pub fn payload_mut(&mut self) -> &mut [u8] {
90 &mut self.data[..self.size as usize]
91 }
92
93 pub fn clear_data(&mut self) {
95 self.data = [0u8; 64];
96 self.size = 0;
97 }
98
99 pub fn remaining_capacity(&self) -> usize {
101 64 - self.size as usize
102 }
103
104 pub fn is_empty(&self) -> bool {
106 self.size == 0
107 }
108
109 pub fn brs_enabled(&self) -> bool {
111 matches!(self.brs, Toggle::ForceOn | Toggle::Default)
112 }
113
114 pub fn fdcan_enabled(&self) -> bool {
116 matches!(self.fdcan_frame, Toggle::ForceOn | Toggle::Default)
117 }
118
119 pub fn set_brs(&mut self, enabled: bool) {
121 self.brs = if enabled {
122 Toggle::ForceOn
123 } else {
124 Toggle::ForceOff
125 };
126 }
127
128 pub fn set_fdcan(&mut self, enabled: bool) {
130 self.fdcan_frame = if enabled {
131 Toggle::ForceOn
132 } else {
133 Toggle::ForceOff
134 };
135 }
136
137 pub fn round_up_dlc(size: usize) -> usize {
139 match size {
140 0..=8 => size,
141 9..=12 => 12,
142 13..=16 => 16,
143 17..=20 => 20,
144 21..=24 => 24,
145 25..=32 => 32,
146 33..=48 => 48,
147 _ => 64,
148 }
149 }
150
151 pub fn pad_to_dlc(&mut self) {
153 let on_wire_size = Self::round_up_dlc(self.size as usize);
154 for i in self.size as usize..on_wire_size {
155 self.data[i] = 0x50;
156 }
157 self.size = on_wire_size as u8;
158 }
159}
160
161impl core::fmt::Debug for CanFdFrame {
162 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
163 let (source, destination, _) = parse_arbitration_id(self.arbitration_id);
164 f.debug_struct("CanFdFrame")
165 .field("channel", &self.channel)
166 .field(
167 "arbitration_id",
168 &format_args!("0x{:08x}", self.arbitration_id),
169 )
170 .field("size", &self.size)
171 .field("data", &format_args!("{:02x?}", self.payload()))
172 .field("destination", &destination)
173 .field("source", &source)
174 .finish()
175 }
176}
177
178pub fn calculate_arbitration_id(
202 source: i8,
203 destination: i8,
204 can_prefix: u16,
205 reply_required: bool,
206) -> u32 {
207 let prefix = (can_prefix as u32) << 16;
208 let src = ((source as u8) as u32) << 8;
209 let dest = (destination as u8) as u32;
210 let reply = if reply_required { 0x8000 } else { 0 };
211 prefix | src | dest | reply
212}
213
214pub fn parse_arbitration_id(arb_id: u32) -> (i8, i8, u16) {
230 let source = ((arb_id >> 8) & 0x7F) as i8;
231 let destination = (arb_id & 0xFF) as i8;
232 let can_prefix = ((arb_id >> 16) & 0x1FFF) as u16;
233 (source, destination, can_prefix)
234}
235
236#[cfg(test)]
237mod tests {
238 use super::*;
239
240 #[test]
241 fn test_new_frame() {
242 let frame = CanFdFrame::new();
243 assert_eq!(frame.size, 0);
244 assert_eq!(frame.arbitration_id, 0);
245 assert!(frame.channel.is_none());
246 }
247
248 #[test]
249 fn test_payload() {
250 let mut frame = CanFdFrame::new();
251 frame.data[0] = 0x01;
252 frame.data[1] = 0x02;
253 frame.size = 2;
254
255 assert_eq!(frame.payload(), &[0x01, 0x02]);
256 }
257
258 #[test]
259 fn test_calculate_arbitration_id() {
260 let arb_id = calculate_arbitration_id(0, 1, 0, true);
262 assert_eq!(arb_id, 0x8001);
263
264 let arb_id = calculate_arbitration_id(0, 1, 0, false);
266 assert_eq!(arb_id, 0x0001);
267
268 let arb_id = calculate_arbitration_id(5, 3, 0x10, true);
270 assert_eq!(arb_id, 0x00_10_85_03);
271 }
272
273 #[test]
274 fn test_parse_arbitration_id() {
275 let (source, dest, prefix) = parse_arbitration_id(0x00_10_85_03);
276 assert_eq!(source, 5);
277 assert_eq!(dest, 3);
278 assert_eq!(prefix, 0x10);
279 }
280
281 #[test]
282 fn test_arbitration_id_roundtrip() {
283 let arb_id = calculate_arbitration_id(7, 42, 0x1A, true);
284 let (source, dest, prefix) = parse_arbitration_id(arb_id);
285 assert_eq!(source, 7);
286 assert_eq!(dest, 42);
287 assert_eq!(prefix, 0x1A);
288 }
289}