rpdo/
error.rs

1use core::fmt;
2
3/// Error code for unknown host
4pub const ERR_UNKNOWN_HOST: u16 = 0x0001;
5/// Error code for invalid command
6pub const ERR_INVALID_COMMAND: u16 = 0x0002;
7/// Error code for invalid register
8pub const ERR_INVALID_REGISTER: u16 = 0x0003;
9/// Error code for invalid offset
10pub const ERR_INVALID_OFFSET: u16 = 0x0004;
11/// Error code for invalid reply
12pub const ERR_INVALID_REPLY: u16 = 0x0005;
13/// Error code for overflow
14pub const ERR_OVERFLOW: u16 = 0x0006;
15/// Error code for invalid version
16pub const ERR_INVALID_VERSION: u16 = 0x0007;
17/// Error code for I/O error
18pub const ERR_IO: u16 = 0x0008;
19/// Error code for invalid data
20pub const ERR_INVALID_DATA: u16 = 0x0009;
21/// Error code for failed data packing/unpacking
22pub const ERR_PACKER: u16 = 0x0010;
23/// Error code for all other errors
24pub const ERR_FAILED: u16 = 0x0000;
25
26/// Error type
27#[derive(thiserror::Error, Debug)]
28pub enum Error {
29    /// Host unknown
30    #[error("Host unknown")]
31    UnknownHost,
32    /// Invalid command
33    #[error("Invalid command")]
34    InvalidCommand,
35    /// Invalid register
36    #[error("Invalid register")]
37    InvalidRegister,
38    /// Invalid register offset
39    #[error("Invalid offset")]
40    InvalidOffset,
41    /// Invalid reply received
42    #[error("Invalid reply")]
43    InvalidReply,
44
45    /// Overflow (e.g. register size)
46    #[error("Overflow")]
47    Overflow,
48    /// Unsupported protocol version
49    #[error("Invalid version")]
50    UnsupportedVersion,
51    /// I/O error
52    #[error("I/O: {0}")]
53    Io(#[from] std::io::Error),
54    /// Invalid data
55    #[error("Invalid data")]
56    InvalidData,
57    /// Packer/Unpacker error
58    #[error("Packer: {0}")]
59    Packer(#[from] binrw::Error),
60    /// Failed
61    #[error("Failed: {0}")]
62    Failed(String),
63}
64
65impl From<Error> for Vec<u8> {
66    fn from(err: Error) -> Self {
67        let mut buf = Vec::<u8>::with_capacity(2);
68        buf.extend_from_slice(&err.code().to_le_bytes());
69        match err {
70            Error::Io(e) => buf.extend_from_slice(e.to_string().as_bytes()),
71            Error::Packer(e) => buf.extend_from_slice(e.to_string().as_bytes()),
72            Error::Failed(msg) => buf.extend_from_slice(msg.as_bytes()),
73            _ => (),
74        }
75        buf
76    }
77}
78
79impl From<std::num::TryFromIntError> for Error {
80    fn from(_: std::num::TryFromIntError) -> Self {
81        Self::Overflow
82    }
83}
84
85impl From<&[u8]> for Error {
86    fn from(slice: &[u8]) -> Self {
87        if slice.len() < 2 {
88            return Error::Failed(String::new());
89        }
90        let code = u16::from_le_bytes(slice[..2].try_into().unwrap());
91        let msg = std::str::from_utf8(&slice[2..]).unwrap_or_default();
92        match code {
93            ERR_UNKNOWN_HOST => Self::UnknownHost,
94            ERR_INVALID_COMMAND => Self::InvalidCommand,
95            ERR_INVALID_REGISTER => Self::InvalidRegister,
96            ERR_INVALID_OFFSET => Self::InvalidOffset,
97            ERR_INVALID_REPLY => Self::InvalidReply,
98            ERR_OVERFLOW => Self::Overflow,
99            ERR_INVALID_VERSION => Self::UnsupportedVersion,
100            ERR_IO => Self::Io(std::io::Error::new(std::io::ErrorKind::Other, msg)),
101            ERR_INVALID_DATA => Self::InvalidData,
102            ERR_FAILED => Self::Failed(msg.to_string()),
103            _ => Self::Failed(format!("Unknown error code: 0x{:04X}", code)),
104        }
105    }
106}
107
108impl From<u16> for Error {
109    fn from(e: u16) -> Self {
110        match e {
111            ERR_UNKNOWN_HOST => Self::UnknownHost,
112            ERR_INVALID_COMMAND => Self::InvalidCommand,
113            ERR_INVALID_REGISTER => Self::InvalidRegister,
114            ERR_INVALID_OFFSET => Self::InvalidOffset,
115            ERR_INVALID_REPLY => Self::InvalidReply,
116            ERR_OVERFLOW => Self::Overflow,
117            ERR_INVALID_VERSION => Self::UnsupportedVersion,
118            ERR_IO => Self::Io(std::io::Error::new(std::io::ErrorKind::Other, "I/O error")),
119            ERR_INVALID_DATA => Self::InvalidData,
120            _ => Self::Failed(format!("Unknown error code: 0x{:04X}", e)),
121        }
122    }
123}
124
125impl Error {
126    /// Get the error code
127    pub const fn code(&self) -> u16 {
128        match self {
129            Self::UnknownHost => ERR_UNKNOWN_HOST,
130            Self::InvalidCommand => ERR_INVALID_COMMAND,
131            Self::InvalidRegister => ERR_INVALID_REGISTER,
132            Self::InvalidOffset => ERR_INVALID_OFFSET,
133            Self::InvalidReply => ERR_INVALID_REPLY,
134            Self::Overflow => ERR_OVERFLOW,
135            Self::UnsupportedVersion => ERR_INVALID_VERSION,
136            Self::Io(_) => ERR_IO,
137            Self::InvalidData => ERR_INVALID_DATA,
138            Self::Packer(_) => ERR_PACKER,
139            Self::Failed(_) => ERR_FAILED,
140        }
141    }
142    /// Create a failed error
143    pub fn failed<D: fmt::Display>(msg: D) -> Self {
144        Self::Failed(msg.to_string())
145    }
146}