Skip to content

Commit d0bd316

Browse files
committed
Add error traits for communication interfaces
1 parent c2ceb78 commit d0bd316

File tree

10 files changed

+207
-44
lines changed

10 files changed

+207
-44
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1515
### Added
1616
- Added `IoPin` trait for pins that can change between being inputs or outputs
1717
dynamically.
18+
- `Error` traits for SPI, I2C and Serial traits. The error types used in those must
19+
implement these `Error` traits, which implies providing a conversion to a common
20+
set of error kinds. Generic drivers using these interfaces can then convert the errors
21+
to this common set to act upon them.
1822
- Added `Debug` to all spi mode types.
1923
- Add impls of all traits for references (`&T` or `&mut T` depending on the trait) when `T` implements the trait.
2024

src/fmt.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
//! TODO write example of usage
44
use core::fmt::{Result, Write};
55

6-
impl<Word, Error: core::fmt::Debug> Write for dyn crate::serial::nb::Write<Word, Error = Error> + '_
6+
impl<Word, Error: crate::serial::Error> Write
7+
for dyn crate::serial::nb::Write<Word, Error = Error> + '_
78
where
89
Word: From<u8>,
910
{

src/i2c.rs

Lines changed: 67 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@
2626
//! Here is an example of an embedded-hal implementation of the `Write` trait
2727
//! for both modes:
2828
//! ```
29-
//! # use embedded_hal::i2c::{SevenBitAddress, TenBitAddress, blocking::Write};
29+
//! # use embedded_hal::i2c::{ErrorKind, SevenBitAddress, TenBitAddress, blocking::Write};
3030
//! /// I2C0 hardware peripheral which supports both 7-bit and 10-bit addressing.
3131
//! pub struct I2c0;
3232
//!
3333
//! impl Write<SevenBitAddress> for I2c0
3434
//! {
35-
//! # type Error = ();
35+
//! # type Error = ErrorKind;
3636
//! #
3737
//! fn write(&mut self, addr: u8, output: &[u8]) -> Result<(), Self::Error> {
3838
//! // ...
@@ -42,7 +42,7 @@
4242
//!
4343
//! impl Write<TenBitAddress> for I2c0
4444
//! {
45-
//! # type Error = ();
45+
//! # type Error = ErrorKind;
4646
//! #
4747
//! fn write(&mut self, addr: u16, output: &[u8]) -> Result<(), Self::Error> {
4848
//! // ...
@@ -56,14 +56,14 @@
5656
//! For demonstration purposes the address mode parameter has been omitted in this example.
5757
//!
5858
//! ```
59-
//! # use embedded_hal::i2c::blocking::WriteRead;
59+
//! # use embedded_hal::i2c::{blocking::WriteRead, Error};
6060
//! const ADDR: u8 = 0x15;
6161
//! # const TEMP_REGISTER: u8 = 0x1;
6262
//! pub struct TemperatureSensorDriver<I2C> {
6363
//! i2c: I2C,
6464
//! }
6565
//!
66-
//! impl<I2C, E: core::fmt::Debug> TemperatureSensorDriver<I2C>
66+
//! impl<I2C, E: Error> TemperatureSensorDriver<I2C>
6767
//! where
6868
//! I2C: WriteRead<Error = E>,
6969
//! {
@@ -79,14 +79,14 @@
7979
//! ### Device driver compatible only with 10-bit addresses
8080
//!
8181
//! ```
82-
//! # use embedded_hal::i2c::{TenBitAddress, blocking::WriteRead};
82+
//! # use embedded_hal::i2c::{Error, TenBitAddress, blocking::WriteRead};
8383
//! const ADDR: u16 = 0x158;
8484
//! # const TEMP_REGISTER: u8 = 0x1;
8585
//! pub struct TemperatureSensorDriver<I2C> {
8686
//! i2c: I2C,
8787
//! }
8888
//!
89-
//! impl<I2C, E: core::fmt::Debug> TemperatureSensorDriver<I2C>
89+
//! impl<I2C, E: Error> TemperatureSensorDriver<I2C>
9090
//! where
9191
//! I2C: WriteRead<TenBitAddress, Error = E>,
9292
//! {
@@ -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.
@@ -119,12 +171,12 @@ impl AddressMode for TenBitAddress {}
119171
/// Blocking I2C traits
120172
pub mod blocking {
121173

122-
use super::{AddressMode, SevenBitAddress};
174+
use super::{AddressMode, Error, SevenBitAddress};
123175

124176
/// Blocking read
125177
pub trait Read<A: AddressMode = SevenBitAddress> {
126178
/// Error type
127-
type Error: core::fmt::Debug;
179+
type Error: Error;
128180

129181
/// Reads enough bytes from slave with `address` to fill `buffer`
130182
///
@@ -158,7 +210,7 @@ pub mod blocking {
158210
/// Blocking write
159211
pub trait Write<A: AddressMode = SevenBitAddress> {
160212
/// Error type
161-
type Error: core::fmt::Debug;
213+
type Error: Error;
162214

163215
/// Writes bytes to slave with address `address`
164216
///
@@ -190,7 +242,7 @@ pub mod blocking {
190242
/// Blocking write (iterator version)
191243
pub trait WriteIter<A: AddressMode = SevenBitAddress> {
192244
/// Error type
193-
type Error: core::fmt::Debug;
245+
type Error: Error;
194246

195247
/// Writes bytes to slave with address `address`
196248
///
@@ -216,7 +268,7 @@ pub mod blocking {
216268
/// Blocking write + read
217269
pub trait WriteRead<A: AddressMode = SevenBitAddress> {
218270
/// Error type
219-
type Error: core::fmt::Debug;
271+
type Error: Error;
220272

221273
/// Writes bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a
222274
/// single transaction*
@@ -264,7 +316,7 @@ pub mod blocking {
264316
/// Blocking write (iterator version) + read
265317
pub trait WriteIterRead<A: AddressMode = SevenBitAddress> {
266318
/// Error type
267-
type Error: core::fmt::Debug;
319+
type Error: Error;
268320

269321
/// Writes bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a
270322
/// single transaction*
@@ -314,7 +366,7 @@ pub mod blocking {
314366
/// This allows combining operations within an I2C transaction.
315367
pub trait Transactional<A: AddressMode = SevenBitAddress> {
316368
/// Error type
317-
type Error: core::fmt::Debug;
369+
type Error: Error;
318370

319371
/// Execute the provided operations on the I2C bus.
320372
///
@@ -353,7 +405,7 @@ pub mod blocking {
353405
/// This allows combining operation within an I2C transaction.
354406
pub trait TransactionalIter<A: AddressMode = SevenBitAddress> {
355407
/// Error type
356-
type Error: core::fmt::Debug;
408+
type Error: Error;
357409

358410
/// Execute the provided operations on the I2C bus (iterator version).
359411
///

src/lib.rs

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -143,24 +143,16 @@
143143
//! // convenience type alias
144144
//! pub type Serial1 = Serial<USART1>;
145145
//!
146-
//! /// Serial interface error
147-
//! #[derive(Debug)]
148-
//! pub enum Error {
149-
//! /// Buffer overrun
150-
//! Overrun,
151-
//! // omitted: other error variants
152-
//! }
153-
//!
154146
//! impl hal::serial::nb::Read<u8> for Serial<USART1> {
155-
//! type Error = Error;
147+
//! type Error = hal::serial::ErrorKind;
156148
//!
157-
//! fn read(&mut self) -> nb::Result<u8, Error> {
149+
//! fn read(&mut self) -> nb::Result<u8, Self::Error> {
158150
//! // read the status register
159151
//! let isr = self.usart.sr.read();
160152
//!
161153
//! if isr.ore().bit_is_set() {
162154
//! // Error: Buffer overrun
163-
//! Err(nb::Error::Other(Error::Overrun))
155+
//! Err(nb::Error::Other(Self::Error::Overrun))
164156
//! }
165157
//! // omitted: checks for other errors
166158
//! else if isr.rxne().bit_is_set() {
@@ -174,14 +166,14 @@
174166
//! }
175167
//!
176168
//! impl hal::serial::nb::Write<u8> for Serial<USART1> {
177-
//! type Error = Error;
169+
//! type Error = hal::serial::ErrorKind;
178170
//!
179-
//! fn write(&mut self, byte: u8) -> nb::Result<(), Error> {
171+
//! fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
180172
//! // Similar to the `read` implementation
181173
//! # Ok(())
182174
//! }
183175
//!
184-
//! fn flush(&mut self) -> nb::Result<(), Error> {
176+
//! fn flush(&mut self) -> nb::Result<(), Self::Error> {
185177
//! // Similar to the `read` implementation
186178
//! # Ok(())
187179
//! }
@@ -327,12 +319,11 @@
327319
//! use embedded_hal as hal;
328320
//! use hal::nb;
329321
//!
330-
//! use hal::serial::nb::Write;
331-
//! use ::core::convert::Infallible;
322+
//! use hal::serial::{ErrorKind, nb::Write};
332323
//!
333324
//! fn flush<S>(serial: &mut S, cb: &mut CircularBuffer)
334325
//! where
335-
//! S: hal::serial::nb::Write<u8, Error = Infallible>,
326+
//! S: hal::serial::nb::Write<u8, Error = ErrorKind>,
336327
//! {
337328
//! loop {
338329
//! if let Some(byte) = cb.peek() {
@@ -397,9 +388,9 @@
397388
//! # }
398389
//! # struct Serial1;
399390
//! # impl hal::serial::nb::Write<u8> for Serial1 {
400-
//! # type Error = Infallible;
401-
//! # fn write(&mut self, _: u8) -> nb::Result<(), Infallible> { Err(::nb::Error::WouldBlock) }
402-
//! # fn flush(&mut self) -> nb::Result<(), Infallible> { Err(::nb::Error::WouldBlock) }
391+
//! # type Error = ErrorKind;
392+
//! # fn write(&mut self, _: u8) -> nb::Result<(), Self::Error> { Err(::nb::Error::WouldBlock) }
393+
//! # fn flush(&mut self) -> nb::Result<(), Self::Error> { Err(::nb::Error::WouldBlock) }
403394
//! # }
404395
//! # struct CircularBuffer;
405396
//! # impl CircularBuffer {

src/serial/blocking.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
/// Write half of a serial interface (blocking variant)
88
pub trait Write<Word> {
99
/// The type of error that can occur when writing
10-
type Error: core::fmt::Debug;
10+
type Error: crate::serial::Error;
1111

1212
/// Writes a slice, blocking until everything has been written
1313
///

src/serial/mod.rs

Lines changed: 55 additions & 0 deletions
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/serial/nb.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
/// This can be encoded in this trait via the `Word` type parameter.
77
pub trait Read<Word> {
88
/// Read error
9-
type Error: core::fmt::Debug;
9+
type Error: crate::serial::Error;
1010

1111
/// Reads a single word from the serial interface
1212
fn read(&mut self) -> nb::Result<Word, Self::Error>;
@@ -23,7 +23,7 @@ impl<T: Read<Word>, Word> Read<Word> for &mut T {
2323
/// Write half of a serial interface
2424
pub trait Write<Word> {
2525
/// Write error
26-
type Error: core::fmt::Debug;
26+
type Error: crate::serial::Error;
2727

2828
/// Writes a single word to the serial interface
2929
fn write(&mut self, word: Word) -> nb::Result<(), Self::Error>;

0 commit comments

Comments
 (0)