Compare commits

...

2 Commits

@ -0,0 +1,26 @@
[package]
name = "graphics_derive"
version = "0.1.0"
authors = ["Christoph Groß <caemor@mailbox.org>"]
edition = "2018"
# [package]
# authors = ["Christoph Groß <caemor@mailbox.org>"]
# categories = ["embedded", "hardware-support", "no-std"]
# description = "An embedded-hal based driver for ePaper displays from Waveshare formerly published as eink-waveshare-rs"
# documentation = "https://docs.rs/epd-waveshare"
# homepage = "https://github.com/caemor/epd-waveshare"
# keywords = ["ePaper", "Display", "epd", "eink"]
# license = "ISC"
# name = "epd-waveshare"
# readme = "README.md"
# repository = "https://github.com/Caemor/epd-waveshare.git"
# version = "0.3.2"
# edition = "2018"
[lib]
proc-macro = true
[dependencies]
syn = "1.0.5"
quote = "1.0.2"

@ -0,0 +1,88 @@
//https://doc.rust-lang.org/book/ch19-06-macros.html?highlight=procedural#how-to-write-a-custom-derive-macro
extern crate proc_macro;
use crate::proc_macro::TokenStream;
use quote::quote;
use syn;
#[proc_macro_derive(Graphics)]
pub fn graphics_derive(input: TokenStream) -> TokenStream {
// Construct a representation of Rust code as a syntax tree
// that we can manipulate
let ast = syn::parse(input).unwrap();
// Build the trait implementation
impl_graphics_macro(&ast)
}
fn impl_graphics_macro(ast: &syn::DeriveInput) -> TokenStream {
let name = &ast.ident;
let gen = quote! {
use crate::epd2in9::{DEFAULT_BACKGROUND_COLOR, HEIGHT, WIDTH};
use crate::graphics::{Display, DisplayRotation};
use crate::prelude::*;
use embedded_graphics::prelude::*;
/// 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 Display2in9 {
buffer: [u8; WIDTH as usize * HEIGHT as usize / 8],
rotation: DisplayRotation,
}
impl Default for Display2in9 {
fn default() -> Self {
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: IntoIterator<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
}
}
impl HelloMacro for #name {
fn hello_macro() {
println!("Hello, Macro! My name is {}", stringify!(#name));
}
}
};
gen.into()
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}

@ -84,6 +84,8 @@ where
spi: &mut SPI,
delay: &mut DELAY,
) -> Result<(), SPI::Error> {
self.wait_until_idle();
self.interface.reset(delay);
// 3 Databytes:
@ -127,7 +129,6 @@ where
self.set_lut(spi, None)?;
self.wait_until_idle();
Ok(())
}
}
@ -179,22 +180,20 @@ where
}
fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
self.wait_until_idle();
// 0x00 for Normal mode (Power on Reset), 0x01 for Deep Sleep Mode
//TODO: is 0x00 needed here or would 0x01 be even more efficient?
self.interface
.cmd_with_data(spi, Command::DEEP_SLEEP_MODE, &[0x00])?;
self.wait_until_idle();
Ok(())
.cmd_with_data(spi, Command::DEEP_SLEEP_MODE, &[0x00])
}
fn update_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
self.wait_until_idle();
self.use_full_frame(spi)?;
self.interface
.cmd_with_data(spi, Command::WRITE_RAM, buffer)?;
self.wait_until_idle();
Ok(())
.cmd_with_data(spi, Command::WRITE_RAM, buffer)
}
//TODO: update description: last 3 bits will be ignored for width and x_pos
@ -207,17 +206,18 @@ where
width: u32,
height: u32,
) -> Result<(), SPI::Error> {
self.wait_until_idle();
self.set_ram_area(spi, x, y, x + width, y + height)?;
self.set_ram_counter(spi, x, y)?;
self.interface
.cmd_with_data(spi, Command::WRITE_RAM, buffer)?;
self.wait_until_idle();
Ok(())
.cmd_with_data(spi, Command::WRITE_RAM, buffer)
}
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
self.wait_until_idle();
// enable clock signal, enable cp, display pattern -> 0xC4 (tested with the arduino version)
//TODO: test control_1 or control_2 with default value 0xFF (from the datasheet)
self.interface
@ -226,24 +226,19 @@ where
self.interface.cmd(spi, Command::MASTER_ACTIVATION)?;
// MASTER Activation should not be interupted to avoid currption of panel images
// therefore a terminate command is send
self.interface.cmd(spi, Command::NOP)?;
self.wait_until_idle();
Ok(())
self.interface.cmd(spi, Command::NOP)
}
fn clear_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
self.wait_until_idle();
self.use_full_frame(spi)?;
// clear the ram with the background color
let color = self.background_color.get_byte_value();
self.interface.cmd(spi, Command::WRITE_RAM)?;
self.interface
.data_x_times(spi, color, WIDTH / 8 * HEIGHT)?;
self.wait_until_idle();
Ok(())
self.interface.data_x_times(spi, color, WIDTH / 8 * HEIGHT)
}
fn set_background_color(&mut self, background_color: Color) {
@ -304,6 +299,8 @@ where
assert!(start_x < end_x);
assert!(start_y < end_y);
self.wait_until_idle();
// x is positioned in bytes, so the last 3 bits which show the position inside a byte in the ram
// aren't relevant
self.interface.cmd_with_data(
@ -322,10 +319,7 @@ where
end_y as u8,
(end_y >> 8) as u8,
],
)?;
self.wait_until_idle();
Ok(())
)
}
pub(crate) fn set_ram_counter(
@ -334,6 +328,8 @@ where
x: u32,
y: u32,
) -> Result<(), SPI::Error> {
self.wait_until_idle();
// x is positioned in bytes, so the last 3 bits which show the position inside a byte in the ram
// aren't relevant
self.interface
@ -344,20 +340,16 @@ where
spi,
Command::SET_RAM_Y_ADDRESS_COUNTER,
&[y as u8, (y >> 8) as u8],
)?;
self.wait_until_idle();
Ok(())
)
}
fn set_lut_helper(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
assert!(buffer.len() == 30);
self.interface
.cmd_with_data(spi, Command::WRITE_LUT_REGISTER, buffer)?;
self.wait_until_idle();
Ok(())
self.interface
.cmd_with_data(spi, Command::WRITE_LUT_REGISTER, buffer)
}
}

