include display driver,
and use rust_tls to make crosscompile easy
This commit is contained in:
274
src/epaper.rs
Normal file
274
src/epaper.rs
Normal file
@@ -0,0 +1,274 @@
|
||||
use embedded_graphics::{
|
||||
image::{Image, ImageRaw}, mono_font::{MonoTextStyleBuilder},prelude::*, text::{Baseline, Text, TextStyleBuilder}
|
||||
};
|
||||
|
||||
use crate::epd7in5_v2::Epd7in5;
|
||||
use crate::epd7in5_v2::Display7in5;
|
||||
use crate::graphics::Display;
|
||||
use linux_embedded_hal::{
|
||||
spidev::{self, SpidevOptions}, Delay, SPIError, SpidevDevice
|
||||
};
|
||||
|
||||
use crate::traits::{*};
|
||||
use crate::color::Color;
|
||||
use embedded_hal::digital::OutputPin;
|
||||
use embedded_hal::digital::PinState;
|
||||
|
||||
|
||||
use crate::killinfo::KillInfo;
|
||||
use image::RgbImage;
|
||||
|
||||
|
||||
pub struct EPaper {
|
||||
spi : SpidevDevice,
|
||||
epd: Epd7in5<SpidevDevice, gpiocdev_embedded_hal::InputPin, gpiocdev_embedded_hal::OutputPin, gpiocdev_embedded_hal::OutputPin, Delay>,
|
||||
display: Display<800, 480, false, 48000 , Color>,
|
||||
delay :Delay,
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl EPaper {
|
||||
pub fn new() -> Result<EPaper, SPIError> {
|
||||
|
||||
let mut spi = SpidevDevice::open("/dev/spidev0.0").expect("spidev directory");
|
||||
let options = SpidevOptions::new()
|
||||
.bits_per_word(8)
|
||||
.max_speed_hz(10_000_000)
|
||||
.mode(spidev::SpiModeFlags::SPI_MODE_0)
|
||||
.build();
|
||||
spi.configure(&options).expect("spi configuration");
|
||||
|
||||
// setup display pins
|
||||
let mut cs = gpiocdev_embedded_hal::OutputPin::new("/dev/gpiochip0", 26, PinState::High).unwrap();
|
||||
cs.set_high().unwrap();
|
||||
let busy = gpiocdev_embedded_hal::InputPin::new("/dev/gpiochip0", 24).unwrap();
|
||||
let dc = gpiocdev_embedded_hal::OutputPin::new("/dev/gpiochip0", 25, PinState::High).unwrap();
|
||||
let rst = gpiocdev_embedded_hal::OutputPin::new("/dev/gpiochip0", 17, PinState::High).unwrap();
|
||||
|
||||
let mut delay = Delay {};
|
||||
println!("START");
|
||||
let epd7in5 = Epd7in5::new(&mut spi, busy, dc, rst, &mut delay, None).expect("epd new");
|
||||
let display = Display7in5::default();
|
||||
println!("Device successfully initialized!");
|
||||
|
||||
return Ok(EPaper { spi, epd: epd7in5, display, delay : Delay {}});
|
||||
|
||||
}
|
||||
|
||||
pub fn flush(&mut self) -> Result<(), SPIError> {
|
||||
self.epd.update_and_display_frame(&mut self.spi, self.display.buffer(), &mut self.delay)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
pub fn sleep(&mut self) -> Result<(), SPIError> {
|
||||
self.epd.sleep(&mut self.spi, &mut self.delay)?;
|
||||
Ok(())
|
||||
|
||||
}
|
||||
|
||||
pub fn clear(&mut self, on: bool) {
|
||||
let color = if on {
|
||||
Color::Black
|
||||
} else {
|
||||
Color::White
|
||||
};
|
||||
|
||||
self.display.clear(color).ok();
|
||||
}
|
||||
|
||||
pub fn draw_text(&mut self, x: i32, y: i32, text: &str) {
|
||||
let style = MonoTextStyleBuilder::new()
|
||||
.font(&embedded_graphics::mono_font::ascii::FONT_8X13)
|
||||
.text_color(Color::White)
|
||||
.background_color(Color::Black)
|
||||
.build();
|
||||
|
||||
let text_style = TextStyleBuilder::new().baseline(Baseline::Top).build();
|
||||
|
||||
let _ = Text::with_text_style(text, Point::new(x, y), style, text_style).draw(&mut self.display);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub fn draw_kill_info(&mut self, kill: &KillInfo, x: i32, y: i32) {
|
||||
let mut current_y = y;
|
||||
|
||||
// Draw Alliance logo (64x64) if present
|
||||
if let Some(alliance) = &kill.victim.alliance {
|
||||
let bw_vec = rgb_to_bw_dithered(&alliance.logo);
|
||||
let logo_raw = ImageRaw::<Color>::new(bw_vec.as_slice(), alliance.logo.width() as u32);
|
||||
Image::new(&logo_raw, Point::new(x, y)).draw(&mut self.display).ok();
|
||||
}
|
||||
|
||||
// Draw Ship icon (64x64) if present
|
||||
if let Some(ship) = &kill.victim.ship {
|
||||
|
||||
let bw_vec = rgb_to_bw_dithered(&ship.icon);
|
||||
let width = ship.icon.width() as u32;
|
||||
let raw_image: ImageRaw<'_, Color> = ImageRaw::<Color>::new(&bw_vec, width);
|
||||
Image::new(&raw_image, Point::new(x + 64 + 4, current_y)).draw(&mut self.display).ok();
|
||||
}
|
||||
|
||||
let text_x = x + 64 + 64 + 8;
|
||||
let style = MonoTextStyleBuilder::new()
|
||||
.font(&embedded_graphics::mono_font::ascii::FONT_8X13)
|
||||
.text_color(Color::White)
|
||||
.background_color(Color::Black)
|
||||
.build();
|
||||
|
||||
current_y += 8;
|
||||
|
||||
// Character name + Alliance short
|
||||
let alliance_short = kill
|
||||
.victim
|
||||
.alliance
|
||||
.as_ref()
|
||||
.map(|a| a.short.as_str())
|
||||
.unwrap_or("");
|
||||
|
||||
|
||||
let char_name = kill
|
||||
.victim
|
||||
.character
|
||||
.as_ref()
|
||||
.map(|a| a.name.as_str())
|
||||
.unwrap_or("");
|
||||
|
||||
let char_line = format!("{} [{}]", char_name, alliance_short);
|
||||
Text::new(&char_line, Point::new(text_x, current_y), style).draw(&mut self.display).ok();
|
||||
current_y += 16;
|
||||
|
||||
// Ship name + total value
|
||||
let ship_name = kill.victim.ship.as_ref().map(|s| s.name.as_str()).unwrap_or("Unknown");
|
||||
let value_line = format!("{} - {:.2}M ISK", ship_name, kill.total_value / 1_000_000f64);
|
||||
Text::new(&value_line, Point::new(text_x, current_y), style).draw(&mut self.display).ok();
|
||||
current_y += 16;
|
||||
|
||||
// System name
|
||||
Text::new(&kill.system_name, Point::new(text_x, current_y), style).draw(&mut self.display).ok();
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub fn draw_loss_info(&mut self, kill: &KillInfo, x: i32, y: i32) {
|
||||
let mut current_y = y;
|
||||
|
||||
// Draw Alliance logo (64x64) if present
|
||||
if let Some(character) = &kill.victim.character {
|
||||
let bw_vec = rgb_to_bw_dithered(&character.portrait);
|
||||
let logo_raw = ImageRaw::<Color>::new(&bw_vec, character.portrait.width() as u32);
|
||||
Image::new(&logo_raw, Point::new(x, y)).draw(&mut self.display).ok();
|
||||
}
|
||||
|
||||
// Draw Ship icon (64x64) if present
|
||||
if let Some(ship) = &kill.victim.ship {
|
||||
|
||||
let bw_vec = rgb_to_bw_dithered(&ship.icon);
|
||||
let logo_raw = ImageRaw::<Color>::new(&bw_vec, ship.icon.width() as u32);
|
||||
Image::new(&logo_raw, Point::new(x + 64 + 4, current_y)).draw(&mut self.display).ok();
|
||||
}
|
||||
|
||||
let text_x = x + 64 + 64 + 8;
|
||||
let style = MonoTextStyleBuilder::new()
|
||||
.font(&embedded_graphics::mono_font::ascii::FONT_8X13)
|
||||
.text_color(Color::Black)
|
||||
.background_color(Color::White)
|
||||
.build();
|
||||
current_y += 8;
|
||||
|
||||
// Character name + Alliance short
|
||||
let alliance_short = kill
|
||||
.victim
|
||||
.alliance
|
||||
.as_ref()
|
||||
.map(|a| a.short.as_str())
|
||||
.unwrap_or("");
|
||||
|
||||
|
||||
let char_name = kill
|
||||
.victim
|
||||
.character
|
||||
.as_ref()
|
||||
.map(|a| a.name.as_str())
|
||||
.unwrap_or("");
|
||||
|
||||
let char_line = format!("{} [{}]", char_name, alliance_short);
|
||||
Text::new(&char_line, Point::new(text_x, current_y), style).draw(&mut self.display).ok();
|
||||
current_y += 16;
|
||||
|
||||
// Ship name + total value
|
||||
let ship_name = kill.victim.ship.as_ref().map(|s| s.name.as_str()).unwrap_or("Unknown");
|
||||
let value_line = format!("{} - {:.2}M ISK", ship_name, kill.total_value / 1_000_000f64);
|
||||
Text::new(&value_line, Point::new(text_x, current_y), style).draw(&mut self.display).ok();
|
||||
current_y += 16;
|
||||
|
||||
// System name
|
||||
Text::new(&kill.system_name, Point::new(text_x, current_y), style).draw(&mut self.display).ok();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
fn rgb_to_bw_dithered(rgb: &RgbImage) -> Vec<u8> {
|
||||
let w = rgb.width() as usize;
|
||||
let h = rgb.height() as usize;
|
||||
|
||||
// Convert to grayscale f32 buffer
|
||||
let mut gray: Vec<f32> = rgb
|
||||
.pixels()
|
||||
.map(|p| {
|
||||
let [r, g, b] = p.0;
|
||||
0.299 * r as f32 + 0.587 * g as f32 + 0.114 * b as f32
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut bits = Vec::new();
|
||||
let mut byte = 0u8;
|
||||
let mut bit_idx = 7;
|
||||
|
||||
for y in 0..h {
|
||||
for x in 0..w {
|
||||
let idx = y * w + x;
|
||||
let old = gray[idx];
|
||||
let new = if old >= 128.0 { 255.0 } else { 0.0 };
|
||||
let error = old - new;
|
||||
|
||||
// Quantize to B/W
|
||||
let bw = new > 127.0;
|
||||
if bw {
|
||||
byte |= 1 << bit_idx;
|
||||
}
|
||||
bit_idx -= 1;
|
||||
if bit_idx == -1 {
|
||||
bits.push(byte);
|
||||
byte = 0;
|
||||
bit_idx = 7;
|
||||
}
|
||||
|
||||
// Distribute error (Floyd–Steinberg)
|
||||
if x + 1 < w {
|
||||
gray[idx + 1] += error * 7.0 / 16.0;
|
||||
}
|
||||
if y + 1 < h {
|
||||
if x > 0 {
|
||||
gray[idx + w - 1] += error * 3.0 / 16.0;
|
||||
}
|
||||
gray[idx + w] += error * 5.0 / 16.0;
|
||||
if x + 1 < w {
|
||||
gray[idx + w + 1] += error * 1.0 / 16.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if bit_idx > 0 {
|
||||
bits.push(byte);
|
||||
}
|
||||
|
||||
bits
|
||||
}
|
||||
Reference in New Issue
Block a user