epd_waveshare/
traits.rs

1use core::marker::Sized;
2use embedded_hal::{delay::*, digital::*, spi::SpiDevice};
3
4/// All commands need to have this trait which gives the address of the command
5/// which needs to be send via SPI with activated CommandsPin (Data/Command Pin in CommandMode)
6pub(crate) trait Command: Copy {
7    fn address(self) -> u8;
8}
9
10/// Seperates the different LUT for the Display Refresh process
11#[derive(Debug, Clone, PartialEq, Eq, Copy, Default)]
12pub enum RefreshLut {
13    /// The "normal" full Lookuptable for the Refresh-Sequence
14    #[default]
15    Full,
16    /// The quick LUT where not the full refresh sequence is followed.
17    /// This might lead to some
18    Quick,
19}
20
21pub(crate) trait InternalWiAdditions<SPI, BUSY, DC, RST, DELAY>
22where
23    SPI: SpiDevice,
24    BUSY: InputPin,
25    DC: OutputPin,
26    RST: OutputPin,
27    DELAY: DelayNs,
28{
29    /// This initialises the EPD and powers it up
30    ///
31    /// This function is already called from
32    ///  - [new()](WaveshareDisplay::new())
33    ///  - [`wake_up`]
34    ///
35    ///
36    /// This function calls [reset](WaveshareDisplay::reset),
37    /// so you don't need to call reset your self when trying to wake your device up
38    /// after setting it to sleep.
39    fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>;
40}
41
42/// Functions to interact with three color panels
43pub trait WaveshareThreeColorDisplay<SPI, BUSY, DC, RST, DELAY>:
44    WaveshareDisplay<SPI, BUSY, DC, RST, DELAY>
45where
46    SPI: SpiDevice,
47    BUSY: InputPin,
48    DC: OutputPin,
49    RST: OutputPin,
50    DELAY: DelayNs,
51{
52    /// Transmit data to the SRAM of the EPD
53    ///
54    /// Updates both the black and the secondary color layers
55    fn update_color_frame(
56        &mut self,
57        spi: &mut SPI,
58        delay: &mut DELAY,
59        black: &[u8],
60        chromatic: &[u8],
61    ) -> Result<(), SPI::Error>;
62
63    /// Update only the black/white data of the display.
64    ///
65    /// This must be finished by calling `update_chromatic_frame`.
66    fn update_achromatic_frame(
67        &mut self,
68        spi: &mut SPI,
69        delay: &mut DELAY,
70        black: &[u8],
71    ) -> Result<(), SPI::Error>;
72
73    /// Update only the chromatic data of the display.
74    ///
75    /// This should be preceded by a call to `update_achromatic_frame`.
76    /// This data takes precedence over the black/white data.
77    fn update_chromatic_frame(
78        &mut self,
79        spi: &mut SPI,
80        delay: &mut DELAY,
81        chromatic: &[u8],
82    ) -> Result<(), SPI::Error>;
83}
84
85/// All the functions to interact with the EPDs
86///
87/// This trait includes all public functions to use the EPDs
88///
89/// # Example
90///
91///```rust, no_run
92///# use embedded_hal_mock::eh1::*;
93///# fn main() -> Result<(), embedded_hal::spi::ErrorKind> {
94///use embedded_graphics::{
95///    pixelcolor::BinaryColor::On as Black, prelude::*, primitives::{Line, PrimitiveStyle},
96///};
97///use epd_waveshare::{epd4in2::*, prelude::*};
98///#
99///# let expectations = [];
100///# let mut spi = spi::Mock::new(&expectations);
101///# let expectations = [];
102///# let cs_pin = digital::Mock::new(&expectations);
103///# let busy_in = digital::Mock::new(&expectations);
104///# let dc = digital::Mock::new(&expectations);
105///# let rst = digital::Mock::new(&expectations);
106///# let mut delay = delay::NoopDelay::new();
107///
108///// Setup EPD
109///let mut epd = Epd4in2::new(&mut spi, busy_in, dc, rst, &mut delay, None)?;
110///
111///// Use display graphics from embedded-graphics
112///let mut display = Display4in2::default();
113///
114///// Use embedded graphics for drawing a line
115///
116///let _ = Line::new(Point::new(0, 120), Point::new(0, 295))
117///    .into_styled(PrimitiveStyle::with_stroke(Color::Black, 1))
118///    .draw(&mut display);
119///
120///    // Display updated frame
121///epd.update_frame(&mut spi, &display.buffer(), &mut delay)?;
122///epd.display_frame(&mut spi, &mut delay)?;
123///
124///// Set the EPD to sleep
125///epd.sleep(&mut spi, &mut delay)?;
126///# Ok(())
127///# }
128///```
129pub trait WaveshareDisplay<SPI, BUSY, DC, RST, DELAY>
130where
131    SPI: SpiDevice,
132    BUSY: InputPin,
133    DC: OutputPin,
134    RST: OutputPin,
135    DELAY: DelayNs,
136{
137    /// The Color Type used by the Display
138    type DisplayColor;
139    /// Creates a new driver from a SPI peripheral, CS Pin, Busy InputPin, DC
140    ///
141    /// `delay_us` is the number of us the idle loop should sleep on.
142    /// Setting it to 0 implies busy waiting.
143    /// Setting it to None means a default value is used.
144    ///
145    /// This already initialises the device.
146    fn new(
147        spi: &mut SPI,
148        busy: BUSY,
149        dc: DC,
150        rst: RST,
151        delay: &mut DELAY,
152        delay_us: Option<u32>,
153    ) -> Result<Self, SPI::Error>
154    where
155        Self: Sized;
156
157    /// Let the device enter deep-sleep mode to save power.
158    ///
159    /// The deep sleep mode returns to standby with a hardware reset.
160    fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>;
161
162    /// Wakes the device up from sleep
163    ///
164    /// Also reintialises the device if necessary.
165    fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>;
166
167    /// Sets the backgroundcolor for various commands like [clear_frame](WaveshareDisplay::clear_frame)
168    fn set_background_color(&mut self, color: Self::DisplayColor);
169
170    /// Get current background color
171    fn background_color(&self) -> &Self::DisplayColor;
172
173    /// Get the width of the display
174    fn width(&self) -> u32;
175
176    /// Get the height of the display
177    fn height(&self) -> u32;
178
179    /// Transmit a full frame to the SRAM of the EPD
180    fn update_frame(
181        &mut self,
182        spi: &mut SPI,
183        buffer: &[u8],
184        delay: &mut DELAY,
185    ) -> Result<(), SPI::Error>;
186
187    /// Transmits partial data to the SRAM of the EPD
188    ///
189    /// (x,y) is the top left corner
190    ///
191    /// BUFFER needs to be of size: width / 8 * height !
192    #[allow(clippy::too_many_arguments)]
193    fn update_partial_frame(
194        &mut self,
195        spi: &mut SPI,
196        delay: &mut DELAY,
197        buffer: &[u8],
198        x: u32,
199        y: u32,
200        width: u32,
201        height: u32,
202    ) -> Result<(), SPI::Error>;
203
204    /// Displays the frame data from SRAM
205    ///
206    /// This function waits until the device isn`t busy anymore
207    fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>;
208
209    /// Provide a combined update&display and save some time (skipping a busy check in between)
210    fn update_and_display_frame(
211        &mut self,
212        spi: &mut SPI,
213        buffer: &[u8],
214        delay: &mut DELAY,
215    ) -> Result<(), SPI::Error>;
216
217    /// Clears the frame buffer on the EPD with the declared background color
218    ///
219    /// The background color can be changed with [`WaveshareDisplay::set_background_color`]
220    fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>;
221
222    /// Trait for using various Waveforms from different LUTs
223    /// E.g. for partial refreshes
224    ///
225    /// A full refresh is needed after a certain amount of quick refreshes!
226    ///
227    /// WARNING: Quick Refresh might lead to ghosting-effects/problems with your display. Especially for the 4.2in Display!
228    ///
229    /// If None is used the old value will be loaded on the LUTs once more
230    fn set_lut(
231        &mut self,
232        spi: &mut SPI,
233        delay: &mut DELAY,
234        refresh_rate: Option<RefreshLut>,
235    ) -> Result<(), SPI::Error>;
236
237    /// Wait until the display has stopped processing data
238    ///
239    /// You can call this to make sure a frame is displayed before goin further
240    fn wait_until_idle(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>;
241}
242
243/// Allows quick refresh support for displays that support it; lets you send both
244/// old and new frame data to support this.
245///
246/// When using the quick refresh look-up table, the display must receive separate display
247/// buffer data marked as old, and new. This is used to determine which pixels need to change,
248/// and how they will change. This isn't required when using full refreshes.
249///
250/// (todo: Example ommitted due to CI failures.)
251/// Example:
252///```rust, no_run
253///# use embedded_hal_mock::eh1::*;
254///# fn main() -> Result<(), embedded_hal::spi::ErrorKind> {
255///# use embedded_graphics::{
256///#   pixelcolor::BinaryColor::On as Black, prelude::*, primitives::{Line, PrimitiveStyle},
257///# };
258///# use epd_waveshare::{epd4in2::*, prelude::*};
259///# use epd_waveshare::graphics::VarDisplay;
260///#
261///# let expectations = [];
262///# let mut spi = spi::Mock::new(&expectations);
263///# let expectations = [];
264///# let cs_pin = digital::Mock::new(&expectations);
265///# let busy_in = digital::Mock::new(&expectations);
266///# let dc = digital::Mock::new(&expectations);
267///# let rst = digital::Mock::new(&expectations);
268///# let mut delay = delay::NoopDelay::new();
269///#
270///# // Setup EPD
271///# let mut epd = Epd4in2::new(&mut spi, busy_in, dc, rst, &mut delay, None)?;
272///let (x, y, frame_width, frame_height) = (20, 40, 80,80);
273///
274///let mut buffer = [DEFAULT_BACKGROUND_COLOR.get_byte_value(); 80 / 8 * 80];
275///let mut display = VarDisplay::new(frame_width, frame_height, &mut buffer,false).unwrap();
276///
277///epd.update_partial_old_frame(&mut spi, &mut delay, display.buffer(), x, y, frame_width, frame_height)
278///  .ok();
279///
280///display.clear(Color::White).ok();
281///// Execute drawing commands here.
282///
283///epd.update_partial_new_frame(&mut spi, &mut delay, display.buffer(), x, y, frame_width, frame_height)
284///  .ok();
285///# Ok(())
286///# }
287///```
288pub trait QuickRefresh<SPI, BUSY, DC, RST, DELAY>
289where
290    SPI: SpiDevice,
291    BUSY: InputPin,
292    DC: OutputPin,
293    RST: OutputPin,
294    DELAY: DelayNs,
295{
296    /// Updates the old frame.
297    fn update_old_frame(
298        &mut self,
299        spi: &mut SPI,
300        buffer: &[u8],
301        delay: &mut DELAY,
302    ) -> Result<(), SPI::Error>;
303
304    /// Updates the new frame.
305    fn update_new_frame(
306        &mut self,
307        spi: &mut SPI,
308        buffer: &[u8],
309        delay: &mut DELAY,
310    ) -> Result<(), SPI::Error>;
311
312    /// Displays the new frame
313    fn display_new_frame(&mut self, spi: &mut SPI, _delay: &mut DELAY) -> Result<(), SPI::Error>;
314
315    /// Updates and displays the new frame.
316    fn update_and_display_new_frame(
317        &mut self,
318        spi: &mut SPI,
319        buffer: &[u8],
320        delay: &mut DELAY,
321    ) -> Result<(), SPI::Error>;
322
323    /// Updates the old frame for a portion of the display.
324    #[allow(clippy::too_many_arguments)]
325    fn update_partial_old_frame(
326        &mut self,
327        spi: &mut SPI,
328        delay: &mut DELAY,
329        buffer: &[u8],
330        x: u32,
331        y: u32,
332        width: u32,
333        height: u32,
334    ) -> Result<(), SPI::Error>;
335
336    /// Updates the new frame for a portion of the display.
337    #[allow(clippy::too_many_arguments)]
338    fn update_partial_new_frame(
339        &mut self,
340        spi: &mut SPI,
341        delay: &mut DELAY,
342        buffer: &[u8],
343        x: u32,
344        y: u32,
345        width: u32,
346        height: u32,
347    ) -> Result<(), SPI::Error>;
348
349    /// Clears the partial frame buffer on the EPD with the declared background color
350    /// The background color can be changed with [`WaveshareDisplay::set_background_color`]
351    fn clear_partial_frame(
352        &mut self,
353        spi: &mut SPI,
354        delay: &mut DELAY,
355        x: u32,
356        y: u32,
357        width: u32,
358        height: u32,
359    ) -> Result<(), SPI::Error>;
360}