diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b0eb1de..026e4732 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Changed + +- implement `embedded_hal::blocking::i2c::Transactional` for `I2c` [#671] + +[#671]: https://github.com/stm32-rs/stm32f4xx-hal/pull/671 + ## [v0.17.0] - 2023-07-11 ### Changed diff --git a/src/i2c.rs b/src/i2c.rs index ca98ecde..229f8a1e 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -6,7 +6,6 @@ use crate::rcc::{Enable, Reset}; use crate::gpio; use crate::rcc::Clocks; -use embedded_hal_one::i2c::Operation; use fugit::{HertzU32 as Hertz, RateExtU32}; mod hal_02; @@ -504,84 +503,57 @@ impl I2c { self.write_bytes(bytes.into_iter())?; self.read(addr, buffer) } +} - pub fn transaction<'a>( - &mut self, - addr: u8, - mut ops: impl Iterator>, - ) -> Result<(), Error> { - if let Some(mut prev_op) = ops.next() { - // 1. Generate Start for operation - match &prev_op { - Operation::Read(_) => self.prepare_read(addr)?, - Operation::Write(_) => self.prepare_write(addr)?, - }; - - for op in ops { - // 2. Execute previous operations. - match &mut prev_op { - Operation::Read(rb) => self.read_bytes(rb)?, - Operation::Write(wb) => self.write_bytes(wb.iter().cloned())?, +macro_rules! transaction_impl { + ($vis:vis fn $function:ident: $operation:ty, $read:path, $write:path) => { + $vis fn $function( + &mut self, + addr: u8, + ops_slice: &mut [$operation], + ) -> Result<(), Error> { + let mut ops = ops_slice.iter_mut(); + + if let Some(mut prev_op) = ops.next() { + // 1. Generate Start for operation + match &prev_op { + $read(_) => self.prepare_read(addr)?, + $write(_) => self.prepare_write(addr)?, }; - // 3. If operation changes type we must generate new start - match (&prev_op, &op) { - (Operation::Read(_), Operation::Write(_)) => self.prepare_write(addr)?, - (Operation::Write(_), Operation::Read(_)) => self.prepare_read(addr)?, - _ => {} // No changes if operation have not changed - } - - prev_op = op; - } - - // 4. Now, prev_op is last command use methods variations that will generate stop - match prev_op { - Operation::Read(rb) => self.read_wo_prepare(rb)?, - Operation::Write(wb) => self.write_wo_prepare(wb)?, - }; - } - // Fallthrough is success - Ok(()) - } - - pub fn transaction_slice( - &mut self, - addr: u8, - ops_slice: &mut [Operation<'_>], - ) -> Result<(), Error> { - let mut ops = ops_slice.iter_mut(); - - if let Some(mut prev_op) = ops.next() { - // 1. Generate Start for operation - match &prev_op { - Operation::Read(_) => self.prepare_read(addr)?, - Operation::Write(_) => self.prepare_write(addr)?, - }; - - for op in ops { - // 2. Execute previous operations. - match &mut prev_op { - Operation::Read(rb) => self.read_bytes(rb)?, - Operation::Write(wb) => self.write_bytes(wb.iter().cloned())?, - }; - // 3. If operation changes type we must generate new start - match (&prev_op, &op) { - (Operation::Read(_), Operation::Write(_)) => self.prepare_write(addr)?, - (Operation::Write(_), Operation::Read(_)) => self.prepare_read(addr)?, - _ => {} // No changes if operation have not changed + for op in ops { + // 2. Execute previous operations. + match &mut prev_op { + $read(rb) => self.read_bytes(rb)?, + $write(wb) => self.write_bytes(wb.iter().cloned())?, + }; + // 3. If operation changes type we must generate new start + match (&prev_op, &op) { + ($read(_), $write(_)) => self.prepare_write(addr)?, + ($write(_), $read(_)) => self.prepare_read(addr)?, + _ => {} // No changes if operation have not changed + } + + prev_op = op; } - prev_op = op; + // 4. Now, prev_op is last command use methods variations that will generate stop + match prev_op { + $read(rb) => self.read_wo_prepare(rb)?, + $write(wb) => self.write_wo_prepare(wb)?, + }; } - // 4. Now, prev_op is last command use methods variations that will generate stop - match prev_op { - Operation::Read(rb) => self.read_wo_prepare(rb)?, - Operation::Write(wb) => self.write_wo_prepare(wb)?, - }; + // Fallthrough is success + Ok(()) } + }; +} - // Fallthrough is success - Ok(()) - } +type Hal1Operation<'a> = embedded_hal_one::i2c::Operation<'a>; +type Hal02Operation<'a> = embedded_hal::blocking::i2c::Operation<'a>; + +impl I2c { + transaction_impl!(pub fn transaction_slice: Hal1Operation<'_>, Hal1Operation::Read, Hal1Operation::Write); + transaction_impl!(fn transaction_slice_hal_02: Hal02Operation<'_>, Hal02Operation::Read, Hal02Operation::Write); } diff --git a/src/i2c/hal_02.rs b/src/i2c/hal_02.rs index 14cb5ef8..900107a2 100644 --- a/src/i2c/hal_02.rs +++ b/src/i2c/hal_02.rs @@ -1,6 +1,8 @@ mod blocking { use super::super::{Error, I2c, Instance}; - use embedded_hal::blocking::i2c::{Read, Write, WriteIter, WriteIterRead, WriteRead}; + use embedded_hal::blocking::i2c::{ + Operation, Read, Transactional, Write, WriteIter, WriteIterRead, WriteRead, + }; impl WriteRead for I2c where @@ -72,4 +74,19 @@ mod blocking { self.read(addr, buffer) } } + + impl Transactional for I2c + where + I2C: Instance, + { + type Error = Error; + + fn exec<'a>( + &mut self, + address: u8, + operations: &mut [Operation<'a>], + ) -> Result<(), Self::Error> { + self.transaction_slice_hal_02(address, operations) + } + } }