use crate::color::Color;
use crate::driver::il0373::Il0373Cmd;
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_t5::Display2in9Gray2;
pub use crate::graphics::display290_mono::Display2in9Mono;
pub const WIDTH: u16 = 296;
pub const HEIGHT: u16 = 128;
#[rustfmt::skip]
const TI_290T5_GRAY4_LUT1: [u8; 42] = [
0x00, 0x0A, 0x00, 0x00, 0x00, 0x01,
0x60, 0x14, 0x14, 0x00, 0x00, 0x01,
0x00, 0x14, 0x00, 0x00, 0x00, 0x01,
0x00, 0x13, 0x0A, 0x01, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
#[rustfmt::skip]
const TI_290T5_GRAY4_LUTWW: [u8; 42] = [
0x40, 0x0A, 0x00, 0x00, 0x00, 0x01,
0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
0x10, 0x14, 0x0A, 0x00, 0x00, 0x01,
0xA0, 0x13, 0x01, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
#[rustfmt::skip]
const TI_290T5_GRAY4_LUTBW: [u8; 42] = [
0x40, 0x0A, 0x00, 0x00, 0x00, 0x01,
0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
0x00, 0x14, 0x0A, 0x00, 0x00, 0x01,
0x99, 0x0C, 0x01, 0x03, 0x04, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
#[rustfmt::skip]
const TI_290T5_GRAY4_LUTWB: [u8; 42] = [
0x40, 0x0A, 0x00, 0x00, 0x00, 0x01,
0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
0x00, 0x14, 0x0A, 0x00, 0x00, 0x01,
0x99, 0x0B, 0x04, 0x04, 0x01, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
#[rustfmt::skip]
const TI_290T5_GRAY4_LUTBB: [u8; 42] = [
0x80, 0x0A, 0x00, 0x00, 0x00, 0x01,
0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
0x20, 0x14, 0x0A, 0x00, 0x00, 0x01,
0x50, 0x13, 0x01, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 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_dtm1(&mut self, buffer: &[u8]) -> Result<(), DisplayError> {
self.interface.cmd_with_data(Il0373Cmd::DTM1, buffer)
}
fn display(&mut self, delay: &mut impl DelayNs) -> Result<(), DisplayError> {
self.interface.cmd(Il0373Cmd::DISPLAY_REFRESH)?;
delay.delay_ms(100);
self.interface.wait_until_idle_active_low(delay);
Ok(())
}
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)
}
}
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 MagTag 2.9\" IL0373 mono display");
self.interface.hard_reset(delay)?;
self.interface
.cmd_with_data(Il0373Cmd::BOOSTER_SOFT_START, &[0x17, 0x17, 0x17])?;
self.interface.cmd(Il0373Cmd::POWER_ON)?;
self.interface.wait_until_idle_active_low(delay);
delay.delay_ms(200);
self.interface
.cmd_with_data(Il0373Cmd::PANEL_SETTING, &[0x1f, 0x0d])?;
self.interface.cmd_with_data(Il0373Cmd::CDI, &[0x97])?;
Ok(())
}
fn sleep(&mut self, delay: &mut impl DelayNs) -> Result<(), DisplayError> {
debug!("powering down MagTag 2.9\" IL0373 mono display");
self.interface.cmd_with_data(Il0373Cmd::CDI, &[0x17])?;
self.interface.cmd(Il0373Cmd::VCM_DC_SETTING)?;
self.interface.cmd(Il0373Cmd::POWER_OFF)?;
delay.delay_ms(1);
Ok(())
}
fn update_bw(&mut self, buffer: &[u8], delay: &mut impl DelayNs) -> Result<(), DisplayError> {
self.write_dtm1(buffer)?;
self.interface.wait_until_idle_active_low(delay);
Ok(())
}
fn update_red(&mut self, _buffer: &[u8], _delay: &mut impl DelayNs) -> Result<(), DisplayError> {
Ok(())
}
fn update(
&mut self,
bw_buffer: &[u8],
_red_buffer: &[u8],
delay: &mut impl DelayNs,
) -> Result<(), DisplayError> {
self.write_dtm1(bw_buffer)?;
self.interface.wait_until_idle_active_low(delay);
Ok(())
}
fn clear_bw_ram(&mut self) -> Result<(), DisplayError> {
let color = Color::White.get_byte_value();
self.interface.cmd(Il0373Cmd::DTM1)?;
self.interface
.data_x_times(color, u32::from(HEIGHT).div_ceil(8) * u32::from(WIDTH))?;
Ok(())
}
fn clear_red_ram(&mut self) -> Result<(), DisplayError> {
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_dtm1(&mut self, buffer: &[u8]) -> Result<(), DisplayError> {
self.interface.cmd_with_data(Il0373Cmd::DTM1, buffer)
}
fn write_dtm2(&mut self, buffer: &[u8]) -> Result<(), DisplayError> {
self.interface.cmd_with_data(Il0373Cmd::DTM2, buffer)
}
fn display(&mut self, delay: &mut impl DelayNs) -> Result<(), DisplayError> {
self.interface.cmd(Il0373Cmd::DISPLAY_REFRESH)?;
delay.delay_ms(100);
self.interface.wait_until_idle_active_low(delay);
Ok(())
}
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)
}
}
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 MagTag 2.9\" IL0373 grayscale display");
self.interface.hard_reset(delay)?;
self.interface
.cmd_with_data(Il0373Cmd::POWER_SETTING, &[0x03, 0x00, 0x2b, 0x2b, 0x13])?;
self.interface
.cmd_with_data(Il0373Cmd::BOOSTER_SOFT_START, &[0x17, 0x17, 0x17])?;
self.interface.cmd(Il0373Cmd::POWER_ON)?;
self.interface.wait_until_idle_active_low(delay);
delay.delay_ms(200);
self.interface
.cmd_with_data(Il0373Cmd::PANEL_SETTING, &[0x3F])?;
self.interface.cmd_with_data(Il0373Cmd::PLL, &[0x3C])?;
self.interface
.cmd_with_data(Il0373Cmd::VCM_DC_SETTING, &[0x12])?;
self.interface.cmd_with_data(Il0373Cmd::CDI, &[0x97])?;
self.interface
.cmd_with_data(Il0373Cmd::LUT1, &TI_290T5_GRAY4_LUT1)?;
self.interface
.cmd_with_data(Il0373Cmd::LUTWW, &TI_290T5_GRAY4_LUTWW)?;
self.interface
.cmd_with_data(Il0373Cmd::LUTBW, &TI_290T5_GRAY4_LUTBW)?;
self.interface
.cmd_with_data(Il0373Cmd::LUTWB, &TI_290T5_GRAY4_LUTWB)?;
self.interface
.cmd_with_data(Il0373Cmd::LUTBB, &TI_290T5_GRAY4_LUTBB)?;
self.interface.cmd_with_data(
Il0373Cmd::RESOLUTION,
&[
(HEIGHT & 0xFF) as u8, ((WIDTH >> 8) & 0xFF) as u8, (HEIGHT & 0xFF) as u8, ],
)?;
Ok(())
}
fn sleep(&mut self, delay: &mut impl DelayNs) -> Result<(), DisplayError> {
debug!("powering down MagTag 2.9\" IL0373 grayscale display");
self.interface.cmd_with_data(Il0373Cmd::CDI, &[0x17])?;
self.interface.cmd(Il0373Cmd::VCM_DC_SETTING)?;
self.interface.cmd(Il0373Cmd::POWER_OFF)?;
delay.delay_ms(1);
Ok(())
}
fn update_bw(&mut self, buffer: &[u8], delay: &mut impl DelayNs) -> Result<(), DisplayError> {
self.write_dtm1(buffer)?;
self.interface.wait_until_idle_active_low(delay);
Ok(())
}
fn update_red(&mut self, buffer: &[u8], delay: &mut impl DelayNs) -> Result<(), DisplayError> {
self.write_dtm2(buffer)?;
self.interface.wait_until_idle_active_low(delay);
Ok(())
}
fn update(
&mut self,
bw_buffer: &[u8],
red_buffer: &[u8],
delay: &mut impl DelayNs,
) -> Result<(), DisplayError> {
self.write_dtm1(bw_buffer)?;
self.write_dtm2(red_buffer)?;
self.interface.wait_until_idle_active_low(delay);
Ok(())
}
fn clear_bw_ram(&mut self) -> Result<(), DisplayError> {
let color = Color::White.get_byte_value();
self.interface.cmd(Il0373Cmd::DTM1)?;
self.interface
.data_x_times(color, u32::from(HEIGHT).div_ceil(8) * u32::from(WIDTH))?;
Ok(())
}
fn clear_red_ram(&mut self) -> Result<(), DisplayError> {
let color = Color::White.inverse().get_byte_value();
self.interface.cmd(Il0373Cmd::DTM2)?;
self.interface
.data_x_times(color, u32::from(HEIGHT).div_ceil(8) * u32::from(WIDTH))?;
Ok(())
}
fn begin(&mut self, delay: &mut impl DelayNs) -> Result<(), DisplayError> {
self.interface.hard_reset(delay)?;
self.sleep(delay)
}
}