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}