@ -166,13 +166,12 @@ where
}
fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
self.wait_until_idle();
// 0x00 for Normal mode (Power on Reset), 0x01 for Deep Sleep Mode
//TODO: is 0x00 needed here? (see also epd1in54)
self.interface
.cmd_with_data(spi, Command::DEEP_SLEEP_MODE, &[0x00])?;
self.wait_until_idle();
Ok(())
.cmd_with_data(spi, Command::DEEP_SLEEP_MODE, &[0x00])
}
fn wake_up<DELAY: DelayMs<u8>>(
@ -180,20 +179,18 @@ where
spi: &mut SPI,
delay: &mut DELAY,
) -> Result<(), SPI::Error> {
self.init(spi, delay)?;
self.wait_until_idle();
Ok(())
self.init(spi, delay)
}
fn update_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
self.wait_until_idle();
self.use_full_frame(spi)?;
self.interface
.cmd_with_data(spi, Command::WRITE_RAM, buffer)?;
self.wait_until_idle();
Ok(())
.cmd_with_data(spi, Command::WRITE_RAM, buffer)
}
//TODO: update description: last 3 bits will be ignored for width and x_pos
@ -206,17 +203,18 @@ where
width: u32,
height: u32,
) -> Result<(), SPI::Error> {
self.wait_until_idle();
self.set_ram_area(spi, x, y, x + width, y + height)?;
self.set_ram_counter(spi, x, y)?;
self.interface
.cmd_with_data(spi, Command::WRITE_RAM, buffer)?;
self.wait_until_idle();
Ok(())
.cmd_with_data(spi, Command::WRITE_RAM, buffer)
}
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
self.wait_until_idle();
// enable clock signal, enable cp, display pattern -> 0xC4 (tested with the arduino version)
//TODO: test control_1 or control_2 with default value 0xFF (from the datasheet)
self.interface
@ -225,24 +223,19 @@ where
self.interface.cmd(spi, Command::MASTER_ACTIVATION)?;
// MASTER Activation should not be interupted to avoid currption of panel images
// therefore a terminate command is send
self.interface.cmd(spi, Command::NOP)?;
self.wait_until_idle();
Ok(())
self.interface.cmd(spi, Command::NOP)
}
fn clear_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
self.wait_until_idle();
self.use_full_frame(spi)?;
// clear the ram with the background color
let color = self.background_color.get_byte_value();
self.interface.cmd(spi, Command::WRITE_RAM)?;
self.interface
.data_x_times(spi, color, WIDTH / 8 * HEIGHT)?;
self.wait_until_idle();
Ok(())
self.interface.data_x_times(spi, color, WIDTH / 8 * HEIGHT)
}
fn set_background_color(&mut self, background_color: Color) {
@ -325,6 +318,8 @@ where
}
fn set_ram_counter(&mut self, spi: &mut SPI, x: u32, y: u32) -> Result<(), SPI::Error> {
self.wait_until_idle();
// x is positioned in bytes, so the last 3 bits which show the position inside a byte in the ram
// aren't relevant
self.interface
@ -335,19 +330,16 @@ where
spi,
Command::SET_RAM_Y_ADDRESS_COUNTER,
&[y as u8, (y >> 8) as u8],
)?;
self.wait_until_idle();
Ok(())
)
}
/// Set your own LUT, this function is also used internally for set_lut
fn set_lut_helper(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
assert!(buffer.len() == 30);
self.interface
.cmd_with_data(spi, Command::WRITE_LUT_REGISTER, buffer)?;
self.wait_until_idle();
Ok(())
self.interface
.cmd_with_data(spi, Command::WRITE_LUT_REGISTER, buffer)
}
}

