1use 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
25pub const CANFD_FDF: libc::c_int = 0x04;
28
29pub const ERR_MASK_ALL: u32 = CAN_ERR_MASK;
31
32pub const ERR_MASK_NONE: u32 = 0;
34
35bitflags! {
36 #[repr(transparent)]
38 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
39 pub struct IdFlags: canid_t {
40 const EFF = CAN_EFF_FLAG;
42 const RTR = CAN_RTR_FLAG;
44 const ERR = CAN_ERR_FLAG;
46 }
47
48 #[repr(transparent)]
50 #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)]
51 pub struct FdFlags: u8 {
52 const BRS = CANFD_BRS as u8;
54 const ESI = CANFD_ESI as u8;
56 const FDF = CANFD_FDF as u8;
59 }
60}
61
62pub 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#[inline]
74pub fn id_is_standard(id: &Id) -> bool {
75 matches!(id, Id::Standard(_))
76}
77
78#[inline]
80pub fn id_is_extended(id: &Id) -> bool {
81 matches!(id, Id::Extended(_))
82}
83
84pub 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#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
103pub enum CanId {
104 Standard(StandardId),
106 Extended(ExtendedId),
108}
109
110impl CanId {
111 pub fn standard(id: u16) -> Option<Self> {
113 let id = StandardId::new(id)?;
114 Some(Self::Standard(id))
115 }
116
117 pub fn extended(id: u32) -> Option<Self> {
119 let id = ExtendedId::new(id)?;
120 Some(Self::Extended(id))
121 }
122
123 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 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 #[inline]
143 pub fn is_standard(&self) -> bool {
144 matches!(self, CanId::Standard(_))
145 }
146
147 #[inline]
149 pub fn is_extended(&self) -> bool {
150 matches!(self, CanId::Extended(_))
151 }
152}
153
154impl 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 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
201impl 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#[cfg(test)]
243mod tests {
244 use super::*;
245
246 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}