1//! Definition for CAN Frames
2use bit_field::BitField;
3
4use crate::can::enums::FrameCreateError;
5
6/// Calculate proper timestamp when available.
7#[cfg(feature = "time")]
8pub type Timestamp = embassy_time::Instant;
9
10/// Raw register timestamp
11#[cfg(not(feature = "time"))]
12pub type Timestamp = u16;
13
14/// CAN Header, without meta data
15#[derive(Debug, Copy, Clone)]
16pub struct Header {
17 id: embedded_can::Id,
18 len: u8,
19 flags: u8,
20}
21
22#[cfg(feature = "defmt")]
23impl defmt::Format for Header {
24 fn format(&self, fmt: defmt::Formatter<'_>) {
25 match self.id() {
26 embedded_can::Id::Standard(id: &StandardId) => {
27 defmt::write!(fmt, "Can Standard ID={:x} len={}", id.as_raw(), self.len,)
28 }
29 embedded_can::Id::Extended(id: &ExtendedId) => {
30 defmt::write!(fmt, "Can Extended ID={:x} len={}", id.as_raw(), self.len,)
31 }
32 }
33 }
34}
35
36impl Header {
37 const FLAG_RTR: usize = 0; // Remote
38 const FLAG_FDCAN: usize = 1; // FDCan vs Classic CAN
39 const FLAG_BRS: usize = 2; // Bit-rate switching, ignored for Classic CAN
40
41 /// Create new CAN Header
42 pub fn new(id: embedded_can::Id, len: u8, rtr: bool) -> Header {
43 let mut flags = 0u8;
44 flags.set_bit(Self::FLAG_RTR, rtr);
45 Header { id, len, flags }
46 }
47
48 /// Create new CAN FD Header
49 pub fn new_fd(id: embedded_can::Id, len: u8, rtr: bool, brs: bool) -> Header {
50 let mut flags = 0u8;
51 flags.set_bit(Self::FLAG_RTR, rtr);
52 flags.set_bit(Self::FLAG_FDCAN, true);
53 flags.set_bit(Self::FLAG_BRS, brs);
54 Header { id, len, flags }
55 }
56
57 /// Return ID
58 pub fn id(&self) -> &embedded_can::Id {
59 &self.id
60 }
61
62 /// Return length as u8
63 pub fn len(&self) -> u8 {
64 self.len
65 }
66
67 /// Is remote frame
68 pub fn rtr(&self) -> bool {
69 self.flags.get_bit(Self::FLAG_RTR)
70 }
71
72 /// Request/is FDCAN frame
73 pub fn fdcan(&self) -> bool {
74 self.flags.get_bit(Self::FLAG_FDCAN)
75 }
76
77 /// Request/is Flexible Data Rate
78 pub fn bit_rate_switching(&self) -> bool {
79 self.flags.get_bit(Self::FLAG_BRS)
80 }
81
82 /// Get priority of frame
83 pub(crate) fn priority(&self) -> u32 {
84 match self.id() {
85 embedded_can::Id::Standard(id) => (id.as_raw() as u32) << 18,
86 embedded_can::Id::Extended(id) => id.as_raw(),
87 }
88 }
89}
90
91/// Trait for FDCAN frame types, providing ability to construct from a Header
92/// and to retrieve the Header from a frame
93pub trait CanHeader: Sized {
94 /// Construct frame from header and payload
95 fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError>;
96
97 /// Get this frame's header struct
98 fn header(&self) -> &Header;
99}
100
101/// Payload of a classic CAN data frame.
102///
103/// Contains 0 to 8 Bytes of data.
104#[derive(Debug, Copy, Clone)]
105#[cfg_attr(feature = "defmt", derive(defmt::Format))]
106pub struct ClassicData {
107 pub(crate) bytes: [u8; Self::MAX_DATA_LEN],
108}
109
110impl ClassicData {
111 pub(crate) const MAX_DATA_LEN: usize = 8;
112 /// Creates a data payload from a raw byte slice.
113 ///
114 /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
115 /// cannot be represented with an FDCAN DLC.
116 pub fn new(data: &[u8]) -> Result<Self, FrameCreateError> {
117 if data.len() > 8 {
118 return Err(FrameCreateError::InvalidDataLength);
119 }
120
121 let mut bytes = [0; 8];
122 bytes[..data.len()].copy_from_slice(data);
123
124 Ok(Self { bytes })
125 }
126
127 /// Raw read access to data.
128 pub fn raw(&self) -> &[u8] {
129 &self.bytes
130 }
131
132 /// Checks if the length can be encoded in FDCAN DLC field.
133 pub const fn is_valid_len(len: usize) -> bool {
134 match len {
135 0..=8 => true,
136 _ => false,
137 }
138 }
139
140 /// Creates an empty data payload containing 0 bytes.
141 #[inline]
142 pub const fn empty() -> Self {
143 Self { bytes: [0; 8] }
144 }
145}
146
147/// Frame with up to 8 bytes of data payload as per Classic(non-FD) CAN
148/// For CAN-FD support use FdFrame
149#[derive(Debug, Copy, Clone)]
150#[cfg_attr(feature = "defmt", derive(defmt::Format))]
151pub struct Frame {
152 can_header: Header,
153 data: ClassicData,
154}
155
156impl Frame {
157 /// Create a new CAN classic Frame
158 pub fn new(can_header: Header, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
159 let data = ClassicData::new(raw_data)?;
160 Ok(Frame { can_header, data: data })
161 }
162
163 /// Creates a new data frame.
164 pub fn new_data(id: impl Into<embedded_can::Id>, data: &[u8]) -> Result<Self, FrameCreateError> {
165 let eid: embedded_can::Id = id.into();
166 let header = Header::new(eid, data.len() as u8, false);
167 Self::new(header, data)
168 }
169
170 /// Create new extended frame
171 pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
172 if let Some(id) = embedded_can::ExtendedId::new(raw_id) {
173 Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data)
174 } else {
175 Err(FrameCreateError::InvalidCanId)
176 }
177 }
178
179 /// Create new standard frame
180 pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
181 if let Some(id) = embedded_can::StandardId::new(raw_id) {
182 Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data)
183 } else {
184 Err(FrameCreateError::InvalidCanId)
185 }
186 }
187
188 /// Create new remote frame
189 pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Result<Self, FrameCreateError> {
190 if len <= 8usize {
191 Self::new(Header::new(id.into(), len as u8, true), &[0; 8])
192 } else {
193 Err(FrameCreateError::InvalidDataLength)
194 }
195 }
196
197 /// Get reference to data
198 pub fn header(&self) -> &Header {
199 &self.can_header
200 }
201
202 /// Return ID
203 pub fn id(&self) -> &embedded_can::Id {
204 &self.can_header.id
205 }
206
207 /// Get reference to data
208 pub fn data(&self) -> &[u8] {
209 &self.data.raw()
210 }
211
212 /// Get priority of frame
213 pub fn priority(&self) -> u32 {
214 self.header().priority()
215 }
216}
217
218impl embedded_can::Frame for Frame {
219 fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> {
220 let frameopt = Frame::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data);
221 match frameopt {
222 Ok(frame) => Some(frame),
223 Err(_) => None,
224 }
225 }
226 fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
227 if len <= 8 {
228 let frameopt = Frame::new(Header::new(id.into(), len as u8, true), &[0; 8]);
229 match frameopt {
230 Ok(frame) => Some(frame),
231 Err(_) => None,
232 }
233 } else {
234 None
235 }
236 }
237 fn is_extended(&self) -> bool {
238 match self.can_header.id {
239 embedded_can::Id::Extended(_) => true,
240 embedded_can::Id::Standard(_) => false,
241 }
242 }
243 fn is_remote_frame(&self) -> bool {
244 self.can_header.rtr()
245 }
246 fn id(&self) -> embedded_can::Id {
247 self.can_header.id
248 }
249 fn dlc(&self) -> usize {
250 self.can_header.len as usize
251 }
252 fn data(&self) -> &[u8] {
253 &self.data.raw()
254 }
255}
256
257impl CanHeader for Frame {
258 fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError> {
259 Self::new(header, data)
260 }
261
262 fn header(&self) -> &Header {
263 self.header()
264 }
265}
266
267/// Contains CAN frame and additional metadata.
268///
269/// Timestamp is available if `time` feature is enabled.
270/// For CAN-FD support use FdEnvelope
271#[derive(Debug, Clone)]
272#[cfg_attr(feature = "defmt", derive(defmt::Format))]
273pub struct Envelope {
274 /// Reception time.
275 pub ts: Timestamp,
276 /// The actual CAN frame.
277 pub frame: Frame,
278}
279
280impl Envelope {
281 /// Convert into a tuple
282 pub fn parts(self) -> (Frame, Timestamp) {
283 (self.frame, self.ts)
284 }
285}
286
287/// Payload of a (FD)CAN data frame.
288///
289/// Contains 0 to 64 Bytes of data.
290#[derive(Debug, Copy, Clone)]
291#[cfg_attr(feature = "defmt", derive(defmt::Format))]
292pub struct FdData {
293 pub(crate) bytes: [u8; 64],
294}
295
296impl FdData {
297 /// Creates a data payload from a raw byte slice.
298 ///
299 /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
300 /// cannot be represented with an FDCAN DLC.
301 pub fn new(data: &[u8]) -> Result<Self, FrameCreateError> {
302 if !FdData::is_valid_len(data.len()) {
303 return Err(FrameCreateError::InvalidDataLength);
304 }
305
306 let mut bytes = [0; 64];
307 bytes[..data.len()].copy_from_slice(data);
308
309 Ok(Self { bytes })
310 }
311
312 /// Raw read access to data.
313 pub fn raw(&self) -> &[u8] {
314 &self.bytes
315 }
316
317 /// Checks if the length can be encoded in FDCAN DLC field.
318 pub const fn is_valid_len(len: usize) -> bool {
319 match len {
320 0..=8 => true,
321 12 => true,
322 16 => true,
323 20 => true,
324 24 => true,
325 32 => true,
326 48 => true,
327 64 => true,
328 _ => false,
329 }
330 }
331
332 /// Creates an empty data payload containing 0 bytes.
333 #[inline]
334 pub const fn empty() -> Self {
335 Self { bytes: [0; 64] }
336 }
337}
338
339/// Frame with up to 8 bytes of data payload as per Fd CAN
340#[derive(Debug, Copy, Clone)]
341#[cfg_attr(feature = "defmt", derive(defmt::Format))]
342pub struct FdFrame {
343 can_header: Header,
344 data: FdData,
345}
346
347impl FdFrame {
348 /// Create a new CAN classic Frame
349 pub fn new(can_header: Header, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
350 let data = FdData::new(raw_data)?;
351 Ok(FdFrame { can_header, data })
352 }
353
354 /// Create new extended frame
355 pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
356 if let Some(id) = embedded_can::ExtendedId::new(raw_id) {
357 Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data)
358 } else {
359 Err(FrameCreateError::InvalidCanId)
360 }
361 }
362
363 /// Create new standard frame
364 pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
365 if let Some(id) = embedded_can::StandardId::new(raw_id) {
366 Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data)
367 } else {
368 Err(FrameCreateError::InvalidCanId)
369 }
370 }
371
372 /// Create new remote frame
373 pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Result<Self, FrameCreateError> {
374 if len <= 8 {
375 Self::new(Header::new(id.into(), len as u8, true), &[0; 8])
376 } else {
377 Err(FrameCreateError::InvalidDataLength)
378 }
379 }
380
381 /// Get reference to data
382 pub fn header(&self) -> &Header {
383 &self.can_header
384 }
385
386 /// Return ID
387 pub fn id(&self) -> &embedded_can::Id {
388 &self.can_header.id
389 }
390
391 /// Get reference to data
392 pub fn data(&self) -> &[u8] {
393 &self.data.raw()
394 }
395}
396
397impl embedded_can::Frame for FdFrame {
398 fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> {
399 match FdFrame::new(Header::new_fd(id.into(), raw_data.len() as u8, false, true), raw_data) {
400 Ok(frame) => Some(frame),
401 Err(_) => None,
402 }
403 }
404 fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
405 if len <= 8 {
406 match FdFrame::new(Header::new_fd(id.into(), len as u8, true, true), &[0; 64]) {
407 Ok(frame) => Some(frame),
408 Err(_) => None,
409 }
410 } else {
411 None
412 }
413 }
414 fn is_extended(&self) -> bool {
415 match self.can_header.id {
416 embedded_can::Id::Extended(_) => true,
417 embedded_can::Id::Standard(_) => false,
418 }
419 }
420 fn is_remote_frame(&self) -> bool {
421 self.can_header.rtr()
422 }
423 fn id(&self) -> embedded_can::Id {
424 self.can_header.id
425 }
426 // Returns length in bytes even for CANFD packets which embedded-can does not really mention.
427 fn dlc(&self) -> usize {
428 self.can_header.len as usize
429 }
430 fn data(&self) -> &[u8] {
431 &self.data.raw()
432 }
433}
434
435impl CanHeader for FdFrame {
436 fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError> {
437 Self::new(header, data)
438 }
439
440 fn header(&self) -> &Header {
441 self.header()
442 }
443}
444
445/// Contains CAN FD frame and additional metadata.
446///
447/// Timestamp is available if `time` feature is enabled.
448#[derive(Debug, Clone)]
449#[cfg_attr(feature = "defmt", derive(defmt::Format))]
450pub struct FdEnvelope {
451 /// Reception time.
452 pub ts: Timestamp,
453
454 /// The actual CAN frame.
455 pub frame: FdFrame,
456}
457
458impl FdEnvelope {
459 /// Convert into a tuple
460 pub fn parts(self) -> (FdFrame, Timestamp) {
461 (self.frame, self.ts)
462 }
463}
464