embedded_hal/can/
id.rs

1//! CAN Identifiers.
2
3/// Standard 11-bit CAN Identifier (`0..=0x7FF`).
4#[derive(Debug, Copy, Clone, Eq, PartialEq)]
5pub struct StandardId(u16);
6
7impl StandardId {
8    /// CAN ID `0`, the highest priority.
9    pub const ZERO: Self = StandardId(0);
10
11    /// CAN ID `0x7FF`, the lowest priority.
12    pub const MAX: Self = StandardId(0x7FF);
13
14    /// Tries to create a `StandardId` from a raw 16-bit integer.
15    ///
16    /// This will return `None` if `raw` is out of range of an 11-bit integer (`> 0x7FF`).
17    #[inline]
18    pub fn new(raw: u16) -> Option<Self> {
19        if raw <= 0x7FF {
20            Some(StandardId(raw))
21        } else {
22            None
23        }
24    }
25
26    /// Creates a new `StandardId` without checking if it is inside the valid range.
27    ///
28    /// # Safety
29    /// Using this method can create an invalid ID and is thus marked as unsafe.
30    #[inline]
31    pub const unsafe fn new_unchecked(raw: u16) -> Self {
32        StandardId(raw)
33    }
34
35    /// Returns this CAN Identifier as a raw 16-bit integer.
36    #[inline]
37    pub fn as_raw(&self) -> u16 {
38        self.0
39    }
40}
41
42/// Extended 29-bit CAN Identifier (`0..=1FFF_FFFF`).
43#[derive(Debug, Copy, Clone, Eq, PartialEq)]
44pub struct ExtendedId(u32);
45
46impl ExtendedId {
47    /// CAN ID `0`, the highest priority.
48    pub const ZERO: Self = ExtendedId(0);
49
50    /// CAN ID `0x1FFFFFFF`, the lowest priority.
51    pub const MAX: Self = ExtendedId(0x1FFF_FFFF);
52
53    /// Tries to create a `ExtendedId` from a raw 32-bit integer.
54    ///
55    /// This will return `None` if `raw` is out of range of an 29-bit integer (`> 0x1FFF_FFFF`).
56    #[inline]
57    pub fn new(raw: u32) -> Option<Self> {
58        if raw <= 0x1FFF_FFFF {
59            Some(ExtendedId(raw))
60        } else {
61            None
62        }
63    }
64
65    /// Creates a new `ExtendedId` without checking if it is inside the valid range.
66    ///
67    /// # Safety
68    /// Using this method can create an invalid ID and is thus marked as unsafe.
69    #[inline]
70    pub const unsafe fn new_unchecked(raw: u32) -> Self {
71        ExtendedId(raw)
72    }
73
74    /// Returns this CAN Identifier as a raw 32-bit integer.
75    #[inline]
76    pub fn as_raw(&self) -> u32 {
77        self.0
78    }
79
80    /// Returns the Base ID part of this extended identifier.
81    pub fn standard_id(&self) -> StandardId {
82        // ID-28 to ID-18
83        StandardId((self.0 >> 18) as u16)
84    }
85}
86
87/// A CAN Identifier (standard or extended).
88#[derive(Debug, Copy, Clone, Eq, PartialEq)]
89pub enum Id {
90    /// Standard 11-bit Identifier (`0..=0x7FF`).
91    Standard(StandardId),
92
93    /// Extended 29-bit Identifier (`0..=0x1FFF_FFFF`).
94    Extended(ExtendedId),
95}
96
97impl From<StandardId> for Id {
98    #[inline]
99    fn from(id: StandardId) -> Self {
100        Id::Standard(id)
101    }
102}
103
104impl From<ExtendedId> for Id {
105    #[inline]
106    fn from(id: ExtendedId) -> Self {
107        Id::Extended(id)
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    #[test]
116    fn standard_id_new() {
117        assert_eq!(
118            StandardId::new(StandardId::MAX.as_raw()),
119            Some(StandardId::MAX)
120        );
121    }
122
123    #[test]
124    fn standard_id_new_out_of_range() {
125        assert_eq!(StandardId::new(StandardId::MAX.as_raw() + 1), None);
126    }
127
128    #[test]
129    fn standard_id_new_unchecked_out_of_range() {
130        let id = StandardId::MAX.as_raw() + 1;
131        assert_eq!(unsafe { StandardId::new_unchecked(id) }, StandardId(id));
132    }
133
134    #[test]
135    fn extended_id_new() {
136        assert_eq!(
137            ExtendedId::new(ExtendedId::MAX.as_raw()),
138            Some(ExtendedId::MAX)
139        );
140    }
141
142    #[test]
143    fn extended_id_new_out_of_range() {
144        assert_eq!(ExtendedId::new(ExtendedId::MAX.as_raw() + 1), None);
145    }
146
147    #[test]
148    fn extended_id_new_unchecked_out_of_range() {
149        let id = ExtendedId::MAX.as_raw() + 1;
150        assert_eq!(unsafe { ExtendedId::new_unchecked(id) }, ExtendedId(id));
151    }
152
153    #[test]
154    fn get_standard_id_from_extended_id() {
155        assert_eq!(
156            Some(ExtendedId::MAX.standard_id()),
157            StandardId::new((ExtendedId::MAX.0 >> 18) as u16)
158        );
159    }
160}