Skip to main content

canlink_hal/
capability.rs

1//! Hardware capability types.
2//!
3//! This module defines types for describing hardware capabilities and limitations.
4
5use serde::{Deserialize, Serialize};
6
7/// Hardware capability description.
8///
9/// Describes the capabilities and limitations of a CAN hardware backend.
10/// Applications can query these capabilities at runtime to adapt their behavior.
11///
12/// # Examples
13///
14/// ```
15/// use canlink_hal::{HardwareCapability, TimestampPrecision};
16///
17/// let capability = HardwareCapability {
18///     channel_count: 2,
19///     supports_canfd: true,
20///     max_bitrate: 8_000_000,
21///     supported_bitrates: vec![125_000, 250_000, 500_000, 1_000_000],
22///     filter_count: 16,
23///     timestamp_precision: TimestampPrecision::Microsecond,
24/// };
25///
26/// assert_eq!(capability.channel_count, 2);
27/// assert!(capability.supports_canfd);
28/// ```
29#[derive(Debug, Clone, PartialEq, Eq)]
30pub struct HardwareCapability {
31    /// Number of supported channels
32    pub channel_count: u8,
33
34    /// Whether CAN-FD is supported
35    pub supports_canfd: bool,
36
37    /// Maximum bitrate in bits per second
38    pub max_bitrate: u32,
39
40    /// List of supported bitrates (bps)
41    pub supported_bitrates: Vec<u32>,
42
43    /// Number of hardware filters supported
44    pub filter_count: u8,
45
46    /// Timestamp precision
47    pub timestamp_precision: TimestampPrecision,
48}
49
50impl HardwareCapability {
51    /// Create a new hardware capability description.
52    ///
53    /// # Examples
54    ///
55    /// ```
56    /// use canlink_hal::{HardwareCapability, TimestampPrecision};
57    ///
58    /// let capability = HardwareCapability::new(
59    ///     2,
60    ///     true,
61    ///     8_000_000,
62    ///     vec![125_000, 250_000, 500_000, 1_000_000],
63    ///     16,
64    ///     TimestampPrecision::Microsecond,
65    /// );
66    /// ```
67    #[must_use]
68    pub fn new(
69        channel_count: u8,
70        supports_canfd: bool,
71        max_bitrate: u32,
72        supported_bitrates: Vec<u32>,
73        filter_count: u8,
74        timestamp_precision: TimestampPrecision,
75    ) -> Self {
76        Self {
77            channel_count,
78            supports_canfd,
79            max_bitrate,
80            supported_bitrates,
81            filter_count,
82            timestamp_precision,
83        }
84    }
85
86    /// Check if a specific bitrate is supported.
87    ///
88    /// # Examples
89    ///
90    /// ```
91    /// use canlink_hal::{HardwareCapability, TimestampPrecision};
92    ///
93    /// let capability = HardwareCapability::new(
94    ///     2,
95    ///     true,
96    ///     8_000_000,
97    ///     vec![125_000, 250_000, 500_000, 1_000_000],
98    ///     16,
99    ///     TimestampPrecision::Microsecond,
100    /// );
101    ///
102    /// assert!(capability.supports_bitrate(500_000));
103    /// assert!(!capability.supports_bitrate(2_000_000));
104    /// ```
105    #[must_use]
106    pub fn supports_bitrate(&self, bitrate: u32) -> bool {
107        self.supported_bitrates.contains(&bitrate)
108    }
109
110    /// Check if a specific channel exists.
111    ///
112    /// # Examples
113    ///
114    /// ```
115    /// use canlink_hal::{HardwareCapability, TimestampPrecision};
116    ///
117    /// let capability = HardwareCapability::new(
118    ///     2,
119    ///     true,
120    ///     8_000_000,
121    ///     vec![125_000, 250_000, 500_000, 1_000_000],
122    ///     16,
123    ///     TimestampPrecision::Microsecond,
124    /// );
125    ///
126    /// assert!(capability.has_channel(0));
127    /// assert!(capability.has_channel(1));
128    /// assert!(!capability.has_channel(2));
129    /// ```
130    #[must_use]
131    pub fn has_channel(&self, channel: u8) -> bool {
132        channel < self.channel_count
133    }
134}
135
136/// Timestamp precision.
137///
138/// Indicates the precision of timestamps provided by the hardware.
139///
140/// # Examples
141///
142/// ```
143/// use canlink_hal::TimestampPrecision;
144///
145/// let precision = TimestampPrecision::Microsecond;
146/// assert_eq!(precision.resolution_us(), Some(1));
147/// ```
148#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
149pub enum TimestampPrecision {
150    /// Microsecond precision (1 µs)
151    Microsecond,
152
153    /// Millisecond precision (1 ms = 1000 µs)
154    Millisecond,
155
156    /// No timestamp support
157    None,
158}
159
160impl TimestampPrecision {
161    /// Get the resolution in microseconds.
162    ///
163    /// Returns `None` if timestamps are not supported.
164    ///
165    /// # Examples
166    ///
167    /// ```
168    /// use canlink_hal::TimestampPrecision;
169    ///
170    /// assert_eq!(TimestampPrecision::Microsecond.resolution_us(), Some(1));
171    /// assert_eq!(TimestampPrecision::Millisecond.resolution_us(), Some(1000));
172    /// assert_eq!(TimestampPrecision::None.resolution_us(), None);
173    /// ```
174    #[must_use]
175    pub const fn resolution_us(&self) -> Option<u64> {
176        match self {
177            Self::Microsecond => Some(1),
178            Self::Millisecond => Some(1000),
179            Self::None => None,
180        }
181    }
182
183    /// Check if timestamps are supported.
184    ///
185    /// # Examples
186    ///
187    /// ```
188    /// use canlink_hal::TimestampPrecision;
189    ///
190    /// assert!(TimestampPrecision::Microsecond.is_supported());
191    /// assert!(TimestampPrecision::Millisecond.is_supported());
192    /// assert!(!TimestampPrecision::None.is_supported());
193    /// ```
194    #[must_use]
195    pub const fn is_supported(&self) -> bool {
196        !matches!(self, Self::None)
197    }
198}
199
200#[cfg(test)]
201mod tests {
202    use super::*;
203
204    #[test]
205    fn test_hardware_capability() {
206        let capability = HardwareCapability::new(
207            2,
208            true,
209            8_000_000,
210            vec![125_000, 250_000, 500_000, 1_000_000],
211            16,
212            TimestampPrecision::Microsecond,
213        );
214
215        assert_eq!(capability.channel_count, 2);
216        assert!(capability.supports_canfd);
217        assert_eq!(capability.max_bitrate, 8_000_000);
218        assert_eq!(capability.filter_count, 16);
219    }
220
221    #[test]
222    fn test_supports_bitrate() {
223        let capability = HardwareCapability::new(
224            2,
225            true,
226            8_000_000,
227            vec![125_000, 250_000, 500_000, 1_000_000],
228            16,
229            TimestampPrecision::Microsecond,
230        );
231
232        assert!(capability.supports_bitrate(500_000));
233        assert!(!capability.supports_bitrate(2_000_000));
234    }
235
236    #[test]
237    fn test_has_channel() {
238        let capability = HardwareCapability::new(
239            2,
240            true,
241            8_000_000,
242            vec![125_000, 250_000, 500_000, 1_000_000],
243            16,
244            TimestampPrecision::Microsecond,
245        );
246
247        assert!(capability.has_channel(0));
248        assert!(capability.has_channel(1));
249        assert!(!capability.has_channel(2));
250    }
251
252    #[test]
253    fn test_timestamp_precision() {
254        assert_eq!(TimestampPrecision::Microsecond.resolution_us(), Some(1));
255        assert_eq!(TimestampPrecision::Millisecond.resolution_us(), Some(1000));
256        assert_eq!(TimestampPrecision::None.resolution_us(), None);
257
258        assert!(TimestampPrecision::Microsecond.is_supported());
259        assert!(TimestampPrecision::Millisecond.is_supported());
260        assert!(!TimestampPrecision::None.is_supported());
261    }
262}