From 1b0f4ee65390ec0e511c2455c0f26c8d4f661ec3 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Mon, 31 Jul 2023 13:35:06 -0500 Subject: [PATCH 1/3] stm32: add outlives bounds to TimeoutI2c impl blocks This should make usage and error messages more clear. --- embassy-stm32/src/i2c/timeout.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/i2c/timeout.rs b/embassy-stm32/src/i2c/timeout.rs index 8dc228b34..bb6e105de 100644 --- a/embassy-stm32/src/i2c/timeout.rs +++ b/embassy-stm32/src/i2c/timeout.rs @@ -22,7 +22,7 @@ fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> { } } -impl<'a, 'd, T: Instance, TXDMA, RXDMA> TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> { +impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> { pub fn new(i2c: &'a mut I2c<'d, T, TXDMA, RXDMA>, timeout: Duration) -> Self { Self { i2c, timeout } } @@ -65,7 +65,9 @@ impl<'a, 'd, T: Instance, TXDMA, RXDMA> TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> { } } -impl<'a, 'd, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Read for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> { +impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Read + for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> +{ type Error = Error; fn read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Self::Error> { @@ -73,7 +75,9 @@ impl<'a, 'd, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Read for } } -impl<'a, 'd, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Write for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> { +impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Write + for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> +{ type Error = Error; fn write(&mut self, addr: u8, write: &[u8]) -> Result<(), Self::Error> { @@ -81,7 +85,7 @@ impl<'a, 'd, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Write fo } } -impl<'a, 'd, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::WriteRead +impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::WriteRead for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> { type Error = Error; @@ -95,11 +99,11 @@ impl<'a, 'd, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::WriteRea mod eh1 { use super::*; - impl<'a, 'd, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> { + impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> { type Error = Error; } - impl<'a, 'd, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::I2c for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> { + impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::I2c for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> { fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { self.blocking_read(address, read) } From 26cc0e634d1e0f51e7c4c5bb55fea4f7bec299aa Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Mon, 31 Jul 2023 13:47:03 -0500 Subject: [PATCH 2/3] stm32: add async timeout functions to I2c and TimeoutI2c --- embassy-stm32/src/i2c/timeout.rs | 74 ++++++++++++++++++++++++++++++++ embassy-stm32/src/i2c/v2.rs | 70 ++++++++++++++++++++++++++---- 2 files changed, 135 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/src/i2c/timeout.rs b/embassy-stm32/src/i2c/timeout.rs index bb6e105de..830de8e9a 100644 --- a/embassy-stm32/src/i2c/timeout.rs +++ b/embassy-stm32/src/i2c/timeout.rs @@ -27,6 +27,80 @@ impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> Self { i2c, timeout } } + // ========================= + // Async public API + + pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> + where + TXDMA: crate::i2c::TxDma, + { + self.write_timeout(address, write, self.timeout).await + } + + pub async fn write_timeout(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error> + where + TXDMA: crate::i2c::TxDma, + { + self.i2c.write_timeout(address, write, timeout_fn(timeout)).await + } + + pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> + where + TXDMA: crate::i2c::TxDma, + { + self.write_vectored_timeout(address, write, self.timeout).await + } + + pub async fn write_vectored_timeout(&mut self, address: u8, write: &[&[u8]], timeout: Duration) -> Result<(), Error> + where + TXDMA: crate::i2c::TxDma, + { + self.i2c + .write_vectored_timeout(address, write, timeout_fn(timeout)) + .await + } + + pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> + where + RXDMA: crate::i2c::RxDma, + { + self.read_timeout(address, buffer, self.timeout).await + } + + pub async fn read_timeout(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> + where + RXDMA: crate::i2c::RxDma, + { + self.i2c.read_timeout(address, buffer, timeout_fn(timeout)).await + } + + pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> + where + TXDMA: super::TxDma, + RXDMA: super::RxDma, + { + self.write_read_timeout(address, write, read, self.timeout).await + } + + pub async fn write_read_timeout( + &mut self, + address: u8, + write: &[u8], + read: &mut [u8], + timeout: Duration, + ) -> Result<(), Error> + where + TXDMA: super::TxDma, + RXDMA: super::RxDma, + { + self.i2c + .write_read_timeout(address, write, read, timeout_fn(timeout)) + .await + } + + // ========================= + // Blocking public API + /// Blocking read with a custom timeout pub fn blocking_read_timeout(&mut self, addr: u8, read: &mut [u8], timeout: Duration) -> Result<(), Error> { self.i2c.blocking_read_timeout(addr, read, timeout_fn(timeout)) diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index eaf980a4d..4327899bb 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -595,17 +595,41 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // Async public API pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> + where + TXDMA: crate::i2c::TxDma, + { + self.write_timeout(address, write, || Ok(())).await + } + + pub async fn write_timeout( + &mut self, + address: u8, + write: &[u8], + check_timeout: impl Fn() -> Result<(), Error>, + ) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, { if write.is_empty() { - self.write_internal(address, write, true, || Ok(())) + self.write_internal(address, write, true, check_timeout) } else { - self.write_dma_internal(address, write, true, true, || Ok(())).await + self.write_dma_internal(address, write, true, true, check_timeout).await } } pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> + where + TXDMA: crate::i2c::TxDma, + { + self.write_vectored_timeout(address, write, || Ok(())).await + } + + pub async fn write_vectored_timeout( + &mut self, + address: u8, + write: &[&[u8]], + check_timeout: impl Fn() -> Result<(), Error>, + ) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, { @@ -620,7 +644,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { let next = iter.next(); let is_last = next.is_none(); - self.write_dma_internal(address, c, first, is_last, || Ok(())).await?; + self.write_dma_internal(address, c, first, is_last, || check_timeout()) + .await?; first = false; current = next; } @@ -628,31 +653,58 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> + where + RXDMA: crate::i2c::RxDma, + { + self.read_timeout(address, buffer, || Ok(())).await + } + + pub async fn read_timeout( + &mut self, + address: u8, + buffer: &mut [u8], + check_timeout: impl Fn() -> Result<(), Error>, + ) -> Result<(), Error> where RXDMA: crate::i2c::RxDma, { if buffer.is_empty() { - self.read_internal(address, buffer, false, || Ok(())) + self.read_internal(address, buffer, false, check_timeout) } else { - self.read_dma_internal(address, buffer, false, || Ok(())).await + self.read_dma_internal(address, buffer, false, check_timeout).await } } pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> + where + TXDMA: super::TxDma, + RXDMA: super::RxDma, + { + self.write_read_timeout(address, write, read, || Ok(())).await + } + + pub async fn write_read_timeout( + &mut self, + address: u8, + write: &[u8], + read: &mut [u8], + check_timeout: impl Fn() -> Result<(), Error>, + ) -> Result<(), Error> where TXDMA: super::TxDma, RXDMA: super::RxDma, { if write.is_empty() { - self.write_internal(address, write, false, || Ok(()))?; + self.write_internal(address, write, false, || check_timeout())?; } else { - self.write_dma_internal(address, write, true, true, || Ok(())).await?; + self.write_dma_internal(address, write, true, true, || check_timeout()) + .await?; } if read.is_empty() { - self.read_internal(address, read, true, || Ok(()))?; + self.read_internal(address, read, true, check_timeout)?; } else { - self.read_dma_internal(address, read, true, || Ok(())).await?; + self.read_dma_internal(address, read, true, check_timeout).await?; } Ok(()) From 036bc669cd46012e37e09af070ddb8353454719a Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Mon, 31 Jul 2023 14:17:50 -0500 Subject: [PATCH 3/3] stm32: only enable async TimeoutI2c on V2 I2C peripheral --- embassy-stm32/src/i2c/timeout.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/embassy-stm32/src/i2c/timeout.rs b/embassy-stm32/src/i2c/timeout.rs index 830de8e9a..103017cd1 100644 --- a/embassy-stm32/src/i2c/timeout.rs +++ b/embassy-stm32/src/i2c/timeout.rs @@ -30,6 +30,7 @@ impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> // ========================= // Async public API + #[cfg(i2c_v2)] pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, @@ -37,6 +38,7 @@ impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> self.write_timeout(address, write, self.timeout).await } + #[cfg(i2c_v2)] pub async fn write_timeout(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, @@ -44,6 +46,7 @@ impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> self.i2c.write_timeout(address, write, timeout_fn(timeout)).await } + #[cfg(i2c_v2)] pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, @@ -51,6 +54,7 @@ impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> self.write_vectored_timeout(address, write, self.timeout).await } + #[cfg(i2c_v2)] pub async fn write_vectored_timeout(&mut self, address: u8, write: &[&[u8]], timeout: Duration) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, @@ -60,6 +64,7 @@ impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> .await } + #[cfg(i2c_v2)] pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> where RXDMA: crate::i2c::RxDma, @@ -67,6 +72,7 @@ impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> self.read_timeout(address, buffer, self.timeout).await } + #[cfg(i2c_v2)] pub async fn read_timeout(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> where RXDMA: crate::i2c::RxDma, @@ -74,6 +80,7 @@ impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> self.i2c.read_timeout(address, buffer, timeout_fn(timeout)).await } + #[cfg(i2c_v2)] pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> where TXDMA: super::TxDma, @@ -82,6 +89,7 @@ impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> self.write_read_timeout(address, write, read, self.timeout).await } + #[cfg(i2c_v2)] pub async fn write_read_timeout( &mut self, address: u8,