epd_waveshare_async/
hw.rs

1use embedded_hal::{
2    digital::{ErrorType as PinErrorType, InputPin, OutputPin, PinState},
3    spi::ErrorType as SpiErrorType,
4};
5use embedded_hal_async::{delay::DelayNs, digital::Wait, spi::SpiDevice};
6
7use crate::log::trace;
8
9/// Provides access to a shared error type.
10///
11/// Drivers rely on this trait to provide a single Error type that supports [From] conversions
12/// from all the hardware-specific error types.
13pub trait ErrorHw {
14    type Error;
15}
16
17/// Describes the SPI hardware to use for interacting with the EPD.
18pub trait SpiHw {
19    type Spi: SpiDevice;
20}
21
22/// Provides access to the Data/Command pin for EPD control.
23pub trait DcHw {
24    type Dc: OutputPin;
25
26    fn dc(&mut self) -> &mut Self::Dc;
27}
28
29/// Provides access to the Reset pin for EPD control.
30pub trait ResetHw {
31    type Reset: OutputPin;
32
33    fn reset(&mut self) -> &mut Self::Reset;
34}
35
36/// Provides access to the Busy pin for EPD status monitoring.
37pub trait BusyHw {
38    type Busy: InputPin + Wait;
39
40    fn busy(&mut self) -> &mut Self::Busy;
41
42    /// Indicates which state of the busy pin indicates that it's busy.
43    ///
44    /// This is user-configurable, rather than enforced by the display driver, to allow the user to
45    /// use more unexpected wiring configurations.
46    fn busy_when(&self) -> embedded_hal::digital::PinState;
47}
48
49/// Provides access to delay functionality for EPD timing control.
50pub trait DelayHw {
51    type Delay: DelayNs;
52
53    fn delay(&mut self) -> &mut Self::Delay;
54}
55
56/// Provides "wait" support for hardware with a busy state.
57pub(crate) trait BusyWait: ErrorHw {
58    /// Waits for the current operation to complete if the display is busy.
59    ///
60    /// Note that this will wait forever if the display is asleep.
61    async fn wait_if_busy(&mut self) -> Result<(), Self::Error>;
62}
63
64/// Provides the ability to send <command> then <data> style communications.
65pub(crate) trait CommandDataSend: SpiHw + ErrorHw {
66    /// Send the following command and data to the display. Waits until the display is no longer busy before sending.
67    async fn send(
68        &mut self,
69        spi: &mut Self::Spi,
70        command: u8,
71        data: &[u8],
72    ) -> Result<(), Self::Error>;
73}
74
75impl<HW> BusyWait for HW
76where
77    HW: BusyHw + ErrorHw,
78    <HW as ErrorHw>::Error: From<<HW::Busy as PinErrorType>::Error>,
79{
80    async fn wait_if_busy(&mut self) -> Result<(), HW::Error> {
81        let busy_when = self.busy_when();
82        let busy = self.busy();
83        match busy_when {
84            PinState::High => {
85                if busy.is_high()? {
86                    trace!("Waiting for busy EPD");
87                    busy.wait_for_low().await?;
88                }
89            }
90            PinState::Low => {
91                if busy.is_low()? {
92                    trace!("Waiting for busy EPD");
93                    busy.wait_for_high().await?;
94                }
95            }
96        };
97        Ok(())
98    }
99}
100
101impl<HW> CommandDataSend for HW
102where
103    HW: DcHw + BusyHw + BusyWait + SpiHw + ErrorHw,
104    HW::Error: From<<HW::Spi as SpiErrorType>::Error>
105        + From<<HW::Dc as PinErrorType>::Error>
106        + From<<HW::Busy as PinErrorType>::Error>,
107{
108    async fn send(
109        &mut self,
110        spi: &mut Self::Spi,
111        command: u8,
112        data: &[u8],
113    ) -> Result<(), Self::Error> {
114        trace!("Sending EPD command: {:?}", command);
115        self.wait_if_busy().await?;
116
117        self.dc().set_low()?;
118        spi.write(&[command]).await?;
119
120        if !data.is_empty() {
121            self.dc().set_high()?;
122            spi.write(data).await?;
123        }
124
125        Ok(())
126    }
127}