1use crate::can::CanError;
4use crate::protocol::ProtocolError;
5use thiserror::Error;
6
7#[derive(Error, Debug)]
9pub enum RobotError {
10 #[error("CAN driver error: {0}")]
12 Can(#[from] CanError),
13
14 #[error("Protocol error: {0}")]
16 Protocol(#[from] ProtocolError),
17
18 #[error("Command channel closed")]
20 ChannelClosed,
21
22 #[error("Command channel full (buffer size: 10)")]
24 ChannelFull,
25
26 #[error("Not in dual-thread mode. Use `new_dual_thread()` instead of `new()`")]
30 NotDualThread,
31
32 #[error("Poisoned lock (thread panic)")]
34 PoisonedLock,
35
36 #[error("IO thread error: {0}")]
38 IoThread(String),
39
40 #[error("Not implemented: {0}")]
42 NotImplemented(String),
43
44 #[error("Operation timeout")]
46 Timeout,
47}
48
49#[cfg(test)]
50mod tests {
51 use super::RobotError;
52 use crate::can::CanError;
53 use crate::protocol::ProtocolError;
54
55 #[test]
57 fn test_robot_error_display() {
58 let can_error = CanError::Timeout;
60 let robot_error = RobotError::Can(can_error);
61 let msg = format!("{}", robot_error);
62 assert!(
63 msg.contains("Read timeout") || msg.contains("CAN"),
64 "Can error message: {}",
65 msg
66 );
67
68 let protocol_error = ProtocolError::InvalidLength {
70 expected: 8,
71 actual: 4,
72 };
73 let robot_error = RobotError::Protocol(protocol_error);
74 let msg = format!("{}", robot_error);
75 assert!(
76 msg.contains("Invalid frame length"),
77 "Protocol error message: {}",
78 msg
79 );
80
81 let robot_error = RobotError::ChannelClosed;
83 let msg = format!("{}", robot_error);
84 assert_eq!(msg, "Command channel closed");
85
86 let robot_error = RobotError::ChannelFull;
88 let msg = format!("{}", robot_error);
89 assert!(msg.contains("channel full") || msg.contains("ChannelFull"));
90
91 let robot_error = RobotError::PoisonedLock;
93 let msg = format!("{}", robot_error);
94 assert!(msg.contains("Poisoned lock") || msg.contains("PoisonedLock"));
95
96 let robot_error = RobotError::IoThread("test error".to_string());
98 let msg = format!("{}", robot_error);
99 assert!(msg.contains("IO thread") && msg.contains("test error"));
100
101 let robot_error = RobotError::NotImplemented("feature".to_string());
103 let msg = format!("{}", robot_error);
104 assert!(msg.contains("Not implemented") && msg.contains("feature"));
105
106 let robot_error = RobotError::Timeout;
108 let msg = format!("{}", robot_error);
109 assert_eq!(msg, "Operation timeout");
110 }
111
112 #[test]
114 fn test_from_can_error() {
115 let can_error = CanError::Timeout;
116 let robot_error: RobotError = can_error.into();
117 match robot_error {
118 RobotError::Can(e) => assert!(matches!(e, CanError::Timeout)),
119 _ => panic!("Expected Can variant"),
120 }
121 }
122
123 #[test]
125 fn test_from_protocol_error() {
126 let protocol_error = ProtocolError::InvalidCanId { id: 0x123 };
127 let robot_error: RobotError = protocol_error.into();
128 match robot_error {
129 RobotError::Protocol(e) => match e {
130 ProtocolError::InvalidCanId { id } => assert_eq!(id, 0x123),
131 _ => panic!("Expected InvalidCanId variant"),
132 },
133 _ => panic!("Expected Protocol variant"),
134 }
135 }
136}