From 7fa1a27f40a0fcdb3030ff81bef951bcea8d1c8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20Gro=C3=9F?= Date: Wed, 8 Aug 2018 15:10:51 +0200 Subject: [PATCH] Shortened TypeDefinitions, made init a private function, added a crate internal extended waveshareinterface, added a combined Connection_interface::data_and_command function, added a wake_up function, added a updated_and_display_partial_frame_function --- src/epd1in54/mod.rs | 176 +++++++++---------- src/epd2in9/mod.rs | 184 +++++++++++--------- src/epd4in2/mod.rs | 240 +++++++++++++------------- src/interface/connection_interface.rs | 58 ++++--- src/interface/mod.rs | 141 +++++++++------ 5 files changed, 431 insertions(+), 368 deletions(-) diff --git a/src/epd1in54/mod.rs b/src/epd1in54/mod.rs index adff9ec..d958e10 100644 --- a/src/epd1in54/mod.rs +++ b/src/epd1in54/mod.rs @@ -39,32 +39,76 @@ use interface::connection_interface::ConnectionInterface; /// EPD1in54 driver /// -pub struct EPD1in54 { +pub struct EPD1in54 { /// SPI - interface: ConnectionInterface, + interface: ConnectionInterface, /// EPD (width, height) //epd: EPD, /// Color background_color: Color, } -impl EPD1in54 +impl EPD1in54 where SPI: Write, CS: OutputPin, BUSY: InputPin, - DataCommand: OutputPin, + DC: OutputPin, RST: OutputPin, Delay: DelayUs + DelayMs, -{} +{ + fn init(&mut self) -> Result<(), E> { + self.interface.reset(); + + // 3 Databytes: + // A[7:0] + // 0.. A[8] + // 0.. B[2:0] + // Default Values: A = Height of Screen (0x127), B = 0x00 (GD, SM and TB=0?) + self.interface.command(Command::DRIVER_OUTPUT_CONTROL)?; + self.interface.data(HEIGHT as u8)?; + self.interface.data((HEIGHT >> 8) as u8)?; + self.interface.data(0x00)?; + + // 3 Databytes: (and default values from datasheet and arduino) + // 1 .. A[6:0] = 0xCF | 0xD7 + // 1 .. B[6:0] = 0xCE | 0xD6 + // 1 .. C[6:0] = 0x8D | 0x9D + //TODO: test + self.interface.command(Command::BOOSTER_SOFT_START_CONTROL)?; + self.interface.data(0xD7)?; + self.interface.data(0xD6)?; + self.interface.data(0x9D)?; + + // One Databyte with value 0xA8 for 7V VCOM + self.interface.command(Command::WRITE_VCOM_REGISTER)?; + self.interface.data(0xA8)?; + + // One Databyte with default value 0x1A for 4 dummy lines per gate + self.interface.command(Command::SET_DUMMY_LINE_PERIOD)?; + self.interface.data(0x1A)?; + + // One Databyte with default value 0x08 for 2us per line + self.interface.command(Command::SET_GATE_LINE_WIDTH)?; + self.interface.data(0x08)?; + + // One Databyte with default value 0x03 + // -> address: x increment, y increment, address counter is updated in x direction + self.interface.command(Command::DATA_ENTRY_MODE_SETTING)?; + self.interface.data(0x03)?; -impl WaveshareInterface - for EPD1in54 + self.set_lut() + } + +} + +impl WaveshareInterface + for EPD1in54 where SPI: Write, CS: OutputPin, BUSY: InputPin, - DataCommand: OutputPin, + DC: OutputPin, RST: OutputPin, Delay: DelayUs + DelayMs, { @@ -77,8 +121,10 @@ where } fn new( - interface: ConnectionInterface, + spi: SPI, cs: CS, busy: BUSY, dc: DC, rst: RST, delay: Delay, ) -> Result { + let interface = ConnectionInterface::new(spi, cs, busy, dc, rst, delay); + let mut epd = EPD1in54 { interface, background_color: DEFAULT_BACKGROUND_COLOR, @@ -89,63 +135,22 @@ where Ok(epd) } - fn init(&mut self) -> Result<(), E> { - self.reset(); - - // 3 Databytes: - // A[7:0] - // 0.. A[8] - // 0.. B[2:0] - // Default Values: A = Height of Screen (0x127), B = 0x00 (GD, SM and TB=0?) - self.interface.send_command(Command::DRIVER_OUTPUT_CONTROL)?; - self.interface.send_data(HEIGHT as u8)?; - self.interface.send_data((HEIGHT >> 8) as u8)?; - self.interface.send_data(0x00)?; - - // 3 Databytes: (and default values from datasheet and arduino) - // 1 .. A[6:0] = 0xCF | 0xD7 - // 1 .. B[6:0] = 0xCE | 0xD6 - // 1 .. C[6:0] = 0x8D | 0x9D - //TODO: test - self.interface.send_command(Command::BOOSTER_SOFT_START_CONTROL)?; - self.interface.send_data(0xD7)?; - self.interface.send_data(0xD6)?; - self.interface.send_data(0x9D)?; - - // One Databyte with value 0xA8 for 7V VCOM - self.interface.send_command(Command::WRITE_VCOM_REGISTER)?; - self.interface.send_data(0xA8)?; - - // One Databyte with default value 0x1A for 4 dummy lines per gate - self.interface.send_command(Command::SET_DUMMY_LINE_PERIOD)?; - self.interface.send_data(0x1A)?; - - // One Databyte with default value 0x08 for 2us per line - self.interface.send_command(Command::SET_GATE_LINE_WIDTH)?; - self.interface.send_data(0x08)?; - - // One Databyte with default value 0x03 - // -> address: x increment, y increment, address counter is updated in x direction - self.interface.send_command(Command::DATA_ENTRY_MODE_SETTING)?; - self.interface.send_data(0x03)?; - - self.set_lut() + fn wake_up(&mut self) -> Result<(), E> { + self.init() } + + fn sleep(&mut self) -> Result<(), E> { - self.interface.send_command(Command::DEEP_SLEEP_MODE)?; + self.interface.command(Command::DEEP_SLEEP_MODE)?; // 0x00 for Normal mode (Power on Reset), 0x01 for Deep Sleep Mode //TODO: is 0x00 needed here? - self.interface.send_data(0x00)?; + self.interface.data(0x00)?; self.wait_until_idle(); Ok(()) } - fn reset(&mut self) { - self.interface.reset() - } - fn delay_ms(&mut self, delay: u16) { self.interface.delay_ms(delay) } @@ -153,8 +158,7 @@ where fn update_frame(&mut self, buffer: &[u8]) -> Result<(), E> { self.use_full_frame()?; - self.interface.send_command(Command::WRITE_RAM)?; - self.interface.send_multiple_data(buffer) + self.interface.command_with_data(Command::WRITE_RAM, buffer) } //TODO: update description: last 3 bits will be ignored for width and x_pos @@ -169,25 +173,19 @@ where self.set_ram_area(x, y, x + width, y + height)?; self.set_ram_counter(x, y)?; - self.interface.send_command(Command::WRITE_RAM)?; - self.interface.send_multiple_data(buffer) + self.interface.command(Command::WRITE_RAM)?; + self.interface.multiple_data(buffer) } fn display_frame(&mut self) -> Result<(), E> { // enable clock signal, enable cp, display pattern -> 0xC4 (tested with the arduino version) //TODO: test control_1 or control_2 with default value 0xFF (from the datasheet) - self.interface.send_command(Command::DISPLAY_UPDATE_CONTROL_2)?; - self.interface.send_data(0xC4)?; + self.interface.command_with_data(Command::DISPLAY_UPDATE_CONTROL_2, &[0xC4])?; - self.interface.send_command(Command::MASTER_ACTIVATION)?; + self.interface.command(Command::MASTER_ACTIVATION)?; // MASTER Activation should not be interupted to avoid currption of panel images // therefore a terminate command is send - self.interface.send_command(Command::TERMINATE_COMMANDS_AND_FRAME_WRITE) - } - - fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), E> { - self.update_frame(buffer)?; - self.display_frame() + self.interface.command(Command::NOP) } fn clear_frame(&mut self) -> Result<(), E> { @@ -196,14 +194,19 @@ where // clear the ram with the background color let color = self.background_color.get_byte_value(); - self.interface.send_command(Command::WRITE_RAM)?; - self.interface.send_data_x_times(color, WIDTH / 8 * HEIGHT) + self.interface.command(Command::WRITE_RAM)?; + self.interface.data_x_times(color, WIDTH / 8 * HEIGHT) } - /// Sets the backgroundcolor for various commands like [WaveshareInterface::clear_frame()](clear_frame()) + fn set_background_color(&mut self, background_color: Color) { self.background_color = background_color; } + + + fn background_color(&self) -> &Color { + &self.background_color + } } impl EPD1in54 @@ -239,28 +242,28 @@ where // x is positioned in bytes, so the last 3 bits which show the position inside a byte in the ram // aren't relevant - self.interface.send_command(Command::SET_RAM_X_ADDRESS_START_END_POSITION)?; - self.interface.send_data((start_x >> 3) as u8)?; - self.interface.send_data((end_x >> 3) as u8)?; + self.interface.command(Command::SET_RAM_X_ADDRESS_START_END_POSITION)?; + self.interface.data((start_x >> 3) as u8)?; + self.interface.data((end_x >> 3) as u8)?; // 2 Databytes: A[7:0] & 0..A[8] for each - start and end - self.interface.send_command(Command::SET_RAM_Y_ADDRESS_START_END_POSITION)?; - self.interface.send_data(start_y as u8)?; - self.interface.send_data((start_y >> 8) as u8)?; - self.interface.send_data(end_y as u8)?; - self.interface.send_data((end_y >> 8) as u8) + self.interface.command(Command::SET_RAM_Y_ADDRESS_START_END_POSITION)?; + self.interface.data(start_y as u8)?; + self.interface.data((start_y >> 8) as u8)?; + self.interface.data(end_y as u8)?; + self.interface.data((end_y >> 8) as u8) } pub(crate) fn set_ram_counter(&mut self, x: u16, y: u16) -> Result<(), E> { // x is positioned in bytes, so the last 3 bits which show the position inside a byte in the ram // aren't relevant - self.interface.send_command(Command::SET_RAM_X_ADDRESS_COUNTER)?; - self.interface.send_data((x >> 3) as u8)?; + self.interface.command_with_data(Command::SET_RAM_X_ADDRESS_COUNTER, &[(x >> 3) as u8])?; // 2 Databytes: A[7:0] & 0..A[8] - self.interface.send_command(Command::SET_RAM_Y_ADDRESS_COUNTER)?; - self.interface.send_data(y as u8)?; - self.interface.send_data((y >> 8) as u8)?; + self.interface.command_with_data( + Command::SET_RAM_Y_ADDRESS_COUNTER, + &[y as u8, (y >> 8) as u8] + )?; self.wait_until_idle(); Ok(()) @@ -283,7 +286,6 @@ where fn set_lut_helper(&mut self, buffer: &[u8]) -> Result<(), E> { assert!(buffer.len() == 30); - self.interface.send_command(Command::WRITE_LUT_REGISTER)?; - self.interface.send_multiple_data(buffer) + self.interface.command_with_data(Command::WRITE_LUT_REGISTER, buffer) } } diff --git a/src/epd2in9/mod.rs b/src/epd2in9/mod.rs index f911e62..b7b08f8 100644 --- a/src/epd2in9/mod.rs +++ b/src/epd2in9/mod.rs @@ -38,33 +38,78 @@ use interface::connection_interface::ConnectionInterface; /// EPD2in9 driver /// -pub struct EPD2in9 { +pub struct EPD2in9 { /// SPI - interface: ConnectionInterface, + interface: ConnectionInterface, /// EPD (width, height) //epd: EPD, /// Color background_color: Color, } -impl EPD2in9 +impl EPD2in9 where SPI: Write, CS: OutputPin, BUSY: InputPin, - DataCommand: OutputPin, + DC: OutputPin, RST: OutputPin, Delay: DelayUs + DelayMs, -{} +{ + fn init(&mut self) -> Result<(), E> { + self.interface.reset(); + + // 3 Databytes: + // A[7:0] + // 0.. A[8] + // 0.. B[2:0] + // Default Values: A = Height of Screen (0x127), B = 0x00 (GD, SM and TB=0?) + self.interface.command(Command::DRIVER_OUTPUT_CONTROL)?; + self.interface.data(HEIGHT as u8)?; + self.interface.data((HEIGHT >> 8) as u8)?; + self.interface.data(0x00)?; -impl - WaveshareInterface - for EPD2in9 + // 3 Databytes: (and default values from datasheet and arduino) + // 1 .. A[6:0] = 0xCF | 0xD7 + // 1 .. B[6:0] = 0xCE | 0xD6 + // 1 .. C[6:0] = 0x8D | 0x9D + //TODO: test + self.interface.command(Command::BOOSTER_SOFT_START_CONTROL)?; + self.interface.data(0xD7)?; + self.interface.data(0xD6)?; + self.interface.data(0x9D)?; + + // One Databyte with value 0xA8 for 7V VCOM + self.interface.command(Command::WRITE_VCOM_REGISTER)?; + self.interface.data(0xA8)?; + + // One Databyte with default value 0x1A for 4 dummy lines per gate + self.interface.command(Command::SET_DUMMY_LINE_PERIOD)?; + self.interface.data(0x1A)?; + + // One Databyte with default value 0x08 for 2us per line + self.interface.command(Command::SET_GATE_LINE_WIDTH)?; + self.interface.data(0x08)?; + + // One Databyte with default value 0x03 + // -> address: x increment, y increment, address counter is updated in x direction + self.interface.command(Command::DATA_ENTRY_MODE_SETTING)?; + self.interface.data(0x03)?; + + self.set_lut() + } + + +} + +impl + WaveshareInterface + for EPD2in9 where SPI: Write, CS: OutputPin, BUSY: InputPin, - DataCommand: OutputPin, + DC: OutputPin, RST: OutputPin, Delay: DelayUs + DelayMs, { @@ -77,11 +122,13 @@ where } fn new( - interface: ConnectionInterface, + spi: SPI, cs: CS, busy: BUSY, dc: DC, rst: RST, delay: Delay, ) -> Result { //let epd = EPD::new(WIDTH, HEIGHT); //let background_color = Color::White; + let interface = ConnectionInterface::new(spi, cs, busy, dc, rst, delay); + let mut epd = EPD2in9 { interface, background_color: DEFAULT_BACKGROUND_COLOR, @@ -92,61 +139,20 @@ where Ok(epd) } - fn init(&mut self) -> Result<(), E> { - self.reset(); - - // 3 Databytes: - // A[7:0] - // 0.. A[8] - // 0.. B[2:0] - // Default Values: A = Height of Screen (0x127), B = 0x00 (GD, SM and TB=0?) - self.interface.send_command(Command::DRIVER_OUTPUT_CONTROL)?; - self.interface.send_data(HEIGHT as u8)?; - self.interface.send_data((HEIGHT >> 8) as u8)?; - self.interface.send_data(0x00)?; - - // 3 Databytes: (and default values from datasheet and arduino) - // 1 .. A[6:0] = 0xCF | 0xD7 - // 1 .. B[6:0] = 0xCE | 0xD6 - // 1 .. C[6:0] = 0x8D | 0x9D - //TODO: test - self.interface.send_command(Command::BOOSTER_SOFT_START_CONTROL)?; - self.interface.send_data(0xD7)?; - self.interface.send_data(0xD6)?; - self.interface.send_data(0x9D)?; - - // One Databyte with value 0xA8 for 7V VCOM - self.interface.send_command(Command::WRITE_VCOM_REGISTER)?; - self.interface.send_data(0xA8)?; - - // One Databyte with default value 0x1A for 4 dummy lines per gate - self.interface.send_command(Command::SET_DUMMY_LINE_PERIOD)?; - self.interface.send_data(0x1A)?; - - // One Databyte with default value 0x08 for 2us per line - self.interface.send_command(Command::SET_GATE_LINE_WIDTH)?; - self.interface.send_data(0x08)?; - - // One Databyte with default value 0x03 - // -> address: x increment, y increment, address counter is updated in x direction - self.interface.send_command(Command::DATA_ENTRY_MODE_SETTING)?; - self.interface.send_data(0x03)?; - - self.set_lut() - } + fn sleep(&mut self) -> Result<(), E> { - self.interface.send_command(Command::DEEP_SLEEP_MODE)?; + self.interface.command(Command::DEEP_SLEEP_MODE)?; // 0x00 for Normal mode (Power on Reset), 0x01 for Deep Sleep Mode //TODO: is 0x00 needed here? - self.interface.send_data(0x00)?; + self.interface.data(0x00)?; self.wait_until_idle(); Ok(()) } - fn reset(&mut self) { - self.interface.reset() + fn wake_up(&mut self) -> Result<(), E> { + self.init() } fn delay_ms(&mut self, delay: u16) { @@ -156,8 +162,8 @@ where fn update_frame(&mut self, buffer: &[u8]) -> Result<(), E> { self.use_full_frame()?; - self.interface.send_command(Command::WRITE_RAM)?; - self.interface.send_multiple_data(buffer) + self.interface.command(Command::WRITE_RAM)?; + self.interface.multiple_data(buffer) } //TODO: update description: last 3 bits will be ignored for width and x_pos @@ -172,20 +178,20 @@ where self.set_ram_area(x, y, x + width, y + height)?; self.set_ram_counter(x, y)?; - self.interface.send_command(Command::WRITE_RAM)?; - self.interface.send_multiple_data(buffer) + self.interface.command(Command::WRITE_RAM)?; + self.interface.multiple_data(buffer) } fn display_frame(&mut self) -> Result<(), E> { // enable clock signal, enable cp, display pattern -> 0xC4 (tested with the arduino version) //TODO: test control_1 or control_2 with default value 0xFF (from the datasheet) - self.interface.send_command(Command::DISPLAY_UPDATE_CONTROL_2)?; - self.interface.send_data(0xC4)?; + self.interface.command(Command::DISPLAY_UPDATE_CONTROL_2)?; + self.interface.data(0xC4)?; - self.interface.send_command(Command::MASTER_ACTIVATION)?; + self.interface.command(Command::MASTER_ACTIVATION)?; // MASTER Activation should not be interupted to avoid currption of panel images // therefore a terminate command is send - self.interface.send_command(Command::TERMINATE_COMMANDS_AND_FRAME_WRITE) + self.interface.command(Command::NOP) } fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), E> { @@ -193,20 +199,36 @@ where self.display_frame() } + fn update_and_display_partial_frame( + &mut self, + buffer: &[u8], + x: u16, + y: u16, + width: u16, + height: u16, + ) -> Result<(), E> { + self.update_partial_frame(buffer, x, y, width, height)?; + self.display_frame() + } + fn clear_frame(&mut self) -> Result<(), E> { self.use_full_frame()?; // clear the ram with the background color let color = self.background_color.get_byte_value(); - self.interface.send_command(Command::WRITE_RAM)?; - self.interface.send_data_x_times(color, WIDTH / 8 * HEIGHT) + self.interface.command(Command::WRITE_RAM)?; + self.interface.data_x_times(color, WIDTH / 8 * HEIGHT) } /// Sets the backgroundcolor for various commands like [WaveshareInterface::clear_frame()](clear_frame()) fn set_background_color(&mut self, background_color: Color) { self.background_color = background_color; } + + fn background_color(&self) -> &Color { + &self.background_color + } } impl EPD2in9 @@ -242,28 +264,28 @@ where // x is positioned in bytes, so the last 3 bits which show the position inside a byte in the ram // aren't relevant - self.interface.send_command(Command::SET_RAM_X_ADDRESS_START_END_POSITION)?; - self.interface.send_data((start_x >> 3) as u8)?; - self.interface.send_data((end_x >> 3) as u8)?; + self.interface.command(Command::SET_RAM_X_ADDRESS_START_END_POSITION)?; + self.interface.data((start_x >> 3) as u8)?; + self.interface.data((end_x >> 3) as u8)?; // 2 Databytes: A[7:0] & 0..A[8] for each - start and end - self.interface.send_command(Command::SET_RAM_Y_ADDRESS_START_END_POSITION)?; - self.interface.send_data(start_y as u8)?; - self.interface.send_data((start_y >> 8) as u8)?; - self.interface.send_data(end_y as u8)?; - self.interface.send_data((end_y >> 8) as u8) + self.interface.command(Command::SET_RAM_Y_ADDRESS_START_END_POSITION)?; + self.interface.data(start_y as u8)?; + self.interface.data((start_y >> 8) as u8)?; + self.interface.data(end_y as u8)?; + self.interface.data((end_y >> 8) as u8) } pub(crate) fn set_ram_counter(&mut self, x: u16, y: u16) -> Result<(), E> { // x is positioned in bytes, so the last 3 bits which show the position inside a byte in the ram // aren't relevant - self.interface.send_command(Command::SET_RAM_X_ADDRESS_COUNTER)?; - self.interface.send_data((x >> 3) as u8)?; + self.interface.command(Command::SET_RAM_X_ADDRESS_COUNTER)?; + self.interface.data((x >> 3) as u8)?; // 2 Databytes: A[7:0] & 0..A[8] - self.interface.send_command(Command::SET_RAM_Y_ADDRESS_COUNTER)?; - self.interface.send_data(y as u8)?; - self.interface.send_data((y >> 8) as u8)?; + self.interface.command(Command::SET_RAM_Y_ADDRESS_COUNTER)?; + self.interface.data(y as u8)?; + self.interface.data((y >> 8) as u8)?; self.wait_until_idle(); Ok(()) @@ -286,7 +308,7 @@ where fn set_lut_helper(&mut self, buffer: &[u8]) -> Result<(), E> { assert!(buffer.len() == 30); - self.interface.send_command(Command::WRITE_LUT_REGISTER)?; - self.interface.send_multiple_data(buffer) + self.interface.command(Command::WRITE_LUT_REGISTER)?; + self.interface.multiple_data(buffer) } } diff --git a/src/epd4in2/mod.rs b/src/epd4in2/mod.rs index 006294f..94dc0a0 100644 --- a/src/epd4in2/mod.rs +++ b/src/epd4in2/mod.rs @@ -51,7 +51,7 @@ use hal::{ digital::*, }; -use interface::{connection_interface::ConnectionInterface, WaveshareInterface}; +use interface::{connection_interface::ConnectionInterface, WaveshareInterface, InternalWiAdditions}; //The Lookup Tables for the Display mod constants; @@ -67,71 +67,30 @@ use self::command::Command; pub struct EPD4in2 { /// Connection Interface interface: ConnectionInterface, - /// Width - width: u16, - /// Height - height: u16, /// Background Color color: Color, } -impl - WaveshareInterface - for EPD4in2 + + + +impl + InternalWiAdditions + for EPD4in2 where - SPI: Write, + SPI: Write, CS: OutputPin, BUSY: InputPin, - DataCommand: OutputPin, + DC: OutputPin, RST: OutputPin, Delay: DelayUs + DelayMs, { - fn get_width(&self) -> u16 { - self.width - } - - fn get_height(&self) -> u16 { - self.height - } - - /// Creates a new driver from a SPI peripheral, CS Pin, Busy InputPin, DC - /// - /// This already initialises the device. That means [init()](init()) isn't needed directly afterwards - /// - /// # Example - /// - /// ```ignore - /// //buffer = some image data; - /// - /// let mut epd4in2 = EPD4in2::new(spi, cs, busy, dc, rst, delay); - /// - /// epd4in2.display_and_transfer_frame(buffer, None); - /// - /// epd4in2.sleep(); - /// ``` - fn new(interface: ConnectionInterface) -> Result { - let width = WIDTH as u16; - let height = HEIGHT as u16; - - let color = Color::White; - let mut epd = EPD4in2 { - interface, - width, - height, - color, - }; - - epd.init()?; - - Ok(epd) - } - - fn init(&mut self) -> Result<(), SpiError> { + fn init(&mut self) -> Result<(), ERR> { // reset the device - self.reset(); + self.interface.reset(); // set the power settings - self.send_command(Command::POWER_SETTING)?; + self.command(Command::POWER_SETTING)?; self.send_data(0x03)?; //VDS_EN, VDG_EN self.send_data(0x00)?; //VCOM_HV, VGHL_LV[1], VGHL_LV[0] self.send_data(0x2b)?; //VDH @@ -139,17 +98,17 @@ where self.send_data(0xff)?; //VDHR // start the booster - self.send_command(Command::BOOSTER_SOFT_START)?; + self.command(Command::BOOSTER_SOFT_START)?; for _ in 0..3 { self.send_data(0x17)?; //07 0f 17 1f 27 2F 37 2f } // power on - self.send_command(Command::POWER_ON)?; + self.command(Command::POWER_ON)?; self.wait_until_idle(); // set the panel settings - self.send_command(Command::PANEL_SETTING)?; + self.command(Command::PANEL_SETTING)?; // 0x0F Red Mode, LUT from OTP // 0x1F B/W Mode, LUT from OTP // 0x2F Red Mode, LUT set by registers @@ -165,63 +124,97 @@ where // 150Hz and 171Hz wasn't tested yet // TODO: Test these other frequencies // 3A 100HZ 29 150Hz 39 200HZ 31 171HZ DEFAULT: 3c 50Hz - self.send_command(Command::PLL_CONTROL)?; + self.command(Command::PLL_CONTROL)?; self.send_data(0x3A)?; self.set_lut()?; Ok(()) } +} - fn sleep(&mut self) -> Result<(), SpiError> { - self.send_command(Command::VCOM_AND_DATA_INTERVAL_SETTING)?; +impl + WaveshareInterface + for EPD4in2 +where + SPI: Write, + CS: OutputPin, + BUSY: InputPin, + DC: OutputPin, + RST: OutputPin, + Delay: DelayUs + DelayMs, +{ + /// Creates a new driver from a SPI peripheral, CS Pin, Busy InputPin, DC + /// + /// This already initialises the device. That means [init()](init()) isn't needed directly afterwards + /// + /// # Example + /// + /// ```ignore + /// //buffer = some image data; + /// + /// let mut epd4in2 = EPD4in2::new(spi, cs, busy, dc, rst, delay); + /// + /// epd4in2.display_and_transfer_frame(buffer, None); + /// + /// epd4in2.sleep(); + /// ``` + fn new(spi: SPI, cs: CS, busy: BUSY, dc: DC, rst: RST, delay: Delay) -> Result { + + let interface = ConnectionInterface::new(spi, cs, busy, dc, rst, delay); + + let color = Color::White; + let mut epd = EPD4in2 { + interface, + color, + }; + + epd.init()?; + + Ok(epd) + } + + fn wake_up(&mut self) -> Result<(), ERR> { + self.init() + } + + fn sleep(&mut self) -> Result<(), ERR> { + self.command(Command::VCOM_AND_DATA_INTERVAL_SETTING)?; self.send_data(0x17)?; //border floating - self.send_command(Command::VCM_DC_SETTING)?; // VCOM to 0V - self.send_command(Command::PANEL_SETTING)?; + self.command(Command::VCM_DC_SETTING)?; // VCOM to 0V + self.command(Command::PANEL_SETTING)?; self.delay_ms(100); - self.send_command(Command::POWER_SETTING)?; //VG&VS to 0V fast + self.command(Command::POWER_SETTING)?; //VG&VS to 0V fast for _ in 0..4 { self.send_data(0x00)?; } self.delay_ms(100); - self.send_command(Command::POWER_OFF)?; + self.command(Command::POWER_OFF)?; self.wait_until_idle(); - self.send_command(Command::DEEP_SLEEP)?; - self.send_data(0xA5)?; - - Ok(()) - } - - fn reset(&mut self) { - self.interface.reset() - } - - fn delay_ms(&mut self, delay: u16) { - self.interface.delay_ms(delay) + self.interface.command_with_data(Command::DEEP_SLEEP, &[0xA5]) } - fn update_frame(&mut self, buffer: &[u8]) -> Result<(), SpiError> { + fn update_frame(&mut self, buffer: &[u8]) -> Result<(), ERR> { let color_value = self.color.get_byte_value(); self.send_resolution()?; - self.send_command(Command::VCM_DC_SETTING)?; - self.send_data(0x12)?; + self.interface.command_with_data(Command::VCM_DC_SETTING, &[0x12])?; - self.send_command(Command::VCOM_AND_DATA_INTERVAL_SETTING)?; + self.command(Command::VCOM_AND_DATA_INTERVAL_SETTING)?; //TODO: this was a send_command instead of a send_data. check if it's alright and doing what it should do (setting the default values) //self.send_command_u8(0x97)?; //VBDF 17|D7 VBDW 97 VBDB 57 VBDF F7 VBDW 77 VBDB 37 VBDR B7 self.send_data(0x97)?; - self.send_command(Command::DATA_START_TRANSMISSION_1)?; + self.command(Command::DATA_START_TRANSMISSION_1)?; for _ in 0..(buffer.len()) { self.send_data(color_value)?; } self.delay_ms(2); - self.send_command(Command::DATA_START_TRANSMISSION_2)?; + self.command(Command::DATA_START_TRANSMISSION_2)?; //self.send_multiple_data(buffer)?; for &elem in buffer.iter() { @@ -238,14 +231,14 @@ where y: u16, width: u16, height: u16, - ) -> Result<(), SpiError> { + ) -> Result<(), ERR> { if buffer.len() as u16 != width / 8 * height { //TODO: panic!! or sth like that //return Err("Wrong buffersize"); } - self.send_command(Command::PARTIAL_IN)?; - self.send_command(Command::PARTIAL_WINDOW)?; + self.command(Command::PARTIAL_IN)?; + self.command(Command::PARTIAL_WINDOW)?; self.send_data((x >> 8) as u8)?; let tmp = x & 0xf8; self.send_data(tmp as u8)?; // x should be the multiple of 8, the last 3 bit will always be ignored @@ -264,38 +257,32 @@ where //TODO: handle dtm somehow let is_dtm1 = false; if is_dtm1 { - self.send_command(Command::DATA_START_TRANSMISSION_1)? + self.command(Command::DATA_START_TRANSMISSION_1)? } else { - self.send_command(Command::DATA_START_TRANSMISSION_2)? + self.command(Command::DATA_START_TRANSMISSION_2)? } self.send_multiple_data(buffer)?; - self.send_command(Command::PARTIAL_OUT) + self.command(Command::PARTIAL_OUT) } - fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), SpiError> { - self.update_frame(buffer)?; - self.display_frame() - } - fn display_frame(&mut self) -> Result<(), SpiError> { - self.send_command(Command::DISPLAY_REFRESH)?; + + fn display_frame(&mut self) -> Result<(), ERR> { + self.command(Command::DISPLAY_REFRESH)?; self.wait_until_idle(); Ok(()) } - // TODO: add this abstraction function - // fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), E>; - - fn clear_frame(&mut self) -> Result<(), SpiError> { + fn clear_frame(&mut self) -> Result<(), ERR> { self.send_resolution()?; - let size = self.width / 8 * self.height; + let size = WIDTH / 8 * HEIGHT; let color_value = self.color.get_byte_value(); - self.send_command(Command::DATA_START_TRANSMISSION_1)?; + self.command(Command::DATA_START_TRANSMISSION_1)?; self.delay_ms(2); for _ in 0..size { self.send_data(color_value)?; @@ -303,7 +290,7 @@ where self.delay_ms(2); - self.send_command(Command::DATA_START_TRANSMISSION_2)?; + self.command(Command::DATA_START_TRANSMISSION_2)?; self.delay_ms(2); for _ in 0..size { self.send_data(color_value)?; @@ -315,38 +302,55 @@ where fn set_background_color(&mut self, color: Color) { self.color = color; } + + fn background_color(&self) -> &Color { + &self.color + } + + fn get_width(&self) -> u16 { + WIDTH + } + + fn get_height(&self) -> u16 { + HEIGHT + } + + + fn delay_ms(&mut self, delay: u16) { + self.interface.delay_ms(delay) + } } -impl EPD4in2 +impl EPD4in2 where - SPI: Write, + SPI: Write, CS: OutputPin, BUSY: InputPin, DC: OutputPin, RST: OutputPin, D: DelayUs + DelayMs, { - fn send_command(&mut self, command: Command) -> Result<(), SpiError> { - self.interface.send_command(command) + fn command(&mut self, command: Command) -> Result<(), ERR> { + self.interface.command(command) } - fn send_data(&mut self, val: u8) -> Result<(), SpiError> { - self.interface.send_data(val) + fn send_data(&mut self, val: u8) -> Result<(), ERR> { + self.interface.data(val) } - fn send_multiple_data(&mut self, data: &[u8]) -> Result<(), SpiError> { - self.interface.send_multiple_data(data) + fn send_multiple_data(&mut self, data: &[u8]) -> Result<(), ERR> { + self.interface.multiple_data(data) } fn wait_until_idle(&mut self) { self.interface.wait_until_idle(true) } - fn send_resolution(&mut self) -> Result<(), SpiError> { + fn send_resolution(&mut self) -> Result<(), ERR> { let w = self.get_width(); let h = self.get_height(); - self.send_command(Command::RESOLUTION_SETTING)?; + self.command(Command::RESOLUTION_SETTING)?; self.send_data((w >> 8) as u8)?; self.send_data(w as u8)?; self.send_data((h >> 8) as u8)?; @@ -355,7 +359,7 @@ where /// Fill the look-up table for the EPD //TODO: make public? - fn set_lut(&mut self) -> Result<(), SpiError> { + fn set_lut(&mut self) -> Result<(), ERR> { self.set_lut_helper(&LUT_VCOM0, &LUT_WW, &LUT_BW, &LUT_WB, &LUT_BB) } @@ -364,7 +368,7 @@ where /// Is automatically done by [EPD4in2::display_frame_quick()](EPD4in2::display_frame_quick()) /// //TODO: make public? #[cfg(feature = "epd4in2_fast_update")] - fn set_lut_quick(&mut self) -> Result<(), SpiError> { + fn set_lut_quick(&mut self) -> Result<(), ERR> { self.set_lut_helper( &LUT_VCOM0_QUICK, &LUT_WW_QUICK, @@ -381,25 +385,25 @@ where lut_bw: &[u8], lut_wb: &[u8], lut_bb: &[u8], - ) -> Result<(), SpiError> { + ) -> Result<(), ERR> { // LUT VCOM - self.send_command(Command::LUT_FOR_VCOM)?; + self.command(Command::LUT_FOR_VCOM)?; self.send_multiple_data(lut_vcom)?; // LUT WHITE to WHITE - self.send_command(Command::LUT_WHITE_TO_WHITE)?; + self.command(Command::LUT_WHITE_TO_WHITE)?; self.send_multiple_data(lut_ww)?; // LUT BLACK to WHITE - self.send_command(Command::LUT_BLACK_TO_WHITE)?; + self.command(Command::LUT_BLACK_TO_WHITE)?; self.send_multiple_data(lut_bw)?; // LUT WHITE to BLACK - self.send_command(Command::LUT_WHITE_TO_BLACK)?; + self.command(Command::LUT_WHITE_TO_BLACK)?; self.send_multiple_data(lut_wb)?; // LUT BLACK to BLACK - self.send_command(Command::LUT_BLACK_TO_BLACK)?; + self.command(Command::LUT_BLACK_TO_BLACK)?; self.send_multiple_data(lut_bb)?; Ok(()) diff --git a/src/interface/connection_interface.rs b/src/interface/connection_interface.rs index 92b0dd3..f825807 100644 --- a/src/interface/connection_interface.rs +++ b/src/interface/connection_interface.rs @@ -7,7 +7,7 @@ use interface::Command; /// The Connection Interface of all (?) Waveshare EPD-Devices /// -pub struct ConnectionInterface { +pub(crate) struct ConnectionInterface { /// SPI spi: SPI, /// CS for SPI @@ -22,17 +22,17 @@ pub struct ConnectionInterface { delay: D, } -impl - ConnectionInterface +impl + ConnectionInterface where - SPI: Write, + SPI: Write, CS: OutputPin, BUSY: InputPin, - DataCommand: OutputPin, + DC: OutputPin, RST: OutputPin, Delay: DelayUs + DelayMs, { - pub fn new(spi: SPI, cs: CS, busy: BUSY, dc: DataCommand, rst: RST, delay: Delay) -> Self { + pub fn new(spi: SPI, cs: CS, busy: BUSY, dc: DC, rst: RST, delay: Delay) -> Self { ConnectionInterface { spi, cs, @@ -45,10 +45,10 @@ where /// Basic function for sending [Commands](Command). /// - /// Enables direct interaction with the device with the help of [send_data()](ConnectionInterface::send_data()) - /// Should rarely be needed! + /// Enables direct interaction with the device with the help of [data()](ConnectionInterface::data()) + /// /// //TODO: make public? - pub(crate) fn send_command(&mut self, command: T) -> Result<(), ErrorSpeziale> { + pub(crate) fn command(&mut self, command: T) -> Result<(), ERR> { // low for commands self.dc.set_low(); @@ -58,11 +58,10 @@ where /// Basic function for sending a single u8 of data over spi /// - /// Enables direct interaction with the device with the help of [Esend_command()](ConnectionInterface::send_command()) - /// - /// Should rarely be needed! + /// Enables direct interaction with the device with the help of [Ecommand()](ConnectionInterface::command()) + /// /// //TODO: make public? - pub(crate) fn send_data(&mut self, val: u8) -> Result<(), ErrorSpeziale> { + pub(crate) fn data(&mut self, val: u8) -> Result<(), ERR> { // high for data self.dc.set_high(); @@ -70,17 +69,24 @@ where self.with_cs(|epd| epd.spi.write(&[val])) } - /// Basic function for sending a single u8 of data over spi - /// - /// Enables direct interaction with the device with the help of [Esend_command()](ConnectionInterface::send_command()) + /// Basic function for sending [Commands](Command) and the data belonging to it. + /// + /// //TODO: make public? + pub(crate) fn command_with_data(&mut self, command: T, data: &[u8]) -> Result<(), ERR> { + self.command(command)?; + self.multiple_data(data) + } + + /// Basic function for sending the same byte of data (one u8) multiple times over spi /// - /// Should rarely be needed! + /// Enables direct interaction with the device with the help of [command()](ConnectionInterface::command()) + /// /// //TODO: make public? - pub(crate) fn send_data_x_times( + pub(crate) fn data_x_times( &mut self, val: u8, repetitions: u16, - ) -> Result<(), ErrorSpeziale> { + ) -> Result<(), ERR> { // high for data self.dc.set_high(); @@ -95,11 +101,10 @@ where /// Basic function for sending an array of u8-values of data over spi /// - /// Enables direct interaction with the device with the help of [send_command()](EPD4in2::send_command()) - /// - /// Should rarely be needed! + /// Enables direct interaction with the device with the help of [command()](EPD4in2::command()) + /// /// //TODO: make public? - pub(crate) fn send_multiple_data(&mut self, data: &[u8]) -> Result<(), ErrorSpeziale> { + pub(crate) fn multiple_data(&mut self, data: &[u8]) -> Result<(), ERR> { // high for data self.dc.set_high(); @@ -108,9 +113,9 @@ where } // spi write helper/abstraction function - pub(crate) fn with_cs(&mut self, f: F) -> Result<(), ErrorSpeziale> + fn with_cs(&mut self, f: F) -> Result<(), ERR> where - F: FnOnce(&mut Self) -> Result<(), ErrorSpeziale>, + F: FnOnce(&mut Self) -> Result<(), ERR>, { // activate spi with cs low self.cs.set_low(); @@ -134,6 +139,7 @@ where /// - FALSE for epd2in9, epd1in54 (for all Display Type A ones?) /// /// Most likely there was a mistake with the 2in9 busy connection + /// //TODO: use the #cfg feature to make this compile the right way for the certain types pub(crate) fn wait_until_idle(&mut self, is_busy_low: bool) { self.delay_ms(1); //low: busy, high: idle @@ -158,7 +164,7 @@ where pub(crate) fn reset(&mut self) { self.rst.set_low(); - //TODO: why 200ms? (besides being in the waveshare code) + //TODO: why 200ms? (besides being in the arduino version) self.delay_ms(200); self.rst.set_high(); diff --git a/src/interface/mod.rs b/src/interface/mod.rs index 8b29d9a..a3158a5 100644 --- a/src/interface/mod.rs +++ b/src/interface/mod.rs @@ -7,8 +7,7 @@ use hal::{ use drawing::color::Color; /// Interface for the physical connection between display and the controlling device -pub mod connection_interface; -use self::connection_interface::ConnectionInterface; +pub(crate) mod connection_interface; /// All commands need to have this trait which gives the address of the command /// which needs to be send via SPI with activated CommandsPin (Data/Command Pin in CommandMode) @@ -18,58 +17,111 @@ pub(crate) trait Command { //TODO: add LUT trait with set_fast_lut and set_manual_lut and set_normal_lut or sth like that? // for partial updates -trait LUTSupport { - fn set_lut(&mut self) -> Result<(), Error>; - fn set_lut_quick(&mut self) -> Result<(), Error>; - fn set_lut_manual(&mut self, data: &[u8]) -> Result<(), Error>; +trait LUTSupport { + fn set_lut(&mut self) -> Result<(), ERR>; + fn set_lut_quick(&mut self) -> Result<(), ERR>; + fn set_lut_manual(&mut self, data: &[u8]) -> Result<(), ERR>; } -pub trait WaveshareInterface +pub(crate) trait InternalWiAdditions where SPI: Write, CS: OutputPin, BUSY: InputPin, - DataCommand: OutputPin, + DC: OutputPin, RST: OutputPin, Delay: DelayUs + DelayMs, { - /// Get the width of the display - fn get_width(&self) -> u16; + /// This initialises the EPD and powers it up + /// + /// This function is already called from + /// - [new()](WaveshareInterface::new()) + /// - [`wake_up`] + /// + /// + /// This function calls [reset()](WaveshareInterface::reset()), + /// so you don't need to call reset your self when trying to wake your device up + /// after setting it to sleep. + fn init(&mut self) -> Result<(), ERR>; +} - /// Get the height of the display - fn get_height(&self) -> u16; + +pub trait WaveshareInterface +where + SPI: Write, + CS: OutputPin, + BUSY: InputPin, + DC: OutputPin, + RST: OutputPin, + Delay: DelayUs + DelayMs, +{ + /// Creates a new driver from a SPI peripheral, CS Pin, Busy InputPin, DC /// /// This already initialises the device. That means [init()](WaveshareInterface::init()) isn't needed directly afterwards fn new( - interface: ConnectionInterface, - ) -> Result + spi: SPI, cs: CS, busy: BUSY, dc: DC, rst: RST, delay: Delay, + ) -> Result where Self: Sized; - /// This initialises the EPD and powers it up + // TODO: add this abstraction function + /// Loads a full image on the EPD and displays it + fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), ERR> { + self.update_frame(buffer)?; + self.display_frame() + } + + /// Loads a partial image on the EPD and displays it + fn update_and_display_partial_frame( + &mut self, + buffer: &[u8], + x: u16, + y: u16, + width: u16, + height: u16, + ) -> Result<(), ERR> { + self.update_partial_frame(buffer, x, y, width, height)?; + self.display_frame() + } + + /// Let the device enter deep-sleep mode to save power. /// - /// This function is already called from [new()](WaveshareInterface::new()) + /// The deep sleep mode returns to standby with a hardware reset. + /// But you can also use [reset()](WaveshareInterface::reset()) to awaken. + /// But as you need to power it up once more anyway you can also just directly use [init()](WaveshareInterface::init()) for resetting + /// and initialising which already contains the reset + fn sleep(&mut self) -> Result<(), ERR>; + + fn wake_up(&mut self) -> Result<(), ERR>; + + + /// Sets the backgroundcolor for various commands like [clear_frame()](WaveshareInterface::clear_frame()) + fn set_background_color(&mut self, color: Color); + + /// Get current background color + fn background_color(&self) -> &Color; + + /// Get the width of the display + fn get_width(&self) -> u16; + + /// Get the height of the display + fn get_height(&self) -> u16; + + /// Abstraction of setting the delay for simpler calls /// - /// This function calls [reset()](WaveshareInterface::reset()), - /// so you don't need to call reset your self when trying to wake your device up - /// after setting it to sleep. - fn init(&mut self) -> Result<(), Error>; + /// maximum delay ~65 seconds (u16:max in ms) + fn delay_ms(&mut self, delay: u16); // void DisplayFrame(const unsigned char* frame_buffer); /// Transmit a full frame to the SRAM of the DPD /// - fn update_frame(&mut self, buffer: &[u8]) -> Result<(), Error>; + fn update_frame(&mut self, buffer: &[u8]) -> Result<(), ERR>; - //TODO: is dtm always used? - /// Transmit partial data to the SRAM of the EPD, - /// the final parameter dtm chooses between the 2 - /// internal buffers - /// - /// Normally it should be dtm2, so use false + /// Transmits partial data to the SRAM of the EPD /// - /// BUFFER needs to be of size: w / 8 * l ! + /// BUFFER needs to be of size: w / 8 * h ! fn update_partial_frame( &mut self, buffer: &[u8], @@ -77,37 +129,14 @@ where y: u16, width: u16, height: u16, - ) -> Result<(), Error>; + ) -> Result<(), ERR>; /// Displays the frame data from SRAM - fn display_frame(&mut self) -> Result<(), Error>; - - // TODO: add this abstraction function - fn update_and_display_frame(&mut self, buffer: &[u8]) -> Result<(), Error>; + fn display_frame(&mut self) -> Result<(), ERR>; - /// Clears the frame from the buffer + /// Clears the frame from the buffer with the declared background color + /// The background color can be changed with [`set_background_color`] /// /// Uses the chosen background color - fn clear_frame(&mut self) -> Result<(), Error>; - - /// Sets the backgroundcolor for various commands like [clear_frame()](WaveshareInterface::clear_frame()) - fn set_background_color(&mut self, color: Color); - - /// Let the device enter deep-sleep mode to save power. - /// - /// The deep sleep mode returns to standby with a hardware reset. - /// But you can also use [reset()](WaveshareInterface::reset()) to awaken. - /// But as you need to power it up once more anyway you can also just directly use [init()](WaveshareInterface::init()) for resetting - /// and initialising which already contains the reset - fn sleep(&mut self) -> Result<(), Error>; - - /// Resets the device. - /// - /// Often used to awake the module from deep sleep. See [sleep()](WaveshareInterface::sleep()) - fn reset(&mut self); - - /// Abstraction of setting the delay for simpler calls - /// - /// maximum delay ~65 seconds (u16:max in ms) - fn delay_ms(&mut self, delay: u16); + fn clear_frame(&mut self) -> Result<(), ERR>; }