Skip to content

Commit f16b10c

Browse files
committed
Add error traits for communication interfaces
1 parent 47354c8 commit f16b10c

File tree

5 files changed

+177
-12
lines changed

5 files changed

+177
-12
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1111
- Added `IoPin` trait for pins that can change between being inputs or outputs
1212
dynamically.
1313
- Added `Debug` to all spi mode types.
14+
- `Error` traits for SPI, I2C and Serial traits. The error types used in those must
15+
implement these `Error` traits, which implies providing a conversion to a common
16+
set of error kinds. Generic drivers using these interfaces can then convert the errors
17+
to this common set to act upon them.
1418

1519
### Changed
1620
- Swap PWM channel arguments to references

src/i2c.rs

+52
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,58 @@
101101
102102
use crate::private;
103103

104+
/// I2C error
105+
pub trait Error: core::fmt::Debug {
106+
/// Convert error to a generic I2C error kind
107+
///
108+
/// By using this method, I2C errors freely defined by HAL implementations
109+
/// can be converted to a set of generic I2C errors upon which generic
110+
/// code can act.
111+
fn kind(&self) -> ErrorKind;
112+
}
113+
114+
/// I2C error kind
115+
///
116+
/// This represents a common set of I2C operation errors. HAL implementations are
117+
/// free to define more specific or additional error types. However, by providing
118+
/// a mapping to these common I2C errors, generic code can still react to them.
119+
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
120+
#[non_exhaustive]
121+
pub enum ErrorKind {
122+
/// An unspecific bus error occurred
123+
Bus,
124+
/// The arbitration was lost, e.g. electrical problems with the clock signal
125+
ArbitrationLoss,
126+
/// A bus operation was not acknowledged, e.g. due to the addressed device not being available on
127+
/// the bus or the device not being ready to process requests at the moment
128+
NoAcknowledge,
129+
/// The peripheral receive buffer was overrun
130+
Overrun,
131+
/// A different error occurred. The original error may contain more information.
132+
Other,
133+
}
134+
135+
impl Error for ErrorKind {
136+
fn kind(&self) -> ErrorKind {
137+
*self
138+
}
139+
}
140+
141+
impl core::fmt::Display for ErrorKind {
142+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
143+
match self {
144+
Self::Bus => write!(f, "An unspecific bus error occurred"),
145+
Self::ArbitrationLoss => write!(f, "The arbitration was lost"),
146+
Self::NoAcknowledge => write!(f, "A bus operation was not acknowledged"),
147+
Self::Overrun => write!(f, "The peripheral receive buffer was overrun"),
148+
Self::Other => write!(
149+
f,
150+
"A different error occurred. The original error may contain more information"
151+
),
152+
}
153+
}
154+
}
155+
104156
/// Address mode (7-bit / 10-bit)
105157
///
106158
/// Note: This trait is sealed and should not be implemented outside of this crate.

src/lib.rs

+6-12
Original file line numberDiff line numberDiff line change
@@ -143,23 +143,17 @@
143143
//! // convenience type alias
144144
//! pub type Serial1 = Serial<USART1>;
145145
//!
146-
//! /// Serial interface error
147-
//! pub enum Error {
148-
//! /// Buffer overrun
149-
//! Overrun,
150-
//! // omitted: other error variants
151-
//! }
152146
//!
153147
//! impl hal::serial::nb::Read<u8> for Serial<USART1> {
154-
//! type Error = Error;
148+
//! type Error = hal::serial::ErrorKind;
155149
//!
156-
//! fn read(&mut self) -> nb::Result<u8, Error> {
150+
//! fn read(&mut self) -> nb::Result<u8, Self::Error> {
157151
//! // read the status register
158152
//! let isr = self.usart.sr.read();
159153
//!
160154
//! if isr.ore().bit_is_set() {
161155
//! // Error: Buffer overrun
162-
//! Err(nb::Error::Other(Error::Overrun))
156+
//! Err(nb::Error::Other(Self::Error::Overrun))
163157
//! }
164158
//! // omitted: checks for other errors
165159
//! else if isr.rxne().bit_is_set() {
@@ -173,14 +167,14 @@
173167
//! }
174168
//!
175169
//! impl hal::serial::nb::Write<u8> for Serial<USART1> {
176-
//! type Error = Error;
170+
//! type Error = hal::serial::ErrorKind;
177171
//!
178-
//! fn write(&mut self, byte: u8) -> nb::Result<(), Error> {
172+
//! fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
179173
//! // Similar to the `read` implementation
180174
//! # Ok(())
181175
//! }
182176
//!
183-
//! fn flush(&mut self) -> nb::Result<(), Error> {
177+
//! fn flush(&mut self) -> nb::Result<(), Self::Error> {
184178
//! // Similar to the `read` implementation
185179
//! # Ok(())
186180
//! }

