ezsp/
error.rs

1//! Error handling for the NCP protocol.
2
3mod decode;
4mod status;
5mod value_error;
6
7use core::convert::Infallible;
8use core::fmt::{self, Debug, Display, Formatter};
9
10pub use decode::Decode;
11pub use status::Status;
12#[allow(clippy::module_name_repetitions)]
13pub use value_error::ValueError;
14
15use crate::frame::parameters::configuration::version;
16use crate::frame::parameters::utilities::invalid_command;
17use crate::parameters::utilities;
18use crate::{Parameters, Response, ember, ezsp};
19
20/// An error that can occur when communicating with an NCP.
21#[derive(Debug)]
22pub enum Error {
23    /// An I/O error occurred.
24    Io(std::io::Error),
25    /// Decoding error.
26    Decode(Decode),
27    /// A status related error.
28    Status(Status),
29    /// An unexpected response was returned.
30    UnexpectedResponse(Box<Parameters>),
31    /// An invalid value was received.
32    ValueError(ValueError),
33    /// The NCP responded with `invalidCommand` (0x0058).
34    InvalidCommand(invalid_command::Response),
35    /// The protocol negotiation failed.
36    ProtocolVersionMismatch {
37        /// The version that was desired.
38        desired: u8,
39        /// The version that was received.
40        negotiated: version::Response,
41    },
42}
43
44impl Display for Error {
45    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
46        match self {
47            Self::Io(error) => Display::fmt(error, f),
48            Self::Decode(decode) => Display::fmt(decode, f),
49            Self::Status(status) => Display::fmt(status, f),
50            Self::UnexpectedResponse(response) => write!(f, "Unexpected response: {response:?}"),
51            Self::ValueError(status) => Display::fmt(status, f),
52            Self::InvalidCommand(response) => write!(f, "Invalid command: {response}"),
53            Self::ProtocolVersionMismatch {
54                desired,
55                negotiated,
56            } => {
57                write!(
58                    f,
59                    "Protocol negotiation failed: {desired:#04X} (desired) != {:#04X} (negotiated)",
60                    negotiated.protocol_version()
61                )
62            }
63        }
64    }
65}
66
67impl core::error::Error for Error {
68    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
69        match self {
70            Self::Io(error) => Some(error),
71            Self::Decode(decode) => Some(decode),
72            Self::Status(status) => Some(status),
73            Self::ValueError(value_error) => Some(value_error),
74            Self::UnexpectedResponse(_)
75            | Self::InvalidCommand(_)
76            | Self::ProtocolVersionMismatch { .. } => None,
77        }
78    }
79}
80
81impl From<std::io::Error> for Error {
82    fn from(error: std::io::Error) -> Self {
83        Self::Io(error)
84    }
85}
86
87impl From<Decode> for Error {
88    fn from(decode: Decode) -> Self {
89        Self::Decode(decode)
90    }
91}
92
93impl From<le_stream::Error> for Error {
94    fn from(error: le_stream::Error) -> Self {
95        Self::Decode(error.into())
96    }
97}
98
99impl From<Status> for Error {
100    fn from(status: Status) -> Self {
101        Self::Status(status)
102    }
103}
104
105impl From<Result<ezsp::Status, u8>> for Error {
106    fn from(status: Result<ezsp::Status, u8>) -> Self {
107        Self::Status(status.into())
108    }
109}
110
111impl From<Result<ember::Status, u8>> for Error {
112    fn from(status: Result<ember::Status, u8>) -> Self {
113        Self::Status(status.into())
114    }
115}
116
117impl From<Result<silizium::Status, u32>> for Error {
118    fn from(status: Result<silizium::Status, u32>) -> Self {
119        Self::Status(status.into())
120    }
121}
122
123impl From<ezsp::Status> for Error {
124    fn from(status: ezsp::Status) -> Self {
125        Self::Status(status.into())
126    }
127}
128
129impl From<ember::Status> for Error {
130    fn from(status: ember::Status) -> Self {
131        Self::Status(status.into())
132    }
133}
134
135impl From<silizium::Status> for Error {
136    fn from(status: silizium::Status) -> Self {
137        Self::Status(status.into())
138    }
139}
140
141impl From<Parameters> for Error {
142    fn from(parameters: Parameters) -> Self {
143        if let Parameters::Response(Response::Utilities(utilities::Response::InvalidCommand(
144            invalid_command,
145        ))) = parameters
146        {
147            Self::InvalidCommand(invalid_command)
148        } else {
149            Self::UnexpectedResponse(parameters.into())
150        }
151    }
152}
153
154impl From<ValueError> for Error {
155    fn from(status: ValueError) -> Self {
156        Self::ValueError(status)
157    }
158}
159
160impl From<invalid_command::Response> for Error {
161    fn from(response: invalid_command::Response) -> Self {
162        Self::InvalidCommand(response)
163    }
164}
165
166impl From<Infallible> for Error {
167    fn from(infallible: Infallible) -> Self {
168        match infallible {}
169    }
170}