Skip to main content

can_hal/
lib.rs

1//! # can-hal
2//!
3//! Hardware-agnostic traits for CAN bus communication.
4//!
5//! This crate defines portable types and traits that CAN hardware backends
6//! (SocketCAN, PCAN, Kvaser, etc.) implement so that application code can be
7//! written once and run on any supported hardware.
8//!
9//! ## `no_std` support
10//!
11//! This crate is `no_std`-compatible. The `std` feature (enabled by default)
12//! is not required for any of the trait definitions or frame types. Disable
13//! default features to use in embedded / `no_std` contexts:
14//!
15//! ```toml
16//! [dependencies]
17//! can-hal-rs = { version = "0.3", default-features = false }
18//! ```
19//!
20//! ## Quick start
21//!
22//! ```rust
23//! use can_hal::{CanId, CanFrame};
24//!
25//! let id = CanId::new_standard(0x123).unwrap();
26//! let frame = CanFrame::new(id, &[0xDE, 0xAD]).unwrap();
27//! assert_eq!(frame.id(), id);
28//! assert_eq!(frame.data(), &[0xDE, 0xAD]);
29//! ```
30
31#![no_std]
32
33#[cfg(feature = "std")]
34extern crate std;
35
36pub mod bus;
37pub mod channel;
38pub mod error;
39pub mod filter;
40pub mod frame;
41pub mod id;
42pub mod timing;
43
44#[cfg(feature = "async")]
45pub mod async_channel;
46
47// Re-export core types at crate root for convenience.
48pub use bus::{BusState, BusStatus, ErrorCounters};
49pub use channel::{Receive, ReceiveFd, Transmit, TransmitFd};
50pub use error::CanError;
51pub use filter::{Filter, Filterable};
52pub use frame::{CanFdFrame, CanFrame, Frame, Timestamped};
53pub use id::CanId;
54pub use timing::SamplePoint;
55
56#[cfg(feature = "async")]
57pub use async_channel::{AsyncReceive, AsyncReceiveFd, AsyncTransmit, AsyncTransmitFd};
58
59#[cfg(all(test, feature = "std"))]
60mod tests {
61    use super::*;
62    use std::collections::VecDeque;
63    use std::fmt;
64    use std::string::String;
65    use std::time::{Duration, Instant};
66    use std::vec::Vec;
67
68    // -- Mock error type --
69
70    #[derive(Debug)]
71    struct MockError(String);
72
73    impl fmt::Display for MockError {
74        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75            write!(f, "MockError: {}", self.0)
76        }
77    }
78
79    impl std::error::Error for MockError {}
80
81    // -- Mock channel --
82
83    struct MockChannel {
84        tx_log: Vec<CanFrame>,
85        rx_queue: VecDeque<CanFrame>,
86    }
87
88    impl MockChannel {
89        const fn new() -> Self {
90            Self {
91                tx_log: Vec::new(),
92                rx_queue: VecDeque::new(),
93            }
94        }
95
96        fn push_rx(&mut self, frame: CanFrame) {
97            self.rx_queue.push_back(frame);
98        }
99    }
100
101    impl Transmit for MockChannel {
102        type Error = MockError;
103
104        fn transmit(&mut self, frame: &CanFrame) -> Result<(), Self::Error> {
105            self.tx_log.push(frame.clone());
106            Ok(())
107        }
108    }
109
110    impl Receive for MockChannel {
111        type Error = MockError;
112        type Timestamp = Instant;
113
114        fn receive(&mut self) -> Result<Timestamped<CanFrame, Instant>, Self::Error> {
115            self.rx_queue
116                .pop_front()
117                .map(|f| Timestamped::new(f, Instant::now()))
118                .ok_or_else(|| MockError("no frames available".into()))
119        }
120
121        fn try_receive(&mut self) -> Result<Option<Timestamped<CanFrame, Instant>>, Self::Error> {
122            Ok(self
123                .rx_queue
124                .pop_front()
125                .map(|f| Timestamped::new(f, Instant::now())))
126        }
127
128        fn receive_timeout(
129            &mut self,
130            _timeout: Duration,
131        ) -> Result<Option<Timestamped<CanFrame, Instant>>, Self::Error> {
132            // Mock: just return immediately like try_receive.
133            self.try_receive()
134        }
135    }
136
137    // -- Tests --
138
139    #[test]
140    fn can_id_standard_valid() {
141        let id = CanId::new_standard(0x123).unwrap();
142        assert_eq!(id.raw(), 0x123);
143        assert!(id.is_standard());
144    }
145
146    #[test]
147    fn can_id_standard_max() {
148        assert!(CanId::new_standard(0x7FF).is_some());
149        assert!(CanId::new_standard(0x800).is_none());
150    }
151
152    #[test]
153    fn can_id_extended_valid() {
154        let id = CanId::new_extended(0x1234_5678).unwrap();
155        assert_eq!(id.raw(), 0x1234_5678);
156        assert!(id.is_extended());
157    }
158
159    #[test]
160    fn can_id_extended_max() {
161        assert!(CanId::new_extended(0x1FFF_FFFF).is_some());
162        assert!(CanId::new_extended(0x2000_0000).is_none());
163    }
164
165    #[test]
166    fn can_frame_valid() {
167        let id = CanId::new_standard(0x100).unwrap();
168        let frame = CanFrame::new(id, &[1, 2, 3]).unwrap();
169        assert_eq!(frame.id(), id);
170        assert_eq!(frame.len(), 3);
171        assert_eq!(frame.data(), &[1, 2, 3]);
172    }
173
174    #[test]
175    fn can_frame_empty() {
176        let id = CanId::new_standard(0x000).unwrap();
177        let frame = CanFrame::new(id, &[]).unwrap();
178        assert_eq!(frame.len(), 0);
179        assert_eq!(frame.data(), &[]);
180    }
181
182    #[test]
183    fn can_frame_too_long() {
184        let id = CanId::new_standard(0x100).unwrap();
185        assert!(CanFrame::new(id, &[0; 9]).is_none());
186    }
187
188    #[test]
189    fn can_fd_frame_valid() {
190        let id = CanId::new_extended(0x100).unwrap();
191        let data = [0xAA; 32];
192        let frame = CanFdFrame::new(id, &data, true, false).unwrap();
193        assert_eq!(frame.len(), 32);
194        assert_eq!(frame.data(), &data);
195        assert!(frame.brs());
196        assert!(!frame.esi());
197    }
198
199    #[test]
200    fn can_fd_frame_invalid_dlc() {
201        let id = CanId::new_standard(0x100).unwrap();
202        // 9 is not a valid FD DLC
203        assert!(CanFdFrame::new(id, &[0; 9], false, false).is_none());
204    }
205
206    #[test]
207    fn frame_enum_accessors() {
208        let id = CanId::new_standard(0x200).unwrap();
209        let classic = CanFrame::new(id, &[0xFF]).unwrap();
210        let frame = Frame::Can(classic);
211        assert_eq!(frame.id(), id);
212        assert_eq!(frame.len(), 1);
213        assert_eq!(frame.data(), &[0xFF]);
214    }
215
216    #[test]
217    fn timestamped_wrapper() {
218        let id = CanId::new_standard(0x100).unwrap();
219        let frame = CanFrame::new(id, &[1, 2]).unwrap();
220        let now = Instant::now();
221        let ts = Timestamped::new(frame.clone(), now);
222        assert_eq!(ts.frame(), &frame);
223        assert_eq!(*ts.timestamp(), now);
224        assert_eq!(ts.into_frame(), frame);
225    }
226
227    #[test]
228    fn mock_transmit_receive() {
229        let mut ch = MockChannel::new();
230        let id = CanId::new_standard(0x100).unwrap();
231        let frame = CanFrame::new(id, &[1, 2]).unwrap();
232
233        ch.transmit(&frame).unwrap();
234        assert_eq!(ch.tx_log.len(), 1);
235        assert_eq!(ch.tx_log[0], frame);
236
237        // try_receive on empty queue
238        assert!(ch.try_receive().unwrap().is_none());
239
240        // Push and receive
241        ch.push_rx(frame.clone());
242        let received = ch.receive().unwrap();
243        assert_eq!(received.into_frame(), frame);
244    }
245
246    #[test]
247    fn mock_receive_timeout() {
248        let mut ch = MockChannel::new();
249        let id = CanId::new_standard(0x100).unwrap();
250        let frame = CanFrame::new(id, &[0xAB]).unwrap();
251
252        // Empty queue returns None
253        let result = ch.receive_timeout(Duration::from_millis(100)).unwrap();
254        assert!(result.is_none());
255
256        // With frame available
257        ch.push_rx(frame.clone());
258        let result = ch.receive_timeout(Duration::from_millis(100)).unwrap();
259        assert_eq!(result.unwrap().into_frame(), frame);
260    }
261
262    // Generic function using trait bounds.
263    fn send_and_recv<T: Transmit<Error = E> + Receive<Error = E>, E: CanError>(
264        channel: &mut T,
265        frame: &CanFrame,
266    ) -> Result<Option<CanFrame>, E> {
267        channel.transmit(frame)?;
268        Ok(channel.try_receive()?.map(Timestamped::into_frame))
269    }
270
271    #[test]
272    fn generic_function_over_traits() {
273        let mut ch = MockChannel::new();
274        let id = CanId::new_standard(0x42).unwrap();
275        let frame = CanFrame::new(id, &[0xBE, 0xEF]).unwrap();
276
277        ch.push_rx(frame.clone());
278        let result = send_and_recv(&mut ch, &frame).unwrap();
279        assert_eq!(result, Some(frame));
280    }
281
282    #[test]
283    fn bus_state_enum() {
284        let state = BusState::ErrorActive;
285        assert_eq!(state, BusState::ErrorActive);
286        assert_ne!(state, BusState::BusOff);
287
288        let counters = ErrorCounters {
289            transmit: 0,
290            receive: 0,
291        };
292        assert_eq!(counters.transmit, 0);
293    }
294}