1use core::time::Duration;
2use embedded_graphics::{
3 prelude::{Point, Size},
4 primitives::Rectangle,
5};
6use embedded_hal::{
7 digital::{OutputPin, PinState},
8 spi::{Phase, Polarity},
9};
10use embedded_hal_async::delay::DelayNs;
11
12use crate::{
13 buffer::{
14 binary_buffer_length, split_low_and_high, BinaryBuffer, BufferView, Gray2SplitBuffer,
15 },
16 hw::{BusyHw, CommandDataSend as _, DcHw, DelayHw, ErrorHw, ResetHw, SpiHw},
17 log::{debug, debug_assert},
18 DisplayPartial, DisplaySimple, Displayable, Reset, Sleep, Wake,
19};
20
21const LUT_FULL_UPDATE: [u8; 153] = [
25 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
26 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
27 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
28 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x19, 0x00, 0x00,
29 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
32 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
33 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34 0x24, 0x42, 0x22, 0x22, 0x23, 0x32, 0x00, 0x00, 0x00,
35];
36const LUT_MAGIC_FULL_UPDATE: [u8; 1] = [0x22];
37const GATE_VOLTAGE_FULL_UPDATE: [u8; 1] = [0x17];
38const SOURCE_VOLTAGE_FULL_UPDATE: [u8; 3] = [0x41, 0xAE, 0x32];
39const VCOM_FULL_UPDATE: [u8; 1] = [0x38];
40const LUT_PARTIAL_UPDATE: [u8; 153] = [
45 0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x80, 0x0, 0x0, 0x0, 0x0,
46 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
47 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
48 0x0, 0x0, 0x0, 0x0, 0x0, 0x0A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
49 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
50 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
51 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
52 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x22, 0x22, 0x22, 0x22, 0x22,
53 0x22, 0x0, 0x0, 0x0,
54];
55const LUT_MAGIC_PARTIAL_UPDATE: [u8; 1] = [0x22];
56const GATE_VOLTAGE_PARTIAL_UPDATE: [u8; 1] = [0x17];
57const SOURCE_VOLTAGE_PARTIAL_UPDATE: [u8; 3] = [0x41, 0xB0, 0x32];
58const VCOM_PARTIAL_UPDATE: [u8; 1] = [0x36];
59const LUT_GRAY2: [u8; 153] = [
60 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x60, 0x10, 0x00,
61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x60, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
62 0x00, 0x00, 0x00, 0x00, 0x2A, 0x60, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
63 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05,
64 0x14, 0x00, 0x00, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x05, 0x14, 0x00,
65 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
66 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69 0x24, 0x22, 0x22, 0x22, 0x23, 0x32, 0x00, 0x00, 0x00,
70];
71const LUT_MAGIC_GRAY2: [u8; 1] = [0x22];
72const GATE_VOLTAGE_GRAY2: [u8; 1] = [0x17];
73const SOURCE_VOLTAGE_GRAY2: [u8; 3] = [0x41, 0xAE, 0x32];
74const VCOM_GRAY2: [u8; 1] = [0x28];
75
76#[cfg_attr(feature = "defmt", derive(defmt::Format))]
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78pub enum RefreshMode {
80 Full,
85 Partial,
91 Gray2,
96}
97
98impl RefreshMode {
99 pub fn border_waveform(&self) -> &[u8] {
101 match self {
102 RefreshMode::Full => &[0x05],
103 RefreshMode::Partial => &[0x80],
104 RefreshMode::Gray2 => &[0x04],
105 }
106 }
107
108 pub fn lut(&self) -> &[u8] {
110 match self {
111 RefreshMode::Full => &LUT_FULL_UPDATE,
112 RefreshMode::Partial => &LUT_PARTIAL_UPDATE,
113 RefreshMode::Gray2 => &LUT_GRAY2,
114 }
115 }
116
117 pub fn lut_magic(&self) -> &[u8] {
118 match self {
119 RefreshMode::Full => &LUT_MAGIC_FULL_UPDATE,
120 RefreshMode::Partial => &LUT_MAGIC_PARTIAL_UPDATE,
121 RefreshMode::Gray2 => &LUT_MAGIC_GRAY2,
122 }
123 }
124
125 pub fn gate_voltage(&self) -> &[u8] {
126 match self {
127 RefreshMode::Full => &GATE_VOLTAGE_FULL_UPDATE,
128 RefreshMode::Partial => &GATE_VOLTAGE_PARTIAL_UPDATE,
129 RefreshMode::Gray2 => &GATE_VOLTAGE_GRAY2,
130 }
131 }
132
133 pub fn source_voltage(&self) -> &[u8] {
134 match self {
135 RefreshMode::Full => &SOURCE_VOLTAGE_FULL_UPDATE,
136 RefreshMode::Partial => &SOURCE_VOLTAGE_PARTIAL_UPDATE,
137 RefreshMode::Gray2 => &SOURCE_VOLTAGE_GRAY2,
138 }
139 }
140
141 pub fn vcom(&self) -> &[u8] {
142 match self {
143 RefreshMode::Full => &VCOM_FULL_UPDATE,
144 RefreshMode::Partial => &VCOM_PARTIAL_UPDATE,
145 RefreshMode::Gray2 => &VCOM_GRAY2,
146 }
147 }
148
149 pub fn display_update_control_2(&self) -> &[u8] {
151 match self {
152 RefreshMode::Partial => &[0xCF],
156 _ => &[0xC7],
157 }
158 }
159
160 pub fn is_black_and_white(&self) -> bool {
162 *self != RefreshMode::Gray2
163 }
164}
165
166pub const DISPLAY_HEIGHT: u16 = 296;
168pub const DISPLAY_WIDTH: u16 = 128;
170pub const RECOMMENDED_MIN_FULL_REFRESH_INTERVAL: Duration = Duration::from_secs(180);
172pub const RECOMMENDED_MAX_FULL_REFRESH_INTERVAL: Duration = Duration::from_secs(24 * 60 * 60);
174pub const RECOMMENDED_SPI_HZ: u32 = 4_000_000; pub const RECOMMENDED_SPI_PHASE: Phase = Phase::CaptureOnFirstTransition;
178pub const RECOMMENDED_SPI_POLARITY: Polarity = Polarity::IdleLow;
181pub const DEFAULT_BUSY_WHEN: PinState = PinState::High;
183
184#[cfg_attr(feature = "defmt", derive(defmt::Format))]
188#[derive(Debug, Clone, Copy, PartialEq, Eq)]
189pub enum Command {
190 DriverOutputControl = 0x01,
192 SetGateDrivingVoltage = 0x03,
194 SetSourceDrivingVoltage = 0x04,
196 DeepSleepMode = 0x10,
198 DataEntryModeSetting = 0x11,
200 SwReset = 0x12,
202 MasterActivation = 0x20,
205 DisplayUpdateControl1 = 0x21,
227 DisplayUpdateControl2 = 0x22,
229 WriteLowRam = 0x24,
231 WriteHighRam = 0x26,
233 ReadVcom = 0x28,
236 SetVcomReadDuration = 0x29,
238 ProgramVcomOtp = 0x2A,
241 WriteVcom = 0x2C,
243
244 ReadOtpRegisters = 0x2D,
246 ReadUserId = 0x2E,
248 ProgramWsOtp = 0x30,
251 LoadWsOtp = 0x31,
254
255 WriteLut = 0x32,
257
258 ProgramOtpSelection = 0x36,
261
262 WriteRegisterForUserId = 0x38,
265 SetOtpProgramMode = 0x39,
270 SetBorderWaveform = 0x3C,
272 SetLutMagic = 0x3F,
274
275 SetRamXStartEnd = 0x44,
284 SetRamYStartEnd = 0x45,
287 SetRamX = 0x4E,
290 SetRamY = 0x4F,
292}
293
294impl Command {
295 fn register(&self) -> u8 {
297 *self as u8
298 }
299}
300
301pub const BINARY_BUFFER_LENGTH: usize =
303 binary_buffer_length(Size::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32));
304pub type Epd2In9BinaryBuffer = BinaryBuffer<BINARY_BUFFER_LENGTH>;
306pub fn new_binary_buffer() -> Epd2In9BinaryBuffer {
308 Epd2In9BinaryBuffer::new(Size::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32))
309}
310pub type Epd2In9Gray2Buffer = Gray2SplitBuffer<BINARY_BUFFER_LENGTH>;
311pub fn new_gray2_buffer() -> Epd2In9Gray2Buffer {
312 Epd2In9Gray2Buffer::new(Size::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32))
313}
314
315const DRIVER_OUTPUT_INIT_DATA: [u8; 3] = [0x27, 0x01, 0x00];
323
324pub struct Epd2In9V2<HW, STATE> {
337 hw: HW,
338 state: STATE,
339}
340
341trait StateInternal {}
342#[allow(private_bounds)]
343pub trait State: StateInternal {}
344pub trait StateAwake: State {}
345
346macro_rules! impl_base_state {
347 ($state:ident) => {
348 impl StateInternal for $state {}
349 impl State for $state {}
350 };
351}
352
353#[cfg_attr(feature = "defmt", derive(defmt::Format))]
354#[derive(Debug, Clone, Copy, PartialEq)]
355pub struct StateUninitialized();
356impl_base_state!(StateUninitialized);
357impl StateAwake for StateUninitialized {}
358
359#[cfg_attr(feature = "defmt", derive(defmt::Format))]
360#[derive(Debug, Clone, Copy, PartialEq)]
361pub struct StateReady {
362 mode: RefreshMode,
363}
364impl_base_state!(StateReady);
365impl StateAwake for StateReady {}
366
367#[cfg_attr(feature = "defmt", derive(defmt::Format))]
368#[derive(Debug, Clone, Copy, PartialEq)]
369pub struct StateAsleep<W: StateAwake> {
370 wake_state: W,
371}
372impl<W: StateAwake> StateInternal for StateAsleep<W> {}
373impl<W: StateAwake> State for StateAsleep<W> {}
374
375impl<HW> Epd2In9V2<HW, StateUninitialized>
376where
377 HW: BusyHw + DcHw + ResetHw + DelayHw + SpiHw + ErrorHw,
378 HW::Error: From<<HW::Busy as embedded_hal::digital::ErrorType>::Error>
379 + From<<HW::Dc as embedded_hal::digital::ErrorType>::Error>
380 + From<<HW::Reset as embedded_hal::digital::ErrorType>::Error>
381 + From<<HW::Spi as embedded_hal_async::spi::ErrorType>::Error>,
382{
383 pub fn new(hw: HW) -> Self {
384 Epd2In9V2 {
385 hw,
386 state: StateUninitialized(),
387 }
388 }
389}
390
391pub enum Bypass {
392 Normal = 0,
394 AllZero = 0b100,
396 Inverted = 0b1000,
398}
399
400impl<HW, STATE> Epd2In9V2<HW, STATE>
401where
402 HW: BusyHw + DcHw + ResetHw + DelayHw + SpiHw + ErrorHw,
403 HW::Error: From<<HW::Busy as embedded_hal::digital::ErrorType>::Error>
404 + From<<HW::Dc as embedded_hal::digital::ErrorType>::Error>
405 + From<<HW::Reset as embedded_hal::digital::ErrorType>::Error>
406 + From<<HW::Spi as embedded_hal_async::spi::ErrorType>::Error>,
407 STATE: StateAwake,
408{
409 pub async fn init(
411 mut self,
412 spi: &mut HW::Spi,
413 mode: RefreshMode,
414 ) -> Result<Epd2In9V2<HW, StateReady>, HW::Error> {
415 debug!("Initialising display");
416 self = self.reset().await?;
417
418 let mut epd = Epd2In9V2 {
419 hw: self.hw,
420 state: StateReady { mode },
421 };
422
423 epd.set_refresh_mode_impl(spi, mode).await?;
424 Ok(epd)
425 }
426}
427
428impl<HW, STATE> Epd2In9V2<HW, STATE>
429where
430 HW: BusyHw + DcHw + SpiHw + ErrorHw,
431 HW::Error: From<<HW::Busy as embedded_hal::digital::ErrorType>::Error>
432 + From<<HW::Dc as embedded_hal::digital::ErrorType>::Error>
433 + From<<HW::Spi as embedded_hal_async::spi::ErrorType>::Error>,
434 STATE: StateAwake,
435{
436 pub async fn send(
438 &mut self,
439 spi: &mut HW::Spi,
440 command: Command,
441 data: &[u8],
442 ) -> Result<(), HW::Error> {
443 self.hw.send(spi, command.register(), data).await
444 }
445}
446
447impl<HW> Epd2In9V2<HW, StateReady>
448where
449 HW: BusyHw + DcHw + SpiHw + ErrorHw,
450 HW::Error: From<<HW::Busy as embedded_hal::digital::ErrorType>::Error>
451 + From<<HW::Dc as embedded_hal::digital::ErrorType>::Error>
452 + From<<HW::Spi as embedded_hal_async::spi::ErrorType>::Error>,
453{
454 pub async fn set_refresh_mode(
456 &mut self,
457 spi: &mut HW::Spi,
458 mode: RefreshMode,
459 ) -> Result<(), HW::Error> {
460 if self.state.mode == mode {
461 Ok(())
462 } else {
463 debug!("Changing refresh mode to {:?}", mode);
464 self.set_refresh_mode_impl(spi, mode).await?;
465 Ok(())
466 }
467 }
468
469 async fn set_refresh_mode_impl(
470 &mut self,
471 spi: &mut HW::Spi,
472 mode: RefreshMode,
473 ) -> Result<(), HW::Error> {
474 self.send(spi, Command::SwReset, &[]).await?;
476
477 self.send(spi, Command::DriverOutputControl, &DRIVER_OUTPUT_INIT_DATA)
478 .await?;
479 self.send(spi, Command::DataEntryModeSetting, &[0b11])
481 .await?;
482
483 let black_and_white_byte = if mode.is_black_and_white() {
484 0x80
485 } else {
486 0x00
487 };
488 self.send(
489 spi,
490 Command::DisplayUpdateControl1,
491 &[0x00, black_and_white_byte],
492 )
493 .await?;
494
495 self.send(spi, Command::SetBorderWaveform, mode.border_waveform())
496 .await?;
497
498 self.send(spi, Command::WriteLut, mode.lut()).await?;
499 self.send(spi, Command::SetLutMagic, mode.lut_magic())
500 .await?;
501 self.send(spi, Command::SetGateDrivingVoltage, mode.gate_voltage())
502 .await?;
503 self.send(spi, Command::SetSourceDrivingVoltage, mode.source_voltage())
504 .await?;
505 self.send(spi, Command::WriteVcom, mode.vcom()).await?;
506
507 if mode == RefreshMode::Partial {
508 self.hw
510 .send(
511 spi,
512 0x37,
513 &[0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00],
514 )
515 .await?;
516
517 self.send(spi, Command::DisplayUpdateControl2, &[0xC3])
518 .await?;
519 self.send(spi, Command::MasterActivation, &[]).await?;
520 }
521 self.state.mode = mode;
522
523 Ok(())
524 }
525
526 pub async fn set_ram_bypass(
534 &mut self,
535 spi: &mut HW::Spi,
536 low_bypass: Bypass,
537 high_bypass: Bypass,
538 ) -> Result<(), HW::Error> {
539 let black_and_white_byte = if self.state.mode.is_black_and_white() {
540 0x80
541 } else {
542 0x00
543 };
544 self.send(
545 spi,
546 Command::DisplayUpdateControl1,
547 &[
548 ((high_bypass as u8) << 4) | (low_bypass as u8),
549 black_and_white_byte,
550 ],
551 )
552 .await
553 }
554
555 pub async fn set_window(
560 &mut self,
561 spi: &mut HW::Spi,
562 shape: Rectangle,
563 ) -> Result<(), HW::Error> {
564 let (x_start, x_end) = if self.state.mode == RefreshMode::Gray2 {
565 let x_start = shape.top_left.x + 8;
567 let x_end = shape.top_left.x + shape.size.width as i32 + 7;
568 (x_start, x_end)
569 } else {
570 let x_start = shape.top_left.x;
571 (x_start, x_start + shape.size.width as i32 - 1)
572 };
573 debug_assert!(
576 x_start % 8 == 0 && x_end % 8 == 7,
577 "window's top_left.x and width must be 8-bit aligned"
578 );
579 let x_start_byte = ((x_start >> 3) & 0xFF) as u8;
580 let x_end_byte = ((x_end >> 3) & 0xFF) as u8;
581 self.send(spi, Command::SetRamXStartEnd, &[x_start_byte, x_end_byte])
582 .await?;
583
584 let (y_start_low, y_start_high) = split_low_and_high(shape.top_left.y as u16);
585 let (y_end_low, y_end_high) =
586 split_low_and_high((shape.top_left.y + shape.size.height as i32 - 1) as u16);
587 self.send(
588 spi,
589 Command::SetRamYStartEnd,
590 &[y_start_low, y_start_high, y_end_low, y_end_high],
591 )
592 .await?;
593
594 Ok(())
595 }
596
597 pub async fn set_cursor(
602 &mut self,
603 spi: &mut HW::Spi,
604 position: Point,
605 ) -> Result<(), HW::Error> {
606 debug_assert_eq!(position.x % 8, 0, "position.x must be 8-bit aligned");
609 let x_pos = if self.state.mode == RefreshMode::Gray2 {
610 position.x + 8
611 } else {
612 position.x
613 };
614
615 self.send(spi, Command::SetRamX, &[(x_pos >> 3) as u8])
616 .await?;
617 let (y_low, y_high) = split_low_and_high(position.y as u16);
618 self.send(spi, Command::SetRamY, &[y_low, y_high]).await?;
619 Ok(())
620 }
621}
622
623async fn reset_impl<HW>(hw: &mut HW) -> Result<(), HW::Error>
624where
625 HW: ResetHw + DelayHw + ErrorHw,
626 HW::Error: From<<HW::Reset as embedded_hal::digital::ErrorType>::Error>,
627{
628 debug!("Resetting EPD");
629 hw.reset().set_low()?;
631 hw.delay().delay_ms(10).await;
632 hw.reset().set_high()?;
633 hw.delay().delay_ms(10).await;
634 Ok(())
635}
636
637impl<HW, STATE: StateAwake> Reset<HW::Error> for Epd2In9V2<HW, STATE>
638where
639 HW: ResetHw + DelayHw + ErrorHw,
640 HW::Error: From<<HW::Reset as embedded_hal::digital::ErrorType>::Error>,
641{
642 type DisplayOut = Epd2In9V2<HW, STATE>;
643
644 async fn reset(mut self) -> Result<Self::DisplayOut, HW::Error> {
645 reset_impl(&mut self.hw).await?;
646 Ok(self)
647 }
648}
649
650impl<HW, W: StateAwake> Reset<HW::Error> for Epd2In9V2<HW, StateAsleep<W>>
651where
652 HW: ResetHw + DelayHw + ErrorHw,
653 HW::Error: From<<HW::Reset as embedded_hal::digital::ErrorType>::Error>,
654{
655 type DisplayOut = Epd2In9V2<HW, W>;
656
657 async fn reset(mut self) -> Result<Self::DisplayOut, HW::Error> {
658 reset_impl(&mut self.hw).await?;
659 Ok(Epd2In9V2 {
660 hw: self.hw,
661 state: self.state.wake_state,
662 })
663 }
664}
665
666impl<HW, STATE: StateAwake> Sleep<HW::Spi, HW::Error> for Epd2In9V2<HW, STATE>
667where
668 HW: BusyHw + DcHw + SpiHw + ErrorHw,
669 HW::Error: From<<HW::Busy as embedded_hal::digital::ErrorType>::Error>
670 + From<<HW::Dc as embedded_hal::digital::ErrorType>::Error>
671 + From<<HW::Spi as embedded_hal_async::spi::ErrorType>::Error>,
672{
673 type DisplayOut = Epd2In9V2<HW, StateAsleep<STATE>>;
674
675 async fn sleep(mut self, spi: &mut HW::Spi) -> Result<Self::DisplayOut, HW::Error> {
676 debug!("Sleeping EPD");
677 self.send(spi, Command::DeepSleepMode, &[0x01]).await?;
678 Ok(Epd2In9V2 {
679 hw: self.hw,
680 state: StateAsleep {
681 wake_state: self.state,
682 },
683 })
684 }
685}
686
687impl<HW, W: StateAwake> Wake<HW::Spi, HW::Error> for Epd2In9V2<HW, StateAsleep<W>>
688where
689 HW: BusyHw + DcHw + ResetHw + DelayHw + SpiHw + ErrorHw,
690 HW::Error: From<<HW::Busy as embedded_hal::digital::ErrorType>::Error>
691 + From<<HW::Dc as embedded_hal::digital::ErrorType>::Error>
692 + From<<HW::Reset as embedded_hal::digital::ErrorType>::Error>
693 + From<<HW::Spi as embedded_hal_async::spi::ErrorType>::Error>,
694{
695 type DisplayOut = Epd2In9V2<HW, W>;
696 async fn wake(self, _spi: &mut HW::Spi) -> Result<Self::DisplayOut, HW::Error> {
697 debug!("Waking EPD");
698 self.reset().await
699 }
700}
701
702impl<HW> Displayable<HW::Spi, HW::Error> for Epd2In9V2<HW, StateReady>
703where
704 HW: BusyHw + DcHw + SpiHw + ErrorHw,
705 HW::Error: From<<HW::Busy as embedded_hal::digital::ErrorType>::Error>
706 + From<<HW::Dc as embedded_hal::digital::ErrorType>::Error>
707 + From<<HW::Spi as embedded_hal_async::spi::ErrorType>::Error>,
708{
709 async fn update_display(&mut self, spi: &mut HW::Spi) -> Result<(), HW::Error> {
710 debug!("Updating display");
711
712 let mode = self.state.mode;
713 let update_control = mode.display_update_control_2();
714 self.send(spi, Command::DisplayUpdateControl2, update_control)
715 .await?;
716
717 self.send(spi, Command::MasterActivation, &[]).await?;
718 Ok(())
719 }
720}
721
722impl<HW> DisplaySimple<1, 1, HW::Spi, HW::Error> for Epd2In9V2<HW, StateReady>
723where
724 HW: BusyHw + DcHw + SpiHw + ErrorHw,
725 HW::Error: From<<HW::Busy as embedded_hal::digital::ErrorType>::Error>
726 + From<<HW::Dc as embedded_hal::digital::ErrorType>::Error>
727 + From<<HW::Spi as embedded_hal_async::spi::ErrorType>::Error>,
728{
729 async fn display_framebuffer(
730 &mut self,
731 spi: &mut HW::Spi,
732 buf: &dyn BufferView<1, 1>,
733 ) -> Result<(), HW::Error> {
734 self.write_framebuffer(spi, buf).await?;
735
736 self.update_display(spi).await
737 }
738
739 async fn write_framebuffer(
740 &mut self,
741 spi: &mut HW::Spi,
742 buf: &dyn BufferView<1, 1>,
743 ) -> Result<(), HW::Error> {
744 let buffer_bounds = buf.window();
745 self.set_window(spi, buffer_bounds).await?;
746 self.set_cursor(spi, buffer_bounds.top_left).await?;
747 self.send(spi, Command::WriteLowRam, buf.data()[0]).await
748 }
749}
750
751impl<HW> DisplaySimple<1, 2, HW::Spi, HW::Error> for Epd2In9V2<HW, StateReady>
752where
753 HW: BusyHw + DcHw + SpiHw + ErrorHw,
754 HW::Error: From<<HW::Busy as embedded_hal::digital::ErrorType>::Error>
755 + From<<HW::Dc as embedded_hal::digital::ErrorType>::Error>
756 + From<<HW::Spi as embedded_hal_async::spi::ErrorType>::Error>,
757{
758 async fn display_framebuffer(
759 &mut self,
760 spi: &mut HW::Spi,
761 buf: &dyn BufferView<1, 2>,
762 ) -> Result<(), HW::Error> {
763 self.write_framebuffer(spi, buf).await?;
764
765 self.update_display(spi).await
766 }
767
768 async fn write_framebuffer(
769 &mut self,
770 spi: &mut HW::Spi,
771 buf: &dyn BufferView<1, 2>,
772 ) -> Result<(), HW::Error> {
773 let buffer_bounds = buf.window();
774 self.set_window(spi, buffer_bounds).await?;
775 self.set_cursor(spi, buffer_bounds.top_left).await?;
776 self.send(spi, Command::WriteLowRam, buf.data()[0]).await?;
777 self.send(spi, Command::WriteHighRam, buf.data()[1]).await
778 }
779}
780
781impl<HW> DisplayPartial<1, 1, HW::Spi, HW::Error> for Epd2In9V2<HW, StateReady>
782where
783 HW: BusyHw + DcHw + SpiHw + ErrorHw,
784 HW::Error: From<<HW::Busy as embedded_hal::digital::ErrorType>::Error>
785 + From<<HW::Dc as embedded_hal::digital::ErrorType>::Error>
786 + From<<HW::Spi as embedded_hal_async::spi::ErrorType>::Error>,
787{
788 async fn write_base_framebuffer(
789 &mut self,
790 spi: &mut HW::Spi,
791 buf: &dyn BufferView<1, 1>,
792 ) -> Result<(), HW::Error> {
793 let buffer_bounds = buf.window();
794 self.set_window(spi, buffer_bounds).await?;
795 self.set_cursor(spi, buffer_bounds.top_left).await?;
796 self.send(spi, Command::WriteHighRam, buf.data()[0]).await
797 }
798}