use embedded_hal::{
digital::{ErrorType as PinErrorType, InputPin, OutputPin, PinState},
spi::ErrorType as SpiErrorType,
};
use embedded_hal_async::{delay::DelayNs, digital::Wait, spi::SpiDevice};
use crate::log::trace;
pub trait ErrorHw {
type Error;
}
pub trait SpiHw {
type Spi: SpiDevice;
}
pub trait DcHw {
type Dc: OutputPin;
fn dc(&mut self) -> &mut Self::Dc;
}
pub trait ResetHw {
type Reset: OutputPin;
fn reset(&mut self) -> &mut Self::Reset;
}
pub trait BusyHw {
type Busy: InputPin + Wait;
fn busy(&mut self) -> &mut Self::Busy;
fn busy_when(&self) -> embedded_hal::digital::PinState;
}
pub trait DelayHw {
type Delay: DelayNs;
fn delay(&mut self) -> &mut Self::Delay;
}
pub(crate) trait BusyWait: ErrorHw {
async fn wait_if_busy(&mut self) -> Result<(), Self::Error>;
}
pub(crate) trait CommandDataSend: SpiHw + ErrorHw {
async fn send(
&mut self,
spi: &mut Self::Spi,
command: u8,
data: &[u8],
) -> Result<(), Self::Error>;
}
impl<HW> BusyWait for HW
where
HW: BusyHw + ErrorHw,
<HW as ErrorHw>::Error: From<<HW::Busy as PinErrorType>::Error>,
{
async fn wait_if_busy(&mut self) -> Result<(), HW::Error> {
let busy_when = self.busy_when();
let busy = self.busy();
match busy_when {
PinState::High => {
if busy.is_high()? {
trace!("Waiting for busy EPD");
busy.wait_for_low().await?;
}
}
PinState::Low => {
if busy.is_low()? {
trace!("Waiting for busy EPD");
busy.wait_for_high().await?;
}
}
};
Ok(())
}
}
impl<HW> CommandDataSend for HW
where
HW: DcHw + BusyHw + BusyWait + SpiHw + ErrorHw,
HW::Error: From<<HW::Spi as SpiErrorType>::Error>
+ From<<HW::Dc as PinErrorType>::Error>
+ From<<HW::Busy as PinErrorType>::Error>,
{
async fn send(
&mut self,
spi: &mut Self::Spi,
command: u8,
data: &[u8],
) -> Result<(), Self::Error> {
trace!("Sending EPD command: {:?}", command);
self.wait_if_busy().await?;
self.dc().set_low()?;
spi.write(&[command]).await?;
if !data.is_empty() {
self.dc().set_high()?;
spi.write(data).await?;
}
Ok(())
}
}