Skip to content

Commit a3e4fd5

Browse files
committed
Add error traits for communication interfaces
1 parent ecd9898 commit a3e4fd5

File tree

8 files changed

+174
-25
lines changed

8 files changed

+174
-25
lines changed

src/blocking/i2c.rs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,21 @@
2222
//! Here is an example of an embedded-hal implementation of the `Write` trait
2323
//! for both modes:
2424
//! ```
25-
//! # use embedded_hal::blocking::i2c::{SevenBitAddress, TenBitAddress, Write};
25+
//! # use embedded_hal::blocking::i2c::{Error, ErrorKind, SevenBitAddress, TenBitAddress, Write};
2626
//! /// I2C0 hardware peripheral which supports both 7-bit and 10-bit addressing.
2727
//! pub struct I2c0;
2828
//!
29+
//! # #[derive(Debug)]
30+
//! # pub struct I2cError;
31+
//! # impl Error for I2cError {
32+
//! # fn kind(&self) -> ErrorKind {
33+
//! # unreachable!()
34+
//! # }
35+
//! # }
36+
//! #
2937
//! impl Write<SevenBitAddress> for I2c0
3038
//! {
31-
//! # type Error = ();
39+
//! # type Error = I2cError;
3240
//! #
3341
//! fn write(&mut self, addr: u8, output: &[u8]) -> Result<(), Self::Error> {
3442
//! // ...
@@ -38,7 +46,7 @@
3846
//!
3947
//! impl Write<TenBitAddress> for I2c0
4048
//! {
41-
//! # type Error = ();
49+
//! # type Error = I2cError;
4250
//! #
4351
//! fn write(&mut self, addr: u16, output: &[u8]) -> Result<(), Self::Error> {
4452
//! // ...
@@ -52,7 +60,7 @@
5260
//! For demonstration purposes the address mode parameter has been omitted in this example.
5361
//!
5462
//! ```
55-
//! # use embedded_hal::blocking::i2c::WriteRead;
63+
//! # use embedded_hal::blocking::i2c::{Error, WriteRead};
5664
//! const ADDR: u8 = 0x15;
5765
//! # const TEMP_REGISTER: u8 = 0x1;
5866
//! pub struct TemperatureSensorDriver<I2C> {
@@ -62,6 +70,7 @@
6270
//! impl<I2C, E> TemperatureSensorDriver<I2C>
6371
//! where
6472
//! I2C: WriteRead<Error = E>,
73+
//! E: Error,
6574
//! {
6675
//! pub fn read_temperature(&mut self) -> Result<u8, E> {
6776
//! let mut temp = [0];
@@ -75,7 +84,7 @@
7584
//! ### Device driver compatible only with 10-bit addresses
7685
//!
7786
//! ```
78-
//! # use embedded_hal::blocking::i2c::{TenBitAddress, WriteRead};
87+
//! # use embedded_hal::blocking::i2c::{Error, TenBitAddress, WriteRead};
7988
//! const ADDR: u16 = 0x158;
8089
//! # const TEMP_REGISTER: u8 = 0x1;
8190
//! pub struct TemperatureSensorDriver<I2C> {
@@ -85,6 +94,7 @@
8594
//! impl<I2C, E> TemperatureSensorDriver<I2C>
8695
//! where
8796
//! I2C: WriteRead<TenBitAddress, Error = E>,
97+
//! E: Error,
8898
//! {
8999
//! pub fn read_temperature(&mut self) -> Result<u8, E> {
90100
//! let mut temp = [0];
@@ -112,10 +122,12 @@ impl AddressMode for SevenBitAddress {}
112122

113123
impl AddressMode for TenBitAddress {}
114124

