Browse Source

Merge pull request #76 from lrbalt/tri-color

Enable drawing in three colors for epd2in13 with TriColor thanks to @lrbalt
main
Chris 5 years ago committed by GitHub
parent
commit
253cc101fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 53
      examples/epd2in13bc.rs
  2. 23
      src/color.rs
  3. 33
      src/epd2in13bc/graphics.rs
  4. 45
      src/epd2in13bc/mod.rs
  5. 85
      src/graphics.rs
  6. 2
      src/lib.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);
}

23
src/color.rs

@ -169,6 +169,29 @@ 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,
}
}
}
#[cfg(feature = "graphics")]
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()..]
}
}

45
src/epd2in13bc/mod.rs

@ -7,10 +7,8 @@
//!```rust, no_run
//!# use embedded_hal_mock::*;
//!# fn main() -> Result<(), MockError> {
//!use embedded_graphics::{
//! pixelcolor::BinaryColor::On as Black, prelude::*, primitives::Line, style::PrimitiveStyle,
//!};
//!use epd_waveshare::{epd2in13bc::*, prelude::*};
//!use embedded_graphics::{prelude::*, primitives::Line, style::PrimitiveStyle};
//!use epd_waveshare::{epd2in13bc::*, prelude::*, color::TriColor};
//!#
//!# let expectations = [];
//!# let mut spi = spi::Mock::new(&expectations);
@ -25,28 +23,24 @@
//!let mut epd = Epd2in13bc::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay)?;
//!
//!// Use display graphics from embedded-graphics
//!// This display is for the black/white pixels
//!let mut mono_display = Display2in13bc::default();
//!// This display is for the black/white/chromatic pixels
//!let mut tricolor_display = Display2in13bc::default();
//!
//!// Use embedded graphics for drawing
//!// A black line
//!// Use embedded graphics for drawing a black line
//!let _ = Line::new(Point::new(0, 120), Point::new(0, 200))
//! .into_styled(PrimitiveStyle::with_stroke(Black, 1))
//! .draw(&mut mono_display);
//! .into_styled(PrimitiveStyle::with_stroke(TriColor::Black, 1))
//! .draw(&mut tricolor_display);
//!
//!// Use a second display for red/yellow
//!let mut chromatic_display = Display2in13bc::default();
//!
//!// We use `Black` but it will be shown as red/yellow
//!// We use `chromatic` but it will be shown as red/yellow
//!let _ = Line::new(Point::new(15, 120), Point::new(15, 200))
//! .into_styled(PrimitiveStyle::with_stroke(Black, 1))
//! .draw(&mut chromatic_display);
//! .into_styled(PrimitiveStyle::with_stroke(TriColor::Chromatic, 1))
//! .draw(&mut tricolor_display);
//!
//!// Display updated frame
//!epd.update_color_frame(
//! &mut spi,
//! &mono_display.buffer(),
//! &chromatic_display.buffer()
//! &tricolor_display.bw_buffer(),
//! &tricolor_display.chromatic_buffer()
//!)?;
//!epd.display_frame(&mut spi, &mut delay)?;
//!
@ -70,8 +64,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 +76,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 +86,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 +191,7 @@ where
RST: OutputPin,
DELAY: DelayMs<u8>,
{
type DisplayColor = Color;
type DisplayColor = TriColor;
fn new(
spi: &mut SPI,
cs: CS,
@ -236,11 +231,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:

2
src/lib.rs

@ -99,7 +99,7 @@ pub mod prelude {
pub use crate::SPI_MODE;
#[cfg(feature = "graphics")]
pub use crate::graphics::{Display, DisplayRotation, OctDisplay};
pub use crate::graphics::{Display, DisplayRotation, OctDisplay, TriDisplay};
}
/// Computes the needed buffer length. Takes care of rounding up in case width

Loading…
Cancel
Save