use core::time::Duration;
use embedded_graphics::{
prelude::{Point, Size},
primitives::Rectangle,
};
use embedded_hal::{
digital::{OutputPin, PinState},
spi::{Phase, Polarity},
};
use embedded_hal_async::delay::DelayNs;
use crate::{
buffer::{
binary_buffer_length, split_low_and_high, BinaryBuffer, BufferView, Gray2SplitBuffer,
},
hw::{BusyHw, CommandDataSend as _, DcHw, DelayHw, ErrorHw, ResetHw, SpiHw},
log::{debug, debug_assert},
DisplayPartial, DisplaySimple, Displayable, Reset, Sleep, Wake,
};
const LUT_FULL_SLOW_UPDATE: [u8; 153] = [
0x80, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x10, 0x66, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x80, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0,
0x10, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0x8, 0x0, 0x0, 0x0, 0x0, 0x2, 0xA, 0xA, 0x0, 0xA, 0xA, 0x0,
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0x8, 0x0, 0x1, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x44, 0x44, 0x44, 0x44,
0x44, 0x44, 0x0, 0x0, 0x0,
];
const LUT_MAGIC_FULL_SLOW_UPDATE: [u8; 1] = [0x22];
const GATE_VOLTAGE_FULL_SLOW_UPDATE: [u8; 1] = [0x17];
const SOURCE_VOLTAGE_FULL_SLOW_UPDATE: [u8; 3] = [0x41, 0x0, 0x32];
const VCOM_FULL_SLOW_UPDATE: [u8; 1] = [0x36];
const LUT_FULL_UPDATE: [u8; 153] = [
0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x19, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x42, 0x22, 0x22, 0x23, 0x32, 0x00, 0x00, 0x00,
];
const LUT_MAGIC_FULL_UPDATE: [u8; 1] = [0x22];
const GATE_VOLTAGE_FULL_UPDATE: [u8; 1] = [0x17];
const SOURCE_VOLTAGE_FULL_UPDATE: [u8; 3] = [0x41, 0xAE, 0x32];
const VCOM_FULL_UPDATE: [u8; 1] = [0x38];
const LUT_PARTIAL_UPDATE: [u8; 153] = [
0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x80, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x22, 0x22, 0x22, 0x22, 0x22,
0x22, 0x0, 0x0, 0x0,
];
const LUT_MAGIC_PARTIAL_UPDATE: [u8; 1] = [0x22];
const GATE_VOLTAGE_PARTIAL_UPDATE: [u8; 1] = [0x17];
const SOURCE_VOLTAGE_PARTIAL_UPDATE: [u8; 3] = [0x41, 0xB0, 0x32];
const VCOM_PARTIAL_UPDATE: [u8; 1] = [0x36];
const LUT_GRAY2: [u8; 153] = [
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x60, 0x10, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x60, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x2A, 0x60, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05,
0x14, 0x00, 0x00, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x05, 0x14, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x22, 0x22, 0x22, 0x23, 0x32, 0x00, 0x00, 0x00,
];
const LUT_MAGIC_GRAY2: [u8; 1] = [0x22];
const GATE_VOLTAGE_GRAY2: [u8; 1] = [0x17];
const SOURCE_VOLTAGE_GRAY2: [u8; 3] = [0x41, 0xAE, 0x32];
const VCOM_GRAY2: [u8; 1] = [0x28];
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RefreshMode {
Full,
FullSlow,
Partial,
Gray2,
}
impl RefreshMode {
pub fn border_waveform(&self) -> Option<&[u8]> {
match self {
RefreshMode::Full => Some(&[0x05]),
RefreshMode::FullSlow => None,
RefreshMode::Partial => Some(&[0x80]),
RefreshMode::Gray2 => Some(&[0x04]),
}
}
pub fn lut(&self) -> &[u8] {
match self {
RefreshMode::Full => &LUT_FULL_UPDATE,
RefreshMode::FullSlow => &LUT_FULL_SLOW_UPDATE,
RefreshMode::Partial => &LUT_PARTIAL_UPDATE,
RefreshMode::Gray2 => &LUT_GRAY2,
}
}
pub fn lut_magic(&self) -> &[u8] {
match self {
RefreshMode::Full => &LUT_MAGIC_FULL_UPDATE,
RefreshMode::FullSlow => &LUT_MAGIC_FULL_SLOW_UPDATE,
RefreshMode::Partial => &LUT_MAGIC_PARTIAL_UPDATE,
RefreshMode::Gray2 => &LUT_MAGIC_GRAY2,
}
}
pub fn gate_voltage(&self) -> &[u8] {
match self {
RefreshMode::Full => &GATE_VOLTAGE_FULL_UPDATE,
RefreshMode::FullSlow => &GATE_VOLTAGE_FULL_SLOW_UPDATE,
RefreshMode::Partial => &GATE_VOLTAGE_PARTIAL_UPDATE,
RefreshMode::Gray2 => &GATE_VOLTAGE_GRAY2,
}
}
pub fn source_voltage(&self) -> &[u8] {
match self {
RefreshMode::Full => &SOURCE_VOLTAGE_FULL_UPDATE,
RefreshMode::FullSlow => &SOURCE_VOLTAGE_FULL_SLOW_UPDATE,
RefreshMode::Partial => &SOURCE_VOLTAGE_PARTIAL_UPDATE,
RefreshMode::Gray2 => &SOURCE_VOLTAGE_GRAY2,
}
}
pub fn vcom(&self) -> &[u8] {
match self {
RefreshMode::Full => &VCOM_FULL_UPDATE,
RefreshMode::FullSlow => &VCOM_FULL_SLOW_UPDATE,
RefreshMode::Partial => &VCOM_PARTIAL_UPDATE,
RefreshMode::Gray2 => &VCOM_GRAY2,
}
}
pub fn display_update_control_2(&self) -> &[u8] {
match self {
RefreshMode::Partial => &[0xCF],
_ => &[0xC7],
}
}
pub fn is_black_and_white(&self) -> bool {
*self != RefreshMode::Gray2
}
}
pub const DISPLAY_HEIGHT: u16 = 296;
pub const DISPLAY_WIDTH: u16 = 128;
pub const RECOMMENDED_MIN_FULL_REFRESH_INTERVAL: Duration = Duration::from_secs(180);
pub const RECOMMENDED_MAX_FULL_REFRESH_INTERVAL: Duration = Duration::from_secs(24 * 60 * 60);
pub const RECOMMENDED_SPI_HZ: u32 = 4_000_000; pub const RECOMMENDED_SPI_PHASE: Phase = Phase::CaptureOnFirstTransition;
pub const RECOMMENDED_SPI_POLARITY: Polarity = Polarity::IdleLow;
pub const DEFAULT_BUSY_WHEN: PinState = PinState::High;
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Command {
DriverOutputControl = 0x01,
SetGateDrivingVoltage = 0x03,
SetSourceDrivingVoltage = 0x04,
DeepSleepMode = 0x10,
DataEntryModeSetting = 0x11,
SwReset = 0x12,
MasterActivation = 0x20,
DisplayUpdateControl1 = 0x21,
DisplayUpdateControl2 = 0x22,
WriteLowRam = 0x24,
WriteHighRam = 0x26,
ReadVcom = 0x28,
SetVcomReadDuration = 0x29,
ProgramVcomOtp = 0x2A,
WriteVcom = 0x2C,
ReadOtpRegisters = 0x2D,
ReadUserId = 0x2E,
ProgramWsOtp = 0x30,
LoadWsOtp = 0x31,
WriteLut = 0x32,
ProgramOtpSelection = 0x36,
WriteRegisterForUserId = 0x38,
SetOtpProgramMode = 0x39,
SetBorderWaveform = 0x3C,
SetLutMagic = 0x3F,
SetRamXStartEnd = 0x44,
SetRamYStartEnd = 0x45,
SetRamX = 0x4E,
SetRamY = 0x4F,
}
impl Command {
fn register(&self) -> u8 {
*self as u8
}
}
pub const BINARY_BUFFER_LENGTH: usize =
binary_buffer_length(Size::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32));
pub type Epd2In9BinaryBuffer = BinaryBuffer<BINARY_BUFFER_LENGTH>;
pub fn new_binary_buffer() -> Epd2In9BinaryBuffer {
Epd2In9BinaryBuffer::new(Size::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32))
}
pub type Epd2In9Gray2Buffer = Gray2SplitBuffer<BINARY_BUFFER_LENGTH>;
pub fn new_gray2_buffer() -> Epd2In9Gray2Buffer {
Epd2In9Gray2Buffer::new(Size::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32))
}
const DRIVER_OUTPUT_INIT_DATA: [u8; 3] = [0x27, 0x01, 0x00];
pub struct Epd2In9V2<HW, STATE> {
hw: HW,
state: STATE,
}
trait StateInternal {}
#[allow(private_bounds)]
pub trait State: StateInternal {}
pub trait StateAwake: State {}
macro_rules! impl_base_state {
($state:ident) => {
impl StateInternal for $state {}
impl State for $state {}
};
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct StateUninitialized();
impl_base_state!(StateUninitialized);
impl StateAwake for StateUninitialized {}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct StateReady {
mode: RefreshMode,
}
impl_base_state!(StateReady);
impl StateAwake for StateReady {}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct StateAsleep<W: StateAwake> {
wake_state: W,
}
impl<W: StateAwake> StateInternal for StateAsleep<W> {}
impl<W: StateAwake> State for StateAsleep<W> {}
impl<HW> Epd2In9V2<HW, StateUninitialized>
where
HW: BusyHw + DcHw + ResetHw + DelayHw + SpiHw + ErrorHw,
HW::Error: From<<HW::Busy as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Dc as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Reset as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Spi as embedded_hal_async::spi::ErrorType>::Error>,
{
pub fn new(hw: HW) -> Self {
Epd2In9V2 {
hw,
state: StateUninitialized(),
}
}
}
pub enum Bypass {
Normal = 0,
AllZero = 0b100,
Inverted = 0b1000,
}
impl<HW, STATE> Epd2In9V2<HW, STATE>
where
HW: BusyHw + DcHw + ResetHw + DelayHw + SpiHw + ErrorHw,
HW::Error: From<<HW::Busy as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Dc as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Reset as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Spi as embedded_hal_async::spi::ErrorType>::Error>,
STATE: StateAwake,
{
pub async fn init(
mut self,
spi: &mut HW::Spi,
mode: RefreshMode,
) -> Result<Epd2In9V2<HW, StateReady>, HW::Error> {
debug!("Initialising display");
self = self.reset().await?;
let mut epd = Epd2In9V2 {
hw: self.hw,
state: StateReady { mode },
};
epd.set_refresh_mode_impl(spi, mode).await?;
Ok(epd)
}
}
impl<HW, STATE> Epd2In9V2<HW, STATE>
where
HW: BusyHw + DcHw + SpiHw + ErrorHw,
HW::Error: From<<HW::Busy as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Dc as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Spi as embedded_hal_async::spi::ErrorType>::Error>,
STATE: StateAwake,
{
pub async fn send(
&mut self,
spi: &mut HW::Spi,
command: Command,
data: &[u8],
) -> Result<(), HW::Error> {
self.hw.send(spi, command.register(), data).await
}
}
impl<HW> Epd2In9V2<HW, StateReady>
where
HW: BusyHw + DcHw + SpiHw + ErrorHw,
HW::Error: From<<HW::Busy as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Dc as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Spi as embedded_hal_async::spi::ErrorType>::Error>,
{
pub async fn set_refresh_mode(
&mut self,
spi: &mut HW::Spi,
mode: RefreshMode,
) -> Result<(), HW::Error> {
if self.state.mode == mode {
Ok(())
} else {
debug!("Changing refresh mode to {:?}", mode);
self.set_refresh_mode_impl(spi, mode).await?;
Ok(())
}
}
async fn set_refresh_mode_impl(
&mut self,
spi: &mut HW::Spi,
mode: RefreshMode,
) -> Result<(), HW::Error> {
self.send(spi, Command::SwReset, &[]).await?;
self.send(spi, Command::DriverOutputControl, &DRIVER_OUTPUT_INIT_DATA)
.await?;
self.send(spi, Command::DataEntryModeSetting, &[0b11])
.await?;
let black_and_white_byte = if mode.is_black_and_white() {
0x80
} else {
0x00
};
self.send(
spi,
Command::DisplayUpdateControl1,
&[0x00, black_and_white_byte],
)
.await?;
if let Some(border_waveform) = mode.border_waveform() {
self.send(spi, Command::SetBorderWaveform, border_waveform)
.await?;
}
self.send(spi, Command::WriteLut, mode.lut()).await?;
self.send(spi, Command::SetLutMagic, mode.lut_magic())
.await?;
self.send(spi, Command::SetGateDrivingVoltage, mode.gate_voltage())
.await?;
self.send(spi, Command::SetSourceDrivingVoltage, mode.source_voltage())
.await?;
self.send(spi, Command::WriteVcom, mode.vcom()).await?;
if mode == RefreshMode::Partial {
self.hw
.send(
spi,
0x37,
&[0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00],
)
.await?;
self.send(spi, Command::DisplayUpdateControl2, &[0xC3])
.await?;
self.send(spi, Command::MasterActivation, &[]).await?;
}
self.state.mode = mode;
Ok(())
}
pub async fn set_ram_bypass(
&mut self,
spi: &mut HW::Spi,
low_bypass: Bypass,
high_bypass: Bypass,
) -> Result<(), HW::Error> {
let black_and_white_byte = if self.state.mode.is_black_and_white() {
0x80
} else {
0x00
};
self.send(
spi,
Command::DisplayUpdateControl1,
&[
((high_bypass as u8) << 4) | (low_bypass as u8),
black_and_white_byte,
],
)
.await
}
pub async fn set_window(
&mut self,
spi: &mut HW::Spi,
shape: Rectangle,
) -> Result<(), HW::Error> {
let (x_start, x_end) = if self.state.mode == RefreshMode::Gray2 {
let x_start = shape.top_left.x + 8;
let x_end = shape.top_left.x + shape.size.width as i32 + 7;
(x_start, x_end)
} else {
let x_start = shape.top_left.x;
(x_start, x_start + shape.size.width as i32 - 1)
};
debug_assert!(
x_start % 8 == 0 && x_end % 8 == 7,
"window's top_left.x and width must be 8-bit aligned"
);
let x_start_byte = ((x_start >> 3) & 0xFF) as u8;
let x_end_byte = ((x_end >> 3) & 0xFF) as u8;
self.send(spi, Command::SetRamXStartEnd, &[x_start_byte, x_end_byte])
.await?;
let (y_start_low, y_start_high) = split_low_and_high(shape.top_left.y as u16);
let (y_end_low, y_end_high) =
split_low_and_high((shape.top_left.y + shape.size.height as i32 - 1) as u16);
self.send(
spi,
Command::SetRamYStartEnd,
&[y_start_low, y_start_high, y_end_low, y_end_high],
)
.await?;
Ok(())
}
pub async fn set_cursor(
&mut self,
spi: &mut HW::Spi,
position: Point,
) -> Result<(), HW::Error> {
debug_assert_eq!(position.x % 8, 0, "position.x must be 8-bit aligned");
let x_pos = if self.state.mode == RefreshMode::Gray2 {
position.x + 8
} else {
position.x
};
self.send(spi, Command::SetRamX, &[(x_pos >> 3) as u8])
.await?;
let (y_low, y_high) = split_low_and_high(position.y as u16);
self.send(spi, Command::SetRamY, &[y_low, y_high]).await?;
Ok(())
}
}
async fn reset_impl<HW>(hw: &mut HW) -> Result<(), HW::Error>
where
HW: ResetHw + DelayHw + ErrorHw,
HW::Error: From<<HW::Reset as embedded_hal::digital::ErrorType>::Error>,
{
debug!("Resetting EPD");
hw.reset().set_low()?;
hw.delay().delay_ms(10).await;
hw.reset().set_high()?;
hw.delay().delay_ms(10).await;
Ok(())
}
impl<HW, STATE: StateAwake> Reset<HW::Error> for Epd2In9V2<HW, STATE>
where
HW: ResetHw + DelayHw + ErrorHw,
HW::Error: From<<HW::Reset as embedded_hal::digital::ErrorType>::Error>,
{
type DisplayOut = Epd2In9V2<HW, STATE>;
async fn reset(mut self) -> Result<Self::DisplayOut, HW::Error> {
reset_impl(&mut self.hw).await?;
Ok(self)
}
}
impl<HW, W: StateAwake> Reset<HW::Error> for Epd2In9V2<HW, StateAsleep<W>>
where
HW: ResetHw + DelayHw + ErrorHw,
HW::Error: From<<HW::Reset as embedded_hal::digital::ErrorType>::Error>,
{
type DisplayOut = Epd2In9V2<HW, W>;
async fn reset(mut self) -> Result<Self::DisplayOut, HW::Error> {
reset_impl(&mut self.hw).await?;
Ok(Epd2In9V2 {
hw: self.hw,
state: self.state.wake_state,
})
}
}
impl<HW, STATE: StateAwake> Sleep<HW::Spi, HW::Error> for Epd2In9V2<HW, STATE>
where
HW: BusyHw + DcHw + SpiHw + ErrorHw,
HW::Error: From<<HW::Busy as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Dc as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Spi as embedded_hal_async::spi::ErrorType>::Error>,
{
type DisplayOut = Epd2In9V2<HW, StateAsleep<STATE>>;
async fn sleep(mut self, spi: &mut HW::Spi) -> Result<Self::DisplayOut, HW::Error> {
debug!("Sleeping EPD");
self.send(spi, Command::DeepSleepMode, &[0x01]).await?;
Ok(Epd2In9V2 {
hw: self.hw,
state: StateAsleep {
wake_state: self.state,
},
})
}
}
impl<HW, W: StateAwake> Wake<HW::Spi, HW::Error> for Epd2In9V2<HW, StateAsleep<W>>
where
HW: BusyHw + DcHw + ResetHw + DelayHw + SpiHw + ErrorHw,
HW::Error: From<<HW::Busy as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Dc as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Reset as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Spi as embedded_hal_async::spi::ErrorType>::Error>,
{
type DisplayOut = Epd2In9V2<HW, W>;
async fn wake(self, _spi: &mut HW::Spi) -> Result<Self::DisplayOut, HW::Error> {
debug!("Waking EPD");
self.reset().await
}
}
impl<HW> Displayable<HW::Spi, HW::Error> for Epd2In9V2<HW, StateReady>
where
HW: BusyHw + DcHw + SpiHw + ErrorHw,
HW::Error: From<<HW::Busy as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Dc as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Spi as embedded_hal_async::spi::ErrorType>::Error>,
{
async fn update_display(&mut self, spi: &mut HW::Spi) -> Result<(), HW::Error> {
debug!("Updating display");
let mode = self.state.mode;
let update_control = mode.display_update_control_2();
self.send(spi, Command::DisplayUpdateControl2, update_control)
.await?;
self.send(spi, Command::MasterActivation, &[]).await?;
Ok(())
}
}
impl<HW> DisplaySimple<1, 1, HW::Spi, HW::Error> for Epd2In9V2<HW, StateReady>
where
HW: BusyHw + DcHw + SpiHw + ErrorHw,
HW::Error: From<<HW::Busy as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Dc as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Spi as embedded_hal_async::spi::ErrorType>::Error>,
{
async fn display_framebuffer(
&mut self,
spi: &mut HW::Spi,
buf: &dyn BufferView<1, 1>,
) -> Result<(), HW::Error> {
self.write_framebuffer(spi, buf).await?;
self.update_display(spi).await
}
async fn write_framebuffer(
&mut self,
spi: &mut HW::Spi,
buf: &dyn BufferView<1, 1>,
) -> Result<(), HW::Error> {
let buffer_bounds = buf.window();
self.set_window(spi, buffer_bounds).await?;
self.set_cursor(spi, buffer_bounds.top_left).await?;
self.send(spi, Command::WriteLowRam, buf.data()[0]).await
}
}
impl<HW> DisplaySimple<1, 2, HW::Spi, HW::Error> for Epd2In9V2<HW, StateReady>
where
HW: BusyHw + DcHw + SpiHw + ErrorHw,
HW::Error: From<<HW::Busy as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Dc as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Spi as embedded_hal_async::spi::ErrorType>::Error>,
{
async fn display_framebuffer(
&mut self,
spi: &mut HW::Spi,
buf: &dyn BufferView<1, 2>,
) -> Result<(), HW::Error> {
self.write_framebuffer(spi, buf).await?;
self.update_display(spi).await
}
async fn write_framebuffer(
&mut self,
spi: &mut HW::Spi,
buf: &dyn BufferView<1, 2>,
) -> Result<(), HW::Error> {
let buffer_bounds = buf.window();
self.set_window(spi, buffer_bounds).await?;
self.set_cursor(spi, buffer_bounds.top_left).await?;
self.send(spi, Command::WriteLowRam, buf.data()[0]).await?;
self.send(spi, Command::WriteHighRam, buf.data()[1]).await
}
}
impl<HW> DisplayPartial<1, 1, HW::Spi, HW::Error> for Epd2In9V2<HW, StateReady>
where
HW: BusyHw + DcHw + SpiHw + ErrorHw,
HW::Error: From<<HW::Busy as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Dc as embedded_hal::digital::ErrorType>::Error>
+ From<<HW::Spi as embedded_hal_async::spi::ErrorType>::Error>,
{
async fn write_base_framebuffer(
&mut self,
spi: &mut HW::Spi,
buf: &dyn BufferView<1, 1>,
) -> Result<(), HW::Error> {
let buffer_bounds = buf.window();
self.set_window(spi, buffer_bounds).await?;
self.set_cursor(spi, buffer_bounds.top_left).await?;
self.send(spi, Command::WriteHighRam, buf.data()[0]).await
}
}