diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a6f498b3..7262aed74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed - `i2c`: traits now enforce all impls on the same struct have the same `Error` type. +- `i2c`: unify all traits into a single `I2c` trait. ## [v1.0.0-alpha.6] - 2021-11-19 diff --git a/src/i2c.rs b/src/i2c.rs index 3e8415ad5..9707a4632 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -22,22 +22,70 @@ //! Here is an example of an embedded-hal implementation of the `Write` trait //! for both modes: //! ``` -//! # use embedded_hal::i2c::{ErrorKind, ErrorType, SevenBitAddress, TenBitAddress, blocking::Write}; +//! # use embedded_hal::i2c::{ErrorKind, ErrorType, SevenBitAddress, TenBitAddress, blocking::{I2c, Operation}}; //! /// I2C0 hardware peripheral which supports both 7-bit and 10-bit addressing. //! pub struct I2c0; //! //! # impl ErrorType for I2c0 { type Error = ErrorKind; } -//! impl Write for I2c0 +//! impl I2c for I2c0 //! { -//! fn write(&mut self, addr: u8, output: &[u8]) -> Result<(), Self::Error> { +//! fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { +//! // ... +//! # Ok(()) +//! } +//! fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { +//! // ... +//! # Ok(()) +//! } +//! fn write_iter>(&mut self, addr: u8, bytes: B) -> Result<(), Self::Error> { +//! // ... +//! # Ok(()) +//! } +//! fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { +//! // ... +//! # Ok(()) +//! } +//! fn write_iter_read>(&mut self, addr: u8, bytes: B, buffer: &mut [u8]) -> Result<(), Self::Error> { +//! // ... +//! # Ok(()) +//! } +//! fn transaction<'a>(&mut self, address: u8, operations: &mut [Operation<'a>]) -> Result<(), Self::Error> { +//! // ... +//! # Ok(()) +//! } +//! fn transaction_iter<'a, O: IntoIterator>>(&mut self, address: u8, operations: O) -> Result<(), Self::Error> { //! // ... //! # Ok(()) //! } //! } //! -//! impl Write for I2c0 +//! impl I2c for I2c0 //! { -//! fn write(&mut self, addr: u16, output: &[u8]) -> Result<(), Self::Error> { +//! fn read(&mut self, addr: u16, buffer: &mut [u8]) -> Result<(), Self::Error> { +//! // ... +//! # Ok(()) +//! } +//! fn write(&mut self, addr: u16, bytes: &[u8]) -> Result<(), Self::Error> { +//! // ... +//! # Ok(()) +//! } +//! fn write_iter>(&mut self, addr: u16, bytes: B) -> Result<(), Self::Error> { +//! // ... +//! # Ok(()) +//! } +//! fn write_read(&mut self, addr: u16, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { +//! // ... +//! # Ok(()) +//! } +//! fn write_iter_read>(&mut self, addr: u16, bytes: B, buffer: &mut [u8]) -> Result<(), Self::Error> { +//! // ... +//! # Ok(()) +//! } +//! fn transaction<'a>(&mut self, address: u16, operations: &mut [Operation<'a>]) -> Result<(), Self::Error> { +//! // ... +//! # Ok(()) +//! } +//! fn transaction_iter<'a, O: IntoIterator>>(&mut self, address: u16, operations: O) -> Result<(), Self::Error> { //! // ... //! # Ok(()) //! } @@ -49,7 +97,7 @@ //! For demonstration purposes the address mode parameter has been omitted in this example. //! //! ``` -//! # use embedded_hal::i2c::{blocking::WriteRead, Error}; +//! # use embedded_hal::i2c::{blocking::I2c, Error}; //! const ADDR: u8 = 0x15; //! # const TEMP_REGISTER: u8 = 0x1; //! pub struct TemperatureSensorDriver { @@ -58,7 +106,7 @@ //! //! impl TemperatureSensorDriver //! where -//! I2C: WriteRead, +//! I2C: I2c, //! { //! pub fn read_temperature(&mut self) -> Result { //! let mut temp = [0]; @@ -72,7 +120,7 @@ //! ### Device driver compatible only with 10-bit addresses //! //! ``` -//! # use embedded_hal::i2c::{Error, TenBitAddress, blocking::WriteRead}; +//! # use embedded_hal::i2c::{Error, TenBitAddress, blocking::I2c}; //! const ADDR: u16 = 0x158; //! # const TEMP_REGISTER: u8 = 0x1; //! pub struct TemperatureSensorDriver { @@ -81,7 +129,7 @@ //! //! impl TemperatureSensorDriver //! where -//! I2C: WriteRead, +//! I2C: I2c, //! { //! pub fn read_temperature(&mut self) -> Result { //! let mut temp = [0]; @@ -213,8 +261,19 @@ pub mod blocking { use super::{AddressMode, ErrorType, SevenBitAddress}; - /// Blocking read - pub trait Read: ErrorType { + /// Transactional I2C operation. + /// + /// Several operations can be combined as part of a transaction. + #[derive(Debug, PartialEq)] + pub enum Operation<'a> { + /// Read data into the provided buffer + Read(&'a mut [u8]), + /// Write data from the provided buffer + Write(&'a [u8]), + } + + /// Blocking I2C + pub trait I2c: ErrorType { /// Reads enough bytes from slave with `address` to fill `buffer` /// /// # I2C Events (contract) @@ -234,16 +293,7 @@ pub mod blocking { /// - `NMAK` = master no acknowledge /// - `SP` = stop condition fn read(&mut self, address: A, buffer: &mut [u8]) -> Result<(), Self::Error>; - } - - impl> Read for &mut T { - fn read(&mut self, address: A, buffer: &mut [u8]) -> Result<(), Self::Error> { - T::read(self, address, buffer) - } - } - /// Blocking write - pub trait Write: ErrorType { /// Writes bytes to slave with address `address` /// /// # I2C Events (contract) @@ -261,37 +311,16 @@ pub mod blocking { /// - `Bi` = ith byte of data /// - `SP` = stop condition fn write(&mut self, address: A, bytes: &[u8]) -> Result<(), Self::Error>; - } - - impl> Write for &mut T { - fn write(&mut self, address: A, bytes: &[u8]) -> Result<(), Self::Error> { - T::write(self, address, bytes) - } - } - /// Blocking write (iterator version) - pub trait WriteIter: ErrorType { /// Writes bytes to slave with address `address` /// /// # I2C Events (contract) /// - /// Same as `Write` + /// Same as the `write` method fn write_iter(&mut self, address: A, bytes: B) -> Result<(), Self::Error> where B: IntoIterator; - } - - impl> WriteIter for &mut T { - fn write_iter(&mut self, address: A, bytes: B) -> Result<(), Self::Error> - where - B: IntoIterator, - { - T::write_iter(self, address, bytes) - } - } - /// Blocking write + read - pub trait WriteRead: ErrorType { /// Writes bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a /// single transaction* /// @@ -320,27 +349,13 @@ pub mod blocking { bytes: &[u8], buffer: &mut [u8], ) -> Result<(), Self::Error>; - } - - impl> WriteRead for &mut T { - fn write_read( - &mut self, - address: A, - bytes: &[u8], - buffer: &mut [u8], - ) -> Result<(), Self::Error> { - T::write_read(self, address, bytes, buffer) - } - } - /// Blocking write (iterator version) + read - pub trait WriteIterRead: ErrorType { /// Writes bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a /// single transaction* /// /// # I2C Events (contract) /// - /// Same as the `WriteRead` trait + /// Same as the `write_read` method fn write_iter_read( &mut self, address: A, @@ -349,37 +364,7 @@ pub mod blocking { ) -> Result<(), Self::Error> where B: IntoIterator; - } - - impl> WriteIterRead for &mut T { - fn write_iter_read( - &mut self, - address: A, - bytes: B, - buffer: &mut [u8], - ) -> Result<(), Self::Error> - where - B: IntoIterator, - { - T::write_iter_read(self, address, bytes, buffer) - } - } - /// Transactional I2C operation. - /// - /// Several operations can be combined as part of a transaction. - #[derive(Debug, PartialEq)] - pub enum Operation<'a> { - /// Read data into the provided buffer - Read(&'a mut [u8]), - /// Write data from the provided buffer - Write(&'a [u8]), - } - - /// Transactional I2C interface. - /// - /// This allows combining operations within an I2C transaction. - pub trait Transactional: ErrorType { /// Execute the provided operations on the I2C bus. /// /// Transaction contract: @@ -393,27 +378,12 @@ pub mod blocking { /// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or 0 to indicate writing /// - `SR` = repeated start condition /// - `SP` = stop condition - fn exec<'a>( + fn transaction<'a>( &mut self, address: A, operations: &mut [Operation<'a>], ) -> Result<(), Self::Error>; - } - impl> Transactional for &mut T { - fn exec<'a>( - &mut self, - address: A, - operations: &mut [Operation<'a>], - ) -> Result<(), Self::Error> { - T::exec(self, address, operations) - } - } - - /// Transactional I2C interface (iterator version). - /// - /// This allows combining operation within an I2C transaction. - pub trait TransactionalIter: ErrorType { /// Execute the provided operations on the I2C bus (iterator version). /// /// Transaction contract: @@ -427,17 +397,61 @@ pub mod blocking { /// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or 0 to indicate writing /// - `SR` = repeated start condition /// - `SP` = stop condition - fn exec_iter<'a, O>(&mut self, address: A, operations: O) -> Result<(), Self::Error> + fn transaction_iter<'a, O>(&mut self, address: A, operations: O) -> Result<(), Self::Error> where O: IntoIterator>; } - impl> TransactionalIter for &mut T { - fn exec_iter<'a, O>(&mut self, address: A, operations: O) -> Result<(), Self::Error> + impl> I2c for &mut T { + fn read(&mut self, address: A, buffer: &mut [u8]) -> Result<(), Self::Error> { + T::read(self, address, buffer) + } + + fn write(&mut self, address: A, bytes: &[u8]) -> Result<(), Self::Error> { + T::write(self, address, bytes) + } + + fn write_iter(&mut self, address: A, bytes: B) -> Result<(), Self::Error> + where + B: IntoIterator, + { + T::write_iter(self, address, bytes) + } + + fn write_read( + &mut self, + address: A, + bytes: &[u8], + buffer: &mut [u8], + ) -> Result<(), Self::Error> { + T::write_read(self, address, bytes, buffer) + } + + fn write_iter_read( + &mut self, + address: A, + bytes: B, + buffer: &mut [u8], + ) -> Result<(), Self::Error> + where + B: IntoIterator, + { + T::write_iter_read(self, address, bytes, buffer) + } + + fn transaction<'a>( + &mut self, + address: A, + operations: &mut [Operation<'a>], + ) -> Result<(), Self::Error> { + T::transaction(self, address, operations) + } + + fn transaction_iter<'a, O>(&mut self, address: A, operations: O) -> Result<(), Self::Error> where O: IntoIterator>, { - T::exec_iter(self, address, operations) + T::transaction_iter(self, address, operations) } } }