Skip to main content

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    async fn send_iter<I: IntoIterator<Item = u8>>(
75        &mut self,
76        spi: &mut Self::Spi,
77        command: u8,
78        iter: Option<I>,
79    ) -> Result<(), Self::Error>;
80}
81
82impl<HW> BusyWait for HW
83where
84    HW: BusyHw + ErrorHw,
85    <HW as ErrorHw>::Error: From<<HW::Busy as PinErrorType>::Error>,
86{
87    async fn wait_if_busy(&mut self) -> Result<(), HW::Error> {
88        let busy_when = self.busy_when();
89        let busy = self.busy();
90        match busy_when {
91            PinState::High => {
92                if busy.is_high()? {
93                    trace!("Waiting for busy EPD");
94                    busy.wait_for_low().await?;
95                }
96            }
97            PinState::Low => {
98                if busy.is_low()? {
99                    trace!("Waiting for busy EPD");
100                    busy.wait_for_high().await?;
101                }
102            }
103        };
104        Ok(())
105    }
106}
107
108impl<HW> CommandDataSend for HW
109where
110    HW: DcHw + BusyHw + BusyWait + SpiHw + ErrorHw,
111    HW::Error: From<<HW::Spi as SpiErrorType>::Error>
112        + From<<HW::Dc as PinErrorType>::Error>
113        + From<<HW::Busy as PinErrorType>::Error>,
114{
115    async fn send(
116        &mut self,
117        spi: &mut Self::Spi,
118        command: u8,
119        data: &[u8],
120    ) -> Result<(), Self::Error> {
121        trace!("Sending EPD command: 0x{:02x}", command);
122        self.wait_if_busy().await?;
123
124        self.dc().set_low()?;
125        spi.write(&[command]).await?;
126
127        if data.len() > 0 {
128            self.dc().set_high()?;
129            spi.write(data).await?;
130        }
131
132        Ok(())
133    }
134
135    async fn send_iter<I: IntoIterator<Item = u8>>(
136        &mut self,
137        spi: &mut Self::Spi,
138        command: u8,
139        iter: Option<I>,
140    ) -> Result<(), Self::Error> {
141        trace!("Sending EPD command: 0x{:02x}", command);
142        self.wait_if_busy().await?;
143
144        self.dc().set_low()?;
145        spi.write(&[command]).await?;
146
147        if let Some(data) = iter {
148            self.dc().set_high()?;
149            for byte in data {
150                spi.write(&[byte]).await?;
151            }
152        }
153
154        Ok(())
155    }
156}