From 492f7aeea6c309a0a8e60fb2028278fb906164cb Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 2 Mar 2021 15:09:47 -0600 Subject: [PATCH 1/4] add i2c trait --- embassy-traits/src/i2c.rs | 409 ++++++++++++++++++++++++++++++++++++++ embassy-traits/src/lib.rs | 2 + 2 files changed, 411 insertions(+) create mode 100644 embassy-traits/src/i2c.rs diff --git a/embassy-traits/src/i2c.rs b/embassy-traits/src/i2c.rs new file mode 100644 index 000000000..bd8c72ab5 --- /dev/null +++ b/embassy-traits/src/i2c.rs @@ -0,0 +1,409 @@ +//! Blocking I2C API +//! +//! This API supports 7-bit and 10-bit addresses. Traits feature an `AddressMode` +//! marker type parameter. Two implementation of the `AddressMode` exist: +//! `SevenBitAddress` and `TenBitAddress`. +//! +//! Through this marker types it is possible to implement each address mode for +//! the traits independently in `embedded-hal` implementations and device drivers +//! can depend only on the mode that they support. +//! +//! Additionally, the I2C 10-bit address mode has been developed to be fully +//! backwards compatible with the 7-bit address mode. This allows for a +//! software-emulated 10-bit addressing implementation if the address mode +//! is not supported by the hardware. +//! +//! Since 7-bit addressing is the mode of the majority of I2C devices, +//! `SevenBitAddress` has been set as default mode and thus can be omitted if desired. +//! +//! ## Examples +//! +//! ### `embedded-hal` implementation for an MCU +//! Here is an example of an embedded-hal implementation of the `Write` trait +//! for both modes: +//! ``` +//! # use embedded_hal::blocking::i2c::{SevenBitAddress, TenBitAddress, Write}; +//! /// I2C0 hardware peripheral which supports both 7-bit and 10-bit addressing. +//! pub struct I2c0; +//! +//! impl Write for I2c0 +//! { +//! # type Error = (); +//! # +//! fn try_write(&mut self, addr: u8, output: &[u8]) -> Result<(), Self::Error> { +//! // ... +//! # Ok(()) +//! } +//! } +//! +//! impl Write for I2c0 +//! { +//! # type Error = (); +//! # +//! fn try_write(&mut self, addr: u16, output: &[u8]) -> Result<(), Self::Error> { +//! // ... +//! # Ok(()) +//! } +//! } +//! ``` +//! +//! ### Device driver compatible only with 7-bit addresses +//! +//! For demonstration purposes the address mode parameter has been omitted in this example. +//! +//! ``` +//! # use embedded_hal::blocking::i2c::WriteRead; +//! const ADDR: u8 = 0x15; +//! # const TEMP_REGISTER: u8 = 0x1; +//! pub struct TemperatureSensorDriver { +//! i2c: I2C, +//! } +//! +//! impl TemperatureSensorDriver +//! where +//! I2C: WriteRead, +//! { +//! pub fn read_temperature(&mut self) -> Result { +//! let mut temp = [0]; +//! self.i2c +//! .try_write_read(ADDR, &[TEMP_REGISTER], &mut temp) +//! .and(Ok(temp[0])) +//! } +//! } +//! ``` +//! +//! ### Device driver compatible only with 10-bit addresses +//! +//! ``` +//! # use embedded_hal::blocking::i2c::{TenBitAddress, WriteRead}; +//! const ADDR: u16 = 0x158; +//! # const TEMP_REGISTER: u8 = 0x1; +//! pub struct TemperatureSensorDriver { +//! i2c: I2C, +//! } +//! +//! impl TemperatureSensorDriver +//! where +//! I2C: WriteRead, +//! { +//! pub fn read_temperature(&mut self) -> Result { +//! let mut temp = [0]; +//! self.i2c +//! .try_write_read(ADDR, &[TEMP_REGISTER], &mut temp) +//! .and(Ok(temp[0])) +//! } +//! } +//! ``` + +use core::future::Future; + +mod private { + pub trait Sealed {} +} + +/// Address mode (7-bit / 10-bit) +/// +/// Note: This trait is sealed and should not be implemented outside of this crate. +pub trait AddressMode: private::Sealed {} + +/// 7-bit address mode type +pub type SevenBitAddress = u8; + +/// 10-bit address mode type +pub type TenBitAddress = u16; + +impl private::Sealed for SevenBitAddress {} +impl private::Sealed for TenBitAddress {} + +impl AddressMode for SevenBitAddress {} + +impl AddressMode for TenBitAddress {} + +/// Blocking read +pub trait Read { + /// Error type + type Error; + + type ReadFuture<'a>: Future> + 'a; + + /// Reads enough bytes from slave with `address` to fill `buffer` + /// + /// # I2C Events (contract) + /// + /// ``` text + /// Master: ST SAD+R MAK MAK ... NMAK SP + /// Slave: SAK B0 B1 ... BN + /// ``` + /// + /// Where + /// + /// - `ST` = start condition + /// - `SAD+R` = slave address followed by bit 1 to indicate reading + /// - `SAK` = slave acknowledge + /// - `Bi` = ith byte of data + /// - `MAK` = master acknowledge + /// - `NMAK` = master no acknowledge + /// - `SP` = stop condition + fn read<'a>(&mut self, address: A, buffer: &mut [u8]) -> Self::ReadFuture<'a>; +} + +/// Blocking write +pub trait Write { + /// Error type + type Error; + + type WriteFuture<'a>: Future> + 'a; + + /// Sends bytes to slave with address `address` + /// + /// # I2C Events (contract) + /// + /// ``` text + /// Master: ST SAD+W B0 B1 ... BN SP + /// Slave: SAK SAK SAK ... SAK + /// ``` + /// + /// Where + /// + /// - `ST` = start condition + /// - `SAD+W` = slave address followed by bit 0 to indicate writing + /// - `SAK` = slave acknowledge + /// - `Bi` = ith byte of data + /// - `SP` = stop condition + fn write<'a>(&mut self, address: A, bytes: &[u8]) -> Self::WriteFuture<'a>; +} + +/// Blocking write (iterator version) +pub trait WriteIter { + /// Error type + type Error; + + type WriteIterFuture<'a>: Future> + 'a; + + /// Sends bytes to slave with address `address` + /// + /// # I2C Events (contract) + /// + /// Same as `Write` + fn write_iter<'a, B>(&mut self, address: A, bytes: B) -> Self::WriteIterFuture<'a> + where + B: IntoIterator; +} + +/// Blocking write + read +pub trait WriteRead { + /// Error type + type Error; + + type WriteReadFuture<'a>: Future> + 'a; + + /// Sends bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a + /// single transaction* + /// + /// # I2C Events (contract) + /// + /// ``` text + /// Master: ST SAD+W O0 O1 ... OM SR SAD+R MAK MAK ... NMAK SP + /// Slave: SAK SAK SAK ... SAK SAK I0 I1 ... IN + /// ``` + /// + /// Where + /// + /// - `ST` = start condition + /// - `SAD+W` = slave address followed by bit 0 to indicate writing + /// - `SAK` = slave acknowledge + /// - `Oi` = ith outgoing byte of data + /// - `SR` = repeated start condition + /// - `SAD+R` = slave address followed by bit 1 to indicate reading + /// - `Ii` = ith incoming byte of data + /// - `MAK` = master acknowledge + /// - `NMAK` = master no acknowledge + /// - `SP` = stop condition + fn write_read<'a>( + &mut self, + address: A, + bytes: &[u8], + buffer: &mut [u8], + ) -> Self::WriteReadFuture<'a>; +} + +/// Blocking write (iterator version) + read +pub trait WriteIterRead { + /// Error type + type Error; + + type WriteIterReadFuture<'a>: Future> + 'a; + + /// Sends 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 + fn write_iter_read<'a, B>( + &mut self, + address: A, + bytes: B, + buffer: &mut [u8], + ) -> Self::WriteIterReadFuture<'a> + where + B: IntoIterator; +} + +/// 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 { + /// Error type + type Error; + + type TransactionalFuture<'a>: Future> + 'a; + + /// Execute the provided operations on the I2C bus. + /// + /// Transaction contract: + /// - Before executing the first operation an ST is sent automatically. This is followed by SAD+R/W as appropriate. + /// - Data from adjacent operations of the same type are sent after each other without an SP or SR. + /// - Between adjacent operations of a different type an SR and SAD+R/W is sent. + /// - After executing the last operation an SP is sent automatically. + /// - If the last operation is a `Read` the master does not send an acknowledge for the last byte. + /// + /// - `ST` = start condition + /// - `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>( + &mut self, + address: A, + operations: &mut [Operation<'a>], + ) -> Self::TransactionalFuture<'a>; +} + +/// Transactional I2C interface (iterator version). +/// +/// This allows combining operation within an I2C transaction. +pub trait TransactionalIter { + /// Error type + type Error; + + type TransactionalIterFuture<'a>: Future> + 'a; + + /// Execute the provided operations on the I2C bus (iterator version). + /// + /// Transaction contract: + /// - Before executing the first operation an ST is sent automatically. This is followed by SAD+R/W as appropriate. + /// - Data from adjacent operations of the same type are sent after each other without an SP or SR. + /// - Between adjacent operations of a different type an SR and SAD+R/W is sent. + /// - After executing the last operation an SP is sent automatically. + /// - If the last operation is a `Read` the master does not send an acknowledge for the last byte. + /// + /// - `ST` = start condition + /// - `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) -> Self::TransactionalIterFuture<'a> + where + O: IntoIterator>; +} + +/// Default implementation of `blocking::i2c::Write`, `blocking::i2c::Read` and +/// `blocking::i2c::WriteRead` traits for `blocking::i2c::Transactional` implementers. +/// +/// If you implement `blocking::i2c::Transactional` for your I2C peripheral, +/// you can use this default implementation so that you do not need to implement +/// the `blocking::i2c::Write`, `blocking::i2c::Read` and `blocking::i2c::WriteRead` +/// traits as well. +/// ``` +/// use embedded_hal::blocking::i2c; +/// +/// struct I2c1; +/// +/// impl i2c::Transactional for I2c1 { +/// # type Error = (); +/// fn try_exec<'a>( +/// &mut self, +/// address: i2c::SevenBitAddress, +/// operations: &mut [i2c::Operation<'a>], +/// ) -> Result<(), Self::Error> { +/// // ... +/// # Ok(()) +/// } +/// } +/// +/// // This is all you need to do: +/// impl i2c::transactional::Default for I2c1 {}; +/// +/// // Then you can use `Write` and so on: +/// use i2c::Write; +/// +/// let mut i2c1 = I2c1{}; +/// i2c1.try_write(0x01, &[0xAB, 0xCD]).unwrap(); +/// ``` +pub mod transactional { + use core::future::Future; + + use super::{AddressMode, Operation, Read, Transactional, Write, WriteRead}; + + /// Default implementation of `blocking::i2c::Write`, `blocking::i2c::Read` and + /// `blocking::i2c::WriteRead` traits for `blocking::i2c::Transactional` implementers. + pub trait Default: Transactional {} + + // impl Write for S + // where + // A: AddressMode + 'static, + // S: self::Default + Transactional + 'static, + // E: 'static, + // { + // type Error = E; + // + // type WriteFuture<'a> = impl Future> + 'a; + // + // fn write<'a>(&mut self, address: A, bytes: &[u8]) -> Self::WriteFuture<'a> { + // self.exec(address, &mut [Operation::Write(bytes)]) + // } + // } + /* + impl Read for S + where + A: AddressMode, + S: self::Default + Transactional, + { + type Error = E; + + fn read(&mut self, address: A, buffer: &mut [u8]) -> Result<(), Self::Error> { + self.exec(address, &mut [Operation::Read(buffer)]) + } + } + + impl WriteRead for S + where + A: AddressMode, + S: self::Default + Transactional, + { + type Error = E; + + fn write_read( + &mut self, + address: A, + bytes: &[u8], + buffer: &mut [u8], + ) -> Result<(), Self::Error> { + self.exec( + address, + &mut [Operation::Write(bytes), Operation::Read(buffer)], + ) + } + } + */ +} diff --git a/embassy-traits/src/lib.rs b/embassy-traits/src/lib.rs index 849bbaec3..10d44d9de 100644 --- a/embassy-traits/src/lib.rs +++ b/embassy-traits/src/lib.rs @@ -4,8 +4,10 @@ #![feature(const_fn_fn_ptr_basics)] #![feature(const_option)] #![allow(incomplete_features)] +#![feature(type_alias_impl_trait)] pub mod delay; pub mod flash; pub mod gpio; +pub mod i2c; pub mod uart; From a3a36517bd8beae30b4d9ca23b3da8db1a14de12 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 3 Mar 2021 09:29:18 -0600 Subject: [PATCH 2/4] update i2c trait --- embassy-traits/src/i2c.rs | 54 +++++++++++---------------------------- 1 file changed, 15 insertions(+), 39 deletions(-) diff --git a/embassy-traits/src/i2c.rs b/embassy-traits/src/i2c.rs index bd8c72ab5..02755b571 100644 --- a/embassy-traits/src/i2c.rs +++ b/embassy-traits/src/i2c.rs @@ -1,4 +1,4 @@ -//! Blocking I2C API +//! Async I2C API //! //! This API supports 7-bit and 10-bit addresses. Traits feature an `AddressMode` //! marker type parameter. Two implementation of the `AddressMode` exist: @@ -16,37 +16,6 @@ //! Since 7-bit addressing is the mode of the majority of I2C devices, //! `SevenBitAddress` has been set as default mode and thus can be omitted if desired. //! -//! ## Examples -//! -//! ### `embedded-hal` implementation for an MCU -//! Here is an example of an embedded-hal implementation of the `Write` trait -//! for both modes: -//! ``` -//! # use embedded_hal::blocking::i2c::{SevenBitAddress, TenBitAddress, Write}; -//! /// I2C0 hardware peripheral which supports both 7-bit and 10-bit addressing. -//! pub struct I2c0; -//! -//! impl Write for I2c0 -//! { -//! # type Error = (); -//! # -//! fn try_write(&mut self, addr: u8, output: &[u8]) -> Result<(), Self::Error> { -//! // ... -//! # Ok(()) -//! } -//! } -//! -//! impl Write for I2c0 -//! { -//! # type Error = (); -//! # -//! fn try_write(&mut self, addr: u16, output: &[u8]) -> Result<(), Self::Error> { -//! // ... -//! # Ok(()) -//! } -//! } -//! ``` -//! //! ### Device driver compatible only with 7-bit addresses //! //! For demonstration purposes the address mode parameter has been omitted in this example. @@ -66,7 +35,8 @@ //! pub fn read_temperature(&mut self) -> Result { //! let mut temp = [0]; //! self.i2c -//! .try_write_read(ADDR, &[TEMP_REGISTER], &mut temp) +//! .write_read(ADDR, &[TEMP_REGISTER], &mut temp) +//! .await //! .and(Ok(temp[0])) //! } //! } @@ -89,13 +59,15 @@ //! pub fn read_temperature(&mut self) -> Result { //! let mut temp = [0]; //! self.i2c -//! .try_write_read(ADDR, &[TEMP_REGISTER], &mut temp) +//! .write_read(ADDR, &[TEMP_REGISTER], &mut temp) +//! .await //! .and(Ok(temp[0])) //! } //! } //! ``` use core::future::Future; +use core::pin::Pin; mod private { pub trait Sealed {} @@ -144,7 +116,7 @@ pub trait Read { /// - `MAK` = master acknowledge /// - `NMAK` = master no acknowledge /// - `SP` = stop condition - fn read<'a>(&mut self, address: A, buffer: &mut [u8]) -> Self::ReadFuture<'a>; + fn read<'a>(self: Pin<&'a mut Self>, address: A, buffer: &mut [u8]) -> Self::ReadFuture<'a>; } /// Blocking write @@ -170,7 +142,7 @@ pub trait Write { /// - `SAK` = slave acknowledge /// - `Bi` = ith byte of data /// - `SP` = stop condition - fn write<'a>(&mut self, address: A, bytes: &[u8]) -> Self::WriteFuture<'a>; + fn write<'a>(self: Pin<&'a mut Self>, address: A, bytes: &[u8]) -> Self::WriteFuture<'a>; } /// Blocking write (iterator version) @@ -185,7 +157,11 @@ pub trait WriteIter { /// # I2C Events (contract) /// /// Same as `Write` - fn write_iter<'a, B>(&mut self, address: A, bytes: B) -> Self::WriteIterFuture<'a> + fn write_iter<'a, B>( + self: Pin<&'a mut Self>, + address: A, + bytes: B, + ) -> Self::WriteIterFuture<'a> where B: IntoIterator; } @@ -220,7 +196,7 @@ pub trait WriteRead { /// - `NMAK` = master no acknowledge /// - `SP` = stop condition fn write_read<'a>( - &mut self, + self: Pin<&'a mut Self>, address: A, bytes: &[u8], buffer: &mut [u8], @@ -241,7 +217,7 @@ pub trait WriteIterRead { /// /// Same as the `WriteRead` trait fn write_iter_read<'a, B>( - &mut self, + self: Pin<&'a mut Self>, address: A, bytes: B, buffer: &mut [u8], From 7a46e66298437d412eef0899ae82ab51b78cda88 Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 5 Mar 2021 21:19:56 -0600 Subject: [PATCH 3/4] revise i2c trait --- embassy-traits/src/i2c.rs | 248 +------------------------------------- 1 file changed, 1 insertion(+), 247 deletions(-) diff --git a/embassy-traits/src/i2c.rs b/embassy-traits/src/i2c.rs index 02755b571..f9f462b50 100644 --- a/embassy-traits/src/i2c.rs +++ b/embassy-traits/src/i2c.rs @@ -97,6 +97,7 @@ pub trait Read { type Error; type ReadFuture<'a>: Future> + 'a; + type WriteFuture<'a>: Future> + 'a; /// Reads enough bytes from slave with `address` to fill `buffer` /// @@ -117,14 +118,6 @@ pub trait Read { /// - `NMAK` = master no acknowledge /// - `SP` = stop condition fn read<'a>(self: Pin<&'a mut Self>, address: A, buffer: &mut [u8]) -> Self::ReadFuture<'a>; -} - -/// Blocking write -pub trait Write { - /// Error type - type Error; - - type WriteFuture<'a>: Future> + 'a; /// Sends bytes to slave with address `address` /// @@ -144,242 +137,3 @@ pub trait Write { /// - `SP` = stop condition fn write<'a>(self: Pin<&'a mut Self>, address: A, bytes: &[u8]) -> Self::WriteFuture<'a>; } - -/// Blocking write (iterator version) -pub trait WriteIter { - /// Error type - type Error; - - type WriteIterFuture<'a>: Future> + 'a; - - /// Sends bytes to slave with address `address` - /// - /// # I2C Events (contract) - /// - /// Same as `Write` - fn write_iter<'a, B>( - self: Pin<&'a mut Self>, - address: A, - bytes: B, - ) -> Self::WriteIterFuture<'a> - where - B: IntoIterator; -} - -/// Blocking write + read -pub trait WriteRead { - /// Error type - type Error; - - type WriteReadFuture<'a>: Future> + 'a; - - /// Sends bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a - /// single transaction* - /// - /// # I2C Events (contract) - /// - /// ``` text - /// Master: ST SAD+W O0 O1 ... OM SR SAD+R MAK MAK ... NMAK SP - /// Slave: SAK SAK SAK ... SAK SAK I0 I1 ... IN - /// ``` - /// - /// Where - /// - /// - `ST` = start condition - /// - `SAD+W` = slave address followed by bit 0 to indicate writing - /// - `SAK` = slave acknowledge - /// - `Oi` = ith outgoing byte of data - /// - `SR` = repeated start condition - /// - `SAD+R` = slave address followed by bit 1 to indicate reading - /// - `Ii` = ith incoming byte of data - /// - `MAK` = master acknowledge - /// - `NMAK` = master no acknowledge - /// - `SP` = stop condition - fn write_read<'a>( - self: Pin<&'a mut Self>, - address: A, - bytes: &[u8], - buffer: &mut [u8], - ) -> Self::WriteReadFuture<'a>; -} - -/// Blocking write (iterator version) + read -pub trait WriteIterRead { - /// Error type - type Error; - - type WriteIterReadFuture<'a>: Future> + 'a; - - /// Sends 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 - fn write_iter_read<'a, B>( - self: Pin<&'a mut Self>, - address: A, - bytes: B, - buffer: &mut [u8], - ) -> Self::WriteIterReadFuture<'a> - where - B: IntoIterator; -} - -/// 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 { - /// Error type - type Error; - - type TransactionalFuture<'a>: Future> + 'a; - - /// Execute the provided operations on the I2C bus. - /// - /// Transaction contract: - /// - Before executing the first operation an ST is sent automatically. This is followed by SAD+R/W as appropriate. - /// - Data from adjacent operations of the same type are sent after each other without an SP or SR. - /// - Between adjacent operations of a different type an SR and SAD+R/W is sent. - /// - After executing the last operation an SP is sent automatically. - /// - If the last operation is a `Read` the master does not send an acknowledge for the last byte. - /// - /// - `ST` = start condition - /// - `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>( - &mut self, - address: A, - operations: &mut [Operation<'a>], - ) -> Self::TransactionalFuture<'a>; -} - -/// Transactional I2C interface (iterator version). -/// -/// This allows combining operation within an I2C transaction. -pub trait TransactionalIter { - /// Error type - type Error; - - type TransactionalIterFuture<'a>: Future> + 'a; - - /// Execute the provided operations on the I2C bus (iterator version). - /// - /// Transaction contract: - /// - Before executing the first operation an ST is sent automatically. This is followed by SAD+R/W as appropriate. - /// - Data from adjacent operations of the same type are sent after each other without an SP or SR. - /// - Between adjacent operations of a different type an SR and SAD+R/W is sent. - /// - After executing the last operation an SP is sent automatically. - /// - If the last operation is a `Read` the master does not send an acknowledge for the last byte. - /// - /// - `ST` = start condition - /// - `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) -> Self::TransactionalIterFuture<'a> - where - O: IntoIterator>; -} - -/// Default implementation of `blocking::i2c::Write`, `blocking::i2c::Read` and -/// `blocking::i2c::WriteRead` traits for `blocking::i2c::Transactional` implementers. -/// -/// If you implement `blocking::i2c::Transactional` for your I2C peripheral, -/// you can use this default implementation so that you do not need to implement -/// the `blocking::i2c::Write`, `blocking::i2c::Read` and `blocking::i2c::WriteRead` -/// traits as well. -/// ``` -/// use embedded_hal::blocking::i2c; -/// -/// struct I2c1; -/// -/// impl i2c::Transactional for I2c1 { -/// # type Error = (); -/// fn try_exec<'a>( -/// &mut self, -/// address: i2c::SevenBitAddress, -/// operations: &mut [i2c::Operation<'a>], -/// ) -> Result<(), Self::Error> { -/// // ... -/// # Ok(()) -/// } -/// } -/// -/// // This is all you need to do: -/// impl i2c::transactional::Default for I2c1 {}; -/// -/// // Then you can use `Write` and so on: -/// use i2c::Write; -/// -/// let mut i2c1 = I2c1{}; -/// i2c1.try_write(0x01, &[0xAB, 0xCD]).unwrap(); -/// ``` -pub mod transactional { - use core::future::Future; - - use super::{AddressMode, Operation, Read, Transactional, Write, WriteRead}; - - /// Default implementation of `blocking::i2c::Write`, `blocking::i2c::Read` and - /// `blocking::i2c::WriteRead` traits for `blocking::i2c::Transactional` implementers. - pub trait Default: Transactional {} - - // impl Write for S - // where - // A: AddressMode + 'static, - // S: self::Default + Transactional + 'static, - // E: 'static, - // { - // type Error = E; - // - // type WriteFuture<'a> = impl Future> + 'a; - // - // fn write<'a>(&mut self, address: A, bytes: &[u8]) -> Self::WriteFuture<'a> { - // self.exec(address, &mut [Operation::Write(bytes)]) - // } - // } - /* - impl Read for S - where - A: AddressMode, - S: self::Default + Transactional, - { - type Error = E; - - fn read(&mut self, address: A, buffer: &mut [u8]) -> Result<(), Self::Error> { - self.exec(address, &mut [Operation::Read(buffer)]) - } - } - - impl WriteRead for S - where - A: AddressMode, - S: self::Default + Transactional, - { - type Error = E; - - fn write_read( - &mut self, - address: A, - bytes: &[u8], - buffer: &mut [u8], - ) -> Result<(), Self::Error> { - self.exec( - address, - &mut [Operation::Write(bytes), Operation::Read(buffer)], - ) - } - } - */ -} From 9497d6c68a23528dc149265b23a720862be94748 Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 5 Mar 2021 21:30:39 -0600 Subject: [PATCH 4/4] add write_read --- embassy-traits/src/i2c.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/embassy-traits/src/i2c.rs b/embassy-traits/src/i2c.rs index f9f462b50..4dc8865e3 100644 --- a/embassy-traits/src/i2c.rs +++ b/embassy-traits/src/i2c.rs @@ -98,6 +98,7 @@ pub trait Read { type ReadFuture<'a>: Future> + 'a; type WriteFuture<'a>: Future> + 'a; + type WriteReadFuture<'a>: Future> + 'a; /// Reads enough bytes from slave with `address` to fill `buffer` /// @@ -136,4 +137,33 @@ pub trait Read { /// - `Bi` = ith byte of data /// - `SP` = stop condition fn write<'a>(self: Pin<&'a mut Self>, address: A, bytes: &[u8]) -> Self::WriteFuture<'a>; + + /// Sends bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a + /// single transaction* + /// + /// # I2C Events (contract) + /// + /// ``` text + /// Master: ST SAD+W O0 O1 ... OM SR SAD+R MAK MAK ... NMAK SP + /// Slave: SAK SAK SAK ... SAK SAK I0 I1 ... IN + /// ``` + /// + /// Where + /// + /// - `ST` = start condition + /// - `SAD+W` = slave address followed by bit 0 to indicate writing + /// - `SAK` = slave acknowledge + /// - `Oi` = ith outgoing byte of data + /// - `SR` = repeated start condition + /// - `SAD+R` = slave address followed by bit 1 to indicate reading + /// - `Ii` = ith incoming byte of data + /// - `MAK` = master acknowledge + /// - `NMAK` = master no acknowledge + /// - `SP` = stop condition + fn write_read<'a>( + self: Pin<&'a mut Self>, + address: A, + bytes: &[u8], + buffer: &mut [u8], + ) -> Self::WriteReadFuture<'a>; }