From 87832f604365f0f9be1a6e9ad9e05a7bb58d3a74 Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 10 Oct 2018 16:06:27 +0200 Subject: [PATCH] Made SPI shareable Disown spi for better shareabilty --- src/epd1in54/mod.rs | 99 ++++++++------- src/epd2in9/mod.rs | 108 +++++++++-------- src/epd4in2/mod.rs | 186 ++++++++++++++++------------- src/traits/connection_interface.rs | 36 +++--- src/traits/mod.rs | 23 ++-- 5 files changed, 241 insertions(+), 211 deletions(-) diff --git a/src/epd1in54/mod.rs b/src/epd1in54/mod.rs index 6c17f3e..d220532 100644 --- a/src/epd1in54/mod.rs +++ b/src/epd1in54/mod.rs @@ -48,15 +48,15 @@ pub struct EPD1in54 { background_color: Color, } -impl EPD1in54 +impl EPD1in54 where - SPI: Write, + SPI: Write, CS: OutputPin, BUSY: InputPin, DC: OutputPin, RST: OutputPin, { - fn init>(&mut self, delay: &mut DELAY) -> Result<(), E> { + fn init>(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { self.interface.reset(delay); // 3 Databytes: @@ -65,6 +65,7 @@ where // 0.. B[2:0] // Default Values: A = Height of Screen (0x127), B = 0x00 (GD, SM and TB=0?) self.interface.cmd_with_data( + spi, Command::DRIVER_OUTPUT_CONTROL, &[HEIGHT as u8, (HEIGHT >> 8) as u8, 0x00] )?; @@ -74,27 +75,27 @@ where // 1 .. B[6:0] = 0xCE | 0xD6 // 1 .. C[6:0] = 0x8D | 0x9D //TODO: test - self.interface.cmd_with_data(Command::BOOSTER_SOFT_START_CONTROL, &[0xD7, 0xD6, 0x9D])?; + self.interface.cmd_with_data(spi, Command::BOOSTER_SOFT_START_CONTROL, &[0xD7, 0xD6, 0x9D])?; // One Databyte with value 0xA8 for 7V VCOM - self.interface.cmd_with_data(Command::WRITE_VCOM_REGISTER, &[0xA8])?; + self.interface.cmd_with_data(spi, Command::WRITE_VCOM_REGISTER, &[0xA8])?; // One Databyte with default value 0x1A for 4 dummy lines per gate - self.interface.cmd_with_data(Command::SET_DUMMY_LINE_PERIOD, &[0x1A])?; + self.interface.cmd_with_data(spi, Command::SET_DUMMY_LINE_PERIOD, &[0x1A])?; // One Databyte with default value 0x08 for 2us per line - self.interface.cmd_with_data(Command::SET_GATE_LINE_WIDTH, &[0x08])?; + self.interface.cmd_with_data(spi, Command::SET_GATE_LINE_WIDTH, &[0x08])?; // One Databyte with default value 0x03 // -> address: x increment, y increment, address counter is updated in x direction - self.interface.cmd_with_data(Command::DATA_ENTRY_MODE_SETTING, &[0x03])?; + self.interface.cmd_with_data(spi, Command::DATA_ENTRY_MODE_SETTING, &[0x03])?; - self.set_lut() + self.set_lut(spi) } } -impl WaveshareInterface +impl WaveshareInterface for EPD1in54 where SPI: Write, @@ -112,74 +113,76 @@ where } fn new>( - spi: SPI, cs: CS, busy: BUSY, dc: DC, rst: RST, delay: &mut DELAY, - ) -> Result { - let interface = ConnectionInterface::new(spi, cs, busy, dc, rst); + spi: &mut SPI, cs: CS, busy: BUSY, dc: DC, rst: RST, delay: &mut DELAY, + ) -> Result { + let interface = ConnectionInterface::new(cs, busy, dc, rst); let mut epd = EPD1in54 { interface, background_color: DEFAULT_BACKGROUND_COLOR, }; - epd.init(delay)?; + epd.init(spi, delay)?; Ok(epd) } - fn wake_up>(&mut self, delay: &mut DELAY) -> Result<(), E> { - self.init(delay) + fn wake_up>(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay) } - fn sleep(&mut self) -> Result<(), E> { + fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { // 0x00 for Normal mode (Power on Reset), 0x01 for Deep Sleep Mode //TODO: is 0x00 needed here or would 0x01 be even more efficient? - self.interface.cmd_with_data(Command::DEEP_SLEEP_MODE, &[0x00])?; + self.interface.cmd_with_data(spi, Command::DEEP_SLEEP_MODE, &[0x00])?; self.wait_until_idle(); Ok(()) } - fn update_frame(&mut self, buffer: &[u8]) -> Result<(), E> { - self.use_full_frame()?; - self.interface.cmd_with_data(Command::WRITE_RAM, buffer) + fn update_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> { + self.use_full_frame(spi)?; + self.interface.cmd_with_data(spi, Command::WRITE_RAM, buffer) } //TODO: update description: last 3 bits will be ignored for width and x_pos fn update_partial_frame( &mut self, + spi: &mut SPI, buffer: &[u8], x: u16, y: u16, width: u16, height: u16, - ) -> Result<(), E> { - self.set_ram_area(x, y, x + width, y + height)?; - self.set_ram_counter(x, y)?; + ) -> Result<(), SPI::Error> { + self.set_ram_area(spi, x, y, x + width, y + height)?; + self.set_ram_counter(spi, x, y)?; - self.interface.cmd_with_data(Command::WRITE_RAM, buffer) + self.interface.cmd_with_data(spi, Command::WRITE_RAM, buffer) } - fn display_frame(&mut self) -> Result<(), E> { + fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { // 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.cmd_with_data(Command::DISPLAY_UPDATE_CONTROL_2, &[0xC4])?; + self.interface.cmd_with_data(spi, Command::DISPLAY_UPDATE_CONTROL_2, &[0xC4])?; - self.interface.cmd(Command::MASTER_ACTIVATION)?; + self.interface.cmd(spi, Command::MASTER_ACTIVATION)?; // MASTER Activation should not be interupted to avoid currption of panel images // therefore a terminate command is send - self.interface.cmd(Command::NOP) + self.interface.cmd(spi, Command::NOP) } - fn clear_frame(&mut self) -> Result<(), E> { - self.use_full_frame()?; + fn clear_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + self.use_full_frame(spi)?; // clear the ram with the background color let color = self.background_color.get_byte_value(); //TODO: this is using a big buffer atm, is it better to just loop over sending a single byte? self.interface.cmd_with_data( + spi, Command::WRITE_RAM, &[color; WIDTH as usize / 8 * HEIGHT as usize] ) @@ -196,9 +199,9 @@ where } } -impl EPD1in54 +impl EPD1in54 where - SPI: Write, + SPI: Write, CS: OutputPin, BUSY: InputPin, DC: OutputPin, @@ -208,45 +211,49 @@ where self.interface.wait_until_idle(false); } - pub(crate) fn use_full_frame(&mut self) -> Result<(), E> { + pub(crate) fn use_full_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { // choose full frame/ram - self.set_ram_area(0, 0, WIDTH - 1, HEIGHT - 1)?; + self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?; // start from the beginning - self.set_ram_counter(0, 0) + self.set_ram_counter(spi, 0, 0) } pub(crate) fn set_ram_area( - &mut self, + &mut self, + spi: &mut SPI, start_x: u16, start_y: u16, end_x: u16, end_y: u16, - ) -> Result<(), E> { + ) -> Result<(), SPI::Error> { assert!(start_x < end_x); assert!(start_y < end_y); // 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.cmd_with_data( + spi, Command::SET_RAM_X_ADDRESS_START_END_POSITION, &[(start_x >> 3) as u8, (end_x >> 3) as u8] )?; // 2 Databytes: A[7:0] & 0..A[8] for each - start and end self.interface.cmd_with_data( + spi, Command::SET_RAM_Y_ADDRESS_START_END_POSITION, &[start_y as u8, (start_y >> 8) as u8, end_y as u8, (end_y >> 8) as u8] ) } - pub(crate) fn set_ram_counter(&mut self, x: u16, y: u16) -> Result<(), E> { + pub(crate) fn set_ram_counter(&mut self, spi: &mut SPI, x: u16, y: u16) -> Result<(), SPI::Error> { // 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.cmd_with_data(Command::SET_RAM_X_ADDRESS_COUNTER, &[(x >> 3) as u8])?; + self.interface.cmd_with_data(spi, Command::SET_RAM_X_ADDRESS_COUNTER, &[(x >> 3) as u8])?; // 2 Databytes: A[7:0] & 0..A[8] self.interface.cmd_with_data( + spi, Command::SET_RAM_Y_ADDRESS_COUNTER, &[ y as u8, @@ -258,13 +265,13 @@ where } /// Uses the slower full update - pub fn set_lut(&mut self) -> Result<(), E> { - self.set_lut_helper(&LUT_FULL_UPDATE) + pub fn set_lut(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + self.set_lut_helper(spi, &LUT_FULL_UPDATE) } /// Uses the quick partial refresh - pub fn set_lut_quick(&mut self) -> Result<(), E> { - self.set_lut_helper(&LUT_PARTIAL_UPDATE) + pub fn set_lut_quick(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + self.set_lut_helper(spi, &LUT_PARTIAL_UPDATE) } //TODO: assert length for LUT is exactly 30 @@ -272,9 +279,9 @@ where // self.set_lut_helper(buffer) //} - fn set_lut_helper(&mut self, buffer: &[u8]) -> Result<(), E> { + fn set_lut_helper(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> { assert!(buffer.len() == 30); - self.interface.cmd_with_data(Command::WRITE_LUT_REGISTER, buffer) + self.interface.cmd_with_data(spi, Command::WRITE_LUT_REGISTER, buffer) } } diff --git a/src/epd2in9/mod.rs b/src/epd2in9/mod.rs index 35199f0..c154d19 100644 --- a/src/epd2in9/mod.rs +++ b/src/epd2in9/mod.rs @@ -47,15 +47,15 @@ pub struct EPD2in9 { background_color: Color, } -impl EPD2in9 +impl EPD2in9 where - SPI: Write, + SPI: Write, CS: OutputPin, BUSY: InputPin, DC: OutputPin, RST: OutputPin, { - fn init>(&mut self, delay: &mut DELAY) -> Result<(), E> { + fn init>(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { self.interface.reset(delay); // 3 Databytes: @@ -63,37 +63,37 @@ where // 0.. A[8] // 0.. B[2:0] // Default Values: A = Height of Screen (0x127), B = 0x00 (GD, SM and TB=0?) - self.interface.cmd_with_data(Command::DRIVER_OUTPUT_CONTROL, &[0x27, 0x01, 0x00])?; + self.interface.cmd_with_data(spi, Command::DRIVER_OUTPUT_CONTROL, &[0x27, 0x01, 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.cmd_with_data(Command::BOOSTER_SOFT_START_CONTROL, &[0xD7, 0xD6, 0x9D])?; + self.interface.cmd_with_data(spi, Command::BOOSTER_SOFT_START_CONTROL, &[0xD7, 0xD6, 0x9D])?; // One Databyte with value 0xA8 for 7V VCOM - self.interface.cmd_with_data(Command::WRITE_VCOM_REGISTER, &[0xA8])?; + self.interface.cmd_with_data(spi, Command::WRITE_VCOM_REGISTER, &[0xA8])?; // One Databyte with default value 0x1A for 4 dummy lines per gate - self.interface.cmd_with_data(Command::SET_DUMMY_LINE_PERIOD, &[0x1A])?; + self.interface.cmd_with_data(spi, Command::SET_DUMMY_LINE_PERIOD, &[0x1A])?; // One Databyte with default value 0x08 for 2us per line - self.interface.cmd_with_data(Command::SET_GATE_LINE_WIDTH, &[0x08])?; + self.interface.cmd_with_data(spi, Command::SET_GATE_LINE_WIDTH, &[0x08])?; // One Databyte with default value 0x03 // -> address: x increment, y increment, address counter is updated in x direction - self.interface.cmd_with_data(Command::DATA_ENTRY_MODE_SETTING, &[0x03])?; + self.interface.cmd_with_data(spi, Command::DATA_ENTRY_MODE_SETTING, &[0x03])?; - self.set_lut() + self.set_lut(spi) } } -impl - WaveshareInterface +impl + WaveshareInterface for EPD2in9 where - SPI: Write, + SPI: Write, CS: OutputPin, BUSY: InputPin, DC: OutputPin, @@ -108,75 +108,77 @@ where } fn new>( - spi: SPI, cs: CS, busy: BUSY, dc: DC, rst: RST, delay: &mut DELAY, - ) -> Result { - let interface = ConnectionInterface::new(spi, cs, busy, dc, rst); + spi: &mut SPI, cs: CS, busy: BUSY, dc: DC, rst: RST, delay: &mut DELAY, + ) -> Result { + let interface = ConnectionInterface::new(cs, busy, dc, rst); let mut epd = EPD2in9 { interface, background_color: DEFAULT_BACKGROUND_COLOR, }; - epd.init(delay)?; + epd.init(spi, delay)?; Ok(epd) } - fn sleep(&mut self) -> Result<(), ERR> { + fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { // 0x00 for Normal mode (Power on Reset), 0x01 for Deep Sleep Mode //TODO: is 0x00 needed here? (see also epd1in54) - self.interface.cmd_with_data(Command::DEEP_SLEEP_MODE, &[0x00])?; + self.interface.cmd_with_data(spi, Command::DEEP_SLEEP_MODE, &[0x00])?; self.wait_until_idle(); Ok(()) } - fn wake_up>(&mut self, delay: &mut DELAY) -> Result<(), ERR> { - self.init(delay) + fn wake_up>(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay) } - fn update_frame(&mut self, buffer: &[u8]) -> Result<(), ERR> { - self.use_full_frame()?; + fn update_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> { + self.use_full_frame(spi)?; - self.interface.cmd_with_data(Command::WRITE_RAM, buffer) + self.interface.cmd_with_data(spi, Command::WRITE_RAM, buffer) } //TODO: update description: last 3 bits will be ignored for width and x_pos fn update_partial_frame( - &mut self, + &mut self, + spi: &mut SPI, buffer: &[u8], x: u16, y: u16, width: u16, height: u16, - ) -> Result<(), ERR> { - self.set_ram_area(x, y, x + width, y + height)?; - self.set_ram_counter(x, y)?; + ) -> Result<(), SPI::Error> { + self.set_ram_area(spi, x, y, x + width, y + height)?; + self.set_ram_counter(spi, x, y)?; - self.interface.cmd_with_data(Command::WRITE_RAM, buffer) + self.interface.cmd_with_data(spi, Command::WRITE_RAM, buffer) } - fn display_frame(&mut self) -> Result<(), ERR> { + fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { // 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.cmd_with_data(Command::DISPLAY_UPDATE_CONTROL_2, &[0xC4])?; + self.interface.cmd_with_data(spi, Command::DISPLAY_UPDATE_CONTROL_2, &[0xC4])?; - self.interface.cmd(Command::MASTER_ACTIVATION)?; + self.interface.cmd(spi, Command::MASTER_ACTIVATION)?; // MASTER Activation should not be interupted to avoid currption of panel images // therefore a terminate command is send - self.interface.cmd(Command::NOP) + self.interface.cmd(spi, Command::NOP) } - fn clear_frame(&mut self) -> Result<(), ERR> { - self.use_full_frame()?; + fn clear_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + self.use_full_frame(spi)?; // clear the ram with the background color let color = self.background_color.get_byte_value(); //TODO: this is using a big buffer atm, is it better to just loop over sending a single byte? self.interface.cmd_with_data( + spi, Command::WRITE_RAM, &[color; WIDTH as usize / 8 * HEIGHT as usize] ) @@ -192,9 +194,9 @@ where } } -impl EPD2in9 +impl EPD2in9 where - SPI: Write, + SPI: Write, CS: OutputPin, BUSY: InputPin, DC: OutputPin, @@ -204,57 +206,59 @@ where self.interface.wait_until_idle(false); } - pub(crate) fn use_full_frame(&mut self) -> Result<(), E> { + pub(crate) fn use_full_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { // choose full frame/ram - self.set_ram_area(0, 0, WIDTH - 1, HEIGHT - 1)?; + self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?; // start from the beginning - self.set_ram_counter(0, 0) + self.set_ram_counter(spi, 0, 0) } pub(crate) fn set_ram_area( - &mut self, + &mut self, + spi: &mut SPI, start_x: u16, start_y: u16, end_x: u16, end_y: u16, - ) -> Result<(), E> { + ) -> Result<(), SPI::Error> { assert!(start_x < end_x); assert!(start_y < end_y); // 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.cmd_with_data( + spi, Command::SET_RAM_X_ADDRESS_START_END_POSITION, &[(start_x >> 3) as u8, (end_x >> 3) as u8] )?; // 2 Databytes: A[7:0] & 0..A[8] for each - start and end - self.interface.cmd_with_data(Command::SET_RAM_Y_ADDRESS_START_END_POSITION, + self.interface.cmd_with_data(spi, Command::SET_RAM_Y_ADDRESS_START_END_POSITION, &[start_y as u8, (start_y >> 8) as u8, end_y as u8, (end_y >> 8) as u8] ) } - pub(crate) fn set_ram_counter(&mut self, x: u16, y: u16) -> Result<(), E> { + pub(crate) fn set_ram_counter(&mut self, spi: &mut SPI, x: u16, y: u16) -> Result<(), SPI::Error> { // 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.cmd_with_data(Command::SET_RAM_X_ADDRESS_COUNTER, &[(x >> 3) as u8])?; + self.interface.cmd_with_data(spi, Command::SET_RAM_X_ADDRESS_COUNTER, &[(x >> 3) as u8])?; // 2 Databytes: A[7:0] & 0..A[8] - self.interface.cmd_with_data(Command::SET_RAM_Y_ADDRESS_COUNTER, &[y as u8, (y >> 8) as u8])?; + self.interface.cmd_with_data(spi, Command::SET_RAM_Y_ADDRESS_COUNTER, &[y as u8, (y >> 8) as u8])?; self.wait_until_idle(); Ok(()) } /// Uses the slower full update - pub fn set_lut(&mut self) -> Result<(), E> { - self.set_lut_helper(&LUT_FULL_UPDATE) + pub fn set_lut(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + self.set_lut_helper(spi, &LUT_FULL_UPDATE) } /// Uses the quick partial refresh - pub fn set_lut_quick(&mut self) -> Result<(), E> { - self.set_lut_helper(&LUT_PARTIAL_UPDATE) + pub fn set_lut_quick(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + self.set_lut_helper(spi, &LUT_PARTIAL_UPDATE) } //TODO: assert length for LUT is exactly 30 @@ -262,9 +266,9 @@ where // self.set_lut_helper(buffer) //} - fn set_lut_helper(&mut self, buffer: &[u8]) -> Result<(), E> { + fn set_lut_helper(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> { assert!(buffer.len() == 30); - self.interface.cmd_with_data(Command::WRITE_LUT_REGISTER, buffer) + self.interface.cmd_with_data(spi, Command::WRITE_LUT_REGISTER, buffer) } } diff --git a/src/epd4in2/mod.rs b/src/epd4in2/mod.rs index ca8e494..a51371d 100644 --- a/src/epd4in2/mod.rs +++ b/src/epd4in2/mod.rs @@ -74,50 +74,50 @@ pub struct EPD4in2 { -impl - InternalWiAdditions +impl + InternalWiAdditions for EPD4in2 where - SPI: Write, + SPI: Write, CS: OutputPin, BUSY: InputPin, DC: OutputPin, RST: OutputPin, { - fn init>(&mut self, delay: &mut DELAY) -> Result<(), ERR> { + fn init>(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { // reset the device self.interface.reset(delay); // set the power settings - self.interface.cmd_with_data(Command::POWER_SETTING, &[0x03, 0x00, 0x2b, 0x2b, 0xff])?; + self.interface.cmd_with_data(spi, Command::POWER_SETTING, &[0x03, 0x00, 0x2b, 0x2b, 0xff])?; // start the booster - self.interface.cmd_with_data(Command::BOOSTER_SOFT_START, &[0x17, 0x17, 0x17])?; + self.interface.cmd_with_data(spi, Command::BOOSTER_SOFT_START, &[0x17, 0x17, 0x17])?; // power on - self.command(Command::POWER_ON)?; + self.command(spi, Command::POWER_ON)?; self.wait_until_idle(); // set the panel settings - self.cmd_with_data(Command::PANEL_SETTING, &[0x3F])?; + self.cmd_with_data(spi, Command::PANEL_SETTING, &[0x3F])?; // Set Frequency, 200 Hz didn't work on my board // 150Hz and 171Hz wasn't tested yet // TODO: Test these other frequencies // 3A 100HZ 29 150Hz 39 200HZ 31 171HZ DEFAULT: 3c 50Hz - self.cmd_with_data(Command::PLL_CONTROL, &[0x3A])?; + self.cmd_with_data(spi, Command::PLL_CONTROL, &[0x3A])?; - self.set_lut()?; + self.set_lut(spi)?; Ok(()) } } -impl - WaveshareInterface +impl + WaveshareInterface for EPD4in2 where - SPI: Write, + SPI: Write, CS: OutputPin, BUSY: InputPin, DC: OutputPin, @@ -138,8 +138,8 @@ where /// /// epd4in2.sleep(); /// ``` - fn new>(spi: SPI, cs: CS, busy: BUSY, dc: DC, rst: RST, delay: &mut DELAY) -> Result { - let interface = ConnectionInterface::new(spi, cs, busy, dc, rst); + fn new>(spi: &mut SPI, cs: CS, busy: BUSY, dc: DC, rst: RST, delay: &mut DELAY) -> Result { + let interface = ConnectionInterface::new(cs, busy, dc, rst); let color = DEFAULT_BACKGROUND_COLOR; let mut epd = EPD4in2 { @@ -147,120 +147,122 @@ where color, }; - epd.init(delay)?; + epd.init(spi, delay)?; Ok(epd) } - fn wake_up>(&mut self, delay: &mut DELAY) -> Result<(), ERR> { - self.init(delay) + fn wake_up>(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> { + self.init(spi, delay) } //TODO: is such a long delay really needed inbetween? - fn sleep(&mut self) -> Result<(), ERR> { - self.interface.cmd_with_data(Command::VCOM_AND_DATA_INTERVAL_SETTING, &[0x17])?; //border floating - self.command(Command::VCM_DC_SETTING)?; // VCOM to 0V - self.command(Command::PANEL_SETTING)?; + fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + self.interface.cmd_with_data(spi, Command::VCOM_AND_DATA_INTERVAL_SETTING, &[0x17])?; //border floating + self.command(spi, Command::VCM_DC_SETTING)?; // VCOM to 0V + self.command(spi, Command::PANEL_SETTING)?; //TODO: Removal of delay. TEST! //self.delay_ms(100); - self.command(Command::POWER_SETTING)?; //VG&VS to 0V fast + self.command(spi, Command::POWER_SETTING)?; //VG&VS to 0V fast for _ in 0..4 { - self.send_data(&[0x00])?; + self.send_data(spi, &[0x00])?; } //TODO: Removal of delay. TEST! //self.delay_ms(100); - self.command(Command::POWER_OFF)?; + self.command(spi, Command::POWER_OFF)?; self.wait_until_idle(); - self.interface.cmd_with_data(Command::DEEP_SLEEP, &[0xA5]) + self.interface.cmd_with_data(spi, Command::DEEP_SLEEP, &[0xA5]) } - fn update_frame(&mut self, buffer: &[u8]) -> Result<(), ERR> { + fn update_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> { let color_value = self.color.get_byte_value(); - self.send_resolution()?; + self.send_resolution(spi)?; - self.interface.cmd_with_data(Command::VCM_DC_SETTING, &[0x12])?; + self.interface.cmd_with_data(spi, Command::VCM_DC_SETTING, &[0x12])?; //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.interface.cmd_with_data(Command::VCOM_AND_DATA_INTERVAL_SETTING, &[0x97])?; + self.interface.cmd_with_data(spi, Command::VCOM_AND_DATA_INTERVAL_SETTING, &[0x97])?; - self.command(Command::DATA_START_TRANSMISSION_1)?; + self.command(spi, Command::DATA_START_TRANSMISSION_1)?; for _ in 0..buffer.len() { - self.send_data(&[color_value])?; + self.send_data(spi, &[color_value])?; } //TODO: Removal of delay. TEST! //self.delay_ms(2); - self.interface.cmd_with_data(Command::DATA_START_TRANSMISSION_2, buffer) + self.interface.cmd_with_data(spi, Command::DATA_START_TRANSMISSION_2, buffer) } fn update_partial_frame( - &mut self, + &mut self, + spi: &mut SPI, buffer: &[u8], x: u16, y: u16, width: u16, height: u16, - ) -> Result<(), ERR> { + ) -> Result<(), SPI::Error> { if buffer.len() as u16 != width / 8 * height { //TODO: panic!! or sth like that //return Err("Wrong buffersize"); } - self.command(Command::PARTIAL_IN)?; - self.command(Command::PARTIAL_WINDOW)?; - self.send_data(&[(x >> 8) as u8])?; + self.command(spi, Command::PARTIAL_IN)?; + self.command(spi, Command::PARTIAL_WINDOW)?; + self.send_data(spi, &[(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 + self.send_data(spi, &[tmp as u8])?; // x should be the multiple of 8, the last 3 bit will always be ignored let tmp = tmp + width - 1; - self.send_data(&[(tmp >> 8) as u8])?; - self.send_data(&[(tmp | 0x07) as u8])?; + self.send_data(spi, &[(tmp >> 8) as u8])?; + self.send_data(spi, &[(tmp | 0x07) as u8])?; - self.send_data(&[(y >> 8) as u8])?; - self.send_data(&[y as u8])?; + self.send_data(spi, &[(y >> 8) as u8])?; + self.send_data(spi, &[y as u8])?; - self.send_data(&[((y + height - 1) >> 8) as u8])?; - self.send_data(&[(y + height - 1) as u8])?; + self.send_data(spi, &[((y + height - 1) >> 8) as u8])?; + self.send_data(spi, &[(y + height - 1) as u8])?; - self.send_data(&[0x01])?; // Gates scan both inside and outside of the partial window. (default) + self.send_data(spi, &[0x01])?; // Gates scan both inside and outside of the partial window. (default) //TODO: handle dtm somehow let is_dtm1 = false; if is_dtm1 { - self.command(Command::DATA_START_TRANSMISSION_1)? + self.command(spi, Command::DATA_START_TRANSMISSION_1)? } else { - self.command(Command::DATA_START_TRANSMISSION_2)? + self.command(spi, Command::DATA_START_TRANSMISSION_2)? } - self.send_data(buffer)?; + self.send_data(spi, buffer)?; - self.command(Command::PARTIAL_OUT) + self.command(spi, Command::PARTIAL_OUT) } - fn display_frame(&mut self) -> Result<(), ERR> { - self.command(Command::DISPLAY_REFRESH)?; + fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + self.command(spi, Command::DISPLAY_REFRESH)?; self.wait_until_idle(); Ok(()) } - fn clear_frame(&mut self) -> Result<(), ERR> { - self.send_resolution()?; + fn clear_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + self.send_resolution(spi)?; //let size = WIDTH as usize / 8 * HEIGHT as usize; let color_value = self.color.get_byte_value(); //TODO: this is using a big buffer atm, is it better to just loop over sending a single byte? self.interface.cmd_with_data( + spi, Command::DATA_START_TRANSMISSION_1, &[color_value; WIDTH as usize / 8 * HEIGHT as usize] )?; @@ -270,6 +272,7 @@ where //TODO: this is using a big buffer atm, is it better to just loop over sending a single byte? self.interface.cmd_with_data( + spi, Command::DATA_START_TRANSMISSION_2, &[color_value; WIDTH as usize / 8 * HEIGHT as usize] ) @@ -293,45 +296,45 @@ where } } -impl EPD4in2 +impl EPD4in2 where - SPI: Write, + SPI: Write, CS: OutputPin, BUSY: InputPin, DC: OutputPin, RST: OutputPin, { - fn command(&mut self, command: Command) -> Result<(), ERR> { - self.interface.cmd(command) + fn command(&mut self, spi: &mut SPI, command: Command) -> Result<(), SPI::Error> { + self.interface.cmd(spi, command) } - fn send_data(&mut self, data: &[u8]) -> Result<(), ERR> { - self.interface.data(data) + fn send_data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { + self.interface.data(spi, data) } - fn cmd_with_data(&mut self, command: Command, data: &[u8]) -> Result<(), ERR> { - self.interface.cmd_with_data(command, data) + fn cmd_with_data(&mut self, spi: &mut SPI, command: Command, data: &[u8]) -> Result<(), SPI::Error> { + self.interface.cmd_with_data(spi, command, data) } fn wait_until_idle(&mut self) { self.interface.wait_until_idle(true) } - fn send_resolution(&mut self) -> Result<(), ERR> { + fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { let w = self.width(); let h = self.height(); - 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])?; - self.send_data(&[h as u8]) + self.command(spi, Command::RESOLUTION_SETTING)?; + self.send_data(spi, &[(w >> 8) as u8])?; + self.send_data(spi, &[w as u8])?; + self.send_data(spi, &[(h >> 8) as u8])?; + self.send_data(spi, &[h as u8]) } /// Fill the look-up table for the EPD //TODO: make public? - fn set_lut(&mut self) -> Result<(), ERR> { - self.set_lut_helper(&LUT_VCOM0, &LUT_WW, &LUT_BW, &LUT_WB, &LUT_BB) + fn set_lut(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { + self.set_lut_helper(spi, &LUT_VCOM0, &LUT_WW, &LUT_BW, &LUT_WB, &LUT_BB) } /// Fill the look-up table for a quick display (partial refresh) @@ -339,8 +342,9 @@ 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<(), ERR> { + fn set_lut_quick(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> { self.set_lut_helper( + spi, &LUT_VCOM0_QUICK, &LUT_WW_QUICK, &LUT_BW_QUICK, @@ -351,33 +355,47 @@ where fn set_lut_helper( &mut self, + spi: &mut SPI, lut_vcom: &[u8], lut_ww: &[u8], lut_bw: &[u8], lut_wb: &[u8], lut_bb: &[u8], - ) -> Result<(), ERR> { + ) -> Result<(), SPI::Error> { // LUT VCOM - self.command(Command::LUT_FOR_VCOM)?; - self.send_data(lut_vcom)?; + self.cmd_with_data( + spi, + Command::LUT_FOR_VCOM, + lut_vcom + )?; // LUT WHITE to WHITE - self.command(Command::LUT_WHITE_TO_WHITE)?; - self.send_data(lut_ww)?; + self.cmd_with_data( + spi, + Command::LUT_WHITE_TO_WHITE, + lut_ww + )?; // LUT BLACK to WHITE - self.command(Command::LUT_BLACK_TO_WHITE)?; - self.send_data(lut_bw)?; + self.cmd_with_data( + spi, + Command::LUT_BLACK_TO_WHITE, + lut_bw + )?; // LUT WHITE to BLACK - self.command(Command::LUT_WHITE_TO_BLACK)?; - self.send_data(lut_wb)?; + self.cmd_with_data( + spi, + Command::LUT_WHITE_TO_BLACK, + lut_wb, + )?; // LUT BLACK to BLACK - self.command(Command::LUT_BLACK_TO_BLACK)?; - self.send_data(lut_bb)?; - - Ok(()) + self.cmd_with_data( + spi, + Command::LUT_BLACK_TO_BLACK, + lut_bb, + ) } } diff --git a/src/traits/connection_interface.rs b/src/traits/connection_interface.rs index a3da8c6..0a18c86 100644 --- a/src/traits/connection_interface.rs +++ b/src/traits/connection_interface.rs @@ -3,13 +3,15 @@ use hal::{ digital::*, }; +use core::marker::PhantomData; + use traits::Command; /// The Connection Interface of all (?) Waveshare EPD-Devices /// pub(crate) struct ConnectionInterface { /// SPI - spi: SPI, + _spi: PhantomData, /// CS for SPI cs: CS, /// Low for busy, Wait until display is ready! @@ -20,18 +22,18 @@ pub(crate) struct ConnectionInterface { rst: RST, } -impl +impl ConnectionInterface where - SPI: Write, + SPI: Write, CS: OutputPin, BUSY: InputPin, DC: OutputPin, RST: OutputPin, { - pub fn new(spi: SPI, cs: CS, busy: BUSY, dc: DC, rst: RST) -> Self { + pub fn new(cs: CS, busy: BUSY, dc: DC, rst: RST) -> Self { ConnectionInterface { - spi, + _spi: PhantomData::default(), cs, busy, dc, @@ -44,12 +46,12 @@ where /// Enables direct interaction with the device with the help of [data()](ConnectionInterface::data()) /// /// //TODO: make public? - pub(crate) fn cmd(&mut self, command: T) -> Result<(), ERR> { + pub(crate) fn cmd(&mut self, spi: &mut SPI, command: T) -> Result<(), SPI::Error> { // low for commands self.dc.set_low(); // Transfer the command over spi - self.with_cs(|epd| epd.spi.write(&[command.address()])) + self.write(spi, &[command.address()]) } /// Basic function for sending an array of u8-values of data over spi @@ -57,35 +59,33 @@ where /// Enables direct interaction with the device with the help of [command()](EPD4in2::command()) /// /// //TODO: make public? - pub(crate) fn data(&mut self, data: &[u8]) -> Result<(), ERR> { + pub(crate) fn data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { // high for data self.dc.set_high(); // Transfer data (u8-array) over spi - self.with_cs(|epd| epd.spi.write(data)) + self.write(spi, data) } /// Basic function for sending [Commands](Command) and the data belonging to it. /// /// //TODO: make public? - pub(crate) fn cmd_with_data(&mut self, command: T, data: &[u8]) -> Result<(), ERR> { - self.cmd(command)?; - self.data(data) + pub(crate) fn cmd_with_data(&mut self, spi: &mut SPI, command: T, data: &[u8]) -> Result<(), SPI::Error> { + self.cmd(spi, command)?; + self.data(spi, data) } // spi write helper/abstraction function - fn with_cs(&mut self, f: F) -> Result<(), ERR> - where - F: FnOnce(&mut Self) -> Result<(), ERR>, + fn write(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { // activate spi with cs low self.cs.set_low(); // transfer spi data - let result = f(self); + spi.write(data)?; // deativate spi with cs high self.cs.set_high(); - // return result - result + + Ok(()) } /// Waits until device isn't busy anymore (busy == HIGH) diff --git a/src/traits/mod.rs b/src/traits/mod.rs index 0ec5c8f..87860bc 100644 --- a/src/traits/mod.rs +++ b/src/traits/mod.rs @@ -26,7 +26,7 @@ trait LUTSupport { } -pub(crate) trait InternalWiAdditions +pub(crate) trait InternalWiAdditions where SPI: Write, CS: OutputPin, @@ -44,11 +44,11 @@ where /// 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, delay: &mut DELAY) -> Result<(), ERR>; + fn init>(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>; } -pub trait WaveshareInterface +pub trait WaveshareInterface where SPI: Write, CS: OutputPin, @@ -62,8 +62,8 @@ where /// /// This already initialises the device. That means [init()](WaveshareInterface::init()) isn't needed directly afterwards fn new>( - spi: SPI, cs: CS, busy: BUSY, dc: DC, rst: RST, delay: &mut DELAY, - ) -> Result + spi: &mut SPI, cs: CS, busy: BUSY, dc: DC, rst: RST, delay: &mut DELAY, + ) -> Result where Self: Sized; @@ -73,9 +73,9 @@ where /// But you can also use [wake_up()](WaveshareInterface::wake_up()) to awaken. /// But as you need to power it up once more anyway you can also just directly use [new()](WaveshareInterface::new()) for resetting /// and initialising which already contains the reset - fn sleep(&mut self) -> Result<(), ERR>; + fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error>; - fn wake_up>(&mut self, delay: &mut DELAY) -> Result<(), ERR>; + fn wake_up>(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error>; /// Sets the backgroundcolor for various commands like [clear_frame()](WaveshareInterface::clear_frame()) @@ -91,24 +91,25 @@ where fn height(&self) -> u16; /// Transmit a full frame to the SRAM of the EPD - fn update_frame(&mut self, buffer: &[u8]) -> Result<(), ERR>; + fn update_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error>; /// Transmits partial data to the SRAM of the EPD /// /// BUFFER needs to be of size: w / 8 * h ! fn update_partial_frame( &mut self, + spi: &mut SPI, buffer: &[u8], x: u16, y: u16, width: u16, height: u16, - ) -> Result<(), ERR>; + ) -> Result<(), SPI::Error>; /// Displays the frame data from SRAM - fn display_frame(&mut self) -> Result<(), ERR>; + fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error>; /// Clears the frame buffer on the EPD with the declared background color /// The background color can be changed with [`set_background_color`] - fn clear_frame(&mut self) -> Result<(), ERR>; + fn clear_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error>; }