use super::error::{Error, ErrorKind};
use super::packet::{Packet, Response};
use core::fmt::Debug;
use core::iter::from_fn;
use core::slice::from_ref;
use embedded_hal::blocking::delay::DelayUs;
use embedded_hal::blocking::i2c::{Read, Write};
const WAKE_RESPONSE_EXPECTED: &[u8] = &[0x04, 0x11, 0x33, 0x43];
const WAKE_SELFTEST_FAILED: &[u8] = &[0x04, 0x07, 0xC4, 0x40];
const ADDRESS: u8 = 0xc0 >> 1;
const DELAY_US: u32 = 1500;
#[cfg(target_os = "none")]
const RETRY: usize = 20;
#[cfg(not(target_os = "none"))]
const RETRY: usize = 20 * 15;
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) enum Transaction {
Reset = 0x00,
Sleep = 0x01,
Idle = 0x02,
Command = 0x03,
#[allow(dead_code)]
Reserved = 0xff,
}
pub(crate) struct I2c<PHY, D> {
phy: PHY,
delay: D,
}
impl<PHY, D> I2c<PHY, D> {
pub(crate) fn new(phy: PHY, delay: D) -> Self {
Self { phy, delay }
}
}
impl<PHY, D> I2c<PHY, D>
where
PHY: Read + Write,
<PHY as Read>::Error: Debug,
<PHY as Write>::Error: Debug,
D: DelayUs<u32>,
{
pub(crate) fn execute<'a>(
&mut self,
buffer: &'a mut [u8],
packet: Packet,
exec_time: Option<u32>,
) -> Result<Response<'a>, Error> {
self.wake()?;
self.send(&packet.buffer(buffer))?;
self.delay
.try_delay_us(exec_time.unwrap_or(1) * 1000)
.map_err(|_| Error::from(ErrorKind::Timeout))?;
let response_buffer = self.receive(buffer)?;
self.idle()?;
Response::new(response_buffer)
}
fn send<T>(&mut self, bytes: &T) -> Result<(), Error>
where
T: AsRef<[u8]>,
{
self.phy
.try_write(ADDRESS, bytes.as_ref())
.map_err(|_| ErrorKind::TxFail.into())
}
fn receive<'a>(&mut self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], Error> {
let word_address = Transaction::Reset as u8;
from_fn(|| self.phy.try_write(ADDRESS, from_ref(&word_address)).into())
.take(RETRY)
.find_map(Result::<_, _>::ok)
.ok_or_else(|| Error::from(ErrorKind::TxFail))?;
let min_resp_size = 4;
self.phy
.try_read(ADDRESS, &mut buffer[0..2])
.map_err(|_| Error::from(ErrorKind::RxFail))?;
let length_to_read = match buffer[0] {
length if length == 1 => return Ok(buffer[0..1].as_mut()),
length if buffer.len() < length as usize => return Err(ErrorKind::CommFail.into()),
length if length < min_resp_size => return Err(ErrorKind::CommFail.into()),
length => length as usize,
};
self.phy
.try_read(ADDRESS, buffer[2..length_to_read].as_mut())
.map(move |()| buffer[..length_to_read].as_mut())
.map_err(|_| ErrorKind::RxFail.into())
}
fn wake(&mut self) -> Result<(), Error> {
self.phy.try_write(ADDRESS, from_ref(&0x00)).unwrap_err();
self.delay
.try_delay_us(DELAY_US)
.map_err(|_| Error::from(ErrorKind::Timeout))?;
let buffer = &mut [0x00, 0x00, 0x00, 0x00];
from_fn(|| self.phy.try_read(ADDRESS, buffer.as_mut()).into())
.take(RETRY)
.find_map(Result::<_, _>::ok)
.ok_or_else(|| Error::from(ErrorKind::RxFail))?;
match buffer.as_ref() {
WAKE_RESPONSE_EXPECTED => Ok(()),
WAKE_SELFTEST_FAILED => Err(ErrorKind::WakeFailed.into()),
_ => Err(ErrorKind::WakeFailed.into()),
}
}
fn idle(&mut self) -> Result<(), Error> {
let word_address = Transaction::Idle as u8;
self.phy
.try_write(ADDRESS, from_ref(&word_address))
.map_err(|_| ErrorKind::TxFail.into())
}
pub(crate) fn sleep(&mut self) -> Result<(), Error> {
let word_address = Transaction::Sleep as u8;
self.delay
.try_delay_us(30)
.map_err(|_| Error::from(ErrorKind::Timeout))?;
self.phy
.try_write(ADDRESS, from_ref(&word_address))
.map_err(|_| ErrorKind::TxFail.into())
}
}