Open
Description
It's unfortunate that there's no nonblocking variant of the i2c
HAL traits -- but that could easily change.
My first impression is that it should look something like:
//! Inter-integrated Circuit Interface
use nb;
/// Possible I2C errors
pub enum Error<E> {
/// An implementation-specific error ocurred
Other(E),
/// Another master owns the bus
ArbitrationLost,
/// The slave did not acknowledge an address or data byte
ByteNacked,
/// An operation was attempted at an invalid time
///
/// For example, an attempt to `send()` a byte before `send_address()` is called will fail with
/// this error
InvalidOperation,
#[doc(hidden)]
_Extensible,
}
/// Read or write access to the peripheral
pub enum AccessType {
Read,
Write,
}
pub trait Master {
/// An enumeration of implementation-specific I2C errors
type ImplError;
/// Drive a start condition on the bus
///
/// Returns an `Error` if the system is in an invalid state.
///
/// May be used to generate a repeated start condition -- however, at minimum `send_address()`
/// must be called between the start conditions.
///
/// TODO: Does I2C require at least byte transferred before the repeated start? This is by far
/// the most common use-case
fn send_start(&mut self) -> nb::Result<(), Error<Self::ImplError>>;
/// Drive a start condition on the bus
///
/// Returns an `Error` if the system is in an invalid state
fn send_stop(&mut self) -> nb::Result<(), Error<Self::ImplError>>;
/// Send a peripheral address
///
/// Must be the first operation after generating a start condition.
fn send_address(
&mut self,
address: u8,
access: AccessType,
) -> nb::Result<(), Error<Self::ImplError>>;
/// Send a byte to the peripheral
///
/// May be called several times after sending an address with `AccessType::Write`. May not be
/// called after sending an address with `AccessType::Read`
fn send(&mut self, byte: u8) -> nb::Result<(), Error<Self::ImplError>>;
/// Send a byte to the peripheral
///
/// May be called several times after sending an address with `AccessType::Read`. May not be
/// called after sending an address with `AccessType::Write`
fn read(&mut self, send_ack: bool) -> nb::Result<u8, Error<Self::ImplError>>;
}
If this is stabilized, there could be default implementations of blocking::i2c
in terms of it, simplifying driver writers' lives.
Alternatives
The nonblocking trait could operate at a higher-level (basically just mirroring the traits exposed by blocking::i2c
except with a nb::Result
. The above trait has lots of potential for runtime errors, which may be undesirable.