1use crate::constants::{
2 BRS_FLAG, CAN_FD_MAX_DLC, CAN_FD_MIN_LEN, DLC_OFFSET, EDL_FLAG, EFF_FLAG, ERR_FLAG, ESI_FLAG,
3 EXT_ID_MASK, FLAGS_OFFSET, RRS_FLAG, STD_ID_MASK,
4};
5use crate::isotp::address::IsoTpAddressingMode;
6use crate::{constants::DATA_OFFSET, error::CanError};
7use ace_proto::can::frame::fd::{CanFdFrame, CanFdFrameMut};
8
9pub fn dlc_to_len(dlc: u8) -> usize {
31 match dlc {
32 0..=8 => dlc as usize,
33 9 => 12,
34 10 => 16,
35 11 => 20,
36 12 => 24,
37 13 => 32,
38 14 => 48,
39 15 => 64,
40 _ => 64,
41 }
42}
43
44pub fn len_to_dlc(len: usize) -> Option<u8> {
46 match len {
47 0..=8 => Some(len as u8),
48 9..=12 => Some(9),
49 13..=16 => Some(10),
50 17..=20 => Some(11),
51 21..=24 => Some(12),
52 25..=32 => Some(13),
53 33..=48 => Some(14),
54 49..=64 => Some(15),
55 _ => None,
56 }
57}
58
59pub trait CanFdFrameExt {
64 fn as_bytes(&self) -> &[u8];
65
66 fn id_word(&self) -> Option<u32> {
69 let b = self.as_bytes();
70 if b.len() < DATA_OFFSET {
71 return None;
72 }
73 Some(u32::from_be_bytes([b[0], b[1], b[2], b[3]]))
74 }
75
76 fn flags_byte(&self) -> Option<u8> {
77 self.as_bytes().get(FLAGS_OFFSET).copied()
78 }
79
80 fn dlc(&self) -> Option<u8> {
81 self.as_bytes().get(DLC_OFFSET).copied()
82 }
83
84 fn data_bytes(&self) -> Option<&[u8]> {
85 let b = self.as_bytes();
86 let dlc = self.dlc()?;
87 let len = dlc_to_len(dlc);
88 let end = DATA_OFFSET + len;
89 if b.len() < end {
90 return None;
91 }
92 Some(&b[DATA_OFFSET..end])
93 }
94
95 fn is_extended_frame(&self) -> bool {
100 self.id_word().map_or(false, |w| w & EFF_FLAG != 0)
101 }
102
103 fn is_rrs(&self) -> bool {
104 self.id_word().map_or(false, |w| w & RRS_FLAG != 0)
105 }
106
107 fn is_error_frame(&self) -> bool {
108 self.id_word().map_or(false, |w| w & ERR_FLAG != 0)
109 }
110
111 fn is_edl(&self) -> bool {
112 self.flags_byte().map_or(false, |f| f & EDL_FLAG != 0)
113 }
114
115 fn is_brs(&self) -> bool {
116 self.flags_byte().map_or(false, |f| f & BRS_FLAG != 0)
117 }
118
119 fn is_esi(&self) -> bool {
120 self.flags_byte().map_or(false, |f| f & ESI_FLAG != 0)
121 }
122
123 fn can_id(&self) -> Option<Result<ace_proto::can::id::CanId, CanError>> {
128 let word = self.id_word()?;
129 if word & EFF_FLAG != 0 {
130 let raw = word & EXT_ID_MASK;
131 Some(
132 ace_proto::can::id::ExtendedCanId::new(raw)
133 .map(ace_proto::can::id::CanId::Extended)
134 .map_err(CanError::from),
135 )
136 } else {
137 let raw = (word & STD_ID_MASK) as u16;
138 Some(
139 ace_proto::can::id::StandardCanId::new(raw)
140 .map(ace_proto::can::id::CanId::Standard)
141 .map_err(CanError::from),
142 )
143 }
144 }
145
146 fn validate(&self) -> Result<(), CanError> {
151 let b = self.as_bytes();
152
153 if b.len() < CAN_FD_MIN_LEN {
154 return Err(CanError::BufferTooShort {
155 expected: CAN_FD_MIN_LEN,
156 actual: b.len(),
157 });
158 }
159
160 let flags = b[FLAGS_OFFSET];
161
162 if flags & EDL_FLAG == 0 {
164 return Err(CanError::InvalidFlags);
165 }
166
167 if flags & ESI_FLAG != 0 && flags & EDL_FLAG == 0 {
169 return Err(CanError::InvalidFlags);
170 }
171
172 let word = u32::from_be_bytes([b[0], b[1], b[2], b[3]]);
174 if word & RRS_FLAG != 0 {
175 return Err(CanError::InvalidFlags);
176 }
177
178 let dlc = b[DLC_OFFSET];
179 if dlc > CAN_FD_MAX_DLC {
180 return Err(CanError::InvalidDlc(dlc));
181 }
182
183 let expected_len = DATA_OFFSET + dlc_to_len(dlc);
184 if b.len() < expected_len {
185 return Err(CanError::BufferTooShort {
186 expected: expected_len,
187 actual: b.len(),
188 });
189 }
190
191 Ok(())
192 }
193
194 fn is_valid(&self) -> bool {
195 self.validate().is_ok()
196 }
197
198 fn isotp_bytes(&self, mode: &IsoTpAddressingMode) -> Option<&[u8]> {
203 let data = self.data_bytes()?;
204 let offset = mode.pci_offset();
205 if data.len() <= offset {
206 return None;
207 }
208 Some(&data[offset..])
209 }
210
211 }
213
214impl<'a> CanFdFrameExt for CanFdFrame<'a> {
215 fn as_bytes(&self) -> &[u8] {
216 ace_proto::common::RawFrame::as_bytes(self)
217 }
218}
219
220impl<'a> CanFdFrameExt for CanFdFrameMut<'a> {
221 fn as_bytes(&self) -> &[u8] {
222 ace_proto::common::RawFrame::as_bytes(self)
223 }
224}
225
226pub trait CanFdFrameMutExt: CanFdFrameExt {
231 fn as_bytes_mut(&mut self) -> &mut [u8];
232
233 fn set_id_word(&mut self, word: u32) -> Result<(), CanError> {
234 let b = self.as_bytes_mut();
235 if b.len() < DATA_OFFSET {
236 return Err(CanError::BufferTooShort {
237 expected: DATA_OFFSET,
238 actual: b.len(),
239 });
240 }
241 b[0..4].copy_from_slice(&word.to_be_bytes());
242 Ok(())
243 }
244
245 fn set_standard_id(&mut self, id: &ace_proto::can::id::StandardCanId) -> Result<(), CanError> {
246 let word = id.value() as u32 & STD_ID_MASK;
247 self.set_id_word(word)
248 }
249
250 fn set_extended_id(&mut self, id: &ace_proto::can::id::ExtendedCanId) -> Result<(), CanError> {
251 let word = (id.value() & EXT_ID_MASK) | EFF_FLAG;
252 self.set_id_word(word)
253 }
254
255 fn set_flags(&mut self, edl: bool, brs: bool, esi: bool) -> Result<(), CanError> {
256 let b = self.as_bytes_mut();
257 if b.len() <= FLAGS_OFFSET {
258 return Err(CanError::BufferTooShort {
259 expected: FLAGS_OFFSET + 1,
260 actual: b.len(),
261 });
262 }
263 let mut flags = EDL_FLAG; if brs {
265 flags |= BRS_FLAG;
266 }
267 if esi {
268 flags |= ESI_FLAG;
269 }
270 if !edl {
271 return Err(CanError::InvalidFlags);
272 }
273 b[FLAGS_OFFSET] = flags;
274 Ok(())
275 }
276
277 fn set_dlc(&mut self, dlc: u8) -> Result<(), CanError> {
278 if dlc > CAN_FD_MAX_DLC {
279 return Err(CanError::InvalidDlc(dlc));
280 }
281 let b = self.as_bytes_mut();
282 if b.len() <= DLC_OFFSET {
283 return Err(CanError::BufferTooShort {
284 expected: DLC_OFFSET + 1,
285 actual: b.len(),
286 });
287 }
288 b[DLC_OFFSET] = dlc;
289 Ok(())
290 }
291
292 fn write_data(&mut self, data: &[u8]) -> Result<(), CanError> {
293 let dlc = len_to_dlc(data.len()).ok_or(CanError::InvalidDlc(data.len() as u8))?;
294 let b = self.as_bytes_mut();
295 let end = DATA_OFFSET + data.len();
296 if b.len() < end {
297 return Err(CanError::BufferTooShort {
298 expected: end,
299 actual: b.len(),
300 });
301 }
302 b[DATA_OFFSET..DATA_OFFSET + data.len()].copy_from_slice(data);
303 b[DLC_OFFSET] = dlc;
304 Ok(())
305 }
306}
307
308impl<'a> CanFdFrameMutExt for CanFdFrameMut<'a> {
309 fn as_bytes_mut(&mut self) -> &mut [u8] {
310 ace_proto::common::RawFrameMut::as_bytes_mut(self)
311 }
312}
313
314