src/serial/mod.rs

+55
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,58 @@
22
33
pub mod blocking;
44
pub mod nb;
5+
6+
/// Serial error
7+
pub trait Error: core::fmt::Debug {
8+
/// Convert error to a generic serial error kind
9+
///
10+
/// By using this method, serial errors freely defined by HAL implementations
11+
/// can be converted to a set of generic serial errors upon which generic
12+
/// code can act.
13+
fn kind(&self) -> ErrorKind;
14+
}
15+
16+
/// Serial error kind
17+
///
18+
/// This represents a common set of serial operation errors. HAL implementations are
19+
/// free to define more specific or additional error types. However, by providing
20+
/// a mapping to these common serial errors, generic code can still react to them.
21+
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
22+
#[non_exhaustive]
23+
pub enum ErrorKind {
24+
/// The peripheral receive buffer was overrun.
25+
Overrun,
26+
/// Received data does not conform to the peripheral configuration.
27+
/// Can be caused by a misconfigured device on either end of the serial line.
28+
FrameFormat,
29+
/// Parity check failed.
30+
Parity,
31+
/// Serial line is too noisy to read valid data.
32+
Noise,
33+
/// A different error occurred. The original error may contain more information.
34+
Other,
35+
}
36+
37+
impl Error for ErrorKind {
38+
fn kind(&self) -> ErrorKind {
39+
*self
40+
}
41+
}
42+
43+
impl core::fmt::Display for ErrorKind {
44+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
45+
match self {
46+
Self::Overrun => write!(f, "The peripheral receive buffer was overrun"),
47+
Self::Parity => write!(f, "Parity check failed"),
48+
Self::Noise => write!(f, "Serial line is too noisy to read valid data"),
49+
Self::FrameFormat => write!(
50+
f,
51+
"Received data does not conform to the peripheral configuration"
52+
),
53+
Self::Other => write!(
54+
f,
55+
"A different error occurred. The original error may contain more information"
56+
),
57+
}
58+
}
59+
}

src/spi/mod.rs

+60
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,63 @@ pub const MODE_3: Mode = Mode {
5353
polarity: Polarity::IdleHigh,
5454
phase: Phase::CaptureOnSecondTransition,
5555
};
56+
57+
/// SPI error
58+
pub trait Error: core::fmt::Debug {
59+
/// Convert error to a generic SPI error kind
60+
///
61+
/// By using this method, SPI errors freely defined by HAL implementations
62+
/// can be converted to a set of generic SPI errors upon which generic
63+
/// code can act.
64+
fn kind(&self) -> ErrorKind;
65+
}
66+
67+
/// SPI error kind
68+
///
69+
/// This represents a common set of SPI operation errors. HAL implementations are
70+
/// free to define more specific or additional error types. However, by providing
71+
/// a mapping to these common SPI errors, generic code can still react to them.
72+
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
73+
#[non_exhaustive]
74+
pub enum ErrorKind {
75+
/// An unspecific bus error occurred
76+
Bus,
77+
/// The peripheral receive buffer was overrun
78+
Overrun,
79+
/// Multiple devices on the SPI bus are trying across each other, e.g. in a multi-master setup
80+
ModeFault,
81+
/// CRC does not match the received data
82+
Crc,
83+
/// Received data does not conform to the peripheral configuration
84+
FrameFormat,
85+
/// A different error occurred. The original error may contain more information.
86+
Other,
87+
}
88+
89+
impl Error for ErrorKind {
90+
fn kind(&self) -> ErrorKind {
91+
*self
92+
}
93+
}
94+
95+
impl core::fmt::Display for ErrorKind {
96+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
97+
match self {
98+
Self::Bus => write!(f, "An unspecific bus error occurred"),
99+
Self::Overrun => write!(f, "The peripheral receive buffer was overrun"),
100+
Self::ModeFault => write!(
101+
f,
102+
"Multiple devices on the SPI bus are trying across each other"
103+
),
104+
Self::Crc => write!(f, "CRC does not match the received data"),
105+
Self::FrameFormat => write!(
106+
f,
107+
"Received data does not conform to the peripheral configuration"
108+
),
109+
Self::Other => write!(
110+
f,
111+
"A different error occurred. The original error may contain more information"
112+
),
113+
}
114+
}
115+
}

0 commit comments

Comments
 (0)