embassy/embassy-stm32/src/i2c/timeout.rs

122 lines
4.2 KiB
Rust
Raw Normal View History

2022-10-24 10:30:04 +02:00
use embassy_time::{Duration, Instant};
use super::{Error, I2c, Instance};
2022-10-24 11:39:47 +02:00
/// An I2C wrapper, which provides `embassy-time` based timeouts for all `embedded-hal` trait methods.
2022-10-24 21:48:40 +02:00
///
/// This is useful for recovering from a shorted bus or a device stuck in a clock stretching state.
/// A regular [I2c] would freeze until condition is removed.
2022-10-24 21:11:15 +02:00
pub struct TimeoutI2c<'d, T: Instance, TXDMA, RXDMA> {
i2c: &'d mut I2c<'d, T, TXDMA, RXDMA>,
2022-10-24 10:30:04 +02:00
timeout: Duration,
}
fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> {
let deadline = Instant::now() + timeout;
move || {
if Instant::now() > deadline {
Err(Error::Timeout)
} else {
Ok(())
}
}
}
2022-10-24 21:11:15 +02:00
impl<'d, T: Instance, TXDMA, RXDMA> TimeoutI2c<'d, T, TXDMA, RXDMA> {
pub fn new(i2c: &'d mut I2c<'d, T, TXDMA, RXDMA>, timeout: Duration) -> Self {
2022-10-24 10:30:04 +02:00
Self { i2c, timeout }
}
2022-10-24 11:39:47 +02:00
/// Blocking read with a custom timeout
2023-04-06 22:25:24 +02:00
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))
2022-10-24 10:30:04 +02:00
}
2022-10-24 11:39:47 +02:00
/// Blocking read with default timeout, provided in [`TimeoutI2c::new()`]
2023-04-06 22:25:24 +02:00
pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> {
self.blocking_read_timeout(addr, read, self.timeout)
2022-10-24 10:30:04 +02:00
}
2022-10-24 11:39:47 +02:00
/// Blocking write with a custom timeout
2023-04-06 22:25:24 +02:00
pub fn blocking_write_timeout(&mut self, addr: u8, write: &[u8], timeout: Duration) -> Result<(), Error> {
self.i2c.blocking_write_timeout(addr, write, timeout_fn(timeout))
2022-10-24 10:30:04 +02:00
}
2022-10-24 11:39:47 +02:00
/// Blocking write with default timeout, provided in [`TimeoutI2c::new()`]
2023-04-06 22:25:24 +02:00
pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> {
self.blocking_write_timeout(addr, write, self.timeout)
2022-10-24 10:30:04 +02:00
}
2022-10-24 11:39:47 +02:00
/// Blocking write-read with a custom timeout
2022-10-24 10:30:04 +02:00
pub fn blocking_write_read_timeout(
&mut self,
addr: u8,
2023-04-06 22:25:24 +02:00
write: &[u8],
read: &mut [u8],
2022-10-24 10:30:04 +02:00
timeout: Duration,
) -> Result<(), Error> {
self.i2c
2023-04-06 22:25:24 +02:00
.blocking_write_read_timeout(addr, write, read, timeout_fn(timeout))
2022-10-24 10:30:04 +02:00
}
2022-10-24 11:39:47 +02:00
/// Blocking write-read with default timeout, provided in [`TimeoutI2c::new()`]
2023-04-06 22:25:24 +02:00
pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
self.blocking_write_read_timeout(addr, write, read, self.timeout)
2022-10-24 10:30:04 +02:00
}
}
2022-10-24 21:11:15 +02:00
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Read for TimeoutI2c<'d, T, TXDMA, RXDMA> {
2022-10-24 10:30:04 +02:00
type Error = Error;
2023-04-06 22:25:24 +02:00
fn read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_read(addr, read)
2022-10-24 10:30:04 +02:00
}
}
2022-10-24 21:11:15 +02:00
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Write for TimeoutI2c<'d, T, TXDMA, RXDMA> {
2022-10-24 10:30:04 +02:00
type Error = Error;
2023-04-06 22:25:24 +02:00
fn write(&mut self, addr: u8, write: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(addr, write)
2022-10-24 10:30:04 +02:00
}
}
2022-10-24 21:11:15 +02:00
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::WriteRead for TimeoutI2c<'d, T, TXDMA, RXDMA> {
2022-10-24 10:30:04 +02:00
type Error = Error;
2023-04-06 22:25:24 +02:00
fn write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_write_read(addr, write, read)
2022-10-24 10:30:04 +02:00
}
}
#[cfg(feature = "unstable-traits")]
mod eh1 {
use super::*;
2022-10-24 21:11:15 +02:00
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for TimeoutI2c<'d, T, TXDMA, RXDMA> {
2022-10-24 10:30:04 +02:00
type Error = Error;
}
2022-10-24 21:11:15 +02:00
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::I2c for TimeoutI2c<'d, T, TXDMA, RXDMA> {
2023-04-06 22:25:24 +02:00
fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_read(address, read)
2022-10-24 10:30:04 +02:00
}
2023-04-06 22:25:24 +02:00
fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(address, write)
2022-10-24 10:30:04 +02:00
}
2023-04-06 22:25:24 +02:00
fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_write_read(address, write, read)
2022-10-24 10:30:04 +02:00
}
2023-04-06 22:25:24 +02:00
fn transaction(
2022-10-24 10:30:04 +02:00
&mut self,
_address: u8,
2023-04-06 22:25:24 +02:00
_operations: &mut [embedded_hal_1::i2c::Operation<'_>],
2022-10-24 10:30:04 +02:00
) -> Result<(), Self::Error> {
todo!();
}
}
}