Browse Source

Various improvements (#25)

- Added is_busy to Waveshare_Interface
- Added IS_BUSY_LOW const for all supported epds
- Added is_busy to DisplayInterface
- moved width, height and default_background_color directly to epd4in2 module
- Added VarDisplay (a variable buffersize display/graphic driver)
- Removed all Buffers (Buffer1in54,...) and instead made specialised Displays (Display1in54,...) with included Buffers
- Updated and added more examples
- Cargo fmt/clippy
- Improved Docs/Readmes
digi-v2-tests
Chris 4 years ago committed by GitHub
parent
commit
5c0744ff01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 93
      .travis.yml
  2. 5
      README.md
  3. 18
      examples/Readme.md
  4. 9
      examples/epd1in54_full/Cargo.toml
  5. 39
      examples/epd1in54_full/src/main.rs
  6. 12
      examples/epd1in54_no_graphics/Cargo.toml
  7. 105
      examples/epd1in54_no_graphics/src/main.rs
  8. 9
      examples/epd2in9_full/Cargo.toml
  9. 39
      examples/epd2in9_full/src/main.rs
  10. 9
      examples/epd4in2_full/Cargo.toml
  11. 45
      examples/epd4in2_full/src/main.rs
  12. 15
      examples/epd4in2_var_display_buffer/Cargo.toml
  13. 195
      examples/epd4in2_var_display_buffer/src/main.rs
  14. 59
      src/epd1in54/graphics.rs
  15. 21
      src/epd1in54/mod.rs
  16. 49
      src/epd2in9/graphics.rs
  17. 21
      src/epd2in9/mod.rs
  18. 6
      src/epd4in2/constants.rs
  19. 87
      src/epd4in2/graphics.rs
  20. 17
      src/epd4in2/mod.rs
  21. 146
      src/graphics.rs
  22. 25
      src/interface.rs
  23. 48
      src/lib.rs
  24. 8
      src/traits.rs

93
.travis.yml

@ -1,7 +1,5 @@
# Based on the "trust" template v0.1.2
# https://github.com/japaric/trust/tree/v0.1.2
dist: trusty
language: rust
rust:
- stable
@ -11,66 +9,22 @@ sudo: required
# TODO Rust builds on stable by default, this can be
# overridden on a case by case basis down below.
matrix:
allow_failures:
# - nightly
- nightly
# TODO These are all the build jobs. Adjust as necessary. Comment out what you
# don't need
include:
# Android
#- env: TARGET=aarch64-linux-android DISABLE_TESTS=1
#- env: TARGET=arm-linux-androideabi DISABLE_TESTS=1
#- env: TARGET=armv7-linux-androideabi DISABLE_TESTS=1
#- env: TARGET=i686-linux-android DISABLE_TESTS=1
#- env: TARGET=x86_64-linux-android DISABLE_TESTS=1
# iOS
#- env: TARGET=aarch64-apple-ios DISABLE_TESTS=1
# os: osx
#- env: TARGET=armv7-apple-ios DISABLE_TESTS=1
# os: osx
#- env: TARGET=armv7s-apple-ios DISABLE_TESTS=1
# os: osx
#- env: TARGET=i386-apple-ios DISABLE_TESTS=1
# os: osx
#- env: TARGET=x86_64-apple-ios DISABLE_TESTS=1
# os: osx
# Linux
#- env: TARGET=aarch64-unknown-linux-gnu
# Raspberry Pi
- env: TARGET=arm-unknown-linux-gnueabi DISABLE_EXAMPLES=1
- env: TARGET=arm-unknown-linux-gnueabi
# Raspberry Pi 3...
- env: TARGET=armv7-unknown-linux-gnueabihf DISABLE_EXAMPLES=1
#- env: TARGET=i686-unknown-linux-gnu
#- env: TARGET=i686-unknown-linux-musl
#- env: TARGET=mips-unknown-linux-gnu
#- env: TARGET=mips64-unknown-linux-gnuabi64
#- env: TARGET=mips64el-unknown-linux-gnuabi64
#- env: TARGET=mipsel-unknown-linux-gnu
#- env: TARGET=powerpc-unknown-linux-gnu
#- env: TARGET=powerpc64-unknown-linux-gnu
#- env: TARGET=powerpc64le-unknown-linux-gnu
#- env: TARGET=s390x-unknown-linux-gnu DISABLE_TESTS=1
- env: TARGET=armv7-unknown-linux-gnueabihf
- env: TARGET=x86_64-unknown-linux-gnu
- env: TARGET=x86_64-unknown-linux-musl
# OSX
#- env: TARGET=i686-apple-darwin
# os: osx
#- env: TARGET=x86_64-apple-darwin
# os: osx
# *BSD
#- env: TARGET=i686-unknown-freebsd DISABLE_TESTS=1
#- env: TARGET=x86_64-unknown-freebsd DISABLE_TESTS=1
#- env: TARGET=x86_64-unknown-netbsd DISABLE_TESTS=1
# Windows
#- env: TARGET=x86_64-pc-windows-gnu
# Bare metal
# These targets don't support std and as such are likely not suitable for
# most crates.
@ -79,27 +33,6 @@ matrix:
- env: TARGET=thumbv7em-none-eabihf
- env: TARGET=thumbv7m-none-eabi
# Testing other channels
#- env: TARGET=x86_64-unknown-linux-gnu
# rust: nightly
#- env: TARGET=x86_64-apple-darwin
# os: osx
# rust: nightly
#- env: TEST_DIR=examples/embedded_linux
#- env: TEST_DIR=examples/f3_stm32f30x
addons:
apt:
packages:
- libcurl4-openssl-dev
- libelf-dev
- libdw-dev
- cmake
- gcc
- binutils-dev
- libiberty-dev
before_install:
- set -e
@ -108,9 +41,7 @@ before_install:
install:
- cargo install cargo-update || echo "cargo-update already installed"
- cargo install cargo-travis || echo "cargo-travis already installed"
- cargo install-update -a # update outdated cached binaries
- rustup override set nightly
- rustup target add thumbv7m-none-eabi
- rustup component add clippy-preview
- rustup component add rustfmt-preview
@ -122,17 +53,11 @@ script:
- cargo check
- cargo test --all-features --release
- cargo doc --all-features --release
- cd examples/embedded_linux_epd4in2 && cargo fmt --all -- --check && cargo check && cd ../../
- cd examples/embedded_linux_epd1in54 && cargo fmt --all -- --check && cargo check && cd ../../
- cd examples/embedded_linux_epd2in9 && cargo fmt --all -- --check && cargo check && cd ../../
# - cd examples/stm32f3discovery && cargo check --target thumbv7m-none-eabi && cd ../../
#- cd ../f3_stm32f30x && cargo build
after_success:
# measure code coverage and upload to coveralls.io
- cargo coveralls
#- cargo doc-upload
- cd examples/epd4in2_full && cargo fmt --all -- --check && cargo check && cd ../../
- cd examples/epd2in9_full && cargo fmt --all -- --check && cargo check && cd ../../
- cd examples/epd1in54_full && cargo fmt --all -- --check && cargo check && cd ../../
- cd examples/epd1in54_no_graphics && cargo fmt --all -- --check && cargo check && cd ../../
- cd examples/epd4in2_var_display_buffer && cargo fmt --all -- --check && cargo check && cd ../../
cache: cargo

5
README.md

@ -10,7 +10,7 @@ Other similiar libraries with support for much more displays are [u8g2](https://
## Examples
There are multiple examples in the examples folder. For more infos about the examples see the seperate Readme [there](/examples/Readme.md).
There are multiple examples in the examples folder. For more infos about the examples see the seperate Readme [there](/examples/Readme.md). These examples are all rust projects of their own, so you need to go inside the project to execute it (cargo run --example doesn't work).
```Rust
// Setup the epd
@ -92,9 +92,6 @@ They are also called A and B, but you shouldn't get confused and mix it with the
| | 7.5in (B) |
| | 7.5in (C) |
## TODO's
- [ ] improve the partial drawing/check the timings/timing improvements/....

18
examples/Readme.md

@ -1,12 +1,20 @@
# Examples:
### embedded_linux_epd4in2
All of these examples are projects of their own.
Basic example of using a Raspberry Pi with the 4in2 Waveshare E-Ink Display.
A few notes:
- If not stated otherwise the example is for a Raspberry Pi running Linux.
- epdXinYY_full showcase most of what can be done with this crate. This means that they are using graphics feature and use the DisplayXinYY with its buffer.
It showcases most of what can be done with the crate.
Special Examples:
### epd4in2_var_display_buffer
This examples used the graphics feature with VarDisplay and therefore a variable buffer(size).
### epd1in54_no_graphics (Fastest Example)
This example doesn't use the graphics feature and handles all the "drawing" by itself. It also has a speeddemonstration included.
### embedded_linux_epd1in54
This example doesn't use the graphics feature of the crate and shows the fast update rate of the 1in54 EPD.

9
examples/embedded_linux_epd1in54/Cargo.toml → examples/epd1in54_full/Cargo.toml

@ -2,13 +2,12 @@
name = "embedded_linux_eink_example"
version = "0.1.0"
authors = ["Christoph Groß <christoph-gross@mailbox.org>"]
edition = "2018"
[dependencies]
epd-waveshare = { path = "../../", default-features = false, features = ["epd1in54", "graphics"]}
linux-embedded-hal = "0.2.1"
embedded-graphics = "0.4.3"
embedded-hal = { version = "0.2.1", features = ["unproven"] }
linux-embedded-hal = "0.2.2"
embedded-graphics = "0.4.5"
embedded-hal = { version = "0.2.2", features = ["unproven"] }

39
examples/embedded_linux_epd1in54/src/main.rs → examples/epd1in54_full/src/main.rs

@ -1,36 +1,26 @@
// the library for the embedded linux device
extern crate linux_embedded_hal as lin_hal;
use lin_hal::spidev::{self, SpidevOptions};
use lin_hal::sysfs_gpio::Direction;
use lin_hal::Delay;
use lin_hal::{Pin, Spidev};
// the eink library
extern crate epd_waveshare;
#![deny(warnings)]
use embedded_graphics::{coord::Coord, fonts::Font6x8, prelude::*, Drawing};
use embedded_hal::prelude::*;
use epd_waveshare::{
epd1in54::{Buffer1in54, EPD1in54},
epd1in54::{Display1in54, EPD1in54},
graphics::{Display, DisplayRotation},
prelude::*,
};
// Graphics
extern crate embedded_graphics;
use embedded_graphics::coord::Coord;
use embedded_graphics::fonts::Font6x8;
use embedded_graphics::prelude::*;
//use embedded_graphics::primitives::{Circle, Line};
use embedded_graphics::Drawing;
// HAL (Traits)
extern crate embedded_hal;
use embedded_hal::prelude::*;
use linux_embedded_hal::{
spidev::{self, SpidevOptions},
sysfs_gpio::Direction,
Delay, Pin, Spidev,
};
// activate spi, gpio in raspi-config
// needs to be run with sudo because of some sysfs_gpio permission problems and follow-up timing problems
// see https://github.com/rust-embedded/rust-sysfs-gpio/issues/5 and follow-up issues
fn main() {
run().unwrap();
if let Err(e) = run() {
eprintln!("Program exited early with error: {}", e);
}
}
fn run() -> Result<(), std::io::Error> {
@ -86,8 +76,7 @@ fn run() -> Result<(), std::io::Error> {
epd.display_frame(&mut spi).expect("disp 1");
println!("Test all the rotations");
let mut buffer = Buffer1in54::default();
let mut display = Display::new(epd.width(), epd.height(), &mut buffer.buffer);
let mut display = Display1in54::default();
display.set_rotation(DisplayRotation::Rotate0);
display.draw(
Font6x8::render_str("Rotate 0!")

12
examples/epd1in54_no_graphics/Cargo.toml

@ -0,0 +1,12 @@
[package]
name = "embedded_linux_eink_example"
version = "0.1.0"
authors = ["Christoph Groß <christoph-gross@mailbox.org>"]
edition = "2018"
[dependencies]
epd-waveshare = { path = "../../", default-features = false, features = ["epd1in54"]}
linux-embedded-hal = "0.2.2"
embedded-hal = { version = "0.2.2", features = ["unproven"] }

105
examples/epd1in54_no_graphics/src/main.rs

@ -0,0 +1,105 @@
#![deny(warnings)]
use embedded_hal::prelude::*;
use epd_waveshare::{epd1in54::EPD1in54, prelude::*};
use linux_embedded_hal::{
spidev::{self, SpidevOptions},
sysfs_gpio::Direction,
Delay, Pin, Spidev,
};
// activate spi, gpio in raspi-config
// needs to be run with sudo because of some sysfs_gpio permission problems and follow-up timing problems
// see https://github.com/rust-embedded/rust-sysfs-gpio/issues/5 and follow-up issues
fn main() {
if let Err(e) = run() {
eprintln!("Program exited early with error: {}", e);
}
}
fn run() -> Result<(), std::io::Error> {
// Configure SPI
// SPI settings are from eink-waveshare-rs documenation
let mut spi = Spidev::open("/dev/spidev0.0")?;
let options = SpidevOptions::new()
.bits_per_word(8)
.max_speed_hz(4_000_000)
.mode(spidev::SPI_MODE_0)
.build();
spi.configure(&options).expect("spi configuration");
// Configure Digital I/O Pin to be used as Chip Select for SPI
let cs_pin = Pin::new(26); //BCM7 CE0
cs_pin.export().expect("cs_pin export");
while !cs_pin.is_exported() {}
cs_pin
.set_direction(Direction::Out)
.expect("cs_pin Direction");
cs_pin.set_value(1).expect("cs_pin Value set to 1");
// Configure Busy Input Pin
let busy = Pin::new(5); //pin 29
busy.export().expect("busy export");
while !busy.is_exported() {}
busy.set_direction(Direction::In).expect("busy Direction");
//busy.set_value(1).expect("busy Value set to 1");
// Configure Data/Command OutputPin
let dc = Pin::new(6); //pin 31 //bcm6
dc.export().expect("dc export");
while !dc.is_exported() {}
dc.set_direction(Direction::Out).expect("dc Direction");
dc.set_value(1).expect("dc Value set to 1");
// Configure Reset OutputPin
let rst = Pin::new(16); //pin 36 //bcm16
rst.export().expect("rst export");
while !rst.is_exported() {}
rst.set_direction(Direction::Out).expect("rst Direction");
rst.set_value(1).expect("rst Value set to 1");
// Configure Delay
let mut delay = Delay {};
// Setup of the needed pins is finished here
// Now the "real" usage of the eink-waveshare-rs crate begins
let mut epd = EPD1in54::new(&mut spi, cs_pin, busy, dc, rst, &mut delay)?;
// Clear the full screen
epd.clear_frame(&mut spi)?;
epd.display_frame(&mut spi)?;
// Speeddemo
epd.set_lut(&mut spi, Some(RefreshLUT::QUICK))?;
let small_buffer = [Color::Black.get_byte_value(); 32]; //16x16
let number_of_runs = 1;
for i in 0..number_of_runs {
let offset = i * 8 % 150;
epd.update_partial_frame(&mut spi, &small_buffer, 25 + offset, 25 + offset, 16, 16)?;
epd.display_frame(&mut spi)?;
}
// Clear the full screen
epd.clear_frame(&mut spi)?;
epd.display_frame(&mut spi)?;
// Draw some squares
let small_buffer = [Color::Black.get_byte_value(); 3200]; //160x160
epd.update_partial_frame(&mut spi, &small_buffer, 20, 20, 160, 160)?;
let small_buffer = [Color::White.get_byte_value(); 800]; //80x80
epd.update_partial_frame(&mut spi, &small_buffer, 60, 60, 80, 80)?;
let small_buffer = [Color::Black.get_byte_value(); 8]; //8x8
epd.update_partial_frame(&mut spi, &small_buffer, 96, 96, 8, 8)?;
// Display updated frame
epd.display_frame(&mut spi)?;
delay.delay_ms(5000u16);
// Set the EPD to sleep
epd.sleep(&mut spi)?;
Ok(())
}

9
examples/embedded_linux_epd2in9/Cargo.toml → examples/epd2in9_full/Cargo.toml

@ -2,13 +2,12 @@
name = "embedded_linux_eink_example"
version = "0.1.0"
authors = ["Christoph Groß <christoph-gross@mailbox.org>"]
edition = "2018"
[dependencies]
epd-waveshare = { path = "../../", default-features = false, features = ["epd2in9", "graphics"]}
linux-embedded-hal = "0.2.1"
embedded-graphics = "0.4.3"
embedded-hal = { version = "0.2.1", features = ["unproven"] }
linux-embedded-hal = "0.2.2"
embedded-graphics = "0.4.5"
embedded-hal = { version = "0.2.2", features = ["unproven"] }

39
examples/embedded_linux_epd2in9/src/main.rs → examples/epd2in9_full/src/main.rs

@ -1,29 +1,17 @@
// the library for the embedded linux device
extern crate linux_embedded_hal as lin_hal;
use lin_hal::spidev::{self, SpidevOptions};
use lin_hal::sysfs_gpio::Direction;
use lin_hal::Delay;
use lin_hal::{Pin, Spidev};
// the eink library
extern crate epd_waveshare;
#![deny(warnings)]
use embedded_graphics::{coord::Coord, fonts::Font6x8, prelude::*, Drawing};
use embedded_hal::prelude::*;
use epd_waveshare::{
epd2in9::{Buffer2in9, EPD2in9},
epd2in9::{Display2in9, EPD2in9},
graphics::{Display, DisplayRotation},
prelude::*,
};
// Graphics
extern crate embedded_graphics;
use embedded_graphics::coord::Coord;
use embedded_graphics::fonts::Font6x8;
use embedded_graphics::prelude::*;
//use embedded_graphics::primitives::{Circle, Line};
use embedded_graphics::Drawing;
// HAL (Traits)
extern crate embedded_hal;
use embedded_hal::prelude::*;
use linux_embedded_hal::{
spidev::{self, SpidevOptions},
sysfs_gpio::Direction,
Delay, Pin, Spidev,
};
// activate spi, gpio in raspi-config
// needs to be run with sudo because of some sysfs_gpio permission problems and follow-up timing problems
@ -31,7 +19,9 @@ use embedded_hal::prelude::*;
//TODO: Test this implemenation with a new display
fn main() {
run().unwrap();
if let Err(e) = run() {
eprintln!("Program exited early with error: {}", e);
}
}
fn run() -> Result<(), std::io::Error> {
@ -87,8 +77,7 @@ fn run() -> Result<(), std::io::Error> {
epd.display_frame(&mut spi).expect("disp 1");
println!("Test all the rotations");
let mut buffer = Buffer2in9::default();
let mut display = Display::new(epd.width(), epd.height(), &mut buffer.buffer);
let mut display = Display2in9::default();
epd.update_frame(&mut spi, display.buffer()).unwrap();
epd.display_frame(&mut spi).expect("display frame x03");

9
examples/embedded_linux_epd4in2/Cargo.toml → examples/epd4in2_full/Cargo.toml

@ -2,6 +2,7 @@
name = "embedded_linux_eink_example"
version = "0.1.0"
authors = ["Christoph Groß <christoph-gross@mailbox.org>"]
edition = "2018"
[dependencies]
@ -9,8 +10,6 @@ authors = ["Christoph Groß <christoph-gross@mailbox.org>"]
#epd_waveshare = { path = "../../"}
epd-waveshare = { path = "../../", default-features = false, features = ["epd4in2", "graphics"]}
linux-embedded-hal = "0.2.1"
embedded-graphics = "0.4.3"
embedded-hal = { version = "0.2.1", features = ["unproven"] }
linux-embedded-hal = "0.2.2"
embedded-graphics = "0.4.5"
embedded-hal = { version = "0.2.2", features = ["unproven"] }

45
examples/embedded_linux_epd4in2/src/main.rs → examples/epd4in2_full/src/main.rs

@ -1,36 +1,32 @@
// the library for the embedded linux device
extern crate linux_embedded_hal as lin_hal;
use lin_hal::spidev::{self, SpidevOptions};
use lin_hal::sysfs_gpio::Direction;
use lin_hal::Delay;
use lin_hal::{Pin, Spidev};
// the eink library
extern crate epd_waveshare;
#![deny(warnings)]
use embedded_graphics::{
coord::Coord,
fonts::{Font12x16, Font6x8},
prelude::*,
primitives::{Circle, Line},
Drawing,
};
use embedded_hal::prelude::*;
use epd_waveshare::{
epd4in2::{Buffer4in2, EPD4in2},
epd4in2::{Display4in2, EPD4in2},
graphics::{Display, DisplayRotation},
prelude::*,
};
// Graphics
extern crate embedded_graphics;
use embedded_graphics::coord::Coord;
use embedded_graphics::fonts::{Font12x16, Font6x8};
use embedded_graphics::prelude::*;
use embedded_graphics::primitives::{Circle, Line};
use embedded_graphics::Drawing;
// HAL (Traits)
extern crate embedded_hal;
use embedded_hal::prelude::*;
use linux_embedded_hal::{
spidev::{self, SpidevOptions},
sysfs_gpio::Direction,
Delay, Pin, Spidev,
};
// activate spi, gpio in raspi-config
// needs to be run with sudo because of some sysfs_gpio permission problems and follow-up timing problems
// see https://github.com/rust-embedded/rust-sysfs-gpio/issues/5 and follow-up issues
fn main() {
run().map_err(|e| println!("{}", e.to_string())).unwrap();
if let Err(e) = run() {
eprintln!("Program exited early with error: {}", e);
}
}
fn run() -> Result<(), std::io::Error> {
@ -75,8 +71,7 @@ fn run() -> Result<(), std::io::Error> {
EPD4in2::new(&mut spi, cs, busy, dc, rst, &mut delay).expect("eink initalize error");
println!("Test all the rotations");
let mut buffer = Buffer4in2::default();
let mut display = Display::new(epd4in2.width(), epd4in2.height(), &mut buffer.buffer);
let mut display = Display4in2::default();
display.set_rotation(DisplayRotation::Rotate0);
display.draw(
Font6x8::render_str("Rotate 0!")

15
examples/epd4in2_var_display_buffer/Cargo.toml

@ -0,0 +1,15 @@
[package]
name = "embedded_linux_eink_example"
version = "0.1.0"
authors = ["Christoph Groß <christoph-gross@mailbox.org>"]
edition = "2018"
[dependencies]
## The Only difference between this one and the one without default features sizewise seems to be a different .d-file Size (dependencies-file)
#epd_waveshare = { path = "../../"}
epd-waveshare = { path = "../../", default-features = false, features = ["epd4in2", "graphics"]}
linux-embedded-hal = "0.2.2"
embedded-graphics = "0.4.5"
embedded-hal = { version = "0.2.2", features = ["unproven"] }

195
examples/epd4in2_var_display_buffer/src/main.rs

@ -0,0 +1,195 @@
#![deny(warnings)]
use embedded_graphics::{
coord::Coord,
fonts::{Font12x16, Font6x8},
prelude::*,
primitives::{Circle, Line},
Drawing,
};
use embedded_hal::prelude::*;
use epd_waveshare::{
epd4in2::{self, EPD4in2},
graphics::{Display, DisplayRotation, VarDisplay},
prelude::*,
};
use linux_embedded_hal::{
spidev::{self, SpidevOptions},
sysfs_gpio::Direction,
Delay, Pin, Spidev,
};
// activate spi, gpio in raspi-config
// needs to be run with sudo because of some sysfs_gpio permission problems and follow-up timing problems
// see https://github.com/rust-embedded/rust-sysfs-gpio/issues/5 and follow-up issues
fn main() {
if let Err(e) = run() {
eprintln!("Program exited early with error: {}", e);
}
}
fn run() -> Result<(), std::io::Error> {
// Configure SPI
// Settings are taken from
let mut spi = Spidev::open("/dev/spidev0.0").expect("spidev directory");
let options = SpidevOptions::new()
.bits_per_word(8)
.max_speed_hz(4_000_000)
.mode(spidev::SPI_MODE_0)
.build();
spi.configure(&options).expect("spi configuration");
// Configure Digital I/O Pin to be used as Chip Select for SPI
let cs = Pin::new(26); //BCM7 CE0
cs.export().expect("cs export");
while !cs.is_exported() {}
cs.set_direction(Direction::Out).expect("CS Direction");
cs.set_value(1).expect("CS Value set to 1");
let busy = Pin::new(5); //pin 29
busy.export().expect("busy export");
while !busy.is_exported() {}
busy.set_direction(Direction::In).expect("busy Direction");
//busy.set_value(1).expect("busy Value set to 1");
let dc = Pin::new(6); //pin 31 //bcm6
dc.export().expect("dc export");
while !dc.is_exported() {}
dc.set_direction(Direction::Out).expect("dc Direction");
dc.set_value(1).expect("dc Value set to 1");
let rst = Pin::new(16); //pin 36 //bcm16
rst.export().expect("rst export");
while !rst.is_exported() {}
rst.set_direction(Direction::Out).expect("rst Direction");
rst.set_value(1).expect("rst Value set to 1");
let mut delay = Delay {};
let mut epd4in2 =
EPD4in2::new(&mut spi, cs, busy, dc, rst, &mut delay).expect("eink initalize error");
println!("Test all the rotations");
let (x, y, width, height) = (50, 50, 250, 250);
let mut buffer = [epd4in2::DEFAULT_BACKGROUND_COLOR.get_byte_value(); 62500]; //250*250
let mut display = VarDisplay::new(width, height, &mut buffer);
display.set_rotation(DisplayRotation::Rotate0);
display.draw(
Font6x8::render_str("Rotate 0!")
.with_stroke(Some(Color::Black))
.with_fill(Some(Color::White))
.translate(Coord::new(5, 50))
.into_iter(),
);
display.set_rotation(DisplayRotation::Rotate90);
display.draw(
Font6x8::render_str("Rotate 90!")
.with_stroke(Some(Color::Black))
.with_fill(Some(Color::White))
.translate(Coord::new(5, 50))
.into_iter(),
);
display.set_rotation(DisplayRotation::Rotate180);
display.draw(
Font6x8::render_str("Rotate 180!")
.with_stroke(Some(Color::Black))
.with_fill(Some(Color::White))
.translate(Coord::new(5, 50))
.into_iter(),
);
display.set_rotation(DisplayRotation::Rotate270);
display.draw(
Font6x8::render_str("Rotate 270!")
.with_stroke(Some(Color::Black))
.with_fill(Some(Color::White))
.translate(Coord::new(5, 50))
.into_iter(),
);
epd4in2
.update_partial_frame(&mut spi, &display.buffer(), x, y, width, height)
.unwrap();
epd4in2
.display_frame(&mut spi)
.expect("display frame new graphics");
delay.delay_ms(5000u16);
println!("Now test new graphics with default rotation and some special stuff:");
display.clear_buffer(Color::White);
// draw a analog clock
display.draw(
Circle::new(Coord::new(64, 64), 64)
.with_stroke(Some(Color::Black))
.into_iter(),
);
display.draw(
Line::new(Coord::new(64, 64), Coord::new(0, 64))
.with_stroke(Some(Color::Black))
.into_iter(),
);
display.draw(
Line::new(Coord::new(64, 64), Coord::new(80, 80))
.with_stroke(Some(Color::Black))
.into_iter(),
);
// draw white on black background
display.draw(
Font6x8::render_str("It's working-WoB!")
// Using Style here
.with_style(Style {
fill_color: Some(Color::Black),
stroke_color: Some(Color::White),
stroke_width: 0u8, // Has no effect on fonts
})
.translate(Coord::new(175, 250))
.into_iter(),
);
// use bigger/different font
display.draw(
Font12x16::render_str("It's working-BoW!")
// Using Style here
.with_style(Style {
fill_color: Some(Color::White),
stroke_color: Some(Color::Black),
stroke_width: 0u8, // Has no effect on fonts
})
.translate(Coord::new(50, 200))
.into_iter(),
);
// a moving `Hello World!`
let limit = 10;
for i in 0..limit {
println!("Moving Hello World. Loop {} from {}", (i + 1), limit);
display.draw(
Font6x8::render_str(" Hello World! ")
.with_style(Style {
fill_color: Some(Color::White),
stroke_color: Some(Color::Black),
stroke_width: 0u8, // Has no effect on fonts
})
.translate(Coord::new(5 + i * 12, 50))
.into_iter(),
);
epd4in2.update_frame(&mut spi, &display.buffer()).unwrap();
epd4in2
.display_frame(&mut spi)
.expect("display frame new graphics");
delay.delay_ms(1_000u16);
}
println!("Finished tests - going to sleep");
epd4in2.sleep(&mut spi)
}

59
src/epd1in54/graphics.rs

@ -1,44 +1,73 @@
use crate::epd1in54::{DEFAULT_BACKGROUND_COLOR, HEIGHT, WIDTH};
use crate::graphics::{Display, DisplayRotation};
use crate::prelude::*;
use embedded_graphics::prelude::*;
/// Full size buffer for use with the 1in54 EPD
///
/// Can also be manuall constructed:
/// `buffer: [DEFAULT_BACKGROUND_COLOR.get_byte_value(); WIDTH / 8 * HEIGHT]`
pub struct Buffer1in54BlackWhite {
pub buffer: [u8; WIDTH as usize * HEIGHT as usize / 8],
pub struct Display1in54 {
buffer: [u8; WIDTH as usize * HEIGHT as usize / 8],
rotation: DisplayRotation,
}
impl Default for Buffer1in54BlackWhite {
impl Default for Display1in54 {
fn default() -> Self {
Buffer1in54BlackWhite {
Display1in54 {
buffer: [DEFAULT_BACKGROUND_COLOR.get_byte_value();
WIDTH as usize * HEIGHT as usize / 8],
rotation: DisplayRotation::default(),
}
}
}
impl Drawing<Color> for Display1in54 {
fn draw<T>(&mut self, item_pixels: T)
where
T: Iterator<Item = Pixel<Color>>,
{
self.draw_helper(WIDTH, HEIGHT, item_pixels);
}
}
impl Display for Display1in54 {
fn buffer(&self) -> &[u8] {
&self.buffer
}
fn get_mut_buffer(&mut self) -> &mut [u8] {
&mut self.buffer
}
fn set_rotation(&mut self, rotation: DisplayRotation) {
self.rotation = rotation;
}
fn rotation(&self) -> DisplayRotation {
self.rotation
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::color::Color;
use crate::graphics::{Display, DisplayRotation};
use embedded_graphics::coord::Coord;
use embedded_graphics::prelude::*;
use embedded_graphics::primitives::Line;
// test buffer length
#[test]
fn graphics_size() {
let mut display1in54 = Buffer1in54BlackWhite::default();
let display = Display::new(WIDTH, HEIGHT, &mut display1in54.buffer);
let display = Display1in54::default();
assert_eq!(display.buffer().len(), 5000);
}
// test default background color on all bytes
#[test]
fn graphics_default() {
let mut display1in54 = Buffer1in54BlackWhite::default();
let display = Display::new(WIDTH, HEIGHT, &mut display1in54.buffer);
let display = Display1in54::default();
for &byte in display.buffer() {
assert_eq!(byte, DEFAULT_BACKGROUND_COLOR.get_byte_value());
}
@ -46,8 +75,7 @@ mod tests {
#[test]
fn graphics_rotation_0() {
let mut display1in54 = Buffer1in54BlackWhite::default();
let mut display = Display::new(WIDTH, HEIGHT, &mut display1in54.buffer);
let mut display = Display1in54::default();
display.draw(
Line::new(Coord::new(0, 0), Coord::new(7, 0))
.with_stroke(Some(Color::Black))
@ -65,8 +93,7 @@ mod tests {
#[test]
fn graphics_rotation_90() {
let mut display1in54 = Buffer1in54BlackWhite::default();
let mut display = Display::new(WIDTH, HEIGHT, &mut display1in54.buffer);
let mut display = Display1in54::default();
display.set_rotation(DisplayRotation::Rotate90);
display.draw(
Line::new(Coord::new(0, 192), Coord::new(0, 199))
@ -85,8 +112,7 @@ mod tests {
#[test]
fn graphics_rotation_180() {
let mut display1in54 = Buffer1in54BlackWhite::default();
let mut display = Display::new(WIDTH, HEIGHT, &mut display1in54.buffer);
let mut display = Display1in54::default();
display.set_rotation(DisplayRotation::Rotate180);
display.draw(
Line::new(Coord::new(192, 199), Coord::new(199, 199))
@ -108,8 +134,7 @@ mod tests {
#[test]
fn graphics_rotation_270() {
let mut display1in54 = Buffer1in54BlackWhite::default();
let mut display = Display::new(WIDTH, HEIGHT, &mut display1in54.buffer);
let mut display = Display1in54::default();
display.set_rotation(DisplayRotation::Rotate270);
display.draw(
Line::new(Coord::new(199, 0), Coord::new(199, 7))

21
src/epd1in54/mod.rs

@ -2,19 +2,19 @@
//!
//! # Example for the 1.54 in E-Ink Display
//!
//! ```ignore
//! ```rust,ignore
//! use epd_waveshare::{
//! epd1in54::{EPD1in54, Buffer1in54},
//! epd1in54::{EPD1in54, Display1in54},
//! graphics::{Display, DisplayRotation},
//! prelude::*,
//! };
//! use embedded_graphics::Drawing;
//!
//! // Setup EPD
//! let mut epd = EPD1in54::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay)?;
//! let mut epd = EPD1in54::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay).unwrap();
//!
//! // Use display graphics
//! let mut buffer = Buffer1in54::default();
//! let mut display = Display::new(epd.width(), epd.height(), &mut buffer.buffer);
//! let mut display = Display1in54::default();
//!
//! // Write some hello world in the screenbuffer
//! display.draw(
@ -37,6 +37,7 @@ pub const WIDTH: u32 = 200;
pub const HEIGHT: u32 = 200;
//const DPI: u16 = 184;
pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
const IS_BUSY_LOW: bool = false;
use embedded_hal::{
blocking::{delay::*, spi::Write},
@ -54,8 +55,10 @@ use crate::traits::{RefreshLUT, WaveshareDisplay};
use crate::interface::DisplayInterface;
#[cfg(feature = "graphics")]
mod graphics;
pub use crate::epd1in54::graphics::Buffer1in54BlackWhite as Buffer1in54;
#[cfg(feature = "graphics")]
pub use crate::epd1in54::graphics::Display1in54;
/// EPD1in54 driver
///
@ -248,6 +251,10 @@ where
RefreshLUT::QUICK => self.set_lut_helper(spi, &LUT_PARTIAL_UPDATE),
}
}
fn is_busy(&self) -> bool {
self.interface.is_busy(IS_BUSY_LOW)
}
}
impl<SPI, CS, BUSY, DC, RST> EPD1in54<SPI, CS, BUSY, DC, RST>
@ -259,7 +266,7 @@ where
RST: OutputPin,
{
fn wait_until_idle(&mut self) {
self.interface.wait_until_idle(false);
self.interface.wait_until_idle(IS_BUSY_LOW);
}
pub(crate) fn use_full_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {

49
src/epd2in9/graphics.rs

@ -1,40 +1,69 @@
use crate::epd2in9::{DEFAULT_BACKGROUND_COLOR, HEIGHT, WIDTH};
use crate::graphics::{Display, DisplayRotation};
use crate::prelude::*;
use embedded_graphics::prelude::*;
/// Full size buffer for use with the 2in9 EPD
/// Display with Fullsize buffer for use with the 2in9 EPD
///
/// Can also be manuall constructed:
/// `buffer: [DEFAULT_BACKGROUND_COLOR.get_byte_value(); WIDTH / 8 * HEIGHT]`
pub struct Buffer2in9 {
pub buffer: [u8; WIDTH as usize * HEIGHT as usize / 8],
pub struct Display2in9 {
buffer: [u8; WIDTH as usize * HEIGHT as usize / 8],
rotation: DisplayRotation,
}
impl Default for Buffer2in9 {
impl Default for Display2in9 {
fn default() -> Self {
Buffer2in9 {
Display2in9 {
buffer: [DEFAULT_BACKGROUND_COLOR.get_byte_value();
WIDTH as usize * HEIGHT as usize / 8],
rotation: DisplayRotation::default(),
}
}
}
impl Drawing<Color> for Display2in9 {
fn draw<T>(&mut self, item_pixels: T)
where
T: Iterator<Item = Pixel<Color>>,
{
self.draw_helper(WIDTH, HEIGHT, item_pixels);
}
}
impl Display for Display2in9 {
fn buffer(&self) -> &[u8] {
&self.buffer
}
fn get_mut_buffer(&mut self) -> &mut [u8] {
&mut self.buffer
}
fn set_rotation(&mut self, rotation: DisplayRotation) {
self.rotation = rotation;
}
fn rotation(&self) -> DisplayRotation {
self.rotation
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::graphics::Display;
// test buffer length
#[test]
fn graphics_size() {
let mut buffer = Buffer2in9::default();
let display = Display::new(WIDTH, HEIGHT, &mut buffer.buffer);
let display = Display2in9::default();
assert_eq!(display.buffer().len(), 4736);
}
// test default background color on all bytes
#[test]
fn graphics_default() {
let mut buffer = Buffer2in9::default();
let display = Display::new(WIDTH, HEIGHT, &mut buffer.buffer);
let display = Display2in9::default();
for &byte in display.buffer() {
assert_eq!(byte, DEFAULT_BACKGROUND_COLOR.get_byte_value());
}

21
src/epd2in9/mod.rs

@ -4,19 +4,19 @@
//!
//! # Example for the 2.9 in E-Ink Display
//!
//! ```ignore
//! ```rust,ignore
//! use epd_waveshare::{
//! epd2in9::{EPD2in9, Buffer2in9},
//! epd2in9::{EPD2in9, Display2in9},
//! graphics::{Display, DisplayRotation},
//! prelude::*,
//! };
//! use embedded_graphics::Drawing;
//!
//! // Setup EPD
//! let mut epd = EPD2in9::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay)?;
//! let mut epd = EPD2in9::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay).unwrap();
//!
//! // Use display graphics
//! let mut buffer = Buffer2in9::default();
//! let mut display = Display::new(epd.width(), epd.height(), &mut buffer.buffer);
//! let mut display = Display2in9::default();
//!
//! // Write some hello world in the screenbuffer
//! display.draw(
@ -38,6 +38,7 @@
pub const WIDTH: u32 = 128;
pub const HEIGHT: u32 = 296;
pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
const IS_BUSY_LOW: bool = false;
use embedded_hal::{
blocking::{delay::*, spi::Write},
@ -55,8 +56,10 @@ use crate::traits::*;
use crate::interface::DisplayInterface;
#[cfg(feature = "graphics")]
mod graphics;
pub use crate::epd2in9::graphics::Buffer2in9;
#[cfg(feature = "graphics")]
pub use crate::epd2in9::graphics::Display2in9;
/// EPD2in9 driver
///
@ -247,6 +250,10 @@ where
RefreshLUT::QUICK => self.set_lut_helper(spi, &LUT_PARTIAL_UPDATE),
}
}
fn is_busy(&self) -> bool {
self.interface.is_busy(IS_BUSY_LOW)
}
}
impl<SPI, CS, BUSY, DC, RST> EPD2in9<SPI, CS, BUSY, DC, RST>
@ -258,7 +265,7 @@ where
RST: OutputPin,
{
fn wait_until_idle(&mut self) {
self.interface.wait_until_idle(false);
self.interface.wait_until_idle(IS_BUSY_LOW);
}
fn use_full_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {

6
src/epd4in2/constants.rs

@ -1,9 +1,3 @@
use crate::color::Color;
pub const WIDTH: u32 = 400;
pub const HEIGHT: u32 = 300;
pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
#[rustfmt::skip]
pub(crate) const LUT_VCOM0: [u8; 44] = [
0x00, 0x17, 0x00, 0x00, 0x00, 0x02,

87
src/epd4in2/graphics.rs

@ -1,22 +1,54 @@
use crate::epd4in2::constants::{DEFAULT_BACKGROUND_COLOR, HEIGHT, WIDTH};
use crate::epd4in2::{DEFAULT_BACKGROUND_COLOR, HEIGHT, WIDTH};
use crate::graphics::{Display, DisplayRotation};
use crate::prelude::*;
use embedded_graphics::prelude::*;
/// Full size buffer for use with the 4in2 EPD
///
/// Can also be manuall constructed:
/// `buffer: [DEFAULT_BACKGROUND_COLOR.get_byte_value(); WIDTH / 8 * HEIGHT]`
pub struct Buffer4in2 {
pub buffer: [u8; WIDTH as usize * HEIGHT as usize / 8],
pub struct Display4in2 {
buffer: [u8; WIDTH as usize * HEIGHT as usize / 8],
rotation: DisplayRotation,
}
impl Default for Buffer4in2 {
impl Default for Display4in2 {
fn default() -> Self {
Buffer4in2 {
Display4in2 {
buffer: [DEFAULT_BACKGROUND_COLOR.get_byte_value();
WIDTH as usize * HEIGHT as usize / 8],
rotation: DisplayRotation::default(),
}
}
}
impl Drawing<Color> for Display4in2 {
fn draw<T>(&mut self, item_pixels: T)
where
T: Iterator<Item = Pixel<Color>>,
{
self.draw_helper(WIDTH, HEIGHT, item_pixels);
}
}
impl Display for Display4in2 {
fn buffer(&self) -> &[u8] {
&self.buffer
}
fn get_mut_buffer(&mut self) -> &mut [u8] {
&mut self.buffer
}
fn set_rotation(&mut self, rotation: DisplayRotation) {
self.rotation = rotation;
}
fn rotation(&self) -> DisplayRotation {
self.rotation
}
}
#[cfg(test)]
mod tests {
use super::*;
@ -24,35 +56,27 @@ mod tests {
use crate::epd4in2;
use crate::graphics::{Display, DisplayRotation};
use embedded_graphics::coord::Coord;
use embedded_graphics::prelude::*;
use embedded_graphics::primitives::Line;
// test buffer length
#[test]
fn graphics_size() {
let mut display4in2 = Buffer4in2::default();
let display = Display::new(WIDTH, HEIGHT, &mut display4in2.buffer);
let display = Display4in2::default();
assert_eq!(display.buffer().len(), 15000);
}
// test default background color on all bytes
#[test]
fn graphics_default() {
let mut display4in2 = Buffer4in2::default();
let display = Display::new(WIDTH, HEIGHT, &mut display4in2.buffer);
use crate::epd4in2;
let display = Display4in2::default();
for &byte in display.buffer() {
assert_eq!(
byte,
epd4in2::constants::DEFAULT_BACKGROUND_COLOR.get_byte_value()
);
assert_eq!(byte, epd4in2::DEFAULT_BACKGROUND_COLOR.get_byte_value());
}
}
#[test]
fn graphics_rotation_0() {
let mut display4in2 = Buffer4in2::default();
let mut display = Display::new(WIDTH, HEIGHT, &mut display4in2.buffer);
let mut display = Display4in2::default();
display.draw(
Line::new(Coord::new(0, 0), Coord::new(7, 0))
.with_stroke(Some(Color::Black))
@ -64,17 +88,13 @@ mod tests {
assert_eq!(buffer[0], Color::Black.get_byte_value());
for &byte in buffer.iter().skip(1) {
assert_eq!(
byte,
epd4in2::constants::DEFAULT_BACKGROUND_COLOR.get_byte_value()
);
assert_eq!(byte, epd4in2::DEFAULT_BACKGROUND_COLOR.get_byte_value());
}
}
#[test]
fn graphics_rotation_90() {
let mut display4in2 = Buffer4in2::default();
let mut display = Display::new(WIDTH, HEIGHT, &mut display4in2.buffer);
let mut display = Display4in2::default();
display.set_rotation(DisplayRotation::Rotate90);
display.draw(
Line::new(Coord::new(0, 392), Coord::new(0, 399))
@ -87,17 +107,13 @@ mod tests {
assert_eq!(buffer[0], Color::Black.get_byte_value());
for &byte in buffer.iter().skip(1) {
assert_eq!(
byte,
epd4in2::constants::DEFAULT_BACKGROUND_COLOR.get_byte_value()
);
assert_eq!(byte, epd4in2::DEFAULT_BACKGROUND_COLOR.get_byte_value());
}
}
#[test]
fn graphics_rotation_180() {
let mut display4in2 = Buffer4in2::default();
let mut display = Display::new(WIDTH, HEIGHT, &mut display4in2.buffer);
let mut display = Display4in2::default();
display.set_rotation(DisplayRotation::Rotate180);
display.draw(
Line::new(Coord::new(392, 299), Coord::new(399, 299))
@ -113,17 +129,13 @@ mod tests {
assert_eq!(buffer[0], Color::Black.get_byte_value());
for &byte in buffer.iter().skip(1) {
assert_eq!(
byte,
epd4in2::constants::DEFAULT_BACKGROUND_COLOR.get_byte_value()
);
assert_eq!(byte, epd4in2::DEFAULT_BACKGROUND_COLOR.get_byte_value());
}
}
#[test]
fn graphics_rotation_270() {
let mut display4in2 = Buffer4in2::default();
let mut display = Display::new(WIDTH, HEIGHT, &mut display4in2.buffer);
let mut display = Display4in2::default();
display.set_rotation(DisplayRotation::Rotate270);
display.draw(
Line::new(Coord::new(299, 0), Coord::new(299, 7))