dynamixel2/
error.rs

1use crate::instructions::packet_id::BROADCAST;
2
3/// An error that can occur while initializing a bus.
4#[derive(Debug)]
5pub enum InitializeError {
6	/// Failed to get the configuration of the serial port.
7	GetConfiguration(std::io::Error),
8
9	/// Failed to get the baud rate from the configuration of the serial port.
10	GetBaudRate(std::io::Error),
11}
12
13/// An error that can occur during a read/write transfer.
14#[derive(Debug)]
15pub enum TransferError {
16	/// The write of failed.
17	WriteError(WriteError),
18
19	/// The read failed.
20	ReadError(ReadError),
21}
22
23/// An error that can occur during a write transfer.
24#[derive(Debug)]
25pub enum WriteError {
26	/// The write buffer is too small to contain the whole stuffed message.
27	BufferTooSmall(BufferTooSmallError),
28
29	/// Failed to discard the input buffer before writing the instruction.
30	DiscardBuffer(std::io::Error),
31
32	/// Failed to write the instruction.
33	Write(std::io::Error),
34}
35
36/// The buffer is too small to hold the entire message.
37///
38/// Consider increasing the size of the buffer.
39/// Keep in mind that the write buffer needs to be large enough to account for byte stuffing.
40#[derive(Debug)]
41pub struct BufferTooSmallError {
42	/// The required size of the buffer.
43	pub required_size: usize,
44
45	/// The total size of the buffer.
46	pub total_size: usize,
47}
48
49/// An error that can occur during a read transfer.
50#[derive(Debug)]
51pub enum ReadError {
52	/// The read buffer is too small to contain the whole stuffed message.
53	BufferFull(BufferTooSmallError),
54
55	/// Failed to read from the serial port.
56	Io(std::io::Error),
57
58	/// The received message is invalid.
59	InvalidMessage(InvalidMessage),
60
61	/// The motor reported an error instead of a valid response.
62	///
63	/// This error is not returned when a motor signals a hardware error,
64	/// since the instruction has still been exectuted.
65	///
66	/// Instead, the `alert` bit in the response will be set.
67	MotorError(MotorError),
68}
69
70/// The received message is not valid.
71#[derive(Debug, Clone, Eq, PartialEq)]
72pub enum InvalidMessage {
73	/// The header does not start with the proper prefix.
74	InvalidHeaderPrefix(InvalidHeaderPrefix),
75
76	/// The message checksum is invalid.
77	InvalidChecksum(InvalidChecksum),
78
79	/// The message has an invalid packet ID.
80	InvalidPacketId(InvalidPacketId),
81
82	/// The message has an invalid instruction.
83	InvalidInstruction(InvalidInstruction),
84
85	/// The message has an invalid parameter count.
86	InvalidParameterCount(InvalidParameterCount),
87}
88
89/// An error reported by the motor.
90#[derive(Clone, Eq, PartialEq)]
91pub struct MotorError {
92	/// The raw error as returned by the motor.
93	pub raw: u8,
94}
95
96impl MotorError {
97	/// The error number reported by the motor.
98	///
99	/// This is the lower 7 bits of the raw error field.
100	pub fn error_number(&self) -> u8 {
101		self.raw & !0x80
102	}
103
104	/// The alert bit from the error field of the response.
105	///
106	/// This is the 8th bit of the raw error field.
107	///
108	/// If this bit is set, you can normally check the "Hardware Error" register for more details.
109	/// Consult the manual of your motor for more information.
110	pub fn alert(&self) -> bool {
111		self.raw & 0x80 != 0
112	}
113}
114
115impl std::fmt::Debug for MotorError {
116	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117		f.debug_struct("MotorError")
118			.field("error_number", &self.error_number())
119			.field("alert", &self.alert())
120			.finish()
121	}
122}
123
124/// The received message has an invalid header prefix.
125#[derive(Debug, Clone, Eq, PartialEq)]
126pub struct InvalidHeaderPrefix {
127	/// The actual prefix.
128	pub actual: [u8; 4],
129
130	/// The expected prefix.
131	pub expected: [u8; 4],
132}
133
134/// The received message has an invalid checksum value.
135#[derive(Debug, Clone, Eq, PartialEq)]
136pub struct InvalidChecksum {
137	/// The checksum from the messsage.
138	pub message: u16,
139
140	/// The actual checksum.
141	pub computed: u16,
142}
143
144/// The received message has an invalid or unexpected packet ID.
145#[derive(Debug, Clone, Eq, PartialEq)]
146pub struct InvalidPacketId {
147	/// The actual packet ID.
148	pub actual: u8,
149
150	/// The expected packet ID (if a specific ID was expected).
151	pub expected: Option<u8>,
152}
153
154/// The received message has an invalid or unexpected instruction value.
155#[derive(Debug, Clone, Eq, PartialEq)]
156pub struct InvalidInstruction {
157	/// The actual instruction ID.
158	pub actual: u8,
159
160	/// The expected instruction id.
161	pub expected: u8,
162}
163
164/// The expected number of parameters.
165#[derive(Debug, Clone, Eq, PartialEq)]
166pub enum ExpectedCount {
167	/// The exact number of expected parameters.
168	Exact(usize),
169
170	/// An upper limit on the expected number of parameters.
171	Max(usize),
172}
173
174/// The received message has an invalid or unexpected parameter count.
175#[derive(Debug, Clone, Eq, PartialEq)]
176pub struct InvalidParameterCount {
177	/// The actual parameter count.
178	pub actual: usize,
179
180	/// The expected parameter count.
181	pub expected: ExpectedCount,
182}
183
184impl BufferTooSmallError {
185	/// Check if a buffer is large enough for the required total size.
186	pub fn check(required_size: usize, total_size: usize) -> Result<(), Self> {
187		if required_size <= total_size {
188			Ok(())
189		} else {
190			Err(Self { required_size, total_size })
191		}
192	}
193}
194
195impl MotorError {
196	/// Check for a motor error in the response.
197	///
198	/// This ignores the `alert` bit,
199	/// since it indicates a hardware error and not a failed instruction.
200	pub fn check(raw: u8) -> Result<(), Self> {
201		// Ignore the alert bit for this check.
202		// If the alert bit is set, the motor encountered an error, but the instruction was still executed.
203		if raw & !0x80 == 0 {
204			Ok(())
205		} else {
206			Err(Self { raw })
207		}
208	}
209}
210
211impl InvalidHeaderPrefix {
212	/// Check if the header prefix matches the expected value.
213	pub fn check(actual: &[u8], expected: [u8; 4]) -> Result<(), Self> {
214		if actual == expected {
215			Ok(())
216		} else {
217			Err(Self {
218				actual: [actual[0], actual[1], actual[2], actual[3]],
219				expected,
220			})
221		}
222	}
223}
224
225impl InvalidPacketId {
226	/// Check if the packet ID matches the expected value.
227	pub fn check(actual: u8, expected: u8) -> Result<(), Self> {
228		if actual == expected {
229			Ok(())
230		} else {
231			Err(Self {
232				actual,
233				expected: Some(expected),
234			})
235		}
236	}
237
238	/// Check if the packet ID matches the expected value, but don't report an error if the ID is the broadcast ID.
239	pub fn check_ignore_broadcast(actual: u8, expected: u8) -> Result<(), Self> {
240		if expected == BROADCAST {
241			Ok(())
242		} else {
243			Self::check(actual, expected)
244		}
245	}
246}
247
248impl InvalidInstruction {
249	/// Check if the instruction ID is the expected value.
250	pub fn check(actual: u8, expected: u8) -> Result<(), Self> {
251		if actual == expected {
252			Ok(())
253		} else {
254			Err(Self { actual, expected })
255		}
256	}
257}
258
259impl InvalidParameterCount {
260	/// Check if the parameter count matches the expected count.
261	pub fn check(actual: usize, expected: usize) -> Result<(), Self> {
262		if actual == expected {
263			Ok(())
264		} else {
265			Err(Self {
266				actual,
267				expected: ExpectedCount::Exact(expected),
268			})
269		}
270	}
271
272	/// Check if the parameter count is at or below the max count.
273	pub fn check_max(actual: usize, max: usize) -> Result<(), Self> {
274		if actual <= max {
275			Ok(())
276		} else {
277			Err(Self {
278				actual,
279				expected: ExpectedCount::Max(max),
280			})
281		}
282	}
283}
284
285impl std::error::Error for InitializeError {}
286impl std::error::Error for TransferError {}
287impl std::error::Error for WriteError {}
288impl std::error::Error for ReadError {}
289impl std::error::Error for InvalidMessage {}
290impl std::error::Error for MotorError {}
291impl std::error::Error for InvalidHeaderPrefix {}
292impl std::error::Error for InvalidChecksum {}
293impl std::error::Error for InvalidPacketId {}
294impl std::error::Error for InvalidInstruction {}
295impl std::error::Error for InvalidParameterCount {}
296
297impl From<WriteError> for TransferError {
298	fn from(other: WriteError) -> Self {
299		Self::WriteError(other)
300	}
301}
302
303impl From<ReadError> for TransferError {
304	fn from(other: ReadError) -> Self {
305		Self::ReadError(other)
306	}
307}
308
309impl From<InvalidMessage> for TransferError {
310	fn from(other: InvalidMessage) -> Self {
311		Self::ReadError(other.into())
312	}
313}
314
315impl From<InvalidHeaderPrefix> for TransferError {
316	fn from(other: InvalidHeaderPrefix) -> Self {
317		Self::ReadError(other.into())
318	}
319}
320
321impl From<InvalidChecksum> for TransferError {
322	fn from(other: InvalidChecksum) -> Self {
323		Self::ReadError(other.into())
324	}
325}
326
327impl From<InvalidPacketId> for TransferError {
328	fn from(other: InvalidPacketId) -> Self {
329		Self::ReadError(other.into())
330	}
331}
332
333impl From<InvalidInstruction> for TransferError {
334	fn from(other: InvalidInstruction) -> Self {
335		Self::ReadError(other.into())
336	}
337}
338
339impl From<InvalidParameterCount> for TransferError {
340	fn from(other: InvalidParameterCount) -> Self {
341		Self::ReadError(other.into())
342	}
343}
344
345impl From<BufferTooSmallError> for WriteError {
346	fn from(other: BufferTooSmallError) -> Self {
347		Self::BufferTooSmall(other)
348	}
349}
350
351impl From<BufferTooSmallError> for ReadError {
352	fn from(other: BufferTooSmallError) -> Self {
353		Self::BufferFull(other)
354	}
355}
356
357impl From<std::io::Error> for ReadError {
358	fn from(other: std::io::Error) -> Self {
359		Self::Io(other)
360	}
361}
362
363impl From<std::io::ErrorKind> for ReadError {
364	fn from(other: std::io::ErrorKind) -> Self {
365		Self::Io(other.into())
366	}
367}
368
369impl From<InvalidMessage> for ReadError {
370	fn from(other: InvalidMessage) -> Self {
371		Self::InvalidMessage(other)
372	}
373}
374
375impl From<MotorError> for ReadError {
376	fn from(other: MotorError) -> Self {
377		Self::MotorError(other)
378	}
379}
380
381impl From<InvalidHeaderPrefix> for ReadError {
382	fn from(other: InvalidHeaderPrefix) -> Self {
383		Self::InvalidMessage(other.into())
384	}
385}
386
387impl From<InvalidChecksum> for ReadError {
388	fn from(other: InvalidChecksum) -> Self {
389		Self::InvalidMessage(other.into())
390	}
391}
392
393impl From<InvalidPacketId> for ReadError {
394	fn from(other: InvalidPacketId) -> Self {
395		Self::InvalidMessage(other.into())
396	}
397}
398
399impl From<InvalidInstruction> for ReadError {
400	fn from(other: InvalidInstruction) -> Self {
401		Self::InvalidMessage(other.into())
402	}
403}
404
405impl From<InvalidParameterCount> for ReadError {
406	fn from(other: InvalidParameterCount) -> Self {
407		Self::InvalidMessage(other.into())
408	}
409}
410
411impl From<InvalidHeaderPrefix> for InvalidMessage {
412	fn from(other: InvalidHeaderPrefix) -> Self {
413		Self::InvalidHeaderPrefix(other)
414	}
415}
416
417impl From<InvalidChecksum> for InvalidMessage {
418	fn from(other: InvalidChecksum) -> Self {
419		Self::InvalidChecksum(other)
420	}
421}
422
423impl From<InvalidPacketId> for InvalidMessage {
424	fn from(other: InvalidPacketId) -> Self {
425		Self::InvalidPacketId(other)
426	}
427}
428
429impl From<InvalidInstruction> for InvalidMessage {
430	fn from(other: InvalidInstruction) -> Self {
431		Self::InvalidInstruction(other)
432	}
433}
434
435impl From<InvalidParameterCount> for InvalidMessage {
436	fn from(other: InvalidParameterCount) -> Self {
437		Self::InvalidParameterCount(other)
438	}
439}
440
441impl std::fmt::Display for InitializeError {
442	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
443		match self {
444			Self::GetConfiguration(e) => write!(f, "failed to get configuration of serial port: {e}"),
445			Self::GetBaudRate(e) => write!(f, "failed to get baud rate of serial port: {e}"),
446		}
447	}
448}
449
450impl std::fmt::Display for TransferError {
451	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
452		match self {
453			Self::WriteError(e) => write!(f, "{}", e),
454			Self::ReadError(e) => write!(f, "{}", e),
455		}
456	}
457}
458
459impl std::fmt::Display for WriteError {
460	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
461		match self {
462			Self::BufferTooSmall(e) => write!(
463				f,
464				"write buffer is too small: need {} bytes, but the size is {}",
465				e.required_size, e.total_size
466			),
467			Self::DiscardBuffer(e) => write!(f, "failed to discard input buffer: {}", e),
468			Self::Write(e) => write!(f, "failed to write to serial port: {}", e),
469		}
470	}
471}
472
473impl std::fmt::Display for BufferTooSmallError {
474	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
475		write!(
476			f,
477			"buffer is too small: need {} bytes, but the size is {}",
478			self.required_size, self.total_size
479		)
480	}
481}
482
483impl std::fmt::Display for ReadError {
484	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
485		match self {
486			Self::BufferFull(e) => write!(
487				f,
488				"read buffer is too small: need {} bytes, but the size is {}",
489				e.required_size, e.total_size
490			),
491			Self::Io(e) => write!(f, "failed to read from serial port: {}", e),
492			Self::InvalidMessage(e) => write!(f, "{}", e),
493			Self::MotorError(e) => write!(f, "{}", e),
494		}
495	}
496}
497
498impl std::fmt::Display for InvalidMessage {
499	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
500		match self {
501			Self::InvalidHeaderPrefix(e) => write!(f, "{}", e),
502			Self::InvalidChecksum(e) => write!(f, "{}", e),
503			Self::InvalidPacketId(e) => write!(f, "{}", e),
504			Self::InvalidInstruction(e) => write!(f, "{}", e),
505			Self::InvalidParameterCount(e) => write!(f, "{}", e),
506		}
507	}
508}
509
510impl std::fmt::Display for MotorError {
511	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
512		write!(f, "motor reported error status: {:#02X}", self.raw,)
513	}
514}
515
516impl std::fmt::Display for InvalidHeaderPrefix {
517	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
518		write!(
519			f,
520			"invalid header prefix, expected {:02X?}, got {:02X?}",
521			self.expected, self.actual
522		)
523	}
524}
525
526impl std::fmt::Display for InvalidChecksum {
527	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
528		write!(
529			f,
530			"invalid checksum, message claims {:#02X}, computed {:#02X}",
531			self.message, self.computed
532		)
533	}
534}
535
536impl std::fmt::Display for InvalidPacketId {
537	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
538		if let Some(expected) = self.expected {
539			write!(f, "invalid packet ID, expected {:#02X}, got {:#02X}", expected, self.actual)
540		} else {
541			write!(f, "invalid packet ID: {:#02X}", self.actual)
542		}
543	}
544}
545
546impl std::fmt::Display for InvalidInstruction {
547	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
548		write!(
549			f,
550			"invalid instruction ID, expected {:#02X}, got {:#02X}",
551			self.expected, self.actual
552		)
553	}
554}
555
556impl std::fmt::Display for ExpectedCount {
557	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
558		match self {
559			Self::Exact(x) => write!(f, "exactly {}", x),
560			Self::Max(x) => write!(f, "at most {}", x),
561		}
562	}
563}
564
565impl std::fmt::Display for InvalidParameterCount {
566	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
567		write!(f, "invalid parameter count, expected {}, got {}", self.expected, self.actual)
568	}
569}