use hal::{ blocking::{delay::*, spi::Write}, digital::*, }; use core::marker::PhantomData; use traits::Command; /// The Connection Interface of all (?) Waveshare EPD-Devices /// pub(crate) struct DisplayInterface { /// SPI _spi: PhantomData, /// 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, } impl DisplayInterface where SPI: Write, CS: OutputPin, BUSY: InputPin, DC: OutputPin, RST: OutputPin, { pub fn new(cs: CS, busy: BUSY, dc: DC, rst: RST) -> Self { DisplayInterface { _spi: PhantomData::default(), cs, busy, dc, rst, } } /// Basic function for sending [Commands](Command). /// /// Enables direct interaction with the device with the help of [data()](DisplayInterface::data()) /// /// //TODO: make public? 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.write(spi, &[command.address()]) } /// Basic function for sending an array of u8-values of data over spi /// /// Enables direct interaction with the device with the help of [command()](EPD4in2::command()) /// /// //TODO: make public? 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.write(spi, data) } /// Basic function for sending [Commands](Command) and the data belonging to it. /// /// //TODO: make public? /// TODO: directly use ::write? cs wouldn't needed to be changed twice than 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 write(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> { // activate spi with cs low self.cs.set_low(); // transfer spi data spi.write(data)?; // deativate spi with cs high self.cs.set_high(); Ok(()) } /// 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 /// /// is_busy_low /// /// - TRUE for epd4in2, epd2in13, epd2in7, epd5in83, epd7in5 /// - 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) { // TODO: removal of delay. TEST! //self.delay_ms(1); //low: busy, high: idle while (is_busy_low && self.busy.is_low()) || (!is_busy_low && self.busy.is_high()) { //TODO: REMOVAL of DELAY: it's only waiting for the signal anyway and should continue work asap //old: shorten the time? it was 100 in the beginning //self.delay_ms(5); } } /// 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(crate) fn reset>(&mut self, delay: &mut DELAY) { self.rst.set_low(); //TODO: why 200ms? (besides being in the arduino version) delay.delay_ms(200); self.rst.set_high(); //TODO: same as 3 lines above delay.delay_ms(200); } }