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
embedded-hal-1.0
Chris 7 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,20 +1,52 @@
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)]
@ -23,22 +55,19 @@ mod tests {
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,20 +1,52 @@
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)]
@ -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))
@ -139,10 +151,7 @@ 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());
}
}
}

17
src/epd4in2/mod.rs

@ -56,15 +56,22 @@ use crate::traits::{InternalWiAdditions, RefreshLUT, WaveshareDisplay};
//The Lookup Tables for the Display
mod constants;
pub use self::constants::*;
use crate::epd4in2::constants::*;
pub const WIDTH: u32 = 400;
pub const HEIGHT: u32 = 300;
pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
const IS_BUSY_LOW: bool = true;
use crate::color::Color;
pub(crate) mod command;
use self::command::Command;
#[cfg(feature = "graphics")]
mod graphics;
pub use self::graphics::Buffer4in2;
#[cfg(feature = "graphics")]
pub use self::graphics::Display4in2;
/// EPD4in2 driver
///
@ -322,6 +329,10 @@ where
),
}
}
fn is_busy(&self) -> bool {
self.interface.is_busy(IS_BUSY_LOW)
}
}
impl<SPI, CS, BUSY, DC, RST> EPD4in2<SPI, CS, BUSY, DC, RST>
@ -350,7 +361,7 @@ where
}
fn wait_until_idle(&mut self) {
self.interface.wait_until_idle(true)
self.interface.wait_until_idle(IS_BUSY_LOW)
}
fn send_resolution(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {

146
src/graphics.rs

@ -22,71 +22,131 @@ impl Default for DisplayRotation {
}
}
pub struct Display<'a> {
width: u32,
height: u32,
rotation: DisplayRotation,
buffer: &'a mut [u8], //buffer: Box<u8>//[u8; 15000]
}
impl<'a> Display<'a> {
pub fn new(width: u32, height: u32, buffer: &'a mut [u8]) -> Display<'a> {
let len = buffer.len() as u32;
assert!(width / 8 * height >= len);
Display {
width,
height,
rotation: DisplayRotation::default(),
buffer,
pub trait Display: Drawing<Color> {
/// Clears the buffer of the display with the chosen background color
fn clear_buffer(&mut self, background_color: Color) {
for elem in self.get_mut_buffer().iter_mut() {
*elem = background_color.get_byte_value();
}
}
pub fn buffer(&self) -> &[u8] {
&self.buffer
}
/// Returns the buffer
fn buffer(&self) -> &[u8];
pub fn clear_buffer(&mut self, background_color: Color) {
for elem in &mut self.buffer.iter_mut() {
*elem = background_color.get_byte_value();
}
}
/// Returns a mutable buffer
fn get_mut_buffer(&mut self) -> &mut [u8];
pub fn set_rotation(&mut self, rotation: DisplayRotation) {
self.rotation = rotation;
}
/// Sets the rotation of the display
fn set_rotation(&mut self, rotation: DisplayRotation);
pub fn rotation(&self) -> DisplayRotation {
self.rotation
}
}
/// Get the current rotation of the display
fn rotation(&self) -> DisplayRotation;
impl<'a> Drawing<Color> for Display<'a> {
fn draw<T>(&mut self, item_pixels: T)
/// Helperfunction for the Embedded Graphics draw trait
///
/// Becomes uneccesary when const_generics become stablised
fn draw_helper<T>(&mut self, width: u32, height: u32, item_pixels: T)
where
T: Iterator<Item = Pixel<Color>>,
{
let rotation = self.rotation();
let buffer = self.get_mut_buffer();
for Pixel(UnsignedCoord(x, y), color) in item_pixels {
if outside_display(x, y, self.width, self.height, self.rotation) {
if outside_display(x, y, width, height, rotation) {
continue;
}
// Give us index inside the buffer and the bit-position in that u8 which needs to be changed
let (index, bit) = rotation(x, y, self.width, self.height, self.rotation);
let (index, bit) = find_position(x, y, width, height, rotation);
let index = index as usize;
// "Draw" the Pixel on that bit
match color {
Color::Black => {
self.buffer[index] &= !bit;
buffer[index] &= !bit;
}
Color::White => {
self.buffer[index] |= bit;
buffer[index] |= bit;
}
}
}
}
}
/// A variable Display without a predefined buffer
///
/// The buffer can be created as following:
/// buffer: [DEFAULT_BACKGROUND_COLOR.get_byte_value(); WIDTH / 8 * HEIGHT]
///
/// Example:
/// ```rust,no_run
/// # use epd_waveshare::epd2in9::DEFAULT_BACKGROUND_COLOR;
/// # use epd_waveshare::prelude::*;
/// # use epd_waveshare::graphics::VarDisplay;
/// # use embedded_graphics::prelude::*;
/// # use embedded_graphics::primitives::{Circle, Line};
/// let width = 128;
/// let height = 296;
///
/// let mut buffer = [DEFAULT_BACKGROUND_COLOR.get_byte_value(); 128 / 8 * 296];
/// let mut display = VarDisplay::new(width, height, &mut buffer);
///
/// display.set_rotation(DisplayRotation::Rotate90);
///
/// display.draw(
/// Line::new(Coord::new(0, 120), Coord::new(0, 295))
/// .with_stroke(Some(Color::Black))
/// .into_iter(),
/// );
/// ```
pub struct VarDisplay<'a> {
width: u32,
height: u32,
rotation: DisplayRotation,
buffer: &'a mut [u8], //buffer: Box<u8>//[u8; 15000]
}
impl<'a> VarDisplay<'a> {
pub fn new(width: u32, height: u32, buffer: &'a mut [u8]) -> VarDisplay<'a> {
let len = buffer.len() as u32;
assert!(width / 8 * height >= len);
VarDisplay {
width,
height,
rotation: DisplayRotation::default(),
buffer,
}
}
}
impl<'a> Drawing<Color> for VarDisplay<'a> {
fn draw<T>(&mut self, item_pixels: T)
where
T: Iterator<Item = Pixel<Color>>,
{
self.draw_helper(self.width, self.height, item_pixels);
}
}
impl<'a> Display for VarDisplay<'a> {
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
}
}
// Checks if a pos is outside the defined display
fn outside_display(x: u32, y: u32, width: u32, height: u32, rotation: DisplayRotation) -> bool {
match rotation {
DisplayRotation::Rotate0 | DisplayRotation::Rotate180 => {
@ -105,7 +165,7 @@ fn outside_display(x: u32, y: u32, width: u32, height: u32, rotation: DisplayRot
#[rustfmt::skip]
//returns index position in the u8-slice and the bit-position inside that u8
fn rotation(x: u32, y: u32, width: u32, height: u32, rotation: DisplayRotation) -> (u32, u8) {
fn find_position(x: u32, y: u32, width: u32, height: u32, rotation: DisplayRotation) -> (u32, u8) {
match rotation {
DisplayRotation::Rotate0 => (
x / 8 + (width / 8) * y,
@ -128,7 +188,7 @@ fn rotation(x: u32, y: u32, width: u32, height: u32, rotation: DisplayRotation)
#[cfg(test)]
mod tests {
use super::{outside_display, rotation, Display, DisplayRotation};
use super::{find_position, outside_display, Display, DisplayRotation, VarDisplay};
use crate::color::Color;
use embedded_graphics::coord::Coord;
use embedded_graphics::prelude::*;
@ -139,7 +199,7 @@ mod tests {
use crate::epd4in2::{HEIGHT, WIDTH};
let mut buffer = [Color::Black.get_byte_value(); WIDTH as usize / 8 * HEIGHT as usize];
let mut display = Display::new(WIDTH, HEIGHT, &mut buffer);
let mut display = VarDisplay::new(WIDTH, HEIGHT, &mut buffer);
for &byte in display.buffer.iter() {
assert_eq!(byte, Color::Black.get_byte_value());
@ -171,7 +231,7 @@ mod tests {
if outside_display(x, y, width, height, rotation2) {
break;
} else {
let (idx, _) = rotation(x, y, width, height, rotation2);
let (idx, _) = find_position(x, y, width, height, rotation2);
assert!(idx < max_value);
}
}
@ -185,7 +245,7 @@ mod tests {
let height = 296;
let mut buffer = [DEFAULT_BACKGROUND_COLOR.get_byte_value(); 128 / 8 * 296];
let mut display = Display::new(width, height, &mut buffer);
let mut display = VarDisplay::new(width, height, &mut buffer);
display.draw(
Line::new(Coord::new(0, 0), Coord::new(7, 0))
@ -209,7 +269,7 @@ mod tests {
let height = 296;
let mut buffer = [DEFAULT_BACKGROUND_COLOR.get_byte_value(); 128 / 8 * 296];
let mut display = Display::new(width, height, &mut buffer);
let mut display = VarDisplay::new(width, height, &mut buffer);
display.set_rotation(DisplayRotation::Rotate90);

25
src/interface.rs

@ -127,16 +127,33 @@ where
/// Most likely there was a mistake with the 2in9 busy connection
/// //TODO: use the #cfg feature to make this compile the right way for the certain types
pub(crate) fn wait_until_idle(&mut self, is_busy_low: bool) {
// TODO: removal of delay. TEST!
//tested: worked without the delay for all tested devices
//self.delay_ms(1);
//low: busy, high: idle
while (is_busy_low && self.busy.is_low()) || (!is_busy_low && self.busy.is_high()) {
//TODO: REMOVAL of DELAY: it's only waiting for the signal anyway and should continue work asap
while self.is_busy(is_busy_low) {
//tested: REMOVAL of DELAY: it's only waiting for the signal anyway and should continue work asap
//old: shorten the time? it was 100 in the beginning
//self.delay_ms(5);
}
}
/// Checks if device is still busy
///
/// 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
///
/// is_busy_low
///
/// - TRUE for epd4in2, epd2in13, epd2in7, epd5in83, epd7in5
/// - FALSE for epd2in9, epd1in54 (for all Display Type A ones?)
///
/// Most likely there was a mistake with the 2in9 busy connection
/// //TODO: use the #cfg feature to make this compile the right way for the certain types
pub(crate) fn is_busy(&self, is_busy_low: bool) -> bool {
(is_busy_low && self.busy.is_low()) || (!is_busy_low && self.busy.is_high())
}
/// Resets the device.
///
/// Often used to awake the module from deep sleep. See [EPD4in2::sleep()](EPD4in2::sleep())

48
src/lib.rs

@ -20,22 +20,35 @@
//!
//! # Examples
//!
//! ```ignore
//! use eink-waveshare-rs::epd4in2::EPD4in2;
//!
//! let mut epd4in2 = EPD4in2::new(spi, cs, busy, dc, rst, delay).unwrap();
//!
//! let mut buffer = [0u8, epd4in2.get_width() / 8 * epd4in2.get_height()];
//!
//! // draw something into the buffer
//!
//! epd4in2.display_and_transfer_buffer(buffer, None);
//!
//! // wait and look at the image
//!
//! epd4in2.clear_frame(None);
//!
//! epd4in2.sleep();
//! ```rust,ignore
//! use epd_waveshare::{
//! 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).unwrap();
//!
//! // Use display graphics
//! let mut display = Display2in9::default();
//!
//! // Write some hello world in the screenbuffer
//! display.draw(
//! Font6x8::render_str("Hello World!")
//! .with_stroke(Some(Color::Black))
//! .with_fill(Some(Color::White))
//! .translate(Coord::new(5, 50))
//! .into_iter(),
//! );
//!
//! // Display updated frame
//! epd.update_frame(&mut spi, &display.buffer()).unwrap();
//! epd.display_frame(&mut spi).expect("display frame new graphics");
//!
//! // Set the EPD to sleep
//! epd.sleep(&mut spi).expect("sleep");
//! ```
//!
//!
@ -67,6 +80,9 @@ pub mod prelude {
pub use crate::color::Color;
pub use crate::traits::{RefreshLUT, WaveshareDisplay};
pub use crate::SPI_MODE;
#[cfg(feature = "graphics")]
pub use crate::graphics::{Display, DisplayRotation};
}
use embedded_hal::spi::{Mode, Phase, Polarity};

8
src/traits.rs

@ -125,6 +125,7 @@ where
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error>;
/// Clears the frame buffer on the EPD with the declared background color
///
/// The background color can be changed with [`set_background_color`]
fn clear_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error>;
@ -141,4 +142,11 @@ where
spi: &mut SPI,
refresh_rate: Option<RefreshLUT>,
) -> Result<(), SPI::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;
}

Loading…
Cancel
Save