diff --git a/Cargo.toml b/Cargo.toml index 9ddf3b5..8b4dbe9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,3 +24,7 @@ openpty = "0.1.0" # we don't need the `Error` implementation default-features = false version = "0.2.2" + +[patch.crates-io] +embedded-hal = { git = "https://github.com/ryankurte/embedded-hal", branch = "feature/spi-i2c-transactions" } + diff --git a/src/lib.rs b/src/lib.rs index e999faf..cf0ea1b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -228,6 +228,27 @@ impl hal::blocking::i2c::WriteRead for I2cdev { } } +pub use hal::blocking::i2c::{Operation as I2cOperation}; + +impl hal::blocking::i2c::Transactional for I2cdev { + type Error = i2cdev::linux::LinuxI2CError; + + fn exec<'a, O>(&mut self, address: u8, mut operations: O) -> Result<(), Self::Error> + where O: AsMut<[I2cOperation<'a>]> { + + // Map operations from generic to linux objects + let mut messages: Vec<_> = operations.as_mut().iter_mut().map(|a| { + match a { + I2cOperation::Write(w) => LinuxI2CMessage::write(w), + I2cOperation::Read(r) => LinuxI2CMessage::read(r), + } + }).collect(); + + self.set_address(address)?; + self.inner.transfer(&mut messages).map(drop) + } +} + impl ops::Deref for I2cdev { type Target = i2cdev::linux::LinuxI2CDevice; @@ -278,6 +299,38 @@ impl hal::blocking::spi::Write for Spidev { } } +pub use hal::blocking::spi::{Operation as SpiOperation}; + +impl hal::blocking::spi::Transactional for Spidev { + type Error = io::Error; + + fn exec<'a>(&mut self, operations: &mut [SpiOperation<'a, u8>]) -> Result<(), Self::Error> { + + // Map types from generic to linux objects + let mut messages: Vec<_> = operations.iter_mut().map(|a| { + match a { + SpiOperation::Write(w) => SpidevTransfer::write(w), + SpiOperation::WriteRead(r) => { + // TODO: is spidev okay with the same array pointer + // being used twice? If not, need some kind of vector + // pool that will outlive the transfer + let w = unsafe { + let p = r.as_ptr(); + std::slice::from_raw_parts(p, r.len()) + }; + + SpidevTransfer::read_write(w, r) + }, + } + }).collect(); + + // Execute transfer + self.0.transfer_multiple(&mut messages)?; + + Ok(()) + } +} + impl ops::Deref for Spidev { type Target = spidev::Spidev;