Skip to main content

canlink_hal/
error.rs

1//! Error types for the CAN hardware abstraction layer.
2//!
3//! This module provides unified error types that are hardware-independent.
4//! All backends use these error types for consistent error handling.
5
6use thiserror::Error;
7
8/// Unified CAN error type.
9///
10/// This enum represents all possible errors that can occur when working with
11/// CAN hardware through the abstraction layer. Error codes are organized into
12/// ranges:
13///
14/// - 1000-1999: Hardware-related errors
15/// - 2000-2999: Protocol-related errors
16/// - 3000-3999: Configuration-related errors
17/// - 4000-4999: System-related errors
18///
19/// # Examples
20///
21/// ```
22/// use canlink_hal::CanError;
23///
24/// let err = CanError::InvalidId { value: 0x800, max: 0x7FF };
25/// assert!(matches!(err, CanError::InvalidId { .. }));
26/// ```
27#[derive(Error, Debug)]
28pub enum CanError {
29    // Hardware-related errors (1000-1999)
30    /// Backend not found (1001)
31    #[error("[1001] Backend not found: {name}")]
32    BackendNotFound {
33        /// Backend name that was not found
34        name: String,
35    },
36
37    /// Backend already registered (1002)
38    #[error("[1002] Backend '{name}' is already registered")]
39    BackendAlreadyRegistered {
40        /// Backend name that is already registered
41        name: String,
42    },
43
44    /// Backend initialization failed (1003)
45    #[error("[1003] Backend initialization failed: {reason}")]
46    InitializationFailed {
47        /// Reason for initialization failure
48        reason: String,
49    },
50
51    /// Device not found (1004)
52    #[error("[1004] Device not found: {device}")]
53    DeviceNotFound {
54        /// Device identifier
55        device: String,
56    },
57
58    /// Channel not found (1005)
59    #[error("[1005] Channel {channel} does not exist (max: {max})")]
60    ChannelNotFound {
61        /// Channel number that was requested
62        channel: u8,
63        /// Maximum channel number available
64        max: u8,
65    },
66
67    /// Channel already open (1006)
68    #[error("[1006] Channel {channel} is already open")]
69    ChannelAlreadyOpen {
70        /// Channel number
71        channel: u8,
72    },
73
74    /// Channel not open (1007)
75    #[error("[1007] Channel {channel} is not open")]
76    ChannelNotOpen {
77        /// Channel number
78        channel: u8,
79    },
80
81    // Protocol-related errors (2000-2999)
82    /// Invalid CAN ID (2001)
83    #[error("[2001] Invalid CAN ID: {value:#X} (max: {max:#X})")]
84    InvalidId {
85        /// The invalid ID value
86        value: u32,
87        /// Maximum allowed ID value
88        max: u32,
89    },
90
91    /// Invalid data length (2002)
92    #[error("[2002] Invalid data length: expected max {expected}, got {actual}")]
93    InvalidDataLength {
94        /// Expected maximum length
95        expected: usize,
96        /// Actual length provided
97        actual: usize,
98    },
99
100    /// Invalid message format (2003)
101    #[error("[2003] Invalid message format: {reason}")]
102    InvalidFormat {
103        /// Reason for format error
104        reason: String,
105    },
106
107    // Configuration-related errors (3000-3999)
108    /// Configuration error (3001)
109    #[error("[3001] Configuration error: {reason}")]
110    ConfigError {
111        /// Reason for configuration error
112        reason: String,
113    },
114
115    /// Invalid parameter (3002)
116    #[error("[3002] Invalid parameter '{parameter}': {reason}")]
117    InvalidParameter {
118        /// Parameter name
119        parameter: String,
120        /// Reason why parameter is invalid
121        reason: String,
122    },
123
124    /// Version incompatible (3003)
125    #[error("[3003] Version incompatible: backend {backend_version}, expected {expected_version}")]
126    VersionIncompatible {
127        /// Backend version
128        backend_version: String,
129        /// Expected version
130        expected_version: String,
131    },
132
133    // System-related errors (4000-4999)
134    /// Operation timed out (4001)
135    #[error("[4001] Operation timed out after {timeout_ms}ms")]
136    Timeout {
137        /// Timeout duration in milliseconds
138        timeout_ms: u64,
139    },
140
141    /// Insufficient resources (4002)
142    #[error("[4002] Insufficient resources: {resource}")]
143    InsufficientResources {
144        /// Resource that is insufficient
145        resource: String,
146    },
147
148    /// Permission denied (4003)
149    #[error("[4003] Permission denied: {operation}")]
150    PermissionDenied {
151        /// Operation that was denied
152        operation: String,
153    },
154
155    // Operation errors
156    /// Send operation failed
157    #[error("Send failed: {reason}")]
158    SendFailed {
159        /// Reason for send failure
160        reason: String,
161    },
162
163    /// Receive operation failed
164    #[error("Receive failed: {reason}")]
165    ReceiveFailed {
166        /// Reason for receive failure
167        reason: String,
168    },
169
170    /// Bus error occurred
171    #[error("Bus error: {kind:?}")]
172    BusError {
173        /// Type of bus error
174        kind: BusErrorKind,
175    },
176
177    /// Feature not supported by hardware
178    #[error("Unsupported feature: {feature}")]
179    UnsupportedFeature {
180        /// Feature that is not supported
181        feature: String,
182    },
183
184    /// Backend is in wrong state for operation
185    #[error("Invalid state: expected {expected}, current {current}")]
186    InvalidState {
187        /// Expected state
188        expected: String,
189        /// Current state
190        current: String,
191    },
192
193    /// Other error
194    #[error("Other error: {message}")]
195    Other {
196        /// Error message
197        message: String,
198    },
199}
200
201/// Bus error types.
202///
203/// These represent various types of errors that can occur on the CAN bus
204/// at the physical and data link layers.
205///
206/// # Examples
207///
208/// ```
209/// use canlink_hal::BusErrorKind;
210///
211/// let error = BusErrorKind::BitError;
212/// assert_eq!(format!("{:?}", error), "BitError");
213/// ```
214#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
215pub enum BusErrorKind {
216    /// Bit error - transmitted bit differs from monitored bit
217    BitError,
218
219    /// Stuff error - more than 5 consecutive bits of same value
220    StuffError,
221
222    /// CRC error - calculated CRC differs from received CRC
223    CrcError,
224
225    /// ACK error - no acknowledgment received
226    AckError,
227
228    /// Form error - fixed-form bit field contains illegal value
229    FormError,
230
231    /// Bus-off - error counter exceeded threshold
232    BusOff,
233
234    /// Error passive - error counter in passive range
235    ErrorPassive,
236
237    /// Error warning - error counter in warning range
238    ErrorWarning,
239}
240
241impl BusErrorKind {
242    /// Get a human-readable description of the error.
243    ///
244    /// # Examples
245    ///
246    /// ```
247    /// use canlink_hal::BusErrorKind;
248    ///
249    /// let error = BusErrorKind::BitError;
250    /// assert_eq!(error.description(), "Bit error");
251    /// ```
252    #[must_use]
253    pub fn description(&self) -> &'static str {
254        match self {
255            Self::BitError => "Bit error",
256            Self::StuffError => "Stuff error",
257            Self::CrcError => "CRC error",
258            Self::AckError => "ACK error",
259            Self::FormError => "Form error",
260            Self::BusOff => "Bus-off",
261            Self::ErrorPassive => "Error passive",
262            Self::ErrorWarning => "Error warning",
263        }
264    }
265}
266
267/// Result type alias for CAN operations.
268///
269/// This is a convenience alias for `Result<T, CanError>`.
270///
271/// # Examples
272///
273/// ```
274/// use canlink_hal::{CanResult, CanMessage};
275///
276/// fn send_message(msg: &CanMessage) -> CanResult<()> {
277///     // Implementation
278///     Ok(())
279/// }
280/// ```
281pub type CanResult<T> = Result<T, CanError>;
282
283// ============================================================================
284// Filter Errors (FR-005 to FR-009)
285// ============================================================================
286
287/// Filter-related errors
288///
289/// These errors occur during message filter operations.
290#[derive(Error, Debug)]
291pub enum FilterError {
292    /// Invalid filter configuration
293    #[error("Invalid filter configuration: {reason}")]
294    InvalidConfig {
295        /// Reason for invalid configuration
296        reason: String,
297    },
298
299    /// Filter ID out of range
300    #[error("Filter ID {id:#X} out of range (max: {max:#X})")]
301    IdOutOfRange {
302        /// The invalid ID
303        id: u32,
304        /// Maximum allowed ID
305        max: u32,
306    },
307
308    /// Invalid ID range (start > end)
309    #[error("Invalid ID range: start {start:#X} > end {end:#X}")]
310    InvalidRange {
311        /// Start ID
312        start: u32,
313        /// End ID
314        end: u32,
315    },
316
317    /// Hardware filter limit exceeded
318    #[error("Hardware filter limit exceeded: max {max}, requested {requested}")]
319    HardwareFilterLimitExceeded {
320        /// Maximum hardware filters supported
321        max: usize,
322        /// Number of filters requested
323        requested: usize,
324    },
325
326    /// Filter not found
327    #[error("Filter not found at index {index}")]
328    FilterNotFound {
329        /// Index that was not found
330        index: usize,
331    },
332}
333
334/// Result type alias for filter operations
335pub type FilterResult<T> = Result<T, FilterError>;
336
337// ============================================================================
338// Queue Errors (FR-011, FR-017)
339// ============================================================================
340
341/// Queue-related errors
342///
343/// These errors occur during message queue operations.
344#[derive(Error, Debug)]
345pub enum QueueError {
346    /// Queue is full (Block policy timeout)
347    #[error("Queue full: capacity {capacity}")]
348    QueueFull {
349        /// Queue capacity
350        capacity: usize,
351    },
352
353    /// Message was dropped due to overflow policy
354    #[error("Message dropped (ID: {id:#X}): {reason}")]
355    MessageDropped {
356        /// ID of the dropped message
357        id: u32,
358        /// Reason for dropping
359        reason: String,
360    },
361
362    /// Invalid queue capacity
363    #[error("Invalid queue capacity: {capacity} (min: 1)")]
364    InvalidCapacity {
365        /// The invalid capacity value
366        capacity: usize,
367    },
368
369    /// Queue operation timeout
370    #[error("Queue operation timed out after {timeout_ms}ms")]
371    Timeout {
372        /// Timeout in milliseconds
373        timeout_ms: u64,
374    },
375}
376
377/// Result type alias for queue operations
378pub type QueueResult<T> = Result<T, QueueError>;
379
380// ============================================================================
381// Monitor Errors (FR-010)
382// ============================================================================
383
384/// Monitor-related errors
385///
386/// These errors occur during connection monitoring operations.
387#[derive(Error, Debug)]
388pub enum MonitorError {
389    /// Reconnection failed
390    #[error("Reconnect failed: {reason}")]
391    ReconnectFailed {
392        /// Reason for failure
393        reason: String,
394    },
395
396    /// Monitor not started
397    #[error("Monitor not started")]
398    NotStarted,
399
400    /// Monitor already running
401    #[error("Monitor already running")]
402    AlreadyRunning,
403
404    /// Backend error during monitoring
405    #[error("Backend error: {0}")]
406    BackendError(#[from] CanError),
407
408    /// Invalid monitor configuration
409    #[error("Invalid monitor configuration: {reason}")]
410    InvalidConfig {
411        /// Reason for invalid configuration
412        reason: String,
413    },
414
415    /// Heartbeat timeout
416    #[error("Heartbeat timeout after {timeout_ms}ms")]
417    HeartbeatTimeout {
418        /// Timeout in milliseconds
419        timeout_ms: u64,
420    },
421}
422
423/// Result type alias for monitor operations
424pub type MonitorResult<T> = Result<T, MonitorError>;
425
426#[cfg(test)]
427mod tests {
428    use super::*;
429
430    #[test]
431    fn test_error_display() {
432        let err = CanError::InvalidId {
433            value: 0x800,
434            max: 0x7FF,
435        };
436        let msg = format!("{err}");
437        assert!(msg.contains("0x800"));
438        assert!(msg.contains("0x7FF"));
439    }
440
441    #[test]
442    fn test_bus_error_kind() {
443        let error = BusErrorKind::BitError;
444        assert_eq!(error.description(), "Bit error");
445    }
446
447    #[test]
448    fn test_error_codes() {
449        let err = CanError::BackendNotFound {
450            name: "test".to_string(),
451        };
452        let msg = format!("{err}");
453        assert!(msg.contains("[1001]"));
454    }
455}