use core;
use interface::DisplayInterface;
const MAX_GATES: u16 = 296;
const MAX_DUMMY_LINE_PERIOD: u8 = 127;
trait Contains<C>
where
C: Copy + PartialOrd,
{
fn contains(&self, item: C) -> bool;
}
#[derive(Clone, Copy)]
pub enum IncrementAxis {
Horizontal,
Vertical,
}
#[derive(Clone, Copy)]
pub enum DataEntryMode {
DecrementXDecrementY,
IncrementXDecrementY,
DecrementXIncrementY,
IncrementYIncrementX,
}
#[derive(Clone, Copy)]
pub enum TemperatureSensor {
Internal,
External,
}
#[derive(Clone, Copy)]
pub enum RamOption {
Normal,
Bypass,
Invert,
}
#[derive(Clone, Copy)]
pub enum DeepSleepMode {
Normal,
PreserveRAM,
DiscardRAM,
}
#[derive(Clone, Copy)]
pub enum Command {
DriverOutputControl(u16, u8),
GateDrivingVoltage(u8),
SourceDrivingVoltage(u8, u8, u8),
BoosterEnable(u8, u8, u8, u8),
GateScanStartPostion(u16),
DeepSleepMode(DeepSleepMode),
DataEntryMode(DataEntryMode, IncrementAxis),
SoftReset,
TemperatatSensorSelection(TemperatureSensor),
WriteTemperatureSensor(u16),
ReadTemperatureSensor(u16),
WriteExternalTemperatureSensor(u8, u8, u8),
UpdateDisplay,
UpdateDisplayOption1(RamOption, RamOption),
UpdateDisplayOption2(u8),
EnterVCOMSensing,
VCOMSenseDuration(u8),
WriteVCOM(u8),
DummyLinePeriod(u8),
GateLineWidth(u8),
BorderWaveform(u8),
StartEndXPosition(u8, u8),
StartEndYPosition(u16, u16),
AutoWriteRedPattern(u8),
AutoWriteBlackPattern(u8),
XAddress(u8),
YAddress(u8),
AnalogBlockControl(u8),
DigitalBlockControl(u8),
}
pub enum BufCommand<'buf> {
WriteBlackData(&'buf [u8]),
WriteRedData(&'buf [u8]),
WriteLUT(&'buf [u8]),
}
fn u16_as_u8(val: u16) -> [u8; 2] {
[(val & 0xFF00 >> 8) as u8, (val & 0xFF) as u8]
}
macro_rules! pack {
($buf:ident, $cmd:expr,[]) => {
($cmd, &$buf[..0])
};
($buf:ident, $cmd:expr,[$arg0:expr]) => {{
$buf[0] = $arg0;
($cmd, &$buf[..1])
}};
($buf:ident, $cmd:expr,[$arg0:expr, $arg1:expr]) => {{
$buf[0] = $arg0;
$buf[1] = $arg1;
($cmd, &$buf[..2])
}};
($buf:ident, $cmd:expr,[$arg0:expr, $arg1:expr, $arg2:expr]) => {{
$buf[0] = $arg0;
$buf[1] = $arg1;
$buf[2] = $arg2;
($cmd, &$buf[..3])
}};
($buf:ident, $cmd:expr,[$arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr]) => {{
$buf[0] = $arg0;
$buf[1] = $arg1;
$buf[2] = $arg2;
$buf[3] = $arg3;
($cmd, &$buf[..4])
}};
}
impl Command {
pub fn execute<I: DisplayInterface>(&self, interface: &mut I) -> Result<(), I::Error> {
use self::Command::*;
let mut buf = [0u8; 4];
let (command, data) = match *self {
DriverOutputControl(gate_lines, scanning_seq_and_dir) => {
let [upper, lower] = u16_as_u8(gate_lines);
pack!(buf, 0x01, [lower, upper, scanning_seq_and_dir])
}
GateDrivingVoltage(voltages) => pack!(buf, 0x03, [voltages]),
SourceDrivingVoltage(vsh1, vsh2, vsl) => pack!(buf, 0x04, [vsh1, vsh2, vsl]),
BoosterEnable(phase1, phase2, phase3, duration) => {
pack!(buf, 0x0C, [phase1, phase2, phase3, duration])
}
GateScanStartPostion(position) => {
debug_assert!(Contains::contains(&(0..MAX_GATES), position));
let [upper, lower] = u16_as_u8(position);
pack!(buf, 0x0F, [lower, upper])
}
DeepSleepMode(mode) => {
let mode = match mode {
self::DeepSleepMode::Normal => 0b00,
self::DeepSleepMode::PreserveRAM => 0b01,
self::DeepSleepMode::DiscardRAM => 0b11,
};
pack!(buf, 0x10, [mode])
}
DataEntryMode(data_entry_mode, increment_axis) => {
let mode = match data_entry_mode {
self::DataEntryMode::DecrementXDecrementY => 0b00,
self::DataEntryMode::IncrementXDecrementY => 0b01,
self::DataEntryMode::DecrementXIncrementY => 0b10,
self::DataEntryMode::IncrementYIncrementX => 0b11,
};
let axis = match increment_axis {
IncrementAxis::Horizontal => 0b000,
IncrementAxis::Vertical => 0b100,
};
pack!(buf, 0x11, [axis | mode])
}
SoftReset => pack!(buf, 0x12, []),
UpdateDisplay => pack!(buf, 0x20, []),
UpdateDisplayOption2(value) => pack!(buf, 0x22, [value]),
WriteVCOM(value) => pack!(buf, 0x2C, [value]),
DummyLinePeriod(period) => {
debug_assert!(Contains::contains(&(0..=MAX_DUMMY_LINE_PERIOD), period));
pack!(buf, 0x3A, [period])
}
GateLineWidth(tgate) => pack!(buf, 0x3B, [tgate]),
BorderWaveform(border_waveform) => pack!(buf, 0x3C, [border_waveform]),
StartEndXPosition(start, end) => pack!(buf, 0x44, [start, end]),
StartEndYPosition(start, end) => {
let [start_upper, start_lower] = u16_as_u8(start);
let [end_upper, end_lower] = u16_as_u8(end);
pack!(buf, 0x45, [start_lower, start_upper, end_lower, end_upper])
}
XAddress(address) => pack!(buf, 0x4E, [address]),
YAddress(address) => pack!(buf, 0x4F, [address]),
AnalogBlockControl(value) => pack!(buf, 0x74, [value]),
DigitalBlockControl(value) => pack!(buf, 0x7E, [value]),
_ => unimplemented!(),
};
interface.send_command(command)?;
if data.len() == 0 {
Ok(())
} else {
interface.send_data(data)
}
}
}
impl<'buf> BufCommand<'buf> {
pub fn execute<I: DisplayInterface>(&self, interface: &mut I) -> Result<(), I::Error> {
use self::BufCommand::*;
let (command, data) = match self {
WriteBlackData(buffer) => (0x24, buffer),
WriteRedData(buffer) => (0x26, buffer),
WriteLUT(buffer) => (0x32, buffer),
};
interface.send_command(command)?;
if data.len() == 0 {
Ok(())
} else {
interface.send_data(data)
}
}
}
impl<C> Contains<C> for core::ops::Range<C>
where
C: Copy + PartialOrd,
{
fn contains(&self, item: C) -> bool {
item >= self.start && item < self.end
}
}
impl<C> Contains<C> for core::ops::RangeInclusive<C>
where
C: Copy + PartialOrd,
{
fn contains(&self, item: C) -> bool {
item >= *self.start() && item <= *self.end()
}
}