flipperzero_sys/furi/
status.rs

1//! Low-level wrappers around Furi Status API.
2
3use core::fmt::Display;
4
5use crate::FuriStatus;
6
7/// The error type for Furi kernel operations.
8#[derive(Clone, Copy, Debug, ufmt::derive::uDebug, Eq, PartialEq)]
9pub enum Error {
10    Unspecified,
11    TimedOut,
12    ResourceBusy,
13    InvalidParameter,
14    OutOfMemory,
15    ForbiddenInISR,
16    Other(i32),
17}
18
19impl Error {
20    /// Describe the kind of error.
21    pub fn description(&self) -> &str {
22        match self {
23            Self::Unspecified => "Unspecified RTOS error",
24            Self::TimedOut => "Operation not completed within the timeout period",
25            Self::ResourceBusy => "Resource not available",
26            Self::InvalidParameter => "Parameter error",
27            Self::OutOfMemory => "System is out of memory",
28            Self::ForbiddenInISR => "Not allowed in ISR context",
29            _ => "Unknown",
30        }
31    }
32}
33
34/// Create [`Error`] from [`FuriStatus`].
35impl TryFrom<FuriStatus> for Error {
36    type Error = i32;
37
38    fn try_from(status: crate::FuriStatus) -> core::result::Result<Self, Self::Error> {
39        match status {
40            crate::FuriStatusError => Ok(Self::Unspecified),
41            crate::FuriStatusErrorTimeout => Ok(Self::TimedOut),
42            crate::FuriStatusErrorResource => Ok(Self::ResourceBusy),
43            crate::FuriStatusErrorParameter => Ok(Self::InvalidParameter),
44            crate::FuriStatusErrorNoMemory => Ok(Self::OutOfMemory),
45            crate::FuriStatusErrorISR => Ok(Self::ForbiddenInISR),
46            crate::FuriStatus(x) => {
47                if x < 0 {
48                    Ok(Self::Other(x))
49                } else {
50                    Err(x)
51                }
52            }
53        }
54    }
55}
56
57/// Create [`FuriStatus`] from [`Error`].
58impl From<Error> for FuriStatus {
59    fn from(error: Error) -> Self {
60        match error {
61            Error::Unspecified => crate::FuriStatusError,
62            Error::TimedOut => crate::FuriStatusErrorTimeout,
63            Error::ResourceBusy => crate::FuriStatusErrorResource,
64            Error::InvalidParameter => crate::FuriStatusErrorParameter,
65            Error::OutOfMemory => crate::FuriStatusErrorNoMemory,
66            Error::ForbiddenInISR => crate::FuriStatusErrorISR,
67            Error::Other(x) => crate::FuriStatus(x),
68        }
69    }
70}
71
72impl Display for Error {
73    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
74        write!(f, "{} ({})", self.description(), FuriStatus::from(*self).0)
75    }
76}
77
78impl ufmt::uDisplay for Error {
79    fn fmt<W>(&self, f: &mut ufmt::Formatter<'_, W>) -> Result<(), W::Error>
80    where
81        W: ufmt::uWrite + ?Sized,
82    {
83        ufmt::uwrite!(f, "{} ({})", self.description(), FuriStatus::from(*self).0)
84    }
85}
86
87/// Operation status.
88/// The Furi API switches between using `enum FuriStatus`, `int32_t` and `uint32_t`.
89/// Since these all use the same bit representation, we can just "cast" the returns to this type.
90#[repr(transparent)]
91#[derive(Clone, Copy, Debug, ufmt::derive::uDebug, Eq, PartialEq)]
92pub struct Status(pub i32);
93
94impl Status {
95    /// Operation completed successfully.
96    pub const OK: Status = Status(0);
97    /// Unspecified RTOS error: run-time error but no other error message fits.
98    pub const ERR: Status = Status(-1);
99    /// Operation not completed within the timeout period.
100    pub const ERR_TIMEOUT: Status = Status(-2);
101    /// Resource not available.
102    pub const ERR_RESOURCE: Status = Status(-3);
103    /// Parameter error.
104    pub const ERR_PARAMETER: Status = Status(-4);
105    /// System is out of memory: it was impossible to allocate or reserve memory for the operation.
106    pub const ERR_NO_MEMORY: Status = Status(-5);
107    /// Not allowed in ISR context: the function cannot be called from interrupt service routines.
108    pub const ERR_ISR: Status = Status(-6);
109
110    /// Describes the status result of the operation.
111    pub fn description(self) -> &'static str {
112        match self {
113            Self::OK => "Operation completed successfully",
114            Self::ERR => "Unspecified RTOS error",
115            Self::ERR_TIMEOUT => "Operation not completed within the timeout period",
116            Self::ERR_RESOURCE => "Resource not available",
117            Self::ERR_PARAMETER => "Parameter error",
118            Self::ERR_NO_MEMORY => "System is out of memory",
119            Self::ERR_ISR => "Not allowed in ISR context",
120            _ => "Unknown",
121        }
122    }
123
124    /// Check if this is an error status.
125    pub fn is_err(self) -> bool {
126        self != Self::OK
127    }
128
129    /// Convert into [`Result`] type.
130    pub fn into_result(self) -> Result<i32, Error> {
131        match Error::try_from(crate::FuriStatus(self.0)) {
132            Err(x) => Ok(x),
133            Ok(err) => Err(err),
134        }
135    }
136}
137
138impl Display for Status {
139    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
140        write!(f, "{:?}: {}", self, self.description())
141    }
142}
143
144impl ufmt::uDisplay for Status {
145    fn fmt<W>(&self, f: &mut ufmt::Formatter<'_, W>) -> Result<(), W::Error>
146    where
147        W: ufmt::uWrite + ?Sized,
148    {
149        ufmt::uwrite!(f, "{:?}: {}", self, self.description())
150    }
151}
152
153impl From<crate::FuriStatus> for Status {
154    fn from(code: FuriStatus) -> Self {
155        Status(code.0)
156    }
157}
158
159impl From<i32> for Status {
160    fn from(value: i32) -> Self {
161        Status(value)
162    }
163}
164
165impl From<u32> for Status {
166    fn from(value: u32) -> Self {
167        Status(value as i32)
168    }
169}
170
171impl From<Status> for Result<i32, Error> {
172    fn from(status: Status) -> Self {
173        status.into_result()
174    }
175}