From f7e8275b30e3417f8211639ba6623cdee1dd7478 Mon Sep 17 00:00:00 2001 From: Wesley Moore Date: Wed, 28 Nov 2018 08:10:16 +1100 Subject: [PATCH] Add builder for constructing display --- README.md | 4 +- src/command.rs | 7 ++-- src/config.rs | 105 ++++++++++++++++++++++++++++++++++++++++++++++++ src/display.rs | 43 ++++++++++---------- src/graphics.rs | 10 ++--- src/lib.rs | 6 ++- 6 files changed, 142 insertions(+), 33 deletions(-) create mode 100644 src/config.rs diff --git a/README.md b/README.md index 470d51c..ac44482 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ controller, for use with [embedded-hal]. ## Description This driver is intended to work on embedded platforms using the `embedded-hal` -trait library. It is `no_std` compatible, only uses safe Rust, and does not -require an allocator. It supports the 4-wire SPI interface. +trait library. It is `no_std` compatible, builds on stable Rust, and only uses +safe Rust. It supports the 4-wire SPI interface. ## Tested Devices diff --git a/src/command.rs b/src/command.rs index 1c9c7c4..8dee0a1 100644 --- a/src/command.rs +++ b/src/command.rs @@ -50,6 +50,7 @@ pub enum DeepSleepMode { DiscardRAM, } +#[derive(Clone, Copy)] pub enum Command { /// Set the MUX of gate lines, scanning sequence and direction /// 0: MAX gate lines @@ -207,11 +208,11 @@ macro_rules! pack { } impl Command { - pub(crate) fn execute(self, interface: &mut I) -> Result<(), I::Error> { + pub(crate) fn execute(&self, interface: &mut I) -> Result<(), I::Error> { use self::Command::*; let mut buf = [0u8; 4]; - let (command, data) = match self { + 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]) @@ -326,7 +327,7 @@ impl Command { } impl<'buf> BufCommand<'buf> { - pub(crate) fn execute(self, interface: &mut I) -> Result<(), I::Error> { + pub(crate) fn execute(&self, interface: &mut I) -> Result<(), I::Error> { use self::BufCommand::*; let (command, data) = match self { diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..dc75779 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,105 @@ +use command::{BufCommand, Command, DataEntryMode, IncrementAxis}; +use display::{Dimensions, Rotation}; + +pub struct Builder<'a> { + dummy_line_period: Command, + gate_line_width: Command, + write_vcom: Command, + write_lut: Option>, + data_entry_mode: Command, + dimensions: Option, + rotation: Rotation +} + +pub struct BuilderError {} + +pub struct Config<'a> { + pub(crate) dummy_line_period: Command, + pub(crate) gate_line_width: Command, + pub(crate) write_vcom: Command, + pub(crate) write_lut: Option>, + pub(crate) data_entry_mode: Command, + pub(crate) dimensions: Dimensions, + pub(crate) rotation: Rotation +} + +impl<'a> Default for Builder<'a> { + fn default() -> Self { + Builder { + dummy_line_period: Command::DummyLinePeriod(0x07), + gate_line_width: Command::GateLineWidth(0x04), + write_vcom: Command::WriteVCOM(0x3C), + write_lut: None, + data_entry_mode: Command::DataEntryMode(DataEntryMode::IncrementYIncrementX, IncrementAxis::Horizontal), + dimensions: None, + rotation: Rotation::default(), + } + } +} + +impl<'a> Builder<'a> { + pub fn new() -> Self { + Self::default() + } + + pub fn dummy_line_period(self, dummy_line_period: u8) -> Self { + Self { + dummy_line_period: Command::DummyLinePeriod(dummy_line_period), + ..self + } + } + + pub fn gate_line_width(self, gate_line_width: u8) -> Self { + Self { + gate_line_width: Command::GateLineWidth(gate_line_width), + ..self + } + } + + pub fn vcom(self, value: u8) -> Self { + Self { + write_vcom: Command::WriteVCOM(value), + ..self + } + } + + pub fn lut(self, lut: &'a [u8]) -> Self { + Self { + write_lut: Some(BufCommand::WriteLUT(lut)), + ..self + } + } + + pub fn data_entry_mode(self, data_entry_mode: DataEntryMode, increment_axis: IncrementAxis) -> Self { + Self { + data_entry_mode: Command::DataEntryMode(data_entry_mode, increment_axis), + ..self + } + } + + pub fn dimensions(self, dimensions: Dimensions) -> Self { + Self { + dimensions: Some(dimensions), + ..self + } + } + + pub fn rotation(self, rotation: Rotation) -> Self { + Self { + rotation, + ..self + } + } + + pub fn build(self) -> Result, BuilderError> { + Ok(Config { + dummy_line_period: self.dummy_line_period, + gate_line_width: self.gate_line_width, + write_vcom: self.write_vcom, + write_lut: self.write_lut, + data_entry_mode: self.data_entry_mode, + dimensions: self.dimensions.ok_or_else(|| BuilderError {})?, + rotation: self.rotation, + }) + } +} diff --git a/src/display.rs b/src/display.rs index 949fd20..24763b9 100644 --- a/src/display.rs +++ b/src/display.rs @@ -1,5 +1,6 @@ use hal; +use config::Config; use command::{BufCommand, Command, DataEntryMode, DeepSleepMode, IncrementAxis}; use interface::DisplayInterface; @@ -11,8 +12,6 @@ const MAX_GATE_OUTPUTS: usize = 296; const ANALOG_BLOCK_CONTROL_MAGIC: u8 = 0x54; const DIGITAL_BLOCK_CONTROL_MAGIC: u8 = 0x3B; -struct Config {} - pub struct Dimensions { pub rows: u16, pub cols: u8, @@ -32,16 +31,15 @@ impl Default for Rotation { } } -pub struct Display where I: DisplayInterface { +pub struct Display<'a, I> where I: DisplayInterface { interface: I, - dimensions: Dimensions, - rotation: Rotation, + config: Config<'a>, } -impl Display where I: DisplayInterface { - pub fn new(interface: I, dimensions: Dimensions, rotation: Rotation) -> Self { +impl<'a, I> Display<'a, I> where I: DisplayInterface { + pub fn new(interface: I, config: Config<'a>) -> Self { // TODO: Assert dimensions are evenly divisible by 8 - Self { interface, dimensions, rotation } + Self { interface, config } } /// Perform a hardware reset followed by software reset @@ -50,34 +48,37 @@ impl Display where I: DisplayInterface { Command::SoftReset.execute(&mut self.interface)?; self.interface.busy_wait(); - self.init(Config {}) + self.init() } /// Initialise the controller according to Section 9: Typical Operating Sequence /// from the data sheet - fn init(&mut self, config: Config) -> Result<(), I::Error> { + fn init(&mut self) -> Result<(), I::Error> { Command::AnalogBlockControl(ANALOG_BLOCK_CONTROL_MAGIC).execute(&mut self.interface)?; Command::DigitalBlockControl(DIGITAL_BLOCK_CONTROL_MAGIC).execute(&mut self.interface)?; - Command::DriverOutputControl(self.dimensions.rows, 0x00).execute(&mut self.interface)?; + Command::DriverOutputControl(self.config.dimensions.rows, 0x00).execute(&mut self.interface)?; - Command::DummyLinePeriod(0x07).execute(&mut self.interface)?; - Command::GateLineWidth(0x04).execute(&mut self.interface)?; + self.config.dummy_line_period.execute(&mut self.interface)?; + self.config.gate_line_width.execute(&mut self.interface)?; // Command::GateDrivingVoltage(0b10000 | 0b0001); // Command::SourceDrivingVoltage(0x2D, 0xB2, 0x22).execute(&mut self.interface)?; - Command::WriteVCOM(0x3C).execute(&mut self.interface)?; + self.config.write_vcom.execute(&mut self.interface)?; // POR is HiZ. Need pull from config // Command::BorderWaveform(u8).execute(&mut self.interface)?; - BufCommand::WriteLUT(&LUT_RED).execute(&mut self.interface)?; + // BufCommand::WriteLUT(&LUT_RED).execute(&mut self.interface)?; + if let Some(ref write_lut) = self.config.write_lut { + write_lut.execute(&mut self.interface)?; + } - Command::DataEntryMode(DataEntryMode::IncrementYIncrementX, IncrementAxis::Horizontal).execute(&mut self.interface)?; + self.config.data_entry_mode.execute(&mut self.interface)?; - let end = self.dimensions.cols / 8 - 1; + let end = self.config.dimensions.cols / 8 - 1; Command::StartEndXPosition(0, end).execute(&mut self.interface)?; - Command::StartEndYPosition(0, self.dimensions.rows).execute(&mut self.interface)?; + Command::StartEndYPosition(0, self.config.dimensions.rows).execute(&mut self.interface)?; Ok(()) } @@ -112,15 +113,15 @@ impl Display where I: DisplayInterface { } pub fn rows(&self) -> u16 { - self.dimensions.rows + self.config.dimensions.rows } pub fn cols(&self) -> u8 { - self.dimensions.cols + self.config.dimensions.cols } pub fn rotation(&self) -> Rotation { - self.rotation + self.config.rotation } } diff --git a/src/graphics.rs b/src/graphics.rs index 33a878f..89753a0 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -5,13 +5,13 @@ use interface::DisplayInterface; use core::ops::{Deref, DerefMut}; pub struct GraphicDisplay<'a, I> where I: DisplayInterface { - display: Display, + display: Display<'a, I>, black_buffer: &'a mut [u8], red_buffer: &'a mut [u8], } impl<'a, I> GraphicDisplay<'a, I> where I: DisplayInterface { - pub fn new(display: Display, black_buffer: &'a mut [u8], red_buffer: &'a mut [u8]) -> Self { + pub fn new(display: Display<'a, I>, black_buffer: &'a mut [u8], red_buffer: &'a mut [u8]) -> Self { GraphicDisplay { display, black_buffer, red_buffer } } @@ -58,15 +58,15 @@ impl<'a, I> GraphicDisplay<'a, I> where I: DisplayInterface { } impl<'a, I> Deref for GraphicDisplay<'a, I> where I: DisplayInterface { - type Target = Display; + type Target = Display<'a, I>; - fn deref(&self) -> &Display { + fn deref(&self) -> &Display<'a, I> { &self.display } } impl<'a, I> DerefMut for GraphicDisplay<'a, I> where I: DisplayInterface { - fn deref_mut(&mut self) -> &mut Display { + fn deref_mut(&mut self) -> &mut Display<'a, I> { &mut self.display } } diff --git a/src/lib.rs b/src/lib.rs index fbbbdb7..adb8947 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,14 +6,16 @@ extern crate embedded_hal as hal; #[macro_use] extern crate std; +mod color; mod command; -mod interface; +mod config; mod display; mod graphics; -mod color; +mod interface; pub use interface::DisplayInterface; pub use interface::Interface; pub use display::{Display, Dimensions, Rotation}; pub use graphics::GraphicDisplay; pub use color::Color; +pub use config::Builder;