embassy_stm32/can/
frame.rs

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