Thanks to visit codestin.com
Credit goes to docs.rs

socketcan/
id.rs

1// socketcan/src/id.rs
2//
3// Implements CANbus Identifiers.
4//
5// This file is part of the Rust 'socketcan-rs' library.
6//
7// Licensed under the MIT license:
8//   <LICENSE or http://opensource.org/licenses/MIT>
9// This file may not be copied, modified, or distributed except according
10// to those terms.
11
12//! Implementation of CANbus standard and extended identifiers.
13
14use crate::{Error, Result};
15use bitflags::bitflags;
16use embedded_can::{ExtendedId, Id, StandardId};
17use libc::canid_t;
18use std::{io, ops};
19
20pub use libc::{
21    CANFD_BRS, CANFD_ESI, CANFD_MAX_DLEN, CAN_EFF_FLAG, CAN_EFF_MASK, CAN_ERR_FLAG, CAN_ERR_MASK,
22    CAN_MAX_DLEN, CAN_RTR_FLAG, CAN_SFF_MASK,
23};
24
25// TODO: This was sent upstream to libc 2024-12-27
26/// Mark CAN FD for dual use of struct canfd_frame
27pub const CANFD_FDF: libc::c_int = 0x04;
28
29/// An error mask that will cause SocketCAN to report all errors
30pub const ERR_MASK_ALL: u32 = CAN_ERR_MASK;
31
32/// An error mask that will cause SocketCAN to silently drop all errors
33pub const ERR_MASK_NONE: u32 = 0;
34
35bitflags! {
36    /// Bit flags in the composite SocketCAN ID word.
37    #[repr(transparent)]
38    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
39    pub struct IdFlags: canid_t {
40        /// Indicates frame uses a 29-bit extended ID
41        const EFF = CAN_EFF_FLAG;
42        /// Indicates a remote request frame.
43        const RTR = CAN_RTR_FLAG;
44        /// Indicates an error frame.
45        const ERR = CAN_ERR_FLAG;
46    }
47
48    /// Bit flags for the Flexible Data (FD) frames.
49    #[repr(transparent)]
50    #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)]
51    pub struct FdFlags: u8 {
52        /// Bit rate switch (second bit rate for payload data)
53        const BRS = CANFD_BRS as u8;
54        /// Error state indicator of the transmitting node
55        const ESI = CANFD_ESI as u8;
56        /// Mark CAN FD for dual use of struct canfd_frame
57        /// Added in Linux kernel v5.14
58        const FDF = CANFD_FDF as u8;
59    }
60}
61
62/// Gets the canid_t value from an Id
63/// If it's an extended ID, the CAN_EFF_FLAG bit is also set.
64pub fn id_to_canid_t(id: impl Into<Id>) -> canid_t {
65    use Id::*;
66    match id.into() {
67        Standard(id) => id.as_raw() as canid_t,
68        Extended(id) => id.as_raw() | CAN_EFF_FLAG,
69    }
70}
71
72/// Determines if the ID is a standard, 11-bit, ID.
73#[inline]
74pub fn id_is_standard(id: &Id) -> bool {
75    matches!(id, Id::Standard(_))
76}
77
78/// Determines if the ID is an extended, 29-bit, ID.
79#[inline]
80pub fn id_is_extended(id: &Id) -> bool {
81    matches!(id, Id::Extended(_))
82}
83
84/// Creates a CAN ID from a raw integer value.
85///
86/// If the `id` is <= 0x7FF, it's assumed to be a standard ID, otherwise
87/// it is created as an Extended ID. If you require an Extended ID <= 0x7FF,
88/// create it explicitly.
89pub fn id_from_raw(id: u32) -> Option<Id> {
90    let id = match id {
91        n if n <= CAN_SFF_MASK => StandardId::new(n as u16)?.into(),
92        n => ExtendedId::new(n)?.into(),
93    };
94    Some(id)
95}
96
97/////////////////////////////////////////////////////////////////////////////
98/// A CAN identifier that can be standard or extended.
99///
100/// This is similar to and generally interchangeable with
101/// [embedded_can::Id](https://docs.rs/embedded-can/latest/embedded_can/enum.Id.html)
102#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
103pub enum CanId {
104    /// Standard 11-bit Identifier (`0..=0x7FF`).
105    Standard(StandardId),
106    /// Extended 29-bit Identifier (`0..=0x1FFF_FFFF`).
107    Extended(ExtendedId),
108}
109
110impl CanId {
111    /// Creates a standard, 11-bit, ID
112    pub fn standard(id: u16) -> Option<Self> {
113        let id = StandardId::new(id)?;
114        Some(Self::Standard(id))
115    }
116
117    /// Creates an extended, 29-bit, ID
118    pub fn extended(id: u32) -> Option<Self> {
119        let id = ExtendedId::new(id)?;
120        Some(Self::Extended(id))
121    }
122
123    /// Gets the embedded_can::Id representation of the value.
124    pub fn as_id(&self) -> Id {
125        use CanId::*;
126        match self {
127            Standard(id) => Id::Standard(*id),
128            Extended(id) => Id::Extended(*id),
129        }
130    }
131
132    /// Gets the raw numeric value of the ID
133    pub fn as_raw(&self) -> u32 {
134        use CanId::*;
135        match self {
136            Standard(id) => id.as_raw() as u32,
137            Extended(id) => id.as_raw(),
138        }
139    }
140
141    /// Determines if the ID is a standard, 11-bit, ID.
142    #[inline]
143    pub fn is_standard(&self) -> bool {
144        matches!(self, CanId::Standard(_))
145    }
146
147    /// Determines if the ID is an extended, 29-bit, ID.
148    #[inline]
149    pub fn is_extended(&self) -> bool {
150        matches!(self, CanId::Extended(_))
151    }
152}
153
154/// Implement `Ord` according to the CAN arbitration rules
155///
156/// This defers to the `Ord` implementation in the embedded_can crate.
157impl Ord for CanId {
158    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
159        self.as_id().cmp(&other.as_id())
160    }
161}
162
163impl PartialOrd for CanId {
164    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
165        Some(self.cmp(other))
166    }
167}
168
169impl From<StandardId> for CanId {
170    #[inline]
171    fn from(id: StandardId) -> Self {
172        Self::Standard(id)
173    }
174}
175
176impl From<ExtendedId> for CanId {
177    #[inline]
178    fn from(id: ExtendedId) -> Self {
179        Self::Extended(id)
180    }
181}
182
183impl From<Id> for CanId {
184    /// Gets the embedded_can::Id representation of the value.
185    fn from(id: Id) -> Self {
186        use Id::*;
187        match id {
188            Standard(id) => Self::Standard(id),
189            Extended(id) => Self::Extended(id),
190        }
191    }
192}
193
194impl From<CanId> for Id {
195    #[inline]
196    fn from(id: CanId) -> Self {
197        id.as_id()
198    }
199}
200
201/// Creates a CAN ID from a raw integer value.
202///
203/// If the `id` is <= 0x7FF, it's assumed to be a standard ID, otherwise
204/// it is created as an Extended ID. If you require an Extended ID <= 0x7FF,
205/// create it explicitly.
206impl TryFrom<u32> for CanId {
207    type Error = Error;
208
209    fn try_from(id: u32) -> Result<Self> {
210        let id = match id {
211            n if n <= CAN_SFF_MASK => {
212                Self::standard(n as u16).ok_or(io::Error::from(io::ErrorKind::InvalidInput))?
213            }
214            n => Self::extended(n).ok_or(io::Error::from(io::ErrorKind::InvalidInput))?,
215        };
216        Ok(id)
217    }
218}
219
220impl ops::Add<u32> for CanId {
221    type Output = Self;
222
223    fn add(self, val: u32) -> Self::Output {
224        use CanId::*;
225        match self {
226            Standard(id) => {
227                Self::standard((id.as_raw() + val as u16) & CAN_SFF_MASK as u16).unwrap()
228            }
229            Extended(id) => Self::extended((id.as_raw() + val) & CAN_EFF_MASK).unwrap(),
230        }
231    }
232}
233
234impl ops::AddAssign<u32> for CanId {
235    fn add_assign(&mut self, other: u32) {
236        *self = *self + other;
237    }
238}
239
240/////////////////////////////////////////////////////////////////////////////
241
242#[cfg(test)]
243mod tests {
244    use super::*;
245
246    // A standard ID
247    const ID: u32 = 0x100;
248
249    #[test]
250    fn test_id_conv() {
251        let sid = StandardId::MAX;
252        let id = CanId::from(sid);
253
254        assert!(id.is_standard());
255        assert!(matches!(id, CanId::Standard(_)));
256        assert_eq!(id.as_raw(), sid.as_raw() as u32);
257
258        let eid = ExtendedId::MAX;
259        let id = CanId::from(eid);
260
261        assert!(id.is_extended());
262        assert!(matches!(id, CanId::Extended(_)));
263        assert_eq!(id.as_raw(), eid.as_raw());
264
265        let sid = Id::from(StandardId::MAX);
266        let id = CanId::from(sid);
267
268        assert!(id.is_standard());
269        assert!(matches!(id, CanId::Standard(_)));
270        match sid {
271            Id::Standard(sid) => assert_eq!(id.as_raw(), sid.as_raw() as u32),
272            _ => assert!(false),
273        };
274
275        let eid = Id::from(ExtendedId::MAX);
276        let id = CanId::from(eid);
277
278        assert!(id.is_extended());
279        assert!(matches!(id, CanId::Extended(_)));
280        match eid {
281            Id::Extended(eid) => assert_eq!(id.as_raw(), eid.as_raw()),
282            _ => assert!(false),
283        }
284    }
285
286    #[test]
287    fn test_id_raw() {
288        let id = CanId::try_from(ID).unwrap();
289        assert!(matches!(id, CanId::Standard(_)));
290        assert_eq!(id.as_raw(), ID);
291    }
292
293    #[test]
294    fn test_id_add() {
295        let id = CanId::try_from(ID).unwrap();
296        let id = id + 1;
297
298        assert!(matches!(id, CanId::Standard(_)));
299        assert_eq!(id.as_raw(), ID + 1);
300
301        let mut id = CanId::try_from(ID).unwrap();
302        id += 1;
303
304        assert!(matches!(id, CanId::Standard(_)));
305        assert_eq!(id.as_raw(), ID + 1);
306    }
307}