use crate::color::Color;
use crate::driver::ssd1680::{Cmd, Flag};
use crate::driver::EpdDriver;
use crate::interface::SpiDisplayInterface;
use display_interface::DisplayError;
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::{InputPin, OutputPin};
use embedded_hal::spi::SpiDevice;
use log::debug;
pub use crate::graphics::display290_gray4_mfgn::Display2in9Gray2;
pub use crate::graphics::display290_mono::Display2in9Mono;
pub const WIDTH: u16 = 128;
pub const HEIGHT: u16 = 296;
#[rustfmt::skip]
pub const TI_290_MONOFULL_LUT_CODE: [u8; 153] = [
0x80, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x80, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x0A, 0x00, 0x0A, 0x0A, 0x00, 0x01, 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, 0x14, 0x08, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00 ];
#[rustfmt::skip]
pub const TI_290MFGN_GRAY2_LUT_CODE: [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, ];
pub struct ThinkInk2in9Mono<SPI, BSY, DC, RST>
where
SPI: SpiDevice,
BSY: InputPin,
DC: OutputPin,
RST: OutputPin,
{
interface: SpiDisplayInterface<SPI, BSY, DC, RST>,
}
impl<SPI, BSY, DC, RST> ThinkInk2in9Mono<SPI, BSY, DC, RST>
where
SPI: SpiDevice,
BSY: InputPin,
DC: OutputPin,
RST: OutputPin,
{
pub fn new(spi: SPI, busy: BSY, dc: DC, rst: RST) -> Result<Self, DisplayError> {
let interface = SpiDisplayInterface::new(spi, busy, dc, rst);
Ok(Self { interface })
}
fn write_bw_ram(&mut self, buffer: &[u8]) -> Result<(), DisplayError> {
self.set_ram_counter(0, 0)?;
self.interface.cmd_with_data(Cmd::WRITE_BW_DATA, buffer)
}
fn write_red_ram(&mut self, buffer: &[u8]) -> Result<(), DisplayError> {
self.set_ram_counter(0, 0)?;
self.interface.cmd_with_data(Cmd::WRITE_RED_DATA, buffer)
}
fn display(&mut self, delay: &mut impl DelayNs) -> Result<(), DisplayError> {
self.interface
.cmd_with_data(Cmd::DISPLAY_UPDATE_CTRL2, &[Flag::DISPLAY_MODE_1])?;
self.interface.cmd(Cmd::MASTER_ACTIVATE)?;
self.interface.wait_until_idle(delay);
Ok(())
}
pub fn clear_display(&mut self, delay: &mut impl DelayNs) -> Result<(), DisplayError> {
self.clear_bw_ram()?;
self.clear_red_ram()?;
self.display(delay)?;
delay.delay_ms(100);
self.display(delay)
}
pub fn update_and_display(
&mut self,
bw_buffer: &[u8],
delay: &mut impl DelayNs,
) -> Result<(), DisplayError> {
self.init(delay)?;
self.update_bw(bw_buffer, delay)?;
self.display(delay)?;
self.sleep(delay)
}
pub fn update_gray2_and_display(
&mut self,
bw_buffer: &[u8],
red_buffer: &[u8],
delay: &mut impl DelayNs,
) -> Result<(), DisplayError> {
self.init(delay)?;
self.update_bw(bw_buffer, delay)?;
self.update_red(red_buffer, delay)?;
self.display(delay)?;
self.sleep(delay)
}
fn set_ram_counter(&mut self, x: u32, y: u32) -> Result<(), DisplayError> {
self.interface
.cmd_with_data(Cmd::SET_RAMX_COUNTER, &[(x >> 3) as u8])?;
self.interface.cmd_with_data(
Cmd::SET_RAMY_COUNTER,
&[(y & 0xFF) as u8, ((y >> 8) & 0x01) as u8],
)?;
Ok(())
}
}
impl<SPI, BSY, DC, RST> EpdDriver for ThinkInk2in9Mono<SPI, BSY, DC, RST>
where
SPI: SpiDevice,
BSY: InputPin,
DC: OutputPin,
RST: OutputPin,
{
fn init(&mut self, delay: &mut impl DelayNs) -> Result<(), DisplayError> {
debug!("powering up ThinkInk 2.9in mono display");
self.interface.hard_reset(delay)?;
self.interface.cmd(Cmd::SW_RESET)?;
delay.delay_ms(10);
self.interface
.cmd_with_data(Cmd::DRIVER_OUTPUT_CTRL, &[0x27, 0x01, 0x00])?;
self.interface
.cmd_with_data(Cmd::DATA_ENTRY_MODE, &[Flag::DATA_ENTRY_INCRY_INCRX])?;
self.interface
.cmd_with_data(Cmd::SET_RAMXPOS, &[0x00, 0x0F])?;
self.interface
.cmd_with_data(Cmd::SET_RAMYPOS, &[0x00, 0x00, 0x27, 0x01])?;
self.interface.cmd_with_data(
Cmd::BORDER_WAVEFORM_CTRL,
&[Flag::BORDER_WAVEFORM_FOLLOW_LUT | Flag::BORDER_WAVEFORM_LUT1],
)?;
self.interface
.cmd_with_data(Cmd::TEMP_CONTROL, &[Flag::INTERNAL_TEMP_SENSOR])?;
self.interface
.cmd_with_data(Cmd::DISPLAY_UPDATE_CTRL1, &[0x00, 0x80])?;
self.interface
.cmd_with_data(Cmd::END_OPTION, &[Flag::END_OPTION_NORMAL])?;
self.interface
.cmd_with_data(Cmd::GATE_VOLTAGE_CTRL, &[0x17])?;
self.interface
.cmd_with_data(Cmd::SOURCE_VOLTAGE_CTRL, &[0x41, 0x00, 0x32])?;
self.interface.cmd_with_data(Cmd::WRITE_VCOM_REG, &[0x36])?;
self.interface
.cmd_with_data(Cmd::WRITE_LUT_REG, &TI_290_MONOFULL_LUT_CODE)?;
self.interface.wait_until_idle(delay);
Ok(())
}
fn sleep(&mut self, delay: &mut impl DelayNs) -> Result<(), DisplayError> {
debug!("powering down ThinkInk 2.9\" display");
self.interface.cmd_with_data(Cmd::DEEP_SLEEP, &[0x01])?;
delay.delay_ms(1);
Ok(())
}
fn update_bw(&mut self, buffer: &[u8], delay: &mut impl DelayNs) -> Result<(), DisplayError> {
self.write_bw_ram(buffer)?;
self.interface.wait_until_idle(delay);
Ok(())
}
fn update_red(&mut self, buffer: &[u8], delay: &mut impl DelayNs) -> Result<(), DisplayError> {
self.write_red_ram(buffer)?;
self.interface.wait_until_idle(delay);
Ok(())
}
fn update(
&mut self,
low_buffer: &[u8],
high_buffer: &[u8],
delay: &mut impl DelayNs,
) -> Result<(), DisplayError> {
self.write_bw_ram(low_buffer)?;
self.write_red_ram(high_buffer)?;
self.interface.wait_until_idle(delay);
Ok(())
}
fn clear_bw_ram(&mut self) -> Result<(), DisplayError> {
let color = Color::White.get_byte_value();
self.interface.cmd(Cmd::WRITE_BW_DATA)?;
self.interface
.data_x_times(color, u32::from(WIDTH).div_ceil(8) * u32::from(HEIGHT))?;
Ok(())
}
fn clear_red_ram(&mut self) -> Result<(), DisplayError> {
let color = Color::White.inverse().get_byte_value();
self.interface.cmd(Cmd::WRITE_RED_DATA)?;
self.interface
.data_x_times(color, u32::from(WIDTH).div_ceil(8) * u32::from(HEIGHT))?;
Ok(())
}
fn begin(&mut self, delay: &mut impl DelayNs) -> Result<(), DisplayError> {
self.interface.hard_reset(delay)?;
self.sleep(delay)
}
}
pub struct ThinkInk2in9Gray2<SPI, BSY, DC, RST>
where
SPI: SpiDevice,
BSY: InputPin,
DC: OutputPin,
RST: OutputPin,
{
interface: SpiDisplayInterface<SPI, BSY, DC, RST>,
}
impl<SPI, BSY, DC, RST> ThinkInk2in9Gray2<SPI, BSY, DC, RST>
where
SPI: SpiDevice,
BSY: InputPin,
DC: OutputPin,
RST: OutputPin,
{
pub fn new(spi: SPI, busy: BSY, dc: DC, rst: RST) -> Result<Self, DisplayError> {
let interface = SpiDisplayInterface::new(spi, busy, dc, rst);
Ok(Self { interface })
}
fn write_bw_ram(&mut self, buffer: &[u8]) -> Result<(), DisplayError> {
self.set_ram_counter(0, 0)?;
self.interface.cmd_with_data(Cmd::WRITE_BW_DATA, buffer)
}
fn write_red_ram(&mut self, buffer: &[u8]) -> Result<(), DisplayError> {
self.set_ram_counter(0, 0)?;
self.interface.cmd_with_data(Cmd::WRITE_RED_DATA, buffer)
}
fn display(&mut self, delay: &mut impl DelayNs) -> Result<(), DisplayError> {
self.interface
.cmd_with_data(Cmd::DISPLAY_UPDATE_CTRL2, &[Flag::DISPLAY_MODE_1])?;
self.interface.cmd(Cmd::MASTER_ACTIVATE)?;
self.interface.wait_until_idle(delay);
Ok(())
}
pub fn clear_display(&mut self, delay: &mut impl DelayNs) -> Result<(), DisplayError> {
self.clear_bw_ram()?;
self.clear_red_ram()?;
self.display(delay)?;
delay.delay_ms(100);
self.display(delay)
}
pub fn update_and_display(
&mut self,
bw_buffer: &[u8],
delay: &mut impl DelayNs,
) -> Result<(), DisplayError> {
self.init(delay)?;
self.update_bw(bw_buffer, delay)?;
self.display(delay)?;
self.sleep(delay)
}
pub fn update_gray2_and_display(
&mut self,
high_buffer: &[u8],
low_buffer: &[u8],
delay: &mut impl DelayNs,
) -> Result<(), DisplayError> {
self.init(delay)?;
self.update_bw(high_buffer, delay)?;
self.update_red(low_buffer, delay)?;
self.display(delay)?;
self.sleep(delay)
}
fn set_ram_counter(&mut self, x: u32, y: u32) -> Result<(), DisplayError> {
self.interface
.cmd_with_data(Cmd::SET_RAMX_COUNTER, &[(x >> 3) as u8])?;
self.interface.cmd_with_data(
Cmd::SET_RAMY_COUNTER,
&[(y & 0xFF) as u8, ((y >> 8) & 0x01) as u8],
)?;
Ok(())
}
}
impl<SPI, BSY, DC, RST> EpdDriver for ThinkInk2in9Gray2<SPI, BSY, DC, RST>
where
SPI: SpiDevice,
BSY: InputPin,
DC: OutputPin,
RST: OutputPin,
{
fn init(&mut self, delay: &mut impl DelayNs) -> Result<(), DisplayError> {
debug!("powering up ThinkInk 2.9in grayscale display");
self.interface.hard_reset(delay)?;
self.interface.cmd(Cmd::SW_RESET)?;
delay.delay_ms(10);
self.interface
.cmd_with_data(Cmd::DRIVER_OUTPUT_CTRL, &[0x27, 0x01, 0x00])?;
self.interface
.cmd_with_data(Cmd::DATA_ENTRY_MODE, &[Flag::DATA_ENTRY_INCRY_INCRX])?;
self.interface
.cmd_with_data(Cmd::SET_RAMXPOS, &[0x00, 0x0F])?;
self.interface
.cmd_with_data(Cmd::SET_RAMYPOS, &[0x00, 0x00, 0x27, 0x01])?;
self.interface.cmd_with_data(
Cmd::BORDER_WAVEFORM_CTRL,
&[Flag::BORDER_WAVEFORM_FOLLOW_LUT | Flag::BORDER_WAVEFORM_LUT1],
)?;
self.interface
.cmd_with_data(Cmd::TEMP_CONTROL, &[Flag::INTERNAL_TEMP_SENSOR])?;
self.interface
.cmd_with_data(Cmd::DISPLAY_UPDATE_CTRL1, &[0x00, 0x80])?;
self.interface
.cmd_with_data(Cmd::END_OPTION, &[Flag::END_OPTION_NORMAL])?;
self.interface
.cmd_with_data(Cmd::GATE_VOLTAGE_CTRL, &[0x17])?;
self.interface
.cmd_with_data(Cmd::SOURCE_VOLTAGE_CTRL, &[0x41, 0x00, 0x32])?;
self.interface.cmd_with_data(Cmd::WRITE_VCOM_REG, &[0x36])?;
self.interface
.cmd_with_data(Cmd::WRITE_LUT_REG, &TI_290MFGN_GRAY2_LUT_CODE)?;
self.interface.wait_until_idle(delay);
Ok(())
}
fn sleep(&mut self, delay: &mut impl DelayNs) -> Result<(), DisplayError> {
debug!("powering down ThinkInk 2.9\" grayscale display");
self.interface.cmd_with_data(Cmd::DEEP_SLEEP, &[0x01])?;
delay.delay_ms(1);
Ok(())
}
fn update_bw(&mut self, buffer: &[u8], delay: &mut impl DelayNs) -> Result<(), DisplayError> {
self.write_bw_ram(buffer)?;
self.interface.wait_until_idle(delay);
Ok(())
}
fn update_red(&mut self, buffer: &[u8], delay: &mut impl DelayNs) -> Result<(), DisplayError> {
self.write_red_ram(buffer)?;
self.interface.wait_until_idle(delay);
Ok(())
}
fn update(
&mut self,
bw_buffer: &[u8],
red_buffer: &[u8],
delay: &mut impl DelayNs,
) -> Result<(), DisplayError> {
self.write_bw_ram(bw_buffer)?;
self.write_red_ram(red_buffer)?;
self.interface.wait_until_idle(delay);
Ok(())
}
fn clear_bw_ram(&mut self) -> Result<(), DisplayError> {
let color = Color::White.get_byte_value();
self.interface.cmd(Cmd::WRITE_BW_DATA)?;
self.interface
.data_x_times(color, u32::from(WIDTH).div_ceil(8) * u32::from(HEIGHT))?;
Ok(())
}
fn clear_red_ram(&mut self) -> Result<(), DisplayError> {
let color = Color::White.inverse().get_byte_value();
self.interface.cmd(Cmd::WRITE_RED_DATA)?;
self.interface
.data_x_times(color, u32::from(WIDTH).div_ceil(8) * u32::from(HEIGHT))?;
Ok(())
}
fn begin(&mut self, delay: &mut impl DelayNs) -> Result<(), DisplayError> {
self.interface.hard_reset(delay)?;
self.sleep(delay)
}
}