epd_waveshare_async/
lib.rs

1#![no_std]
2
3use core::error::Error as CoreError;
4
5use embedded_graphics::{
6    prelude::{DrawTarget, Point},
7    primitives::Rectangle,
8};
9use embedded_hal::digital::{ErrorType as PinErrorType, InputPin, OutputPin};
10use embedded_hal_async::{
11    delay::DelayNs,
12    digital::Wait,
13    spi::{ErrorType as SpiErrorType, SpiDevice},
14};
15
16pub mod buffer;
17pub mod epd2in9;
18
19mod log;
20
21#[allow(async_fn_in_trait)]
22pub trait Epd<HW>
23where
24    HW: EpdHw,
25{
26    type RefreshMode;
27    type Buffer: DrawTarget;
28
29    /// Creates a buffer for use with this display.
30    fn new_buffer(&self) -> Self::Buffer;
31
32    fn width(&self) -> u32;
33
34    fn height(&self) -> u32;
35
36    /// Initialise the display. This must be called before any other operations.
37    async fn init(&mut self, spi: &mut HW::Spi, mode: Self::RefreshMode) -> Result<(), HW::Error>;
38
39    /// Sets the refresh mode for the display.
40    async fn set_refresh_mode(
41        &mut self,
42        spi: &mut HW::Spi,
43        mode: Self::RefreshMode,
44    ) -> Result<(), HW::Error>;
45
46    /// Hardware reset the display.
47    async fn reset(&mut self) -> Result<(), HW::Error>;
48
49    /// Puts the display to sleep.
50    async fn sleep(&mut self, spi: &mut HW::Spi) -> Result<(), HW::Error>;
51
52    /// Wakes and re-initialises the display (if necessary) if it's asleep.
53    async fn wake(&mut self, spi: &mut HW::Spi) -> Result<(), HW::Error>;
54
55    /// Writes the buffer's data to the display and displays it.
56    async fn display_buffer(
57        &mut self,
58        spi: &mut HW::Spi,
59        buffer: &Self::Buffer,
60    ) -> Result<(), HW::Error>;
61
62    /// Sets the window to write to during a call to [Epd::write_image]. This can enable partial
63    /// writes to a subsection of the display.
64    async fn set_window(&mut self, spi: &mut HW::Spi, shape: Rectangle) -> Result<(), HW::Error>;
65
66    /// Sets the cursor position for where the next byte of image data will be written.
67    async fn set_cursor(
68        &mut self,
69        spi: &mut HW::Spi,
70        position: Point,
71    ) -> Result<(), <HW as EpdHw>::Error>;
72
73    /// Writes raw image data, starting at the current cursor position and auto-incrementing x then
74    /// y within the current window.
75    async fn write_image(&mut self, spi: &mut HW::Spi, image: &[u8]) -> Result<(), HW::Error>;
76
77    /// Updates (refreshes) the display based on what has been written to RAM. Note that this can be
78    /// stateful. For example, on the Epd2in9 display, there are two RAM buffers. Calling this
79    /// function swaps the active buffer. Consider this scenario:
80    ///
81    /// 1. [Epd::write_image] is used to turn the RAM all white.
82    /// 2. [Epd::update_display] is called, which refreshes the display to be all white.
83    /// 3. [Epd::write_image] is used to turn the RAM all black.
84    /// 4. [Epd::update_display] is called, which refreshes the display to be all black.
85    /// 5. [Epd::update_display] is called again, which refreshes the display to be all white again.
86    async fn update_display(&mut self, spi: &mut HW::Spi) -> Result<(), HW::Error>;
87}
88
89/// Provides access to the hardware needed to control an EPD.
90pub trait EpdHw {
91    type Spi: SpiDevice;
92    type Dc: OutputPin;
93    type Reset: OutputPin;
94    type Busy: InputPin + Wait;
95    type Delay: DelayNs;
96    type Error: CoreError
97        + From<<Self::Spi as SpiErrorType>::Error>
98        + From<<Self::Dc as PinErrorType>::Error>
99        + From<<Self::Reset as PinErrorType>::Error>
100        + From<<Self::Busy as PinErrorType>::Error>;
101
102    fn dc(&mut self) -> &mut Self::Dc;
103    fn reset(&mut self) -> &mut Self::Reset;
104    fn busy(&mut self) -> &mut Self::Busy;
105    fn delay(&mut self) -> &mut Self::Delay;
106}