1use core::time::Duration;
2use embedded_graphics::{
3 prelude::{Point, Size},
4 primitives::Rectangle,
5};
6use embedded_hal::{
7 digital::OutputPin,
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::CommandDataSend as _,
17 log::{debug, debug_assert},
18 DisplayPartial, DisplaySimple, Displayable, EpdHw, 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;
181
182#[cfg_attr(feature = "defmt", derive(defmt::Format))]
186#[derive(Debug, Clone, Copy, PartialEq, Eq)]
187pub enum Command {
188 DriverOutputControl = 0x01,
190 SetGateDrivingVoltage = 0x03,
192 SetSourceDrivingVoltage = 0x04,
194 DeepSleepMode = 0x10,
196 DataEntryModeSetting = 0x11,
198 SwReset = 0x12,
200 MasterActivation = 0x20,
203 DisplayUpdateControl1 = 0x21,
225 DisplayUpdateControl2 = 0x22,
227 WriteLowRam = 0x24,
229 WriteHighRam = 0x26,
231 ReadVcom = 0x28,
234 SetVcomReadDuration = 0x29,
236 ProgramVcomOtp = 0x2A,
239 WriteVcom = 0x2C,
241
242 ReadOtpRegisters = 0x2D,
244 ReadUserId = 0x2E,
246 ProgramWsOtp = 0x30,
249 LoadWsOtp = 0x31,
252
253 WriteLut = 0x32,
255
256 ProgramOtpSelection = 0x36,
259
260 WriteRegisterForUserId = 0x38,
263 SetOtpProgramMode = 0x39,
268 SetBorderWaveform = 0x3C,
270 SetLutMagic = 0x3F,
272
273 SetRamXStartEnd = 0x44,
282 SetRamYStartEnd = 0x45,
285 SetRamX = 0x4E,
288 SetRamY = 0x4F,
290}
291
292impl Command {
293 fn register(&self) -> u8 {
295 *self as u8
296 }
297}
298
299pub const BINARY_BUFFER_LENGTH: usize =
301 binary_buffer_length(Size::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32));
302pub type Epd2In9BinaryBuffer = BinaryBuffer<BINARY_BUFFER_LENGTH>;
304pub fn new_binary_buffer() -> Epd2In9BinaryBuffer {
306 Epd2In9BinaryBuffer::new(Size::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32))
307}
308pub type Epd2In9Gray2Buffer = Gray2SplitBuffer<BINARY_BUFFER_LENGTH>;
309pub fn new_gray2_buffer() -> Epd2In9Gray2Buffer {
310 Epd2In9Gray2Buffer::new(Size::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32))
311}
312
313const DRIVER_OUTPUT_INIT_DATA: [u8; 3] = [0x27, 0x01, 0x00];
321
322pub struct Epd2In9V2<HW, STATE>
333where
334 HW: EpdHw,
335 STATE: State,
336{
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: EpdHw,
378{
379 pub fn new(hw: HW) -> Self {
380 Epd2In9V2 {
381 hw,
382 state: StateUninitialized(),
383 }
384 }
385}
386
387pub enum Bypass {
388 Normal = 0,
390 AllZero = 0b100,
392 Inverted = 0b1000,
394}
395
396impl<HW, STATE> Epd2In9V2<HW, STATE>
397where
398 HW: EpdHw,
399 STATE: StateAwake,
400{
401 pub async fn init(
403 mut self,
404 spi: &mut HW::Spi,
405 mode: RefreshMode,
406 ) -> Result<Epd2In9V2<HW, StateReady>, HW::Error> {
407 debug!("Initialising display");
408 self = self.reset().await?;
409
410 let mut epd = Epd2In9V2 {
411 hw: self.hw,
412 state: StateReady { mode },
413 };
414
415 epd.set_refresh_mode_impl(spi, mode).await?;
416 Ok(epd)
417 }
418
419 pub async fn send(
421 &mut self,
422 spi: &mut HW::Spi,
423 command: Command,
424 data: &[u8],
425 ) -> Result<(), HW::Error> {
426 self.hw.send(spi, command.register(), data).await
427 }
428}
429
430impl<HW: EpdHw> Epd2In9V2<HW, StateReady> {
431 pub async fn set_refresh_mode(
433 &mut self,
434 spi: &mut HW::Spi,
435 mode: RefreshMode,
436 ) -> Result<(), HW::Error> {
437 if self.state.mode == mode {
438 Ok(())
439 } else {
440 debug!("Changing refresh mode to {:?}", mode);
441 self.set_refresh_mode_impl(spi, mode).await?;
442 Ok(())
443 }
444 }
445
446 async fn set_refresh_mode_impl(
447 &mut self,
448 spi: &mut <HW as EpdHw>::Spi,
449 mode: RefreshMode,
450 ) -> Result<(), <HW as EpdHw>::Error> {
451 self.send(spi, Command::SwReset, &[]).await?;
453
454 self.send(spi, Command::DriverOutputControl, &DRIVER_OUTPUT_INIT_DATA)
455 .await?;
456 self.send(spi, Command::DataEntryModeSetting, &[0b11])
458 .await?;
459
460 let black_and_white_byte = if mode.is_black_and_white() {
461 0x80
462 } else {
463 0x00
464 };
465 self.send(
466 spi,
467 Command::DisplayUpdateControl1,
468 &[0x00, black_and_white_byte],
469 )
470 .await?;
471
472 self.send(spi, Command::SetBorderWaveform, mode.border_waveform())
473 .await?;
474
475 self.send(spi, Command::WriteLut, mode.lut()).await?;
476 self.send(spi, Command::SetLutMagic, mode.lut_magic())
477 .await?;
478 self.send(spi, Command::SetGateDrivingVoltage, mode.gate_voltage())
479 .await?;
480 self.send(spi, Command::SetSourceDrivingVoltage, mode.source_voltage())
481 .await?;
482 self.send(spi, Command::WriteVcom, mode.vcom()).await?;
483
484 if mode == RefreshMode::Partial {
485 self.hw
487 .send(
488 spi,
489 0x37,
490 &[0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00],
491 )
492 .await?;
493
494 self.send(spi, Command::DisplayUpdateControl2, &[0xC3])
495 .await?;
496 self.send(spi, Command::MasterActivation, &[]).await?;
497 }
498 self.state.mode = mode;
499
500 Ok(())
501 }
502
503 pub async fn set_ram_bypass(
511 &mut self,
512 spi: &mut HW::Spi,
513 low_bypass: Bypass,
514 high_bypass: Bypass,
515 ) -> Result<(), HW::Error> {
516 let black_and_white_byte = if self.state.mode.is_black_and_white() {
517 0x80
518 } else {
519 0x00
520 };
521 self.send(
522 spi,
523 Command::DisplayUpdateControl1,
524 &[
525 ((high_bypass as u8) << 4) | (low_bypass as u8),
526 black_and_white_byte,
527 ],
528 )
529 .await
530 }
531
532 pub async fn set_window(
537 &mut self,
538 spi: &mut HW::Spi,
539 shape: Rectangle,
540 ) -> Result<(), <HW as EpdHw>::Error> {
541 let (x_start, x_end) = if self.state.mode == RefreshMode::Gray2 {
542 let x_start = shape.top_left.x + 8;
544 let x_end = shape.top_left.x + shape.size.width as i32 + 7;
545 (x_start, x_end)
546 } else {
547 let x_start = shape.top_left.x;
548 (x_start, x_start + shape.size.width as i32 - 1)
549 };
550 debug_assert!(
553 x_start % 8 == 0 && x_end % 8 == 7,
554 "window's top_left.x and width must be 8-bit aligned"
555 );
556 let x_start_byte = ((x_start >> 3) & 0xFF) as u8;
557 let x_end_byte = ((x_end >> 3) & 0xFF) as u8;
558 self.send(spi, Command::SetRamXStartEnd, &[x_start_byte, x_end_byte])
559 .await?;
560
561 let (y_start_low, y_start_high) = split_low_and_high(shape.top_left.y as u16);
562 let (y_end_low, y_end_high) =
563 split_low_and_high((shape.top_left.y + shape.size.height as i32 - 1) as u16);
564 self.send(
565 spi,
566 Command::SetRamYStartEnd,
567 &[y_start_low, y_start_high, y_end_low, y_end_high],
568 )
569 .await?;
570
571 Ok(())
572 }
573
574 pub async fn set_cursor(
579 &mut self,
580 spi: &mut HW::Spi,
581 position: Point,
582 ) -> Result<(), <HW as EpdHw>::Error> {
583 debug_assert_eq!(position.x % 8, 0, "position.x must be 8-bit aligned");
586 let x_pos = if self.state.mode == RefreshMode::Gray2 {
587 position.x + 8
588 } else {
589 position.x
590 };
591
592 self.send(spi, Command::SetRamX, &[(x_pos >> 3) as u8])
593 .await?;
594 let (y_low, y_high) = split_low_and_high(position.y as u16);
595 self.send(spi, Command::SetRamY, &[y_low, y_high]).await?;
596 Ok(())
597 }
598}
599
600async fn reset_impl<HW: EpdHw>(hw: &mut HW) -> Result<(), HW::Error> {
601 debug!("Resetting EPD");
602 hw.reset().set_low()?;
604 hw.delay().delay_ms(10).await;
605 hw.reset().set_high()?;
606 hw.delay().delay_ms(10).await;
607 Ok(())
608}
609
610impl<HW: EpdHw, STATE: StateAwake> Reset<HW::Error> for Epd2In9V2<HW, STATE> {
611 type DisplayOut = Epd2In9V2<HW, STATE>;
612
613 async fn reset(mut self) -> Result<Self::DisplayOut, HW::Error> {
614 reset_impl(&mut self.hw).await?;
615 Ok(self)
616 }
617}
618
619impl<HW: EpdHw, W: StateAwake> Reset<HW::Error> for Epd2In9V2<HW, StateAsleep<W>> {
620 type DisplayOut = Epd2In9V2<HW, W>;
621
622 async fn reset(mut self) -> Result<Self::DisplayOut, HW::Error> {
623 reset_impl(&mut self.hw).await?;
624 Ok(Epd2In9V2 {
625 hw: self.hw,
626 state: self.state.wake_state,
627 })
628 }
629}
630
631impl<HW: EpdHw, STATE: StateAwake> Sleep<HW::Spi, HW::Error> for Epd2In9V2<HW, STATE> {
632 type DisplayOut = Epd2In9V2<HW, StateAsleep<STATE>>;
633
634 async fn sleep(mut self, spi: &mut HW::Spi) -> Result<Self::DisplayOut, <HW as EpdHw>::Error> {
635 debug!("Sleeping EPD");
636 self.send(spi, Command::DeepSleepMode, &[0x01]).await?;
637 Ok(Epd2In9V2 {
638 hw: self.hw,
639 state: StateAsleep {
640 wake_state: self.state,
641 },
642 })
643 }
644}
645
646impl<HW: EpdHw, W: StateAwake> Wake<HW::Spi, HW::Error> for Epd2In9V2<HW, StateAsleep<W>> {
647 type DisplayOut = Epd2In9V2<HW, W>;
648 async fn wake(self, _spi: &mut HW::Spi) -> Result<Self::DisplayOut, <HW as EpdHw>::Error> {
649 debug!("Waking EPD");
650 self.reset().await
651 }
652}
653
654impl<HW: EpdHw> Displayable<HW::Spi, HW::Error> for Epd2In9V2<HW, StateReady> {
655 async fn update_display(&mut self, spi: &mut HW::Spi) -> Result<(), <HW as EpdHw>::Error> {
656 debug!("Updating display");
657
658 let mode = self.state.mode;
659 let update_control = mode.display_update_control_2();
660 self.send(spi, Command::DisplayUpdateControl2, update_control)
661 .await?;
662
663 self.send(spi, Command::MasterActivation, &[]).await?;
664 Ok(())
665 }
666}
667
668impl<HW: EpdHw> DisplaySimple<1, 1, HW::Spi, HW::Error> for Epd2In9V2<HW, StateReady> {
669 async fn display_framebuffer(
670 &mut self,
671 spi: &mut HW::Spi,
672 buf: &dyn BufferView<1, 1>,
673 ) -> Result<(), HW::Error> {
674 self.write_framebuffer(spi, buf).await?;
675
676 self.update_display(spi).await
677 }
678
679 async fn write_framebuffer(
680 &mut self,
681 spi: &mut HW::Spi,
682 buf: &dyn BufferView<1, 1>,
683 ) -> Result<(), HW::Error> {
684 let buffer_bounds = buf.window();
685 self.set_window(spi, buffer_bounds).await?;
686 self.set_cursor(spi, buffer_bounds.top_left).await?;
687 self.send(spi, Command::WriteLowRam, buf.data()[0]).await
688 }
689}
690
691impl<HW: EpdHw> DisplaySimple<1, 2, HW::Spi, HW::Error> for Epd2In9V2<HW, StateReady> {
692 async fn display_framebuffer(
693 &mut self,
694 spi: &mut HW::Spi,
695 buf: &dyn BufferView<1, 2>,
696 ) -> Result<(), HW::Error> {
697 self.write_framebuffer(spi, buf).await?;
698
699 self.update_display(spi).await
700 }
701
702 async fn write_framebuffer(
703 &mut self,
704 spi: &mut HW::Spi,
705 buf: &dyn BufferView<1, 2>,
706 ) -> Result<(), HW::Error> {
707 let buffer_bounds = buf.window();
708 self.set_window(spi, buffer_bounds).await?;
709 self.set_cursor(spi, buffer_bounds.top_left).await?;
710 self.send(spi, Command::WriteLowRam, buf.data()[0]).await?;
711 self.send(spi, Command::WriteHighRam, buf.data()[1]).await
712 }
713}
714
715impl<HW: EpdHw> DisplayPartial<1, 1, HW::Spi, HW::Error> for Epd2In9V2<HW, StateReady> {
716 async fn write_base_framebuffer(
717 &mut self,
718 spi: &mut HW::Spi,
719 buf: &dyn BufferView<1, 1>,
720 ) -> Result<(), HW::Error> {
721 let buffer_bounds = buf.window();
722 self.set_window(spi, buffer_bounds).await?;
723 self.set_cursor(spi, buffer_bounds.top_left).await?;
724 self.send(spi, Command::WriteHighRam, buf.data()[0]).await
725 }
726}