diff --git a/src/epd2in9/command.rs b/src/epd2in9/command.rs index c81bd79..63d4da1 100644 --- a/src/epd2in9/command.rs +++ b/src/epd2in9/command.rs @@ -1,6 +1,6 @@ -//! SPI Commands for the Waveshare 4.2" E-Ink Display +//! SPI Commands for the Waveshare 2.9" E-Ink Display -/// EPD4IN2 commands +/// EPD2IN9 commands /// /// Should rarely (never?) be needed directly. /// @@ -10,138 +10,31 @@ #[allow(dead_code)] #[allow(non_camel_case_types)] #[derive(Copy, Clone)] -pub enum Command { - /// Set Resolution, LUT selection, BWR pixels, gate scan direction, source shift direction, booster switch, soft reset - PANEL_SETTING = 0x00, - /// selecting internal and external power - POWER_SETTING = 0x01, - /// After the Power Off command, the driver will power off following the Power Off Sequence. This command will turn off charge - /// pump, T-con, source driver, gate driver, VCOM, and temperature sensor, but register data will be kept until VDD becomes OFF. - /// Source Driver output and Vcom will remain as previous condition, which may have 2 conditions: floating. - POWER_OFF = 0x02, - /// Setting Power OFF sequence - POWER_OFF_SEQUENCE_SETTING = 0x03, - /// Turning On the Power - POWER_ON = 0x04, - /// This command enables the internal bandgap, which will be cleared by the next POF. - POWER_ON_MEASURE = 0x05, - /// Starting data transmission - BOOSTER_SOFT_START = 0x06, - /// After this command is transmitted, the chip would enter the deep-sleep mode to save power. - /// - /// The deep sleep mode would return to standby by hardware reset. - /// - /// The only one parameter is a check code, the command would be excuted if check code = 0xA5. - DEEP_SLEEP = 0x07, - /// This command starts transmitting data and write them into SRAM. To complete data transmission, command DSP (Data - /// transmission Stop) must be issued. Then the chip will start to send data/VCOM for panel. - /// - /// - In B/W mode, this command writes “OLD” data to SRAM. - /// - In B/W/Red mode, this command writes “B/W” data to SRAM. - /// - In Program mode, this command writes “OTP” data to SRAM for programming. - DATA_START_TRANSMISSION_1 = 0x10, - /// Stopping data transmission - DATA_STOP = 0x11, - /// While user sent this command, driver will refresh display (data/VCOM) according to SRAM data and LUT. - /// - /// After Display Refresh command, BUSY_N signal will become “0” and the refreshing of panel starts. - DISPLAY_REFRESH = 0x12, - /// This command starts transmitting data and write them into SRAM. To complete data transmission, command DSP (Data - /// transmission Stop) must be issued. Then the chip will start to send data/VCOM for panel. - /// - In B/W mode, this command writes “NEW” data to SRAM. - /// - In B/W/Red mode, this command writes “RED” data to SRAM. - DATA_START_TRANSMISSION_2 = 0x13, - - /// This command stores VCOM Look-Up Table with 7 groups of data. Each group contains information for one state and is stored - /// with 6 bytes, while the sixth byte indicates how many times that phase will repeat. - /// - /// from IL0373 - LUT_FOR_VCOM = 0x20, - /// This command stores White-to-White Look-Up Table with 7 groups of data. Each group contains information for one state and is - /// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat. - /// - /// from IL0373 - LUT_WHITE_TO_WHITE = 0x21, - /// This command stores Black-to-White Look-Up Table with 7 groups of data. Each group contains information for one state and is - /// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat. - /// - /// from IL0373 - LUT_BLACK_TO_WHITE = 0x22, - /// This command stores White-to-Black Look-Up Table with 7 groups of data. Each group contains information for one state and is - /// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat. - /// - /// from IL0373 - LUT_WHITE_TO_BLACK = 0x23, - /// This command stores Black-to-Black Look-Up Table with 7 groups of data. Each group contains information for one state and is - /// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat. - /// - /// from IL0373 - LUT_BLACK_TO_BLACK = 0x24, - /// The command controls the PLL clock frequency. - PLL_CONTROL = 0x30, - /// This command reads the temperature sensed by the temperature sensor. - /// - /// Doesn't work! Waveshare doesn't connect the read pin - TEMPERATURE_SENSOR_COMMAND = 0x40, - /// Selects the Internal or External temperature sensor and offset - TEMPERATURE_SENSOR_SELECTION = 0x41, - /// Write External Temperature Sensor - TEMPERATURE_SENSOR_WRITE = 0x42, - /// Read External Temperature Sensor - /// - /// Doesn't work! Waveshare doesn't connect the read pin - TEMPERATURE_SENSOR_READ = 0x43, - /// This command indicates the interval of Vcom and data output. When setting the vertical back porch, the total blanking will be kept (20 Hsync) - VCOM_AND_DATA_INTERVAL_SETTING = 0x50, - /// This command indicates the input power condition. Host can read this flag to learn the battery condition. - LOW_POWER_DETECTION = 0x51, - /// This command defines non-overlap period of Gate and Source. - TCON_SETTING = 0x60, - /// This command defines alternative resolution and this setting is of higher priority than the RES[1:0] in R00H (PSR). - RESOLUTION_SETTING = 0x61, - /// This command defines the Fist Active Gate and First Active Source of active channels. - GSST_SETTING = 0x65, - /// The LUT_REV / Chip Revision is read from OTP address = 0x001. - /// - /// Doesn't work! Waveshare doesn't connect the read pin - REVISION = 0x70, - /// Read Flags. This command reads the IC status - /// PTL, I2C_ERR, I2C_BUSY, DATA, PON, POF, BUSY - /// - /// Doesn't work! Waveshare doesn't connect the read pin - GET_STATUS = 0x71, - /// Automatically measure VCOM. This command reads the IC status - AUTO_MEASUREMENT_VCOM = 0x80, - /// This command gets the VCOM value - /// - /// Doesn't work! Waveshare doesn't connect the read pin - READ_VCOM_VALUE = 0x81, - /// Set VCM_DC - VCM_DC_SETTING = 0x82, - /// This command sets partial window - PARTIAL_WINDOW = 0x90, - /// This command makes the display enter partial mode - PARTIAL_IN = 0x91, - /// This command makes the display exit partial mode and enter normal mode - PARTIAL_OUT = 0x92, - /// After this command is issued, the chip would enter the program mode. - /// - /// After the programming procedure completed, a hardware reset is necessary for leaving program mode. - /// - /// The only one parameter is a check code, the command would be excuted if check code = 0xA5. - PROGRAM_MODE = 0xA0, - /// After this command is transmitted, the programming state machine would be activated. - /// - /// The BUSY flag would fall to 0 until the programming is completed. - ACTIVE_PROGRAMMING = 0xA1, - /// The command is used for reading the content of OTP for checking the data of programming. - /// - /// The value of (n) is depending on the amount of programmed data, tha max address = 0xFFF. - READ_OTP = 0xA2, - /// This command is set for saving power during fresh period. If the output voltage of VCOM / Source is from negative to positive or - /// from positive to negative, the power saving mechanism will be activated. The active period width is defined by the following two - /// parameters. - POWER_SAVING = 0xE3, +pub(crate) enum Command { + /// Driver Output control + /// 3 Databytes: + /// A[7:0] + /// 0.. A[8] + /// 0.. B[2:0] + /// Default: Set A[8:0] = 0x127 and B[2:0] = 0x0 + DRIVER_OUTPUT_CONTROL = 0x01, + /// Booster Soft start control + /// 3 Databytes: + /// 1.. A[6:0] + /// 1.. B[6:0] + /// 1.. C[6:0] + /// Default: A[7:0] = 0xCF, B[7:0] = 0xCE, C[7:0] = 0x8D + BOOSTER_SOFT_START_CONTROL = 0x0C, + //TODO: useful? + // GATE_SCAN_START_POSITION = 0x0F, + /// Deep Sleep Mode Control + /// 1 Databyte: + /// 0.. A[0] + /// Values: + /// A[0] = 0: Normal Mode (POR) + /// A[0] = 1: Enter Deep Sleep Mode + DEEP_SLEEP_MODE = 0x10, + // /// Data Entry mode setting } @@ -160,10 +53,10 @@ mod tests { #[test] fn command_addr() { - assert_eq!(Command::POWER_SAVING.addr(), 0xE3); + //assert_eq!(Command::POWER_SAVING.addr(), 0xE3); - assert_eq!(Command::PANEL_SETTING.addr(), 0x00); + //assert_eq!(Command::PANEL_SETTING.addr(), 0x00); - assert_eq!(Command::DISPLAY_REFRESH.addr(), 0x12); + //assert_eq!(Command::DISPLAY_REFRESH.addr(), 0x12); } } \ No newline at end of file diff --git a/src/epd2in9/constants.rs b/src/epd2in9/constants.rs new file mode 100644 index 0000000..d9f65e0 --- /dev/null +++ b/src/epd2in9/constants.rs @@ -0,0 +1,17 @@ +pub(crate) const WIDTH: usize = 128; +pub(crate) const HEIGHT: usize = 296; + +// Original Waveforms from Waveshare +pub(crate) const LUT_FULL_UPDATE: [u8; 30] =[ + 0x02, 0x02, 0x01, 0x11, 0x12, 0x12, 0x22, 0x22, + 0x66, 0x69, 0x69, 0x59, 0x58, 0x99, 0x99, 0x88, + 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB4, 0x13, 0x51, + 0x35, 0x51, 0x51, 0x19, 0x01, 0x00 +]; + +pub(crate) const LUT_PARTIAL_UPDATE: [u8; 30] =[ + 0x10, 0x18, 0x18, 0x08, 0x18, 0x18, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +]; \ No newline at end of file diff --git a/src/epd2in9/lut.rs b/src/epd2in9/lut.rs deleted file mode 100644 index 55c7d39..0000000 --- a/src/epd2in9/lut.rs +++ /dev/null @@ -1,102 +0,0 @@ -pub(crate) const LUT_VCOM0: [u8; 44] = [ -0x00, 0x17, 0x00, 0x00, 0x00, 0x02, -0x00, 0x17, 0x17, 0x00, 0x00, 0x02, -0x00, 0x0A, 0x01, 0x00, 0x00, 0x01, -0x00, 0x0E, 0x0E, 0x00, 0x00, 0x02, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -]; - -pub(crate) const LUT_VCOM0_QUICK: [u8; 44] = [ -0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -]; - -pub(crate) const LUT_WW: [u8; 42] =[ -0x40, 0x17, 0x00, 0x00, 0x00, 0x02, -0x90, 0x17, 0x17, 0x00, 0x00, 0x02, -0x40, 0x0A, 0x01, 0x00, 0x00, 0x01, -0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -]; - -pub(crate) const LUT_WW_QUICK: [u8; 42] =[ -0xA0, 0x0E, 0x00, 0x00, 0x00, 0x01, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -]; - - -pub(crate) const LUT_BW: [u8; 42] =[ -0x40, 0x17, 0x00, 0x00, 0x00, 0x02, -0x90, 0x17, 0x17, 0x00, 0x00, 0x02, -0x40, 0x0A, 0x01, 0x00, 0x00, 0x01, -0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -]; - -pub(crate) const LUT_BW_QUICK: [u8; 42] =[ -0xA0, 0x0E, 0x00, 0x00, 0x00, 0x01, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -]; - - -pub(crate) const LUT_BB: [u8; 42] =[ -0x80, 0x17, 0x00, 0x00, 0x00, 0x02, -0x90, 0x17, 0x17, 0x00, 0x00, 0x02, -0x80, 0x0A, 0x01, 0x00, 0x00, 0x01, -0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -]; - -pub(crate) const LUT_BB_QUICK: [u8; 42] =[ -0x50, 0x0E, 0x00, 0x00, 0x00, 0x01, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -]; - - -pub(crate) const LUT_WB: [u8; 42] =[ -0x80, 0x17, 0x00, 0x00, 0x00, 0x02, -0x90, 0x17, 0x17, 0x00, 0x00, 0x02, -0x80, 0x0A, 0x01, 0x00, 0x00, 0x01, -0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -]; - -pub(crate) const LUT_WB_QUICK: [u8; 42] =[ -0x50, 0x0E, 0x00, 0x00, 0x00, 0x01, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -]; \ No newline at end of file diff --git a/src/epd2in9/mod.rs b/src/epd2in9/mod.rs index 3f53d9a..cb7f79c 100644 --- a/src/epd2in9/mod.rs +++ b/src/epd2in9/mod.rs @@ -57,54 +57,108 @@ use hal::{ digital::* }; -//The Lookup Tables for the Display -mod lut; -use self::lut::*; +mod constants; +use self::constants::*; use drawing::color::Color; pub mod command; pub use command::Command as Command; -//TODO: test spi mode -/// SPI mode - -/// For more infos see [Requirements: SPI](index.html#spi) -pub const SPI_MODE: Mode = Mode { - phase: Phase::CaptureOnFirstTransition, - polarity: Polarity::IdleLow, -}; +use interface::*; + +use interface::data_interface::DataInterface; + +/// EPD4in2 driver +/// +pub struct EPD2in9 { + /// SPI + interface: DataInterface, + /// Width + width: u32, + /// Height + height: u32, +} + + +impl EPD2in9 +where + SPI: Write, + CS: OutputPin, + BUSY: InputPin, + DC: OutputPin, + RST: OutputPin, + D: DelayUs + DelayMs +{ + +} +impl WaveshareInterface for EPD2in9 +where + SPI: Write, + CS: OutputPin, + BUSY: InputPin, + DC: OutputPin, + RST: OutputPin, + D: DelayUs + DelayMs, +{ + fn get_width(&self) -> u32 { + self.width + } + + fn get_height(&self) -> u32 { + self.height + } + fn new( + spi: SPI, + cs: CS, + busy: BUSY, + dc: DC, + rst: RST, + delay: D + ) -> Result { + let width = WIDTH as u32; + let height = HEIGHT as u32; + let mut interface = DataInterface::new(spi, cs, busy, dc, rst, delay); + let mut epd = EPD2in9 {interface, width, height}; + epd.init()?; + + Ok(epd) + } + + + + fn init(&mut self) -> Result<(), E> { + //TODO: + Ok(()) + } + fn sleep(&mut self) -> Result<(), E> { + Ok(()) + } + fn reset(&mut self) { + //TODO: + } + fn wait_until_idle(&mut self) { + + } + fn delay_ms(&mut self, delay: u32) { + + } -/// EPD4in2 driver -/// -pub struct EPD4in2 { - /// SPI - spi: SPI, - /// CS for SPI - cs: CS, - /// Low for busy, Wait until display is ready! - busy: BUSY, - /// Data/Command Control Pin (High for data, Low for command) - dc: DC, - /// Pin for Reseting - rst: RST, - /// The concrete Delay implementation - delay: D, - /// Width - width: u16, - /// Height - height: u16, } -impl EPD4in2 +/* + + +impl EPD2in9 where SPI: Write, CS: OutputPin, @@ -141,8 +195,8 @@ where /// ``` pub fn new(spi: SPI, cs: CS, busy: BUSY, dc: DC, rst: RST, delay: D) -> Result { //TODO: width und height anpassbar machen? - let width = 400; - let height = 300; + let width = WIDTH as u16; + let height = HEIGHT as u16; let mut epd4in2 = EPD4in2 {spi, cs, busy, dc, rst, delay, width, height }; @@ -390,22 +444,7 @@ where Ok(()) } - /// Resets the device. - /// - /// Often used to awake the module from deep sleep. See [EPD4in2::sleep()](EPD4in2::sleep()) - /// - /// TODO: Takes at least 400ms of delay alone, can it be shortened? - pub fn reset(&mut self) { - self.rst.set_low(); - - //TODO: why 200ms? (besides being in the waveshare code) - self.delay_ms(200); - self.rst.set_high(); - - //TODO: same as 3 lines above - self.delay_ms(200); - } @@ -463,89 +502,12 @@ where Ok(()) } - /// Basic function for sending [Commands](Command). - /// - /// Enables direct interaction with the device with the help of [EPD4in2::send_data()](EPD4in2::send_data()) - /// Should rarely be needed! - /// //TODO: make public? - fn send_command(&mut self, command: Command) -> Result<(), E> { - // low for commands - self.dc.set_low(); - - // Transfer the command over spi - self.with_cs(|epd| { - epd.spi.write(&[command.addr()]) - }) - } - - /// Basic function for sending a single u8 of data over spi - /// - /// Enables direct interaction with the device with the help of [EPD4in2::send_command()](EPD4in2::send_command()) - /// - /// Should rarely be needed! - /// //TODO: make public? - fn send_data(&mut self, val: u8) -> Result<(), E> { - // high for data - self.dc.set_high(); - - // Transfer data (u8) over spi - self.with_cs(|epd| { - epd.spi.write(&[val]) - }) - } - - /// Basic function for sending an array of u8-values of data over spi - /// - /// Enables direct interaction with the device with the help of [EPD4in2::send_command()](EPD4in2::send_command()) - /// - /// Should rarely be needed! - /// //TODO: make public? - fn send_multiple_data(&mut self, data: &[u8]) -> Result<(), E> { - // high for data - self.dc.set_high(); - - // Transfer data (u8-array) over spi - self.with_cs(|epd| { - epd.spi.write(data) - }) - } - - // spi write helper/abstraction function - fn with_cs(&mut self, f: F) -> Result<(), E> - where - F: FnOnce(&mut Self) -> Result<(), E>, - { - // activate spi with cs low - self.cs.set_low(); - // transfer spi data - let result = f(self); - // deativate spi with cs high - self.cs.set_high(); - // return result - result - } - - /// Waits until device isn't busy anymore (busy == HIGH) - /// - /// This is normally handled by the more complicated commands themselves, - /// but in the case you send data and commands directly you might need to check - /// if the device is still busy - pub fn wait_until_idle(&mut self) { - //low: busy, high: idle - while self.busy.is_low() { - //TODO: shorten the time? it was 100 in the beginning - self.delay_ms(10); - } - } +} - /// Abstraction of setting the delay for simpler calls - pub fn delay_ms(&mut self, delay: u16) { - self.delay.delay_ms(delay); - } -} +*/ diff --git a/src/interface/data_interface.rs b/src/interface/data_interface.rs new file mode 100644 index 0000000..1fd39b8 --- /dev/null +++ b/src/interface/data_interface.rs @@ -0,0 +1,142 @@ +use hal::{ + blocking::{ + spi::Write, + delay::* + }, + spi::{Mode, Phase, Polarity}, + digital::* +}; + +use interface::Command; + +/// EPD4in2 driver +/// +pub struct DataInterface { + /// SPI + spi: SPI, + /// CS for SPI + cs: CS, + /// Low for busy, Wait until display is ready! + busy: BUSY, + /// Data/Command Control Pin (High for data, Low for command) + dc: DC, + /// Pin for Reseting + rst: RST, + /// The concrete Delay implementation + delay: D, +} + + +impl DataInterface +where + SPI: Write, + CS: OutputPin, + BUSY: InputPin, + DC: OutputPin, + RST: OutputPin, + D: DelayUs + DelayMs, +{ + pub fn new(spi: SPI, cs: CS, busy: BUSY, dc: DC, rst: RST, delay: D) -> Self { + DataInterface {spi, cs, busy, dc, rst, delay } + } + + /// Basic function for sending [Commands](Command). + /// + /// Enables direct interaction with the device with the help of [EPD4in2::send_data()](EPD4in2::send_data()) + /// Should rarely be needed! + /// //TODO: make public? + fn send_command(&mut self, command: T) -> Result<(), E> { + // low for commands + self.dc.set_low(); + + // Transfer the command over spi + self.with_cs(|epd| { + epd.spi.write(&[command.address()]) + }) + } + + /// Basic function for sending a single u8 of data over spi + /// + /// Enables direct interaction with the device with the help of [EPD4in2::send_command()](EPD4in2::send_command()) + /// + /// Should rarely be needed! + /// //TODO: make public? + fn send_data(&mut self, val: u8) -> Result<(), E> { + // high for data + self.dc.set_high(); + + // Transfer data (u8) over spi + self.with_cs(|epd| { + epd.spi.write(&[val]) + }) + } + + /// Basic function for sending an array of u8-values of data over spi + /// + /// Enables direct interaction with the device with the help of [EPD4in2::send_command()](EPD4in2::send_command()) + /// + /// Should rarely be needed! + /// //TODO: make public? + fn send_multiple_data(&mut self, data: &[u8]) -> Result<(), E> { + // high for data + self.dc.set_high(); + + // Transfer data (u8-array) over spi + self.with_cs(|epd| { + epd.spi.write(data) + }) + } + + // spi write helper/abstraction function + fn with_cs(&mut self, f: F) -> Result<(), E> + where + F: FnOnce(&mut Self) -> Result<(), E>, + { + // activate spi with cs low + self.cs.set_low(); + // transfer spi data + let result = f(self); + // deativate spi with cs high + self.cs.set_high(); + // return result + result + } + + + /// Waits until device isn't busy anymore (busy == HIGH) + /// + /// This is normally handled by the more complicated commands themselves, + /// but in the case you send data and commands directly you might need to check + /// if the device is still busy + pub fn wait_until_idle(&mut self) { + //low: busy, high: idle + while self.busy.is_low() { + //TODO: shorten the time? it was 100 in the beginning + self.delay_ms(10); + } + } + + + /// Abstraction of setting the delay for simpler calls + pub fn delay_ms(&mut self, delay: u16) { + self.delay.delay_ms(delay); + } + + /// Resets the device. + /// + /// Often used to awake the module from deep sleep. See [EPD4in2::sleep()](EPD4in2::sleep()) + /// + /// TODO: Takes at least 400ms of delay alone, can it be shortened? + pub fn reset(&mut self) { + self.rst.set_low(); + + //TODO: why 200ms? (besides being in the waveshare code) + self.delay_ms(200); + + self.rst.set_high(); + + //TODO: same as 3 lines above + self.delay_ms(200); + } + +} \ No newline at end of file diff --git a/src/interface/mod.rs b/src/interface/mod.rs new file mode 100644 index 0000000..548033f --- /dev/null +++ b/src/interface/mod.rs @@ -0,0 +1,105 @@ +use hal::{ + blocking::{ + spi::Write, + delay::* + }, + spi::{Mode, Phase, Polarity}, + digital::* +}; + +pub mod data_interface; + +//TODO: test spi mode +/// SPI mode - +/// For more infos see [Requirements: SPI](index.html#spi) +pub const SPI_MODE: Mode = Mode { + phase: Phase::CaptureOnFirstTransition, + polarity: Polarity::IdleLow, +}; + +use core::marker::Sized; + +pub(crate) trait Command { + fn address(&self) -> u8; +} + +pub trait WaveshareInterface + where + SPI: Write, + CS: OutputPin, + BUSY: InputPin, + DC: OutputPin, + RST: OutputPin, + D: DelayUs + DelayMs, +{ + /// Get the width of the display + fn get_width(&self) -> u32; + fn get_height(&self) -> u32; + fn new( + spi: SPI, + cs: CS, + busy: BUSY, + dc: DC, + rst: RST, + delay: D + ) -> Result + where Self: Sized; + fn init(&mut self) -> Result<(), E>; + fn sleep(&mut self) -> Result<(), E>; + fn reset(&mut self); + fn wait_until_idle(&mut self); + fn delay_ms(&mut self, delay: u32); + + /* + fn clear_frame(&mut self, reset_color: Option) -> Result<(), E> + + fn display_frame_quick(&mut self) -> Result<(), E> + + fn display_frame(&mut self) -> Result<(), E> + + pub fn display_and_transfer_frame( + &mut self, + buffer: &[u8], + color: Option +) -> Result<(), E> + + pub fn set_partial_window( + &mut self, + buffer: &[u8], + x: u16, + y: u16, + w: u16, + l: u16, + is_dtm1: bool +) -> Result<(), E> + +*/ + +} + + +pub trait TestInterface +{ + fn get_width(&self) -> u32; + fn get_height(&self) -> u32; + + +} + +struct testStruct { + width: u32, + height: u32, +} + +impl TestInterface for testStruct { + fn get_width(&self) -> u32 { + self.width + } + + fn get_height(&self) -> u32 { + self.height + } + + +} + diff --git a/src/lib.rs b/src/lib.rs index ca53864..4f8851f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,6 +60,12 @@ pub mod drawing; pub mod epd4in2; use epd4in2::*; +pub mod epd2in9; + +pub mod interface; + + + //TODO: test spi mode /// SPI mode - /// For more infos see [Requirements: SPI](index.html#spi)