use crate::interface::{DisplayInterface, Interface4Pin};
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum IncrementAxis {
Horizontal = 0b0,
Vertical = 0b1,
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum DataEntryMode {
DecrementXDecrementY = 0b00,
IncrementXDecrementY = 0b01,
DecrementXIncrementY = 0b10,
IncrementXIncrementY = 0b11,
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum TemperatureSensor {
Internal = 0x80,
External = 48,
}
#[derive(Clone, Copy)]
pub enum RamOption {
Normal = 0b0000,
Bypass = 0b0100,
Invert = 0b1000,
}
#[derive(Clone, Copy)]
pub enum DeepSleepMode {
Normal,
PreserveRAM,
DiscardRAM,
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum BoosterInrush {
Level1 = 0x40,
Level2 = 0x80,
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum WaveformVDBOption {
Transition = 0b00,
Fixed = 0b01,
VCOM = 0b10,
HiZ = 0b11,
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum VDBFixedLevelSetting {
VSS = 0b00,
VSH1 = 0b01,
VSL = 0b10,
VSH2 = 0b11,
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum VDBGSTransitionSetting {
LUT0 = 0b00,
LUT1 = 0b01,
LUT2 = 0b10,
LUT3 = 0b11,
}
pub trait DisplayCommands<SPI>
where
SPI: embedded_hal::spi::SpiDevice,
{
fn set_driver_output_control(
&mut self,
max_gate_lines: u16,
scanning_sequence_and_direction: u8,
) -> Result<(), SPI::Error>;
fn set_driver_output_control_from_width(&mut self, width: u16) -> Result<(), SPI::Error>;
fn set_data_entry_mode(
&mut self,
data_entry_mode: DataEntryMode,
increment_axis: IncrementAxis,
) -> Result<(), SPI::Error>;
fn write_ram_black_and_white(&mut self, data: &[u8]) -> Result<(), SPI::Error>;
fn write_ram_red(&mut self, data: &[u8]) -> Result<(), SPI::Error>;
fn auto_write_ram_red_regular_pattern(&mut self, value: u8) -> Result<(), SPI::Error>;
fn auto_write_ram_black_and_white_regular_pattern(
&mut self,
value: u8,
) -> Result<(), SPI::Error>;
fn set_ram_x_count(&mut self, offset: u16) -> Result<(), SPI::Error>;
fn set_ram_y_count(&mut self, offset: u16) -> Result<(), SPI::Error>;
fn refresh_display(&mut self) -> Result<(), SPI::Error>;
fn set_ram_x_address(&mut self, start: u16, end: u16) -> Result<(), SPI::Error>;
fn set_ram_y_address(&mut self, start: u16, end: u16) -> Result<(), SPI::Error>;
fn set_ram_address_based_on_size(&mut self, width: u16, height: u16) -> Result<(), SPI::Error>;
fn nop(&mut self) -> Result<(), SPI::Error>;
fn set_gate_driving_voltage(&mut self, voltage: f32) -> Result<(), SPI::Error>;
fn set_source_driving_voltage(
&mut self,
vsh1_voltage: f32,
vsh2_voltage: f32,
vsl_voltage: f32,
) -> Result<(), SPI::Error>;
fn update_display_option1(
&mut self,
black_and_white_option: RamOption,
red_option: RamOption,
) -> Result<(), SPI::Error>;
fn update_display_option2(&mut self, option: u8) -> Result<(), SPI::Error>;
fn reset_hardware<D: embedded_hal::delay::DelayNs>(&mut self, delay: &mut D);
fn reset_software(&mut self) -> Result<(), SPI::Error>;
fn set_border_waveform_control(
&mut self,
vdb_option: WaveformVDBOption,
fixed_level_setting: VDBFixedLevelSetting,
transition_setting: VDBGSTransitionSetting,
) -> Result<(), SPI::Error>;
fn set_temperature_sensor(&mut self, sensor: TemperatureSensor) -> Result<(), SPI::Error>;
fn set_booster_soft_start_control(&mut self, inrush: BoosterInrush) -> Result<(), SPI::Error>;
}
impl<SPI, OUT, IN> DisplayCommands<SPI> for Interface4Pin<SPI, OUT, IN>
where
SPI: embedded_hal::spi::SpiDevice,
OUT: embedded_hal::digital::OutputPin,
IN: embedded_hal::digital::InputPin,
{
fn set_driver_output_control(
&mut self,
max_gate_lines: u16,
scanning_sequence_and_direction: u8,
) -> Result<(), SPI::Error> {
self.send_command(0x01)?;
let [upper, lower] = max_gate_lines.to_le_bytes();
self.send_data(&[upper, lower, scanning_sequence_and_direction])?;
Ok(())
}
fn set_driver_output_control_from_width(&mut self, width: u16) -> Result<(), SPI::Error> {
self.send_command(0x01)?;
self.send_data(&[((width - 1) % 256).try_into().unwrap()])?;
self.send_data(&[((width - 1) / 256).try_into().unwrap()])?;
self.send_data(&[0x02])?;
Ok(())
}
fn set_data_entry_mode(
&mut self,
data_entry_mode: DataEntryMode,
increment_axis: IncrementAxis,
) -> Result<(), SPI::Error> {
self.send_command(0x11)?;
let config_option: u8 = ((increment_axis as u8) << 2) | data_entry_mode as u8;
self.send_data(&[config_option])?;
Ok(())
}
fn write_ram_black_and_white(&mut self, data: &[u8]) -> Result<(), SPI::Error> {
self.send_command(0x24)?;
self.send_data(data)?;
Ok(())
}
fn write_ram_red(&mut self, data: &[u8]) -> Result<(), SPI::Error> {
self.send_command(0x26)?;
self.send_data(data)?;
Ok(())
}
fn auto_write_ram_red_regular_pattern(&mut self, value: u8) -> Result<(), SPI::Error> {
self.send_command(0x46)?;
self.send_data(&[value])?;
Ok(())
}
fn auto_write_ram_black_and_white_regular_pattern(
&mut self,
value: u8,
) -> Result<(), SPI::Error> {
self.send_command(0x47)?;
self.send_data(&[value])?;
Ok(())
}
fn set_ram_x_count(&mut self, offset: u16) -> Result<(), SPI::Error> {
self.send_command(0x4E)?;
self.send_data(&offset.to_le_bytes())?;
Ok(())
}
fn set_ram_y_count(&mut self, offset: u16) -> Result<(), SPI::Error> {
self.send_command(0x4F)?;
self.send_data(&offset.to_le_bytes())?;
Ok(())
}
fn refresh_display(&mut self) -> Result<(), SPI::Error> {
self.send_command(0x20)?;
self.busy_wait();
Ok(())
}
fn set_ram_x_address(&mut self, start: u16, end: u16) -> Result<(), SPI::Error> {
let [start_hi, start_lo] = start.to_le_bytes();
let [end_hi, end_lo] = end.to_le_bytes();
let data = [start_hi, start_lo, end_hi, (end_lo & 0b00111111)];
self.send_command(0x44)?;
self.send_data(&data)?;
Ok(())
}
fn set_ram_y_address(&mut self, start: u16, end: u16) -> Result<(), SPI::Error> {
let [start_hi, start_lo] = start.to_le_bytes();
let [end_hi, end_lo] = end.to_le_bytes();
let data = [start_hi, start_lo, end_hi, (end_lo & 0b00111111)];
self.send_command(0x45)?;
self.send_data(&data)?;
Ok(())
}
fn set_ram_address_based_on_size(&mut self, width: u16, height: u16) -> Result<(), SPI::Error> {
self.set_ram_x_address(0, height - 1)?;
self.set_ram_y_address(0, width - 1)?;
Ok(())
}
fn nop(&mut self) -> Result<(), SPI::Error> {
self.send_command(0x7F)?;
Ok(())
}
fn set_gate_driving_voltage(&mut self, voltage: f32) -> Result<(), SPI::Error> {
let value: u8 = match voltage {
12.0 => 0x07,
12.5 => 0x08,
13.0 => 0x09,
13.5 => 0x0A,
14.0 => 0x0B,
14.5 => 0x0C,
15.0 => 0x0D,
15.5 => 0x0E,
16.0 => 0x0F,
16.5 => 0x10,
17.0 => 0x11,
17.5 => 0x12,
18.0 => 0x13,
18.5 => 0x14,
19.0 => 0x15,
19.5 => 0x16,
20.0 => 0x17,
_ => 0, };
self.send_command(0x03)?;
self.send_data(&[value])?;
Ok(())
}
fn set_source_driving_voltage(
&mut self,
vsh1_voltage: f32,
vsh2_voltage: f32,
vsl_voltage: f32,
) -> Result<(), SPI::Error> {
todo!();
}
fn update_display_option1(
&mut self,
black_and_white_option: RamOption,
red_option: RamOption,
) -> Result<(), SPI::Error> {
let data: u8 = (red_option as u8 & 0b1111) << 4 | (black_and_white_option as u8 & 0b1111);
self.send_command(0x21)?;
self.send_data(&[data])?;
Ok(())
}
fn update_display_option2(&mut self, option: u8) -> Result<(), SPI::Error> {
self.send_command(0x22)?;
self.send_data(&[option])?;
Ok(())
}
fn reset_hardware<D: embedded_hal::delay::DelayNs>(&mut self, delay: &mut D) {
use crate::interface::RESET_DELAY_MS;
self.reset_pin.set_low().unwrap();
delay.delay_ms(RESET_DELAY_MS.into());
self.reset_pin.set_high().unwrap();
delay.delay_ms(RESET_DELAY_MS.into());
}
fn reset_software(&mut self) -> Result<(), SPI::Error> {
self.send_command(0x12)?;
self.busy_wait();
Ok(())
}
fn set_border_waveform_control(
&mut self,
vdb_option: WaveformVDBOption,
fixed_level_setting: VDBFixedLevelSetting,
transition_setting: VDBGSTransitionSetting,
) -> Result<(), SPI::Error> {
self.send_command(0x3C)?;
let data = ((vdb_option as u8) << 6)
| ((fixed_level_setting as u8) << 4)
| (transition_setting as u8);
self.send_data(&[data])?;
Ok(())
}
fn set_temperature_sensor(&mut self, sensor: TemperatureSensor) -> Result<(), SPI::Error> {
self.send_command(0x18)?;
self.send_data(&[sensor as u8])?;
Ok(())
}
fn set_booster_soft_start_control(&mut self, inrush: BoosterInrush) -> Result<(), SPI::Error> {
let control_value: [u8; 5] = [0xAE, 0xC7, 0xC3, 0xC0, inrush as u8];
self.send_command(0x0C)?;
self.send_data(&control_value)?;
Ok(())
}
}