125+
pub use crate::errors::i2c::{Error, ErrorKind};
126+
115127
/// Blocking read
116128
pub trait Read<A: AddressMode = SevenBitAddress> {
117129
/// Error type
118-
type Error;
130+
type Error: Error;
119131

120132
/// Reads enough bytes from slave with `address` to fill `buffer`
121133
///
@@ -141,7 +153,7 @@ pub trait Read<A: AddressMode = SevenBitAddress> {
141153
/// Blocking write
142154
pub trait Write<A: AddressMode = SevenBitAddress> {
143155
/// Error type
144-
type Error;
156+
type Error: Error;
145157

146158
/// Writes bytes to slave with address `address`
147159
///
@@ -165,7 +177,7 @@ pub trait Write<A: AddressMode = SevenBitAddress> {
165177
/// Blocking write (iterator version)
166178
pub trait WriteIter<A: AddressMode = SevenBitAddress> {
167179
/// Error type
168-
type Error;
180+
type Error: Error;
169181

170182
/// Writes bytes to slave with address `address`
171183
///
@@ -180,7 +192,7 @@ pub trait WriteIter<A: AddressMode = SevenBitAddress> {
180192
/// Blocking write + read
181193
pub trait WriteRead<A: AddressMode = SevenBitAddress> {
182194
/// Error type
183-
type Error;
195+
type Error: Error;
184196

185197
/// Writes bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a
186198
/// single transaction*
@@ -215,7 +227,7 @@ pub trait WriteRead<A: AddressMode = SevenBitAddress> {
215227
/// Blocking write (iterator version) + read
216228
pub trait WriteIterRead<A: AddressMode = SevenBitAddress> {
217229
/// Error type
218-
type Error;
230+
type Error: Error;
219231

220232
/// Writes bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a
221233
/// single transaction*
@@ -249,7 +261,7 @@ pub enum Operation<'a> {
249261
/// This allows combining operations within an I2C transaction.
250262
pub trait Transactional<A: AddressMode = SevenBitAddress> {
251263
/// Error type
252-
type Error;
264+
type Error: Error;
253265

254266
/// Execute the provided operations on the I2C bus.
255267
///
@@ -273,7 +285,7 @@ pub trait Transactional<A: AddressMode = SevenBitAddress> {
273285
/// This allows combining operation within an I2C transaction.
274286
pub trait TransactionalIter<A: AddressMode = SevenBitAddress> {
275287
/// Error type
276-
type Error;
288+
type Error: Error;
277289

278290
/// Execute the provided operations on the I2C bus (iterator version).
279291
///

src/blocking/serial.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
//! Blocking serial API
22
3+
pub use crate::errors::serial::{Error, ErrorKind};
4+
35
/// Write half of a serial interface (blocking variant)
46
pub trait Write<Word> {
57
/// The type of error that can occur when writing
6-
type Error;
8+
type Error: Error;
79

810
/// Writes a slice, blocking until everything has been written
911
///

src/blocking/spi.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
//! Blocking SPI API
22
3+
pub use crate::errors::spi::{Error, ErrorKind};
4+
35
/// Blocking transfer
46
pub trait Transfer<W> {
57
/// Error type
6-
type Error;
8+
type Error: Error;
79

810
/// Writes and reads simultaneously. The contents of `words` are
911
/// written to the slave, and the received words are stored into the same
@@ -14,7 +16,7 @@ pub trait Transfer<W> {
1416
/// Blocking write
1517
pub trait Write<W> {
1618
/// Error type
17-
type Error;
19+
type Error: Error;
1820

1921
/// Writes `words` to the slave, ignoring all the incoming words
2022
fn write(&mut self, words: &[W]) -> Result<(), Self::Error>;
@@ -23,7 +25,7 @@ pub trait Write<W> {
2325
/// Blocking write (iterator version)
2426
pub trait WriteIter<W> {
2527
/// Error type
26-
type Error;
28+
type Error: Error;
2729

2830
/// Writes `words` to the slave, ignoring all the incoming words
2931
fn write_iter<WI>(&mut self, words: WI) -> Result<(), Self::Error>
@@ -46,7 +48,7 @@ pub enum Operation<'a, W: 'static> {
4648
/// as part of a single SPI transaction
4749
pub trait Transactional<W: 'static> {
4850
/// Associated error type
49-
type Error;
51+
type Error: Error;
5052

5153
/// Execute the provided transactions
5254
fn exec<'a>(&mut self, operations: &mut [Operation<'a, W>]) -> Result<(), Self::Error>;

src/errors.rs

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//! Error definitions
2+
3+
pub mod i2c {
4+
/// I2C error
5+
pub trait Error: core::fmt::Debug {
6+
/// Convert error to a generic I2C error kind
7+
///
8+
/// By using this method I2C errors freely defined by HAL implementations
9+
/// can be converted to a set of generic I2C errors upon which generic
10+
/// code can act.
11+
fn kind(&self) -> ErrorKind;
12+
}
13+
14+
/// I2C error kind
15+
///
16+
/// This represents a common set of I2C operation errors. HAL implementations are
17+
/// free to define more specific or additional error types. However, by providing
18+
/// a mapping to these common I2C errors, generic code can still react to them.
19+
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
20+
#[non_exhaustive]
21+
pub enum ErrorKind {
22+
/// An unspecific bus error occurred
23+
Bus,
24+
/// The arbitration was lost, e.g. electrical problems with the clock signal
25+
ArbitrationLoss,
26+
/// A bus operation was not acknowledged, e.g. due to the addressed device not being available on
27+
/// the bus or the device not being ready to process requests at the moment
28+
NoAcknowledge,
29+
/// The peripheral receive buffer was overrun
30+
Overrun,
31+
/// The peripheral send buffer ran out of data
32+
Underrun,
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+
44+
pub mod spi {
45+
/// SPI error
46+
pub trait Error: core::fmt::Debug {
47+
/// Convert error to a generic SPI error kind
48+
///
49+
/// By using this method SPI errors freely defined by HAL implementations
50+
/// can be converted to a set of generic SPI errors upon which generic
51+
/// code can act.
52+
fn kind(&self) -> ErrorKind;
53+
}
54+
55+
/// SPI error kind
56+
///
57+
/// This represents a common set of SPI operation errors. HAL implementations are
58+
/// free to define more specific or additional error types. However, by providing
59+
/// a mapping to these common SPI errors, generic code can still react to them.
60+
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
61+
#[non_exhaustive]
62+
pub enum ErrorKind {
63+
/// An unspecific bus error occurred
64+
Bus,
65+
/// The peripheral receive buffer was overrun
66+
Overrun,
67+
/// Multiple devices on the SPI bus are trying across each other, e.g. in a multi-master setup
68+
ModeFault,
69+
/// CRC does not match the received data
70+
CrcError,
71+
/// Received data does not conform to the peripheral configuration
72+
FrameFormat,
73+
/// A different error occurred. The original error may contain more information.
74+
Other,
75+
}
76+
77+
impl Error for ErrorKind {
78+
fn kind(&self) -> ErrorKind {
79+
*self
80+
}
81+
}
82+
}
83+
84+
pub mod serial {
85+
/// Serial error
86+
pub trait Error: core::fmt::Debug {
87+
/// Convert error to a generic serial error kind
88+
///
89+
/// By using this method serial errors freely defined by HAL implementations
90+
/// can be converted to a set of generic serial errors upon which generic
91+
/// code can act.
92+
fn kind(&self) -> ErrorKind;
93+
}
94+
95+
/// Serial error kind
96+
///
97+
/// This represents a common set of serial operation errors. HAL implementations are
98+
/// free to define more specific or additional error types. However, by providing
99+
/// a mapping to these common serial errors, generic code can still react to them.
100+
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
101+
#[non_exhaustive]
102+
pub enum ErrorKind {
103+
/// The peripheral receive buffer was overrun.
104+
Overrun,
105+
/// Received data does not conform to the peripheral configuration.
106+
/// Can be caused by a misconfigured device on either end of the serial line.
107+
FrameFormat,
108+
/// Parity check failed.
109+
Parity,
110+
/// Serial line is too noisy to read valid data.
111+
Noise,
112+
/// A different error occurred. The original error may contain more information.
113+
Other,
114+
}
115+
116+
impl Error for ErrorKind {
117+
fn kind(&self) -> ErrorKind {
118+
*self
119+
}
120+
}
121+
}

src/fmt.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use core::fmt::{Result, Write};
66
impl<Word, Error> Write for dyn crate::nb::serial::Write<Word, Error = Error> + '_
77
where
88
Word: From<u8>,
9+
Error: crate::nb::serial::Error,
910
{
1011
fn write_str(&mut self, s: &str) -> Result {
1112
let _ = s

src/lib.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -327,11 +327,10 @@
327327
//! use nb;
328328
//!
329329
//! use hal::nb::serial::Write;
330-
//! use ::core::convert::Infallible;
331330
//!
332331
//! fn flush<S>(serial: &mut S, cb: &mut CircularBuffer)
333332
//! where
334-
//! S: hal::nb::serial::Write<u8, Error = Infallible>,
333+
//! S: hal::nb::serial::Write<u8, Error = SerialError>,
335334
//! {
336335
//! loop {
337336
//! if let Some(byte) = cb.peek() {
@@ -396,16 +395,23 @@
396395
//! # }
397396
//! # struct Serial1;
398397
//! # impl hal::nb::serial::Write<u8> for Serial1 {
399-
//! # type Error = Infallible;
400-
//! # fn write(&mut self, _: u8) -> nb::Result<(), Infallible> { Err(::nb::Error::WouldBlock) }
401-
//! # fn flush(&mut self) -> nb::Result<(), Infallible> { Err(::nb::Error::WouldBlock) }
398+
//! # type Error = SerialError;
399+
//! # fn write(&mut self, _: u8) -> nb::Result<(), Self::Error> { Err(::nb::Error::WouldBlock) }
400+
//! # fn flush(&mut self) -> nb::Result<(), Self::Error> { Err(::nb::Error::WouldBlock) }
402401
//! # }
403402
//! # struct CircularBuffer;
404403
//! # impl CircularBuffer {
405404
//! # pub fn peek(&mut self) -> Option<&u8> { None }
406405
//! # pub fn pop(&mut self) -> Option<u8> { None }
407406
//! # pub fn push(&mut self, _: u8) -> Result<(), ()> { Ok(()) }
408407
//! # }
408+
//! # #[derive(Debug)]
409+
//! # pub struct SerialError;
410+
//! # impl hal::nb::serial::Error for SerialError {
411+
//! # fn kind(&self) -> hal::nb::serial::ErrorKind {
412+
//! # unreachable!()
413+
//! # }
414+
//! # }
409415
//!
410416
//! # fn main() {}
411417
//! ```
@@ -415,6 +421,7 @@
415421
#![no_std]
416422

417423
pub mod blocking;
424+
mod errors;
418425
pub mod fmt;
419426
pub mod nb;
420427

src/nb/serial.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
//! Serial interface
22
3+
pub use crate::errors::serial::{Error, ErrorKind};
4+
35
/// Read half of a serial interface
46
///
57
/// Some serial interfaces support different data sizes (8 bits, 9 bits, etc.);
68
/// This can be encoded in this trait via the `Word` type parameter.
79
pub trait Read<Word> {
810
/// Read error
9-
type Error;
11+
type Error: Error;
1012

1113
/// Reads a single word from the serial interface
1214
fn read(&mut self) -> nb::Result<Word, Self::Error>;
@@ -15,7 +17,7 @@ pub trait Read<Word> {
1517
/// Write half of a serial interface
1618
pub trait Write<Word> {
1719
/// Write error
18-
type Error;
20+
type Error: Error;
1921

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

0 commit comments

Comments
 (0)