1crate::wire_enum! {
2 pub enum Error {
3 None = 0x00,
4 UnknownCmd = 0x01,
5 InvalidPayload = 0x02,
6 InvalidSilencerSetting = 0x04,
7 InvalidTransitionMode = 0x05,
8 MissTransitionTime = 0x06,
9 FpgaTimeout = 0x07,
10 SyncNotReady = 0x08,
11 InvalidSync0Cycle = 0x09,
12 }
13}
14
15impl Error {
16 #[must_use]
17 pub const fn describe(self) -> &'static str {
18 match self {
19 Self::None => "no error",
20 Self::UnknownCmd => "unknown command (device firmware may be out of date)",
21 Self::InvalidPayload => "invalid payload",
22 Self::InvalidSilencerSetting => "invalid silencer setting",
23 Self::InvalidTransitionMode => "invalid transition mode for the target loop behavior",
24 Self::MissTransitionTime => "sys-time transition is too close to now (would be missed)",
25 Self::FpgaTimeout => "FPGA did not acknowledge a register update in time",
26 Self::SyncNotReady => "EtherCAT DC is not configured (no SYNC0 time available)",
27 Self::InvalidSync0Cycle => {
28 "invalid Sync0 cycle time (master's DC config missing or not a multiple of 500us)"
29 }
30 }
31 }
32}
33
34#[must_use]
35pub fn describe_device_error(code: u8) -> &'static str {
36 match Error::from_u8(code) {
37 Some(e) => e.describe(),
38 None => "unknown error code",
39 }
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45
46 #[test]
47 fn error_round_trips() {
48 for raw in 0u8..=0xFF {
49 match Error::from_u8(raw) {
50 Some(e) => {
51 assert_eq!(e.as_u8(), raw);
52 assert_eq!(Error::try_from(raw), Ok(e));
53 }
54 None => assert_eq!(Error::try_from(raw), Err(raw)),
55 }
56 }
57 }
58
59 #[test]
60 fn unknown_code_describes_generically() {
61 assert_eq!(describe_device_error(0xFF), "unknown error code");
62 }
63}