210 lines
6.5 KiB
Rust
210 lines
6.5 KiB
Rust
use embassy_time::{Duration, Instant};
|
|
|
|
use super::{Error, I2c, Instance};
|
|
|
|
/// An I2C wrapper, which provides `embassy-time` based timeouts for all `embedded-hal` trait methods.
|
|
///
|
|
/// 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.
|
|
pub struct TimeoutI2c<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> {
|
|
i2c: &'a mut I2c<'d, T, TXDMA, RXDMA>,
|
|
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(())
|
|
}
|
|
}
|
|
}
|
|
|
|
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 }
|
|
}
|
|
|
|
// =========================
|
|
// Async public API
|
|
|
|
#[cfg(i2c_v2)]
|
|
pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error>
|
|
where
|
|
TXDMA: crate::i2c::TxDma<T>,
|
|
{
|
|
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<T>,
|
|
{
|
|
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<T>,
|
|
{
|
|
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<T>,
|
|
{
|
|
self.i2c
|
|
.write_vectored_timeout(address, write, timeout_fn(timeout))
|
|
.await
|
|
}
|
|
|
|
#[cfg(i2c_v2)]
|
|
pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>
|
|
where
|
|
RXDMA: crate::i2c::RxDma<T>,
|
|
{
|
|
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<T>,
|
|
{
|
|
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<T>,
|
|
RXDMA: super::RxDma<T>,
|
|
{
|
|
self.write_read_timeout(address, write, read, self.timeout).await
|
|
}
|
|
|
|
#[cfg(i2c_v2)]
|
|
pub async fn write_read_timeout(
|
|
&mut self,
|
|
address: u8,
|
|
write: &[u8],
|
|
read: &mut [u8],
|
|
timeout: Duration,
|
|
) -> Result<(), Error>
|
|
where
|
|
TXDMA: super::TxDma<T>,
|
|
RXDMA: super::RxDma<T>,
|
|
{
|
|
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))
|
|
}
|
|
|
|
/// Blocking read with default timeout, provided in [`TimeoutI2c::new()`]
|
|
pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> {
|
|
self.blocking_read_timeout(addr, read, self.timeout)
|
|
}
|
|
|
|
/// Blocking write with a custom timeout
|
|
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))
|
|
}
|
|
|
|
/// Blocking write with default timeout, provided in [`TimeoutI2c::new()`]
|
|
pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> {
|
|
self.blocking_write_timeout(addr, write, self.timeout)
|
|
}
|
|
|
|
/// Blocking write-read with a custom timeout
|
|
pub fn blocking_write_read_timeout(
|
|
&mut self,
|
|
addr: u8,
|
|
write: &[u8],
|
|
read: &mut [u8],
|
|
timeout: Duration,
|
|
) -> Result<(), Error> {
|
|
self.i2c
|
|
.blocking_write_read_timeout(addr, write, read, timeout_fn(timeout))
|
|
}
|
|
|
|
/// Blocking write-read with default timeout, provided in [`TimeoutI2c::new()`]
|
|
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)
|
|
}
|
|
}
|
|
|
|
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> {
|
|
self.blocking_read(addr, read)
|
|
}
|
|
}
|
|
|
|
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> {
|
|
self.blocking_write(addr, write)
|
|
}
|
|
}
|
|
|
|
impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::WriteRead
|
|
for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA>
|
|
{
|
|
type Error = Error;
|
|
|
|
fn write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
|
|
self.blocking_write_read(addr, write, read)
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "unstable-traits")]
|
|
mod eh1 {
|
|
use super::*;
|
|
|
|
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: '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)
|
|
}
|
|
|
|
fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
|
|
self.blocking_write(address, write)
|
|
}
|
|
|
|
fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
|
|
self.blocking_write_read(address, write, read)
|
|
}
|
|
|
|
fn transaction(
|
|
&mut self,
|
|
_address: u8,
|
|
_operations: &mut [embedded_hal_1::i2c::Operation<'_>],
|
|
) -> Result<(), Self::Error> {
|
|
todo!();
|
|
}
|
|
}
|
|
}
|