@ -98,6 +98,8 @@ where
spi: &mut SPI,
delay: &mut DELAY,
) -> Result<(), SPI::Error> {
self.wait_until_idle();
// reset the device
self.interface.reset(delay);
@ -126,10 +128,7 @@ where
// 3A 100HZ 29 150Hz 39 200HZ 31 171HZ DEFAULT: 3c 50Hz
self.cmd_with_data(spi, Command::PLL_CONTROL, &[0x3A])?;
self.set_lut(spi, None)?;
self.wait_until_idle();
Ok(())
self.set_lut(spi, None)
}
}
@ -188,6 +187,8 @@ where
}
fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
self.wait_until_idle();
self.interface
.cmd_with_data(spi, Command::VCOM_AND_DATA_INTERVAL_SETTING, &[0x17])?; //border floating
self.command(spi, Command::VCM_DC_SETTING)?; // VCOM to 0V
@ -201,13 +202,12 @@ where
self.command(spi, Command::POWER_OFF)?;
self.wait_until_idle();
self.interface
.cmd_with_data(spi, Command::DEEP_SLEEP, &[0xA5])?;
self.wait_until_idle();
Ok(())
.cmd_with_data(spi, Command::DEEP_SLEEP, &[0xA5])
}
fn update_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
self.wait_until_idle();
let color_value = self.color.get_byte_value();
self.send_resolution(spi)?;
@ -225,10 +225,7 @@ where
.data_x_times(spi, color_value, WIDTH / 8 * HEIGHT)?;
self.interface
.cmd_with_data(spi, Command::DATA_START_TRANSMISSION_2, buffer)?;
self.wait_until_idle();
Ok(())
.cmd_with_data(spi, Command::DATA_START_TRANSMISSION_2, buffer)
}
fn update_partial_frame(
@ -240,7 +237,13 @@ where
width: u32,
height: u32,
) -> Result<(), SPI::Error> {
self.wait_until_idle();
if buffer.len() as u32 != width / 8 * height {
assert!(
buffer.len() as u32 != width / 8 * height,
"Wrong Buffersize"
);
//TODO: panic!! or sth like that
//return Err("Wrong buffersize");
}
@ -272,20 +275,18 @@ where
self.send_data(spi, buffer)?;
self.command(spi, Command::PARTIAL_OUT)?;
self.wait_until_idle();
Ok(())
self.command(spi, Command::PARTIAL_OUT)
}
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
self.command(spi, Command::DISPLAY_REFRESH)?;
self.wait_until_idle();
Ok(())
self.command(spi, Command::DISPLAY_REFRESH)
}
fn clear_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
self.wait_until_idle();
self.send_resolution(spi)?;
let color_value = self.color.get_byte_value();
@ -298,10 +299,7 @@ where
self.interface
.cmd(spi, Command::DATA_START_TRANSMISSION_2)?;
self.interface
.data_x_times(spi, color_value, WIDTH / 8 * HEIGHT)?;
self.wait_until_idle();
Ok(())
.data_x_times(spi, color_value, WIDTH / 8 * HEIGHT)
}
fn set_background_color(&mut self, color: Color) {
@ -397,6 +395,8 @@ where
lut_wb: &[u8],
lut_bb: &[u8],
) -> Result<(), SPI::Error> {
self.wait_until_idle();
// LUT VCOM
self.cmd_with_data(spi, Command::LUT_FOR_VCOM, lut_vcom)?;
@ -410,10 +410,7 @@ where
self.cmd_with_data(spi, Command::LUT_WHITE_TO_BLACK, lut_wb)?;
// LUT BLACK to BLACK
self.cmd_with_data(spi, Command::LUT_BLACK_TO_BLACK, lut_bb)?;
self.wait_until_idle();
Ok(())
self.cmd_with_data(spi, Command::LUT_BLACK_TO_BLACK, lut_bb)
}
}

Loading…
Cancel
Save