Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
219 changes: 218 additions & 1 deletion src/epd2in13b_v4/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,22 @@
//!# Ok(())
//!# }
//!```
use core::convert::Infallible;

use embedded_graphics_core::prelude::DrawTarget;
// Original Waveforms from Waveshare
use embedded_hal::{
delay::DelayNs,
digital::{InputPin, OutputPin},
spi::SpiDevice,
};

use crate::buffer_len;
use crate::color::TriColor;
use crate::interface::DisplayInterface;
use crate::traits::{
InternalWiAdditions, RefreshLut, WaveshareDisplay, WaveshareThreeColorDisplay,
};
use crate::{buffer_len, color::Color};

pub(crate) mod command;
use self::command::{
Expand All @@ -83,6 +86,29 @@ pub type Display2in13b = crate::graphics::Display<
TriColor,
>;

#[cfg(feature = "graphics")]
/// buffered buffer
pub type BufferMonoDisplay2in13b = crate::graphics::Display<
WIDTH,
{ HEIGHT / BUFFER },
false,
{ buffer_len(WIDTH as usize, (HEIGHT / BUFFER) as usize) },
Color,
>;

#[cfg(feature = "graphics")]
/// buffered buffer
pub type BufferChromaticDisplay2in13b = crate::graphics::Display<
WIDTH,
{ HEIGHT / BUFFER },
false,
{ buffer_len(WIDTH as usize, (HEIGHT / BUFFER) as usize) },
TriColor,
>;

/// buffers
pub const BUFFER: u32 = 4;

/// Width of the display.
pub const WIDTH: u32 = 122;

Expand Down Expand Up @@ -163,6 +189,79 @@ where
}
}

impl<SPI, BUSY, DC, RST, DELAY> Epd2in13b<SPI, BUSY, DC, RST, DELAY>
where
SPI: SpiDevice,
BUSY: InputPin,
DC: OutputPin,
RST: OutputPin,
DELAY: DelayNs,
{
/// Transmit data to the SRAM of the EPD with the provided generators.
///
/// Updates both the black and the secondary color layers
/// Useful for rendering directly from progmem buffers.
///
/// Example:
/// ```rust no_run
/// progmem! {
/// static progmem BLACK: [u8; 4000] = *include_bytes!("black.gray");
/// static progmem RED: [u8; 4000] = *include_bytes!("red.gray");
/// }
/// epd.update_color_frame_with(
/// &mut spi,
/// &mut delay,
/// |i| BLACK.load_at(i),
/// |i| RED.load_at(i),
/// BLACK.len(),
/// RED.len(),
/// )?;
/// ```
pub fn update_color_frame_with(
&mut self,
spi: &mut SPI,
delay: &mut DELAY,
black: impl Fn(usize) -> u8,
chromatic: impl Fn(usize) -> u8,
black_len: usize,
chromatic_len: usize,
) -> Result<(), SPI::Error> {
self.update_achromatic_frame_with(spi, delay, black, black_len)?;
self.update_chromatic_frame_with(spi, delay, chromatic, chromatic_len)
}

/// Update only the black/white data of the display using a generator
///
/// This must be finished by calling `update_chromatic_frame`.
pub fn update_achromatic_frame_with(
&mut self,
spi: &mut SPI,
_delay: &mut DELAY,
black: impl Fn(usize) -> u8,
len: usize,
) -> Result<(), SPI::Error> {
self.interface.cmd(spi, Command::WriteRam)?;
self.interface.data_with(spi, black, len)?;
Ok(())
}

/// 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.
pub fn update_chromatic_frame_with(
&mut self,
spi: &mut SPI,
_delay: &mut DELAY,
chromatic: impl Fn(usize) -> u8,
len: usize,
) -> Result<(), SPI::Error> {
self.interface.cmd(spi, Command::WriteRamRed)?;
self.interface.data_with(spi, chromatic, len)?;
Ok(())
}
}

impl<SPI, BUSY, DC, RST, DELAY> WaveshareThreeColorDisplay<SPI, BUSY, DC, RST, DELAY>
for Epd2in13b<SPI, BUSY, DC, RST, DELAY>
where
Expand Down Expand Up @@ -327,6 +426,41 @@ where
}
}

#[derive(Copy, Clone)]
/// a type safe chunk reperesentation for BufferMonoDisplay
pub enum Chunk {
/// the first chunk of the display
Buf1,
/// the second chunk of the display
Buf2,
/// the third chunk of the display
Buf3,
/// the fourth chunk of the display
Buf4,
}

impl Chunk {
/// converts chunk to a zero-indexed `u32`
pub fn to_zero_indexed(&self) -> u32 {
match self {
Chunk::Buf1 => 0,
Chunk::Buf2 => 1,
Chunk::Buf3 => 2,
Chunk::Buf4 => 3,
}
}
/// converts from zero-indexed `u32` to a `Chunk`
pub const fn from_zero_indexed(i: u32) -> Self {
match i {
0 => Chunk::Buf1,
1 => Chunk::Buf2,
2 => Chunk::Buf3,
3 => Chunk::Buf4,
_ => panic!("please check buffer"),
}
}
}

