mirror of
https://github.com/Feliix42/ssd1675.git
synced 2024-11-24 19:56:30 +00:00
Round out Inky pHAT example
This commit is contained in:
parent
cf4bf8ce76
commit
70a57e2858
3 changed files with 115 additions and 135 deletions
|
@ -15,6 +15,7 @@ version = "0.4.4"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
linux-embedded-hal = "0.2.1" # for examples
|
linux-embedded-hal = "0.2.1" # for examples
|
||||||
|
profont = "0.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["graphics"]
|
default = ["graphics"]
|
||||||
|
|
|
@ -1,28 +1,29 @@
|
||||||
// the library for the embedded linux device
|
|
||||||
extern crate linux_embedded_hal;
|
extern crate linux_embedded_hal;
|
||||||
use linux_embedded_hal::spidev::{self, SpidevOptions};
|
use linux_embedded_hal::spidev::{self, SpidevOptions};
|
||||||
use linux_embedded_hal::sysfs_gpio::Direction;
|
use linux_embedded_hal::sysfs_gpio::Direction;
|
||||||
use linux_embedded_hal::Delay;
|
use linux_embedded_hal::Delay;
|
||||||
use linux_embedded_hal::{Pin, Spidev};
|
use linux_embedded_hal::{Pin, Spidev};
|
||||||
|
|
||||||
// the eink library
|
|
||||||
extern crate ssd1675;
|
extern crate ssd1675;
|
||||||
use ssd1675::{Display, DisplayInterface, Dimensions, GraphicDisplay, Color, Rotation};
|
use ssd1675::{Display, Dimensions, GraphicDisplay, Color, Rotation};
|
||||||
|
|
||||||
// Graphics
|
// Graphics
|
||||||
extern crate embedded_graphics;
|
extern crate embedded_graphics;
|
||||||
use embedded_graphics::coord::Coord;
|
use embedded_graphics::coord::Coord;
|
||||||
use embedded_graphics::fonts::{Font12x16, Font6x8};
|
|
||||||
use embedded_graphics::prelude::*;
|
use embedded_graphics::prelude::*;
|
||||||
use embedded_graphics::primitives::{Circle, Line, Rect};
|
|
||||||
use embedded_graphics::Drawing;
|
use embedded_graphics::Drawing;
|
||||||
|
|
||||||
// HAL (Traits)
|
// Font
|
||||||
extern crate embedded_hal;
|
extern crate profont;
|
||||||
use embedded_hal::prelude::*;
|
use profont::{ProFont9Point, ProFont12Point, ProFont14Point, ProFont24Point};
|
||||||
|
|
||||||
// activate spi, gpio in raspi-config
|
use std::process::Command;
|
||||||
// needs to be run with sudo because of some sysfs_gpio permission problems and follow-up timing problems
|
use std::{fs, io};
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::thread::sleep;
|
||||||
|
|
||||||
|
// 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
|
// see https://github.com/rust-embedded/rust-sysfs-gpio/issues/5 and follow-up issues
|
||||||
|
|
||||||
const ROWS: u16 = 212;
|
const ROWS: u16 = 212;
|
||||||
|
@ -68,141 +69,99 @@ fn main() -> Result<(), std::io::Error> {
|
||||||
|
|
||||||
let controller = ssd1675::Interface::new(spi, cs, busy, dc, reset);
|
let controller = ssd1675::Interface::new(spi, cs, busy, dc, reset);
|
||||||
|
|
||||||
// println!("Test all the rotations");
|
|
||||||
let dimensions = Dimensions { rows: ROWS, cols: COLS };
|
let dimensions = Dimensions { rows: ROWS, cols: COLS };
|
||||||
let mut black_buffer = [0u8; ROWS as usize * COLS as usize]; // FIXME: This is using 1 byte per pixel when it only needs to be one bit
|
let mut black_buffer = [0u8; ROWS as usize * COLS as usize / 8];
|
||||||
let mut red_buffer = [0u8; ROWS as usize * COLS as usize];
|
let mut red_buffer = [0u8; ROWS as usize * COLS as usize / 8];
|
||||||
let display = Display::new(controller, dimensions, Rotation::Rotate270);
|
let display = Display::new(controller, dimensions, Rotation::Rotate270);
|
||||||
let mut display = GraphicDisplay::new(display, &mut black_buffer, &mut red_buffer);
|
let mut display = GraphicDisplay::new(display, &mut black_buffer, &mut red_buffer);
|
||||||
|
|
||||||
|
loop {
|
||||||
display.reset(&mut delay).expect("error resetting display");
|
display.reset(&mut delay).expect("error resetting display");
|
||||||
// display.set_rotation(DisplayRotation::Rotate0);
|
println!("Reset and initialised");
|
||||||
println!("reset and initialised");
|
let one_minute = Duration::from_secs(60);
|
||||||
|
|
||||||
display.clear(Color::White);
|
display.clear(Color::White);
|
||||||
println!("clear");
|
println!("Clear");
|
||||||
|
|
||||||
display.draw(
|
display.draw(
|
||||||
Font12x16::render_str("Hello Rust")
|
ProFont24Point::render_str("Raspberry Pi")
|
||||||
.with_stroke(Some(Color::Red))
|
.with_stroke(Some(Color::Red))
|
||||||
.with_fill(Some(Color::White))
|
.with_fill(Some(Color::White))
|
||||||
.translate(Coord::new(5, 88))
|
.translate(Coord::new(1, -4))
|
||||||
.into_iter(),
|
.into_iter(),
|
||||||
);
|
);
|
||||||
println!("draw");
|
|
||||||
|
|
||||||
// display.set_rotation(DisplayRotation::Rotate90);
|
if let Ok(cpu_temp) = read_cpu_temp() {
|
||||||
// display.draw(
|
|
||||||
// Font::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_frame(&mut spi, &display.buffer()).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(
|
display.draw(
|
||||||
Circle::new(Coord::new(32, 32), 30)
|
ProFont14Point::render_str("CPU Temp:")
|
||||||
.with_stroke(Some(Color::Black))
|
.with_stroke(Some(Color::Black))
|
||||||
.with_stroke_width(2)
|
.with_fill(Some(Color::White))
|
||||||
|
.translate(Coord::new(1, 30))
|
||||||
.into_iter(),
|
.into_iter(),
|
||||||
);
|
);
|
||||||
// display.draw(
|
|
||||||
// Line::new(Coord::new(32, 32), Coord::new(0, 32))
|
|
||||||
// .with_stroke(Some(Color::Black))
|
|
||||||
// .with_stroke_width(2)
|
|
||||||
// .into_iter(),
|
|
||||||
// );
|
|
||||||
// display.draw(
|
|
||||||
// Line::new(Coord::new(32, 32), Coord::new(40, 40))
|
|
||||||
// .with_stroke(Some(Color::Black))
|
|
||||||
// .with_stroke_width(2)
|
|
||||||
// .into_iter(),
|
|
||||||
// );
|
|
||||||
display.draw(
|
display.draw(
|
||||||
Rect::new(Coord::new(32, 32), Coord::new(64, 64))
|
ProFont12Point::render_str(&format!("{:.1}°C", cpu_temp))
|
||||||
.with_fill(Some(Color::Black))
|
.with_stroke(Some(Color::Black))
|
||||||
|
.with_fill(Some(Color::White))
|
||||||
|
.translate(Coord::new(95, 34))
|
||||||
.into_iter(),
|
.into_iter(),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// // draw white on black background
|
if let Some(uptime) = read_uptime() {
|
||||||
// display.draw(
|
display.draw(
|
||||||
// Font6x8::render_str("It's working-WoB!")
|
ProFont9Point::render_str(uptime.trim())
|
||||||
// // Using Style here
|
.with_stroke(Some(Color::Black))
|
||||||
// .with_style(Style {
|
.with_fill(Some(Color::White))
|
||||||
// fill_color: Some(Color::Black),
|
.translate(Coord::new(1, 93))
|
||||||
// stroke_color: Some(Color::White),
|
.into_iter(),
|
||||||
// stroke_width: 0u8, // Has no effect on fonts
|
);
|
||||||
// })
|
}
|
||||||
// .translate(Coord::new(175, 250))
|
|
||||||
// .into_iter(),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// // use bigger/different font
|
if let Some(uname) = read_uname() {
|
||||||
// display.draw(
|
display.draw(
|
||||||
// Font12x16::render_str("It's working-BoW!")
|
ProFont9Point::render_str(uname.trim())
|
||||||
// // Using Style here
|
.with_stroke(Some(Color::Black))
|
||||||
// .with_style(Style {
|
.with_fill(Some(Color::White))
|
||||||
// fill_color: Some(Color::White),
|
.translate(Coord::new(1, 84))
|
||||||
// stroke_color: Some(Color::Black),
|
.into_iter(),
|
||||||
// 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);
|
|
||||||
// }
|
|
||||||
display.update(&mut delay).expect("error updating display");
|
display.update(&mut delay).expect("error updating display");
|
||||||
println!("update...");
|
println!("Update...");
|
||||||
|
|
||||||
println!("Finished - going to sleep");
|
println!("Finished - going to sleep");
|
||||||
display.deep_sleep()
|
display.deep_sleep()?;
|
||||||
|
|
||||||
|
sleep(one_minute);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_cpu_temp() -> Result<f64, io::Error> {
|
||||||
|
fs::read_to_string("/sys/class/thermal/thermal_zone0/temp")?
|
||||||
|
.trim()
|
||||||
|
.parse::<i32>()
|
||||||
|
.map(|temp| temp as f64 / 1000.)
|
||||||
|
.map_err(|err| io::Error::new(io::ErrorKind::Other, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_uptime() -> Option<String> {
|
||||||
|
Command::new("uptime").arg("-p").output().ok().and_then(|output| {
|
||||||
|
if output.status.success() {
|
||||||
|
String::from_utf8(output.stdout).ok()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_uname() -> Option<String> {
|
||||||
|
Command::new("uname").arg("-smr").output().ok().and_then(|output| {
|
||||||
|
if output.status.success() {
|
||||||
|
String::from_utf8(output.stdout).ok()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -37,7 +37,6 @@ impl<'a, I> GraphicDisplay<'a, I> where I: DisplayInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_pixel(&mut self, x: u32, y: u32, color: Color) {
|
fn set_pixel(&mut self, x: u32, y: u32, color: Color) {
|
||||||
// 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.cols() as u32, self.rows() as u32, self.rotation());
|
let (index, bit) = rotation(x, y, self.cols() as u32, self.rows() as u32, self.rotation());
|
||||||
let index = index as usize;
|
let index = index as usize;
|
||||||
|
|
||||||
|
@ -93,6 +92,23 @@ fn rotation(x: u32, y: u32, width: u32, height: u32, rotation: Rotation) -> (u32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn outside_display(x: u32, y: u32, width: u32, height: u32, rotation: Rotation) -> bool {
|
||||||
|
match rotation {
|
||||||
|
Rotation::Rotate0 | Rotation::Rotate180 => {
|
||||||
|
if x >= width || y >= height {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rotation::Rotate90 | Rotation::Rotate270 => {
|
||||||
|
if y >= width || x >= height {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "graphics")]
|
#[cfg(feature = "graphics")]
|
||||||
extern crate embedded_graphics;
|
extern crate embedded_graphics;
|
||||||
#[cfg(feature = "graphics")]
|
#[cfg(feature = "graphics")]
|
||||||
|
@ -108,6 +124,10 @@ where
|
||||||
T: Iterator<Item = Pixel<Color>>,
|
T: Iterator<Item = Pixel<Color>>,
|
||||||
{
|
{
|
||||||
for Pixel(UnsignedCoord(x, y), colour) in item_pixels {
|
for Pixel(UnsignedCoord(x, y), colour) in item_pixels {
|
||||||
|
if outside_display(x, y, self.cols() as u32, self.rows() as u32, self.rotation()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
self.set_pixel(x, y, colour);
|
self.set_pixel(x, y, colour);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue