You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
380 lines
12 KiB
380 lines
12 KiB
use crate::{eh_prelude::*, Error}; |
|
use core::marker::Sized; |
|
|
|
/// 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) |
|
pub(crate) trait Command { |
|
fn address(self) -> u8; |
|
} |
|
|
|
/// Seperates the different LUT for the Display Refresh process |
|
#[derive(Debug, Clone, PartialEq, Eq, Copy)] |
|
pub enum RefreshLut { |
|
/// The "normal" full Lookuptable for the Refresh-Sequence |
|
Full, |
|
/// The quick LUT where not the full refresh sequence is followed. |
|
/// This might lead to some |
|
Quick, |
|
} |
|
|
|
impl Default for RefreshLut { |
|
fn default() -> Self { |
|
RefreshLut::Full |
|
} |
|
} |
|
|
|
pub(crate) trait InternalWiAdditions<SPI, CS, BUSY, DC, RST, DELAY> |
|
where |
|
SPI: Write<u8>, |
|
CS: OutputPin, |
|
BUSY: InputPin, |
|
DC: OutputPin, |
|
RST: OutputPin, |
|
DELAY: DelayUs, |
|
{ |
|
/// This initialises the EPD and powers it up |
|
/// |
|
/// This function is already called from |
|
/// - [new()](WaveshareDisplay::new()) |
|
/// - [`wake_up`] |
|
/// |
|
/// |
|
/// This function calls [reset](WaveshareDisplay::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, |
|
spi: &mut SPI, |
|
delay: &mut DELAY, |
|
) -> Result<(), Error<SPI::Error, CS::Error, BUSY::Error, DC::Error, RST::Error, DELAY::Error>>; |
|
} |
|
|
|
/// Functions to interact with three color panels |
|
pub trait WaveshareThreeColorDisplay<SPI, CS, BUSY, DC, RST, DELAY>: |
|
WaveshareDisplay<SPI, CS, BUSY, DC, RST, DELAY> |
|
where |
|
SPI: Write<u8>, |
|
CS: OutputPin, |
|
BUSY: InputPin, |
|
DC: OutputPin, |
|
RST: OutputPin, |
|
DELAY: DelayUs, |
|
{ |
|
/// Transmit data to the SRAM of the EPD |
|
/// |
|
/// Updates both the black and the secondary color layers |
|
fn update_color_frame( |
|
&mut self, |
|
spi: &mut SPI, |
|
black: &[u8], |
|
chromatic: &[u8], |
|
) -> Result<(), Error<SPI::Error, CS::Error, BUSY::Error, DC::Error, RST::Error, DELAY::Error>>; |
|
|
|
/// Update only the black/white data of the display. |
|
/// |
|
/// This must be finished by calling `update_chromatic_frame`. |
|
fn update_achromatic_frame( |
|
&mut self, |
|
spi: &mut SPI, |
|
black: &[u8], |
|
) -> Result<(), Error<SPI::Error, CS::Error, BUSY::Error, DC::Error, RST::Error, DELAY::Error>>; |
|
|
|
/// Update only the chromatic data of the display. |
|
/// |
|
/// This should be preceded by a call to `update_achromatic_frame`. |
|
/// This data takes precedence over the black/white data. |
|
fn update_chromatic_frame( |
|
&mut self, |
|
spi: &mut SPI, |
|
chromatic: &[u8], |
|
) -> Result<(), Error<SPI::Error, CS::Error, BUSY::Error, DC::Error, RST::Error, DELAY::Error>>; |
|
} |
|
|
|
/// All the functions to interact with the EPDs |
|
/// |
|
/// This trait includes all public functions to use the EPDs |
|
/// |
|
/// # Example |
|
/// |
|
///```rust, no_run |
|
///# use embedded_hal_mock::*; |
|
///# fn main() -> Result<(), MockError> { |
|
///use embedded_graphics::{ |
|
/// pixelcolor::BinaryColor::On as Black, prelude::*, primitives::{Line, PrimitiveStyle}, |
|
///}; |
|
///use epd_waveshare::{epd4in2::*, prelude::*}; |
|
///# |
|
///# let expectations = []; |
|
///# let mut spi = spi::Mock::new(&expectations); |
|
///# let expectations = []; |
|
///# let cs_pin = pin::Mock::new(&expectations); |
|
///# let busy_in = pin::Mock::new(&expectations); |
|
///# let dc = pin::Mock::new(&expectations); |
|
///# let rst = pin::Mock::new(&expectations); |
|
///# let mut delay = delay::MockNoop::new(); |
|
/// |
|
///// Setup EPD |
|
///let mut epd = Epd4in2::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay)?; |
|
/// |
|
///// Use display graphics from embedded-graphics |
|
///let mut display = Display4in2::default(); |
|
/// |
|
///// Use embedded graphics for drawing a line |
|
/// |
|
///let _ = Line::new(Point::new(0, 120), Point::new(0, 295)) |
|
/// .into_styled(PrimitiveStyle::with_stroke(Black, 1)) |
|
/// .draw(&mut display); |
|
/// |
|
/// // Display updated frame |
|
///epd.update_frame(&mut spi, &display.buffer(), &mut delay)?; |
|
///epd.display_frame(&mut spi, &mut delay)?; |
|
/// |
|
///// Set the EPD to sleep |
|
///epd.sleep(&mut spi, &mut delay)?; |
|
///# Ok(()) |
|
///# } |
|
///``` |
|
pub trait WaveshareDisplay<SPI, CS, BUSY, DC, RST, DELAY> |
|
where |
|
SPI: Write<u8>, |
|
CS: OutputPin, |
|
BUSY: InputPin, |
|
DC: OutputPin, |
|
RST: OutputPin, |
|
DELAY: DelayUs, |
|
{ |
|
/// The Color Type used by the Display |
|
type DisplayColor; |
|
/// Creates a new driver from a SPI peripheral, CS Pin, Busy InputPin, DC |
|
/// |
|
/// This already initialises the device. |
|
fn new( |
|
spi: &mut SPI, |
|
cs: CS, |
|
busy: BUSY, |
|
dc: DC, |
|
rst: RST, |
|
delay: &mut DELAY, |
|
) -> Result<Self, Error<SPI::Error, CS::Error, BUSY::Error, DC::Error, RST::Error, DELAY::Error>> |
|
where |
|
Self: Sized; |
|
|
|
/// Let the device enter deep-sleep mode to save power. |
|
/// |
|
/// The deep sleep mode returns to standby with a hardware reset. |
|
fn sleep( |
|
&mut self, |
|
spi: &mut SPI, |
|
delay: &mut DELAY, |
|
) -> Result<(), Error<SPI::Error, CS::Error, BUSY::Error, DC::Error, RST::Error, DELAY::Error>>; |
|
|
|
/// Wakes the device up from sleep |
|
/// |
|
/// Also reintialises the device if necessary. |
|
fn wake_up( |
|
&mut self, |
|
spi: &mut SPI, |
|
delay: &mut DELAY, |
|
) -> Result<(), Error<SPI::Error, CS::Error, BUSY::Error, DC::Error, RST::Error, DELAY::Error>>; |
|
|
|
/// Sets the backgroundcolor for various commands like [clear_frame](WaveshareDisplay::clear_frame) |
|
fn set_background_color(&mut self, color: Self::DisplayColor); |
|
|
|
/// Get current background color |
|
fn background_color(&self) -> &Self::DisplayColor; |
|
|
|
/// Get the width of the display |
|
fn width(&self) -> u32; |
|
|
|
/// Get the height of the display |
|
fn height(&self) -> u32; |
|
|
|
/// Transmit a full frame to the SRAM of the EPD |
|
fn update_frame( |
|
&mut self, |
|
spi: &mut SPI, |
|
buffer: &[u8], |
|
delay: &mut DELAY, |
|
) -> Result<(), Error<SPI::Error, CS::Error, BUSY::Error, DC::Error, RST::Error, DELAY::Error>>; |
|
|
|
/// Transmits partial data to the SRAM of the EPD |
|
/// |
|
/// (x,y) is the top left corner |
|
/// |
|
/// BUFFER needs to be of size: width / 8 * height ! |
|
fn update_partial_frame( |
|
&mut self, |
|
spi: &mut SPI, |
|
buffer: &[u8], |
|
x: u32, |
|
y: u32, |
|
width: u32, |
|
height: u32, |
|
) -> Result<(), Error<SPI::Error, CS::Error, BUSY::Error, DC::Error, RST::Error, DELAY::Error>>; |
|
|
|
/// Displays the frame data from SRAM |
|
/// |
|
/// This function waits until the device isn`t busy anymore |
|
fn display_frame( |
|
&mut self, |
|
spi: &mut SPI, |
|
delay: &mut DELAY, |
|
) -> Result<(), Error<SPI::Error, CS::Error, BUSY::Error, DC::Error, RST::Error, DELAY::Error>>; |
|
|
|
/// Provide a combined update&display and save some time (skipping a busy check in between) |
|
fn update_and_display_frame( |
|
&mut self, |
|
spi: &mut SPI, |
|
buffer: &[u8], |
|
delay: &mut DELAY, |
|
) -> Result<(), Error<SPI::Error, CS::Error, BUSY::Error, DC::Error, RST::Error, DELAY::Error>>; |
|
|
|
/// Clears the frame buffer on the EPD with the declared background color |
|
/// |
|
/// The background color can be changed with [`WaveshareDisplay::set_background_color`] |
|
fn clear_frame( |
|
&mut self, |
|
spi: &mut SPI, |
|
delay: &mut DELAY, |
|
) -> Result<(), Error<SPI::Error, CS::Error, BUSY::Error, DC::Error, RST::Error, DELAY::Error>>; |
|
|
|
/// Trait for using various Waveforms from different LUTs |
|
/// E.g. for partial refreshes |
|
/// |
|
/// A full refresh is needed after a certain amount of quick refreshes! |
|
/// |
|
/// WARNING: Quick Refresh might lead to ghosting-effects/problems with your display. Especially for the 4.2in Display! |
|
/// |
|
/// If None is used the old value will be loaded on the LUTs once more |
|
fn set_lut( |
|
&mut self, |
|
spi: &mut SPI, |
|
refresh_rate: Option<RefreshLut>, |
|
) -> Result<(), Error<SPI::Error, CS::Error, BUSY::Error, DC::Error, RST::Error, DELAY::Error>>; |
|
|
|
/// Checks if the display is busy transmitting data |
|
/// |
|
/// 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 |
|
fn is_busy(&self) -> bool; |
|
} |
|
|
|
/// Allows quick refresh support for displays that support it; lets you send both |
|
/// old and new frame data to support this. |
|
/// |
|
/// When using the quick refresh look-up table, the display must receive separate display |
|
/// buffer data marked as old, and new. This is used to determine which pixels need to change, |
|
/// and how they will change. This isn't required when using full refreshes. |
|
/// |
|
/// (todo: Example ommitted due to CI failures.) |
|
/// Example: |
|
///```rust, no_run |
|
///# use embedded_hal_mock::*; |
|
///# fn main() -> Result<(), MockError> { |
|
///# use embedded_graphics::{ |
|
///# pixelcolor::BinaryColor::On as Black, prelude::*, primitives::{Line, PrimitiveStyle}, |
|
///# }; |
|
///# use epd_waveshare::{epd4in2::*, prelude::*}; |
|
///# use epd_waveshare::graphics::VarDisplay; |
|
///# |
|
///# let expectations = []; |
|
///# let mut spi = spi::Mock::new(&expectations); |
|
///# let expectations = []; |
|
///# let cs_pin = pin::Mock::new(&expectations); |
|
///# let busy_in = pin::Mock::new(&expectations); |
|
///# let dc = pin::Mock::new(&expectations); |
|
///# let rst = pin::Mock::new(&expectations); |
|
///# let mut delay = delay::MockNoop::new(); |
|
///# |
|
///# // Setup EPD |
|
///# let mut epd = Epd4in2::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay)?; |
|
///let (x, y, frame_width, frame_height) = (20, 40, 80,80); |
|
/// |
|
///let mut buffer = [DEFAULT_BACKGROUND_COLOR.get_byte_value(); 80 / 8 * 80]; |
|
///let mut display = VarDisplay::new(frame_width, frame_height, &mut buffer); |
|
/// |
|
///epd.update_partial_old_frame(&mut spi, display.buffer(), x, y, frame_width, frame_height) |
|
/// .ok(); |
|
/// |
|
///display.clear_buffer(Color::White); |
|
///// Execute drawing commands here. |
|
/// |
|
///epd.update_partial_new_frame(&mut spi, display.buffer(), x, y, frame_width, frame_height) |
|
/// .ok(); |
|
///# Ok(()) |
|
///# } |
|
///``` |
|
pub trait QuickRefresh<SPI, CS, BUSY, DC, RST, DELAY> |
|
where |
|
SPI: Write<u8>, |
|
CS: OutputPin, |
|
BUSY: InputPin, |
|
DC: OutputPin, |
|
RST: OutputPin, |
|
DELAY: DelayUs, |
|
{ |
|
/// Updates the old frame. |
|
fn update_old_frame( |
|
&mut self, |
|
spi: &mut SPI, |
|
buffer: &[u8], |
|
delay: &mut DELAY, |
|
) -> Result<(), Error<SPI::Error, CS::Error, BUSY::Error, DC::Error, RST::Error, DELAY::Error>>; |
|
|
|
/// Updates the new frame. |
|
fn update_new_frame( |
|
&mut self, |
|
spi: &mut SPI, |
|
buffer: &[u8], |
|
delay: &mut DELAY, |
|
) -> Result<(), Error<SPI::Error, CS::Error, BUSY::Error, DC::Error, RST::Error, DELAY::Error>>; |
|
|
|
/// Displays the new frame |
|
fn display_new_frame( |
|
&mut self, |
|
spi: &mut SPI, |
|
_delay: &mut DELAY, |
|
) -> Result<(), Error<SPI::Error, CS::Error, BUSY::Error, DC::Error, RST::Error, DELAY::Error>>; |
|
|
|
/// Updates and displays the new frame. |
|
fn update_and_display_new_frame( |
|
&mut self, |
|
spi: &mut SPI, |
|
buffer: &[u8], |
|
delay: &mut DELAY, |
|
) -> Result<(), Error<SPI::Error, CS::Error, BUSY::Error, DC::Error, RST::Error, DELAY::Error>>; |
|
|
|
/// Updates the old frame for a portion of the display. |
|
fn update_partial_old_frame( |
|
&mut self, |
|
spi: &mut SPI, |
|
buffer: &[u8], |
|
x: u32, |
|
y: u32, |
|
width: u32, |
|
height: u32, |
|
) -> Result<(), Error<SPI::Error, CS::Error, BUSY::Error, DC::Error, RST::Error, DELAY::Error>>; |
|
|
|
/// Updates the new frame for a portion of the display. |
|
fn update_partial_new_frame( |
|
&mut self, |
|
spi: &mut SPI, |
|
buffer: &[u8], |
|
x: u32, |
|
y: u32, |
|
width: u32, |
|
height: u32, |
|
) -> Result<(), Error<SPI::Error, CS::Error, BUSY::Error, DC::Error, RST::Error, DELAY::Error>>; |
|
|
|
/// Clears the partial frame buffer on the EPD with the declared background color |
|
/// The background color can be changed with [`WaveshareDisplay::set_background_color`] |
|
fn clear_partial_frame( |
|
&mut self, |
|
spi: &mut SPI, |
|
x: u32, |
|
y: u32, |
|
width: u32, |
|
height: u32, |
|
) -> Result<(), Error<SPI::Error, CS::Error, BUSY::Error, DC::Error, RST::Error, DELAY::Error>>; |
|
}
|
|
|