impl<SPI, BUSY, DC, RST, DELAY> Epd2in13b<SPI, BUSY, DC, RST, DELAY>
where
SPI: SpiDevice,
Expand All @@ -335,6 +469,89 @@ where
RST: OutputPin,
DELAY: DelayNs,
{
/// Due to memory limitations on the arduino boards, this function allows the user to separate the 122x250 board into four 122x62.5(rounding to 63) subgrids.
///
/// for usage on `mono_buffers` and colored_buffers`, please refer to the documentation of `update_achromatic_buffered` and `update_chromatic_buffered`
pub fn update_frame_buffered(
&mut self,
spi: &mut SPI,
delay: &mut DELAY,
mono_buffers: impl FnMut(&mut BufferMonoDisplay2in13b, Chunk) -> Result<Option<()>, Infallible>,
colored_buffers: impl FnMut(
&mut BufferMonoDisplay2in13b,
Chunk,
) -> Result<Option<()>, Infallible>,
) -> Result<(), SPI::Error> {
self.update_achromatic_buffered(spi, delay, mono_buffers)?;
self.update_chromatic_buffered(spi, delay, colored_buffers)
}

/// Due to memory limitations on the arduino boards, this function allows the user to separate the 122x250 board into four 122x62.5(rounding to 63) subgrids.
///
/// IMPORTANT: this must be followed by `update_chromatic_buffered`, even if you're trying to only display purely mono content, otherwise the display won't be updated.
///
/// `buffers`: A function that that should populate the content of each section of the display.
/// - Takes a mutable reference to `BuffermonoDisplay2in13b` and a buffer index(0-3)
/// - Returns `Result<Option<(), Infalliable>>`
/// * `Ok(Some(()))` indicates successful execution.
/// * `Ok(None)` indicates the buffer should be left unmodified, leaving it uncolored.
/// * `Err(Infalliable)` is here purely for allowing `?` with `embedded-graphics` draw operations.
pub fn update_achromatic_buffered(
&mut self,
spi: &mut SPI,
_delay: &mut DELAY,
mut buffers: impl FnMut(&mut BufferMonoDisplay2in13b, Chunk) -> Result<Option<()>, Infallible>,
) -> Result<(), SPI::Error> {
self.interface.cmd(spi, Command::WriteRam)?;
for i in 0..BUFFER {
let mut buffer = BufferMonoDisplay2in13b::default();
if buffers(&mut buffer, Chunk::from_zero_indexed(i))
.unwrap()
.is_none()
{
buffer.clear(Color::White).unwrap();
}
let data = buffer.buffer();
self.interface.data(spi, data)?;
}
Ok(())
}

/// Due to memory limitations on the arduino boards, this function allows the user to separate the 122x250 board into four 122x62.5(rounding to 63) subgrids.
///
/// IMPORTANT: this function must be called after `update_achromatic_buffered`, even if you're trying to only display purely mono content, otherwise the display won't be updated.
///
/// The usage of color within `BufferMonoDisplay2in13b` is a misnomer. `Color::White` stands for colored(red), while `Color::Black` stands for uncolored(white).
///
/// `buffers`: A function that that should populate the content of each section of the display.
/// - Takes a mutable reference to `BufferMonoDisplay2in13b` and a buffer index(0-3)
/// - Returns `Result<Option<(), Infalliable>>`
/// * `Ok(Some(()))` indicates successful execution
/// * `Ok(None)` indicates the buffer should be left unmodified, leaving it uncolored.
/// * `Err(Infalliable)` is here purely for allowing `?` with `embedded-graphics` draw operations.
pub fn update_chromatic_buffered(
&mut self,
spi: &mut SPI,
delay: &mut DELAY,
mut buffers: impl FnMut(&mut BufferMonoDisplay2in13b, Chunk) -> Result<Option<()>, Infallible>,
) -> Result<(), SPI::Error> {
self.command(spi, Command::WriteRamRed)?;
let mut buffer = BufferMonoDisplay2in13b::default();
for i in 0..BUFFER {
if buffers(&mut buffer, Chunk::from_zero_indexed(i))
.unwrap()
.is_none()
{
buffer.clear(Color::Black).unwrap();
}
let data = buffer.buffer();
self.interface.data(spi, data)?;
}
self.interface.cmd(spi, Command::MasterActivation)?;
self.wait_until_idle(spi, delay)?;
Ok(())
}

fn set_display_update_control(
&mut self,
spi: &mut SPI,
Expand Down
24 changes: 24 additions & 0 deletions src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,30 @@ where
Ok(())
}

/// Basic function for sending u8-values with the provided generator.
///
/// Intented for use with rendering from progmem buffers.
pub(crate) fn data_with(
&mut self,
spi: &mut SPI,
data: impl Fn(usize) -> u8,
len: usize,
) -> Result<(), SPI::Error> {
// high for data
let _ = self.dc.set_high();

if SINGLE_BYTE_WRITE {
for i in 0..len {
// Transfer data one u8 at a time over spi
self.write(spi, &[data(i)])?;
}
} else {
unimplemented!();
}

Ok(())
}

/// Basic function for sending [Commands](Command) and the data belonging to it.
///
/// TODO: directly use ::write? cs wouldn't needed to be changed twice than
Expand Down
Loading