bxcan_ng/
frame.rs

1#[cfg(test)]
2mod tests;
3
4use core::cmp::Ordering;
5use core::ops::{Deref, DerefMut};
6
7use crate::{Id, IdReg};
8
9/// A CAN data or remote frame.
10#[derive(Clone, Debug, Eq)]
11#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))]
12pub struct Frame {
13    pub(crate) id: IdReg,
14    pub(crate) data: Data,
15}
16
17impl Frame {
18    /// Creates a new data frame.
19    pub fn new_data(id: impl Into<Id>, data: impl Into<Data>) -> Self {
20        let id = match id.into() {
21            Id::Standard(id) => IdReg::new_standard(id),
22            Id::Extended(id) => IdReg::new_extended(id),
23        };
24
25        Self {
26            id,
27            data: data.into(),
28        }
29    }
30
31    /// Creates a new remote frame with configurable data length code (DLC).
32    ///
33    /// # Panics
34    ///
35    /// This function will panic if `dlc` is not inside the valid range `0..=8`.
36    pub fn new_remote(id: impl Into<Id>, dlc: u8) -> Self {
37        assert!(dlc <= 8);
38
39        let mut frame = Self::new_data(id, []);
40        // Just extend the data length, even with no data present. The API does not hand out this
41        // `Data` object.
42        frame.data.len = dlc;
43        frame.id = frame.id.with_rtr(true);
44        frame
45    }
46
47    /// Returns true if this frame is an extended frame.
48    #[inline]
49    pub fn is_extended(&self) -> bool {
50        self.id.is_extended()
51    }
52
53    /// Returns true if this frame is a standard frame.
54    #[inline]
55    pub fn is_standard(&self) -> bool {
56        self.id.is_standard()
57    }
58
59    /// Returns true if this frame is a remote frame.
60    #[inline]
61    pub fn is_remote_frame(&self) -> bool {
62        self.id.rtr()
63    }
64
65    /// Returns true if this frame is a data frame.
66    #[inline]
67    pub fn is_data_frame(&self) -> bool {
68        !self.is_remote_frame()
69    }
70
71    /// Returns the frame identifier.
72    #[inline]
73    pub fn id(&self) -> Id {
74        self.id.to_id()
75    }
76
77    /// Returns the priority of this frame.
78    #[inline]
79    pub fn priority(&self) -> FramePriority {
80        FramePriority(self.id)
81    }
82
83    /// Returns the data length code (DLC) which is in the range 0..8.
84    ///
85    /// For data frames the DLC value always matches the length of the data.
86    /// Remote frames do not carry any data, yet the DLC can be greater than 0.
87    #[inline]
88    pub fn dlc(&self) -> u8 {
89        self.data.len() as u8
90    }
91
92    /// Returns the frame data (0..8 bytes in length) if this is a data frame.
93    ///
94    /// If this is a remote frame, returns `None`.
95    pub fn data(&self) -> Option<&Data> {
96        if self.is_data_frame() {
97            Some(&self.data)
98        } else {
99            None
100        }
101    }
102}
103
104impl PartialEq for Frame {
105    fn eq(&self, other: &Self) -> bool {
106        match (self.data(), other.data()) {
107            (None, None) => self.id.eq(&other.id),
108            (Some(a), Some(b)) => self.id.eq(&other.id) && a.eq(b),
109            (None, Some(_)) | (Some(_), None) => false,
110        }
111    }
112}
113
114/// Priority of a CAN frame.
115///
116/// Returned by [`Frame::priority`].
117///
118/// The priority of a frame is determined by the bits that are part of the *arbitration field*.
119/// These consist of the frame identifier bits (including the *IDE* bit, which is 0 for extended
120/// frames and 1 for standard frames), as well as the *RTR* bit, which determines whether a frame
121/// is a data or remote frame. Lower values of the *arbitration field* have higher priority.
122///
123/// This struct wraps the *arbitration field* and implements `PartialOrd` and `Ord` accordingly,
124/// ordering higher priorities greater than lower ones.
125#[derive(Debug, Copy, Clone)]
126pub struct FramePriority(IdReg);
127
128/// Ordering is based on the Identifier and frame type (data vs. remote) and can be used to sort
129/// frames by priority.
130impl Ord for FramePriority {
131    fn cmp(&self, other: &Self) -> Ordering {
132        self.0.cmp(&other.0)
133    }
134}
135
136impl PartialOrd for FramePriority {
137    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
138        Some(self.cmp(other))
139    }
140}
141
142impl PartialEq for FramePriority {
143    fn eq(&self, other: &Self) -> bool {
144        self.cmp(other) == Ordering::Equal
145    }
146}
147
148impl Eq for FramePriority {}
149
150/// Payload of a CAN data frame.
151///
152/// Contains 0 to 8 Bytes of data.
153///
154/// `Data` implements `From<[u8; N]>` for all `N` up to 8, which provides a convenient lossless
155/// conversion from fixed-length arrays.
156#[derive(Debug, Copy, Clone)]
157pub struct Data {
158    pub(crate) len: u8,
159    pub(crate) bytes: [u8; 8],
160}
161
162impl Data {
163    /// Creates a data payload from a raw byte slice.
164    ///
165    /// Returns `None` if `data` contains more than 8 Bytes (which is the maximum).
166    ///
167    /// `Data` can also be constructed from fixed-length arrays up to length 8 via `From`/`Into`.
168    pub fn new(data: &[u8]) -> Option<Self> {
169        if data.len() > 8 {
170            return None;
171        }
172
173        let mut bytes = [0; 8];
174        bytes[..data.len()].copy_from_slice(data);
175
176        Some(Self {
177            len: data.len() as u8,
178            bytes,
179        })
180    }
181
182    /// Creates an empty data payload containing 0 bytes.
183    #[inline]
184    pub const fn empty() -> Self {
185        Self {
186            len: 0,
187            bytes: [0; 8],
188        }
189    }
190}
191
192impl Deref for Data {
193    type Target = [u8];
194
195    #[inline]
196    fn deref(&self) -> &[u8] {
197        &self.bytes[..usize::from(self.len)]
198    }
199}
200
201impl DerefMut for Data {
202    #[inline]
203    fn deref_mut(&mut self) -> &mut [u8] {
204        &mut self.bytes[..usize::from(self.len)]
205    }
206}
207
208impl AsRef<[u8]> for Data {
209    #[inline]
210    fn as_ref(&self) -> &[u8] {
211        self.deref()
212    }
213}
214
215impl AsMut<[u8]> for Data {
216    #[inline]
217    fn as_mut(&mut self) -> &mut [u8] {
218        self.deref_mut()
219    }
220}
221
222impl PartialEq for Data {
223    fn eq(&self, other: &Self) -> bool {
224        self.as_ref() == other.as_ref()
225    }
226}
227
228impl Eq for Data {}
229
230#[cfg(feature = "unstable-defmt")]
231impl defmt::Format for Data {
232    fn format(&self, fmt: defmt::Formatter<'_>) {
233        self.as_ref().format(fmt)
234    }
235}
236
237macro_rules! data_from_array {
238    ( $($len:literal),+ ) => {
239        $(
240            impl From<[u8; $len]> for Data {
241                #[inline]
242                fn from(arr: [u8; $len]) -> Self {
243                    let mut bytes = [0; 8];
244                    bytes[..$len].copy_from_slice(&arr);
245                    Self {
246                        len: $len,
247                        bytes,
248                    }
249                }
250            }
251        )+
252    };
253}
254
255data_from_array!(0, 1, 2, 3, 4, 5, 6, 7, 8);