Skip to main content

device_envoy_rp/
error.rs

1#[cfg(not(feature = "host"))]
2use core::convert::Infallible;
3
4use derive_more::derive::{Display, Error};
5use esp_hal_mfrc522::consts::PCDErrorCode;
6
7/// A specialized `Result` where the error is this crate's `Error` type.
8pub type Result<T, E = Error> = core::result::Result<T, E>;
9
10/// Define a unified error type for this crate.
11#[expect(missing_docs, reason = "The variants are self-explanatory.")]
12#[derive(Debug, Display, Error, derive_more::From)]
13pub enum Error {
14    // `#[error(not(source))]` below tells `derive_more` that `embassy_executor::SpawnError` does
15    // not implement Rust's `core::error::Error` trait.  `SpawnError` should, but Rust's `Error`
16    // only recently moved from `std` (which is not available in bare-metal development) to `core`
17    // (which is). Perhaps a future update of `embassy_executor::SpawnError` will implement
18    // `core::error::Error` which will make this unnecessary.
19    #[display("{_0:?}")]
20    TaskSpawn(#[error(not(source))] embassy_executor::SpawnError),
21
22    #[display("bits_to_indexes does not have enough preallocated space")]
23    BitsToIndexesNotEnoughSpace,
24
25    #[display("BitsToIndexes is full")]
26    BitsToIndexesFull,
27
28    #[display("Error setting output state")]
29    CannotSetOutputState,
30
31    #[display("Index out of bounds")]
32    IndexOutOfBounds,
33
34    #[display("MFRC522 initialization failed: {_0:?}")]
35    #[from(ignore)]
36    Mfrc522Init(#[error(not(source))] PCDErrorCode),
37
38    #[display("MFRC522 version read failed: {_0:?}")]
39    #[from(ignore)]
40    Mfrc522Version(#[error(not(source))] PCDErrorCode),
41
42    #[display("Format error")]
43    FormatError,
44
45    #[display("Custom WiFi Auto field missing")]
46    MissingCustomWifiAutoField,
47
48    #[display("Network Time Protocol (NTP) error: {_0}")]
49    Ntp(#[error(not(source))] &'static str),
50
51    #[cfg(feature = "wifi")]
52    #[display("DNS error: {_0:?}")]
53    Dns(#[error(not(source))] embassy_net::dns::Error),
54
55    #[cfg(not(feature = "host"))]
56    #[display("Flash operation failed: {_0:?}")]
57    Flash(#[error(not(source))] embassy_rp::flash::Error),
58
59    #[display("Storage is invalid or corrupted")]
60    StorageCorrupted,
61
62    #[display("{_0:?}")]
63    #[from(ignore)]
64    Core(#[error(not(source))] device_envoy_core::Error),
65
66    #[cfg(target_os = "none")]
67    #[display("CYD operation failed: {_0:?}")]
68    #[from(ignore)]
69    // `cyd::Error` is a diagnostic enum but is not itself a `core::error::Error`;
70    // keep it as structured context rather than claiming it as a source.
71    Cyd(#[error(not(source))] crate::cyd::Error),
72
73    #[cfg(target_os = "none")]
74    #[display("CYD touch unavailable")]
75    CydTouchUnavailable,
76}
77
78#[cfg(target_os = "none")]
79impl From<crate::cyd::Error> for Error {
80    fn from(error: crate::cyd::Error) -> Self {
81        Self::Cyd(error)
82    }
83}
84
85impl From<()> for Error {
86    fn from(_: ()) -> Self {
87        Self::FormatError
88    }
89}
90
91#[cfg(not(feature = "host"))]
92impl From<Infallible> for Error {
93    fn from(value: Infallible) -> Self {
94        match value {}
95    }
96}
97
98impl From<device_envoy_core::Error> for Error {
99    fn from(error: device_envoy_core::Error) -> Self {
100        #[cfg(feature = "wifi")]
101        if let device_envoy_core::Error::TaskSpawn(spawn_error) = error {
102            return Self::TaskSpawn(spawn_error);
103        }
104
105        Self::Core(error)
106    }
107}
108
109impl From<device_envoy_core::led4::Led4BitsToIndexesError> for Error {
110    fn from(error: device_envoy_core::led4::Led4BitsToIndexesError) -> Self {
111        match error {
112            device_envoy_core::led4::Led4BitsToIndexesError::Full => Self::BitsToIndexesFull,
113        }
114    }
115}