Browse Source

Enable drawing in three colors for epd2in13

Move from BinaryColor to TriColor:  use one Display fo drawing
main
Reinier Balt 5 years ago
parent
commit
c25d9f18d3
  1. 53
      examples/epd2in13bc.rs
  2. 22
      src/color.rs
  3. 33
      src/epd2in13bc/graphics.rs
  4. 15
      src/epd2in13bc/mod.rs
  5. 85
      src/graphics.rs

53
examples/epd2in13bc.rs

@ -11,7 +11,7 @@ use embedded_hal::prelude::*;
use epd_waveshare::{
color::*,
epd2in13bc::{Display2in13bc, Epd2in13bc},
graphics::{Display, DisplayRotation},
graphics::{DisplayRotation, TriDisplay},
prelude::*,
};
use linux_embedded_hal::{
@ -77,7 +77,7 @@ fn main() -> Result<(), std::io::Error> {
println!("Test all the rotations");
let mut display = Display2in13bc::default();
let mut display_chromatic = Display2in13bc::default();
display.clear_buffer(TriColor::White);
display.set_rotation(DisplayRotation::Rotate0);
draw_text(&mut display, "Rotation 0!", 5, 50);
@ -91,59 +91,62 @@ fn main() -> Result<(), std::io::Error> {
display.set_rotation(DisplayRotation::Rotate270);
draw_text(&mut display, "Rotation 270!", 5, 50);
// Since we only used black and white, we can resort to updating only
// the bw-buffer of this tri-color screen
epd2in13
.update_and_display_frame(&mut spi, &display.buffer(), &mut delay)
.update_and_display_frame(&mut spi, &display.bw_buffer(), &mut delay)
.expect("display frame new graphics");
println!("First frame done. Waiting 5s");
delay.delay_ms(5000u16);
println!("Now test new graphics with default rotation:");
display.clear_buffer(Color::White);
display_chromatic.clear_buffer(Color::White);
// keep both displays on same rotation
display_chromatic.set_rotation(DisplayRotation::Rotate270);
println!("Now test new graphics with default rotation and three colors:");
display.clear_buffer(TriColor::White);
// draw a analog clock
// draw a analog clock in black
let _ = Circle::new(Point::new(64, 64), 40)
.into_styled(PrimitiveStyle::with_stroke(Black, 1))
.into_styled(PrimitiveStyle::with_stroke(TriColor::Black, 1))
.draw(&mut display);
let _ = Line::new(Point::new(64, 64), Point::new(30, 40))
.into_styled(PrimitiveStyle::with_stroke(Black, 4))
.into_styled(PrimitiveStyle::with_stroke(TriColor::Black, 4))
.draw(&mut display);
let _ = Line::new(Point::new(64, 64), Point::new(80, 40))
.into_styled(PrimitiveStyle::with_stroke(Black, 1))
.into_styled(PrimitiveStyle::with_stroke(TriColor::Black, 1))
.draw(&mut display);
// draw text white on Red background by using the chromatic buffer
// draw text white on chromatic (red or yellow) background
let _ = Text::new("It's working-WoB!", Point::new(90, 10))
.into_styled(text_style!(
font = Font6x8,
text_color = White,
background_color = Black
text_color = TriColor::White,
background_color = TriColor::Chromatic
))
.draw(&mut display_chromatic);
.draw(&mut display);
// use bigger/different font
let _ = Text::new("It's working-WoB!", Point::new(90, 40))
.into_styled(text_style!(
font = Font12x16,
text_color = White,
background_color = Black
text_color = TriColor::White,
background_color = TriColor::Chromatic
))
.draw(&mut display_chromatic);
.draw(&mut display);
epd2in13.update_color_frame(&mut spi, &display.buffer(), &display_chromatic.buffer())?;
// we used three colors, so we need to update both bw-buffer and chromatic-buffer
epd2in13.update_color_frame(&mut spi, display.bw_buffer(), display.chromatic_buffer())?;
epd2in13
.display_frame(&mut spi, &mut delay)
.expect("display frame new graphics");
println!("Second frame done. Waiting 5s");
delay.delay_ms(5000u16);
display.clear_buffer(Color::White);
display_chromatic.clear_buffer(Color::White);
epd2in13.update_color_frame(&mut spi, &display.buffer(), &display_chromatic.buffer())?;
// clear both bw buffer and chromatic buffer
display.clear_buffer(TriColor::White);
epd2in13.update_color_frame(&mut spi, display.bw_buffer(), display.chromatic_buffer())?;
epd2in13.display_frame(&mut spi, &mut delay)?;
println!("Finished tests - going to sleep");
@ -154,8 +157,8 @@ fn draw_text(display: &mut Display2in13bc, text: &str, x: i32, y: i32) {
let _ = Text::new(text, Point::new(x, y))
.into_styled(text_style!(
font = Font6x8,
text_color = Black,
background_color = White
text_color = TriColor::Black,
background_color = TriColor::White
))
.draw(display);
}

22
src/color.rs

@ -169,6 +169,28 @@ impl From<u8> for Color {
}
}
impl TriColor {
/// Get the color encoding of the color for one bit
pub fn get_bit_value(self) -> u8 {
match self {
TriColor::White => 1u8,
TriColor::Black | TriColor::Chromatic => 0u8,
}
}
/// Gets a full byte of black or white pixels
pub fn get_byte_value(self) -> u8 {
match self {
TriColor::White => 0xff,
TriColor::Black | TriColor::Chromatic => 0x00,
}
}
}
impl PixelColor for TriColor {
type Raw = ();
}
#[cfg(test)]
mod tests {
use super::*;

33
src/epd2in13bc/graphics.rs

@ -1,30 +1,33 @@
use crate::color::TriColor;
use crate::epd2in13bc::{DEFAULT_BACKGROUND_COLOR, HEIGHT, NUM_DISPLAY_BITS, WIDTH};
use crate::graphics::{Display, DisplayRotation};
use embedded_graphics::pixelcolor::BinaryColor;
use crate::graphics::{DisplayRotation, TriDisplay};
use embedded_graphics::prelude::*;
/// Full size buffer for use with the 2in13b/c EPD
/// Full size buffer for use with the 2.13" b/c EPD
///
/// Can also be manually constructed and be used together with VarDisplay
pub struct Display2in13bc {
buffer: [u8; NUM_DISPLAY_BITS as usize],
// one buffer for both b/w and for chromatic:
// * &buffer[0..NUM_DISPLAY_BITS] for b/w buffer and
// * &buffer[NUM_DISPLAY_BITS..2*NUM_DISPLAY_BITS] for chromatic buffer
buffer: [u8; 2 * NUM_DISPLAY_BITS as usize],
rotation: DisplayRotation,
}
impl Default for Display2in13bc {
fn default() -> Self {
Display2in13bc {
buffer: [DEFAULT_BACKGROUND_COLOR.get_byte_value(); NUM_DISPLAY_BITS as usize],
buffer: [DEFAULT_BACKGROUND_COLOR.get_byte_value(); 2 * NUM_DISPLAY_BITS as usize],
rotation: DisplayRotation::default(),
}
}
}
impl DrawTarget<BinaryColor> for Display2in13bc {
impl DrawTarget<TriColor> for Display2in13bc {
type Error = core::convert::Infallible;
fn draw_pixel(&mut self, pixel: Pixel<BinaryColor>) -> Result<(), Self::Error> {
self.draw_helper(WIDTH, HEIGHT, pixel)
fn draw_pixel(&mut self, pixel: Pixel<TriColor>) -> Result<(), Self::Error> {
self.draw_helper_tri(WIDTH, HEIGHT, pixel)
}
fn size(&self) -> Size {
@ -32,7 +35,7 @@ impl DrawTarget<BinaryColor> for Display2in13bc {
}
}
impl Display for Display2in13bc {
impl TriDisplay for Display2in13bc {
fn buffer(&self) -> &[u8] {
&self.buffer
}
@ -48,4 +51,16 @@ impl Display for Display2in13bc {
fn rotation(&self) -> DisplayRotation {
self.rotation
}
fn chromatic_offset(&self) -> usize {
NUM_DISPLAY_BITS as usize
}
fn bw_buffer(&self) -> &[u8] {
&self.buffer[0..self.chromatic_offset()]
}
fn chromatic_buffer(&self) -> &[u8] {
&self.buffer[self.chromatic_offset()..]
}
}

15
src/epd2in13bc/mod.rs

@ -70,8 +70,9 @@ pub const WIDTH: u32 = 104;
/// Height of epd2in13bc in pixels
pub const HEIGHT: u32 = 212;
/// Default background color (white) of epd2in13bc display
pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
pub const DEFAULT_BACKGROUND_COLOR: TriColor = TriColor::White;
/// Number of bits for b/w buffer and same for chromatic buffer
const NUM_DISPLAY_BITS: u32 = WIDTH * HEIGHT / 8;
const IS_BUSY_LOW: bool = true;
@ -81,7 +82,7 @@ const BLACK_BORDER: u8 = 0x30;
const CHROMATIC_BORDER: u8 = 0xb0;
const FLOATING_BORDER: u8 = 0xF0;
use crate::color::{Color, TriColor};
use crate::color::TriColor;
pub(crate) mod command;
use self::command::Command;
@ -91,10 +92,10 @@ mod graphics;
#[cfg(feature = "graphics")]
pub use self::graphics::Display2in13bc;
/// Epd2in9bc driver
/// Epd2in13bc driver
pub struct Epd2in13bc<SPI, CS, BUSY, DC, RST, DELAY> {
interface: DisplayInterface<SPI, CS, BUSY, DC, RST, DELAY>,
color: Color,
color: TriColor,
}
impl<SPI, CS, BUSY, DC, RST, DELAY> InternalWiAdditions<SPI, CS, BUSY, DC, RST, DELAY>
@ -196,7 +197,7 @@ where
RST: OutputPin,
DELAY: DelayMs<u8>,
{
type DisplayColor = Color;
type DisplayColor = TriColor;
fn new(
spi: &mut SPI,
cs: CS,
@ -236,11 +237,11 @@ where
self.init(spi, delay)
}
fn set_background_color(&mut self, color: Color) {
fn set_background_color(&mut self, color: TriColor) {
self.color = color;
}
fn background_color(&self) -> &Color {
fn background_color(&self) -> &TriColor {
&self.color
}

85
src/graphics.rs

@ -1,7 +1,7 @@
//! Graphics Support for EPDs
use crate::buffer_len;
use crate::color::{Color, OctColor};
use crate::color::{Color, OctColor, TriColor};
use embedded_graphics::{pixelcolor::BinaryColor, prelude::*};
/// Displayrotation
@ -85,6 +85,89 @@ pub trait Display: DrawTarget<BinaryColor> {
}
}
/// Necessary traits for all displays to implement for drawing
///
/// Adds support for:
/// - Drawing (With the help of DrawTarget/Embedded Graphics)
/// - Rotations
/// - Clearing
pub trait TriDisplay: DrawTarget<TriColor> {
/// Clears the buffer of the display with the chosen background color
fn clear_buffer(&mut self, background_color: TriColor) {
for elem in self.get_mut_buffer().iter_mut() {
*elem = background_color.get_byte_value();
}
}
/// Returns the buffer
fn buffer(&self) -> &[u8];
/// Returns a mutable buffer
fn get_mut_buffer(&mut self) -> &mut [u8];
/// Sets the rotation of the display
fn set_rotation(&mut self, rotation: DisplayRotation);
/// Get the current rotation of the display
fn rotation(&self) -> DisplayRotation;
/// Get the offset into buffer where chromatic data starts
fn chromatic_offset(&self) -> usize;
/// return the b/w part of the buffer
fn bw_buffer(&self) -> &[u8];
/// return the chromatic part of the buffer
fn chromatic_buffer(&self) -> &[u8];
/// Helperfunction for the Embedded Graphics draw trait
///
/// Becomes uneccesary when const_generics become stablised
fn draw_helper_tri(
&mut self,
width: u32,
height: u32,
pixel: Pixel<TriColor>,
) -> Result<(), Self::Error> {
let rotation = self.rotation();
let Pixel(point, color) = pixel;
if outside_display(point, width, height, rotation) {
return Ok(());
}
// Give us index inside the buffer and the bit-position in that u8 which needs to be changed
let (index, bit) = find_position(point.x as u32, point.y as u32, width, height, rotation);
let index = index as usize;
let offset = self.chromatic_offset();
let buffer = self.get_mut_buffer();
// "Draw" the Pixel on that bit
match color {
TriColor::Black => {
// clear bit in bw-buffer -> black
buffer[index] &= !bit;
// set bit in chromatic-buffer -> white
buffer[index+offset] |= bit;
}
TriColor::White => {
// set bit in bw-buffer -> white
buffer[index] |= bit;
// set bit in chromatic-buffer -> white
buffer[index+offset] |= bit;
}
TriColor::Chromatic => {
// set bit in b/w buffer (white)
buffer[index] |= bit;
// clear bit in chromatic buffer -> chromatic
buffer[index+offset] &= !bit;
}
}
Ok(())
}
}
/// Necessary traits for all displays to implement for drawing
///
/// Adds support for:

Loading…
Cancel
Save