cleanup & format

This commit is contained in:
2025-09-03 23:27:26 +02:00
parent b1b4356686
commit 89689c44fd
16 changed files with 251 additions and 393 deletions

View File

@@ -1,20 +1,18 @@
use embedded_graphics::{ use embedded_graphics::{
framebuffer::Framebuffer, framebuffer::Framebuffer,
image::{Image, ImageRaw},
mono_font::{MonoTextStyle, ascii::FONT_8X13}, mono_font::{MonoTextStyle, ascii::FONT_8X13},
pixelcolor::{ pixelcolor::raw::BigEndian,
raw::{BigEndian},
},
prelude::*, prelude::*,
primitives::{PrimitiveStyle, Rectangle, StyledDrawable}, primitives::{PrimitiveStyle, Rectangle, StyledDrawable},
text::Text, text::Text,
image::{Image, ImageRaw},
}; };
use image::GrayImage;
use image::RgbImage; use image::RgbImage;
use image::{GrayImage};
use embedded_graphics::pixelcolor::BinaryColor;
use embedded_graphics::pixelcolor::raw::RawU1;
use crate::killinfo::KillInfo; use crate::killinfo::KillInfo;
use embedded_graphics::pixelcolor::BinaryColor;
use embedded_graphics::pixelcolor::raw::RawU1;
const WIDTH: usize = 800; const WIDTH: usize = 800;
const HEIGHT: usize = 480; const HEIGHT: usize = 480;
@@ -28,10 +26,11 @@ pub struct Display {
impl Display { impl Display {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
width : WIDTH, width: WIDTH,
height : HEIGHT, height: HEIGHT,
buffer: buffer:
Framebuffer::<BinaryColor, RawU1, BigEndian, WIDTH, HEIGHT, { WIDTH * HEIGHT }>::new(), Framebuffer::<BinaryColor, RawU1, BigEndian, WIDTH, HEIGHT, { WIDTH * HEIGHT }>::new(
),
} }
} }
pub fn clear(&mut self, on: bool) { pub fn clear(&mut self, on: bool) {
@@ -42,17 +41,25 @@ impl Display {
}; };
self.buffer.clear(color).ok(); self.buffer.clear(color).ok();
} }
pub fn draw_rect(&mut self, x: i32, y: i32, w: u32, h: u32, color: u8) { pub fn draw_rect(&mut self, x: i32, y: i32, w: u32, h: u32, color: u8) {
let rect = Rectangle::new(Point::new(x, y), Size::new(w, h)); let rect = Rectangle::new(Point::new(x, y), Size::new(w, h));
let bw = if color > 127 { BinaryColor::On } else { BinaryColor::Off }; let bw = if color > 127 {
BinaryColor::On
} else {
BinaryColor::Off
};
let style = PrimitiveStyle::with_fill(bw); let style = PrimitiveStyle::with_fill(bw);
rect.draw_styled(&style, &mut self.buffer).ok(); rect.draw_styled(&style, &mut self.buffer).ok();
} }
pub fn draw_text(&mut self, x: i32, y: i32, text: &str, color: u8) { pub fn draw_text(&mut self, x: i32, y: i32, text: &str, color: u8) {
let bw = if color > 127 { BinaryColor::On } else { BinaryColor::Off }; let bw = if color > 127 {
BinaryColor::On
} else {
BinaryColor::Off
};
let style = MonoTextStyle::new(&FONT_8X13, bw); let style = MonoTextStyle::new(&FONT_8X13, bw);
Text::new(text, Point::new(x, y), style) Text::new(text, Point::new(x, y), style)
.draw(&mut self.buffer) .draw(&mut self.buffer)
@@ -66,19 +73,22 @@ impl Display {
if let Some(alliance) = &kill.victim.alliance { if let Some(alliance) = &kill.victim.alliance {
let bw_vec = rgb_to_bw_dithered(&alliance.logo); let bw_vec = rgb_to_bw_dithered(&alliance.logo);
let logo_raw = ImageRaw::<BinaryColor>::new(&bw_vec, alliance.logo.width() as u32); let logo_raw = ImageRaw::<BinaryColor>::new(&bw_vec, alliance.logo.width() as u32);
Image::new(&logo_raw, Point::new(x, y)).draw(&mut self.buffer).ok(); Image::new(&logo_raw, Point::new(x, y))
.draw(&mut self.buffer)
.ok();
} }
// Draw Ship icon (64x64) if present // Draw Ship icon (64x64) if present
if let Some(ship) = &kill.victim.ship { if let Some(ship) = &kill.victim.ship {
let bw_vec = rgb_to_bw_dithered(&ship.icon); let bw_vec = rgb_to_bw_dithered(&ship.icon);
let logo_raw = ImageRaw::<BinaryColor>::new(&bw_vec, ship.icon.width() as u32); let logo_raw = ImageRaw::<BinaryColor>::new(&bw_vec, ship.icon.width() as u32);
Image::new(&logo_raw, Point::new(x + 64 + 4, current_y)).draw(&mut self.buffer).ok(); Image::new(&logo_raw, Point::new(x + 64 + 4, current_y))
.draw(&mut self.buffer)
.ok();
} }
let text_x = x + 64 + 64 + 8; let text_x = x + 64 + 64 + 8;
let style = MonoTextStyle::new(&FONT_8X13, BinaryColor::Off ); let style = MonoTextStyle::new(&FONT_8X13, BinaryColor::Off);
current_y += 8; current_y += 8;
// Character name + Alliance short // Character name + Alliance short
@@ -89,7 +99,6 @@ impl Display {
.map(|a| a.short.as_str()) .map(|a| a.short.as_str())
.unwrap_or(""); .unwrap_or("");
let char_name = kill let char_name = kill
.victim .victim
.character .character
@@ -98,41 +107,57 @@ impl Display {
.unwrap_or(""); .unwrap_or("");
let char_line = format!("{} [{}]", char_name, alliance_short); let char_line = format!("{} [{}]", char_name, alliance_short);
Text::new(&char_line, Point::new(text_x, current_y), style).draw(&mut self.buffer).ok(); Text::new(&char_line, Point::new(text_x, current_y), style)
.draw(&mut self.buffer)
.ok();
current_y += 16; current_y += 16;
// Ship name + total value // Ship name + total value
let ship_name = kill.victim.ship.as_ref().map(|s| s.name.as_str()).unwrap_or("Unknown"); let ship_name = kill
let value_line = format!("{} - {:.2}M ISK", ship_name, kill.total_value / 1_000_000f64); .victim
Text::new(&value_line, Point::new(text_x, current_y), style).draw(&mut self.buffer).ok(); .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.buffer)
.ok();
current_y += 16; current_y += 16;
// System name // System name
Text::new(&kill.system_name, Point::new(text_x, current_y), style).draw(&mut self.buffer).ok(); Text::new(&kill.system_name, Point::new(text_x, current_y), style)
.draw(&mut self.buffer)
.ok();
} }
pub fn draw_loss_info(&mut self, kill: &KillInfo, x: i32, y: i32) {
pub fn draw_loss_info(&mut self, kill: &KillInfo, x: i32, y: i32) {
let mut current_y = y; let mut current_y = y;
// Draw Alliance logo (64x64) if present // Draw Alliance logo (64x64) if present
if let Some(character) = &kill.victim.character { if let Some(character) = &kill.victim.character {
let bw_vec = rgb_to_bw_dithered(&character.portrait); let bw_vec = rgb_to_bw_dithered(&character.portrait);
let logo_raw = ImageRaw::<BinaryColor>::new(&bw_vec, character.portrait.width() as u32); let logo_raw = ImageRaw::<BinaryColor>::new(&bw_vec, character.portrait.width() as u32);
Image::new(&logo_raw, Point::new(x, y)).draw(&mut self.buffer).ok(); Image::new(&logo_raw, Point::new(x, y))
.draw(&mut self.buffer)
.ok();
} }
// Draw Ship icon (64x64) if present // Draw Ship icon (64x64) if present
if let Some(ship) = &kill.victim.ship { if let Some(ship) = &kill.victim.ship {
let bw_vec = rgb_to_bw_dithered(&ship.icon); let bw_vec = rgb_to_bw_dithered(&ship.icon);
let logo_raw = ImageRaw::<BinaryColor>::new(&bw_vec, ship.icon.width() as u32); let logo_raw = ImageRaw::<BinaryColor>::new(&bw_vec, ship.icon.width() as u32);
Image::new(&logo_raw, Point::new(x + 64 + 4, current_y)).draw(&mut self.buffer).ok(); Image::new(&logo_raw, Point::new(x + 64 + 4, current_y))
.draw(&mut self.buffer)
.ok();
} }
let text_x = x + 64 + 64 + 8; let text_x = x + 64 + 64 + 8;
let style = MonoTextStyle::new(&FONT_8X13, BinaryColor::Off ); let style = MonoTextStyle::new(&FONT_8X13, BinaryColor::Off);
current_y += 8; current_y += 8;
// Character name + Alliance short // Character name + Alliance short
@@ -143,7 +168,6 @@ impl Display {
.map(|a| a.short.as_str()) .map(|a| a.short.as_str())
.unwrap_or(""); .unwrap_or("");
let char_name = kill let char_name = kill
.victim .victim
.character .character
@@ -152,35 +176,48 @@ impl Display {
.unwrap_or(""); .unwrap_or("");
let char_line = format!("{} [{}]", char_name, alliance_short); let char_line = format!("{} [{}]", char_name, alliance_short);
Text::new(&char_line, Point::new(text_x, current_y), style).draw(&mut self.buffer).ok(); Text::new(&char_line, Point::new(text_x, current_y), style)
.draw(&mut self.buffer)
.ok();
current_y += 16; current_y += 16;
// Ship name + total value // Ship name + total value
let ship_name = kill.victim.ship.as_ref().map(|s| s.name.as_str()).unwrap_or("Unknown"); let ship_name = kill
let value_line = format!("{} - {:.2}M ISK", ship_name, kill.total_value / 1_000_000f64); .victim
Text::new(&value_line, Point::new(text_x, current_y), style).draw(&mut self.buffer).ok(); .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.buffer)
.ok();
current_y += 16; current_y += 16;
// System name // System name
Text::new(&kill.system_name, Point::new(text_x, current_y), style).draw(&mut self.buffer).ok(); Text::new(&kill.system_name, Point::new(text_x, current_y), style)
.draw(&mut self.buffer)
.ok();
} }
pub fn flush(&self) {
let buf = self.buffer.data();
let img_data: Vec<u8> = buf
.iter()
.flat_map(|byte| (0..8).map(move |i| if (byte >> (7 - i)) & 1 == 1 { 255 } else { 0 }))
.take(self.width * self.height)
.collect();
pub fn flush(&self) { let img = GrayImage::from_raw(self.width as u32, self.height as u32, img_data).unwrap();
let buf = self.buffer.data(); img.save("output.png").unwrap();
let img_data: Vec<u8> = buf println!("Saved framebuffer to {:?}", "output.png");
.iter() }
.flat_map(|byte| (0..8).map(move |i| if (byte >> (7-i)) & 1 == 1 { 255 } else { 0 }))
.take(self.width * self.height)
.collect();
let img = GrayImage::from_raw(self.width as u32, self.height as u32, img_data).unwrap();
img.save("output.png").unwrap();
println!("Saved framebuffer to {:?}", "output.png");
}
} }
fn rgb_to_bw_dithered(rgb: &RgbImage) -> Vec<u8> { fn rgb_to_bw_dithered(rgb: &RgbImage) -> Vec<u8> {
let w = rgb.width() as usize; let w = rgb.width() as usize;
let h = rgb.height() as usize; let h = rgb.height() as usize;
@@ -238,4 +275,4 @@ fn rgb_to_bw_dithered(rgb: &RgbImage) -> Vec<u8> {
} }
bits bits
} }

View File

@@ -1,36 +1,42 @@
use embedded_graphics::{ use embedded_graphics::{
image::{Image, ImageRaw}, mono_font::{MonoTextStyleBuilder},prelude::*, text::{Baseline, Text, TextStyleBuilder} image::{Image, ImageRaw},
mono_font::MonoTextStyleBuilder,
prelude::*,
text::{Baseline, Text, TextStyleBuilder},
}; };
use crate::epd7in5_v2::Epd7in5; use crate::epd::color::Color;
use crate::epd7in5_v2::Display7in5; use crate::epd::epd7in5_v2::Display7in5;
use crate::graphics::Display; use crate::epd::epd7in5_v2::Epd7in5;
use crate::epd::graphics::Display;
use crate::epd::traits::*;
use linux_embedded_hal::{ use linux_embedded_hal::{
spidev::{self, SpidevOptions}, Delay, SPIError, SpidevDevice Delay, SPIError, SpidevDevice,
spidev::{self, SpidevOptions},
}; };
use crate::traits::{*};
use crate::color::Color;
use embedded_hal::digital::OutputPin; use embedded_hal::digital::OutputPin;
use embedded_hal::digital::PinState; use embedded_hal::digital::PinState;
use crate::killinfo::KillInfo; use crate::killinfo::KillInfo;
use image::RgbImage; use image::RgbImage;
pub struct EPaper { pub struct EPaper {
spi : SpidevDevice, spi: SpidevDevice,
epd: Epd7in5<SpidevDevice, gpiocdev_embedded_hal::InputPin, gpiocdev_embedded_hal::OutputPin, gpiocdev_embedded_hal::OutputPin, Delay>, epd: Epd7in5<
display: Display<800, 480, false, 48000 , Color>, SpidevDevice,
delay :Delay, gpiocdev_embedded_hal::InputPin,
gpiocdev_embedded_hal::OutputPin,
gpiocdev_embedded_hal::OutputPin,
Delay,
>,
display: Display<800, 480, false, 48000, Color>,
delay: Delay,
} }
impl EPaper { impl EPaper {
pub fn new() -> Result<EPaper, SPIError> { pub fn new() -> Result<EPaper, SPIError> {
let mut spi = SpidevDevice::open("/dev/spidev0.0").expect("spidev directory"); let mut spi = SpidevDevice::open("/dev/spidev0.0").expect("spidev directory");
let options = SpidevOptions::new() let options = SpidevOptions::new()
.bits_per_word(8) .bits_per_word(8)
@@ -40,11 +46,14 @@ impl EPaper {
spi.configure(&options).expect("spi configuration"); spi.configure(&options).expect("spi configuration");
// setup display pins // setup display pins
let mut cs = gpiocdev_embedded_hal::OutputPin::new("/dev/gpiochip0", 26, PinState::High).unwrap(); let mut cs =
gpiocdev_embedded_hal::OutputPin::new("/dev/gpiochip0", 26, PinState::High).unwrap();
cs.set_high().unwrap(); cs.set_high().unwrap();
let busy = gpiocdev_embedded_hal::InputPin::new("/dev/gpiochip0", 24).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 dc =
let rst = gpiocdev_embedded_hal::OutputPin::new("/dev/gpiochip0", 17, PinState::High).unwrap(); 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 {}; let mut delay = Delay {};
println!("START"); println!("START");
@@ -52,47 +61,44 @@ impl EPaper {
let display = Display7in5::default(); let display = Display7in5::default();
println!("Device successfully initialized!"); println!("Device successfully initialized!");
return Ok(EPaper { spi, epd: epd7in5, display, delay : Delay {}}); return Ok(EPaper {
spi,
epd: epd7in5,
display,
delay: Delay {},
});
} }
pub fn flush(&mut self) -> Result<(), SPIError> { pub fn flush(&mut self) -> Result<(), SPIError> {
self.epd.update_and_display_frame(&mut self.spi, self.display.buffer(), &mut self.delay)?; self.epd
.update_and_display_frame(&mut self.spi, self.display.buffer(), &mut self.delay)?;
Ok(()) Ok(())
} }
pub fn sleep(&mut self) -> Result<(), SPIError> {
pub fn sleep(&mut self) -> Result<(), SPIError> {
self.epd.sleep(&mut self.spi, &mut self.delay)?; self.epd.sleep(&mut self.spi, &mut self.delay)?;
Ok(()) Ok(())
} }
pub fn clear(&mut self, on: bool) { pub fn clear(&mut self, on: bool) {
let color = if on { let color = if on { Color::Black } else { Color::White };
Color::Black
} else {
Color::White
};
self.display.clear(color).ok(); self.display.clear(color).ok();
} }
pub fn draw_text(&mut self, x: i32, y: i32, text: &str) { pub fn draw_text(&mut self, x: i32, y: i32, text: &str) {
let style = MonoTextStyleBuilder::new() let style = MonoTextStyleBuilder::new()
.font(&embedded_graphics::mono_font::ascii::FONT_8X13) .font(&embedded_graphics::mono_font::ascii::FONT_8X13)
.text_color(Color::White) .text_color(Color::White)
.background_color(Color::Black) .background_color(Color::Black)
.build(); .build();
let text_style = TextStyleBuilder::new().baseline(Baseline::Top).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); 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) { pub fn draw_kill_info(&mut self, kill: &KillInfo, x: i32, y: i32) {
let mut current_y = y; let mut current_y = y;
@@ -100,16 +106,19 @@ impl EPaper {
if let Some(alliance) = &kill.victim.alliance { if let Some(alliance) = &kill.victim.alliance {
let bw_vec = rgb_to_bw_dithered(&alliance.logo); let bw_vec = rgb_to_bw_dithered(&alliance.logo);
let logo_raw = ImageRaw::<Color>::new(bw_vec.as_slice(), alliance.logo.width() as u32); 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(); Image::new(&logo_raw, Point::new(x, y))
.draw(&mut self.display)
.ok();
} }
// Draw Ship icon (64x64) if present // Draw Ship icon (64x64) if present
if let Some(ship) = &kill.victim.ship { if let Some(ship) = &kill.victim.ship {
let bw_vec = rgb_to_bw_dithered(&ship.icon); let bw_vec = rgb_to_bw_dithered(&ship.icon);
let width = ship.icon.width() as u32; let width = ship.icon.width() as u32;
let raw_image: ImageRaw<'_, Color> = ImageRaw::<Color>::new(&bw_vec, width); 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(); Image::new(&raw_image, Point::new(x + 64 + 4, current_y))
.draw(&mut self.display)
.ok();
} }
let text_x = x + 64 + 64 + 8; let text_x = x + 64 + 64 + 8;
@@ -129,7 +138,6 @@ impl EPaper {
.map(|a| a.short.as_str()) .map(|a| a.short.as_str())
.unwrap_or(""); .unwrap_or("");
let char_name = kill let char_name = kill
.victim .victim
.character .character
@@ -138,37 +146,53 @@ impl EPaper {
.unwrap_or(""); .unwrap_or("");
let char_line = format!("{} [{}]", char_name, alliance_short); let char_line = format!("{} [{}]", char_name, alliance_short);
Text::new(&char_line, Point::new(text_x, current_y), style).draw(&mut self.display).ok(); Text::new(&char_line, Point::new(text_x, current_y), style)
.draw(&mut self.display)
.ok();
current_y += 16; current_y += 16;
// Ship name + total value // Ship name + total value
let ship_name = kill.victim.ship.as_ref().map(|s| s.name.as_str()).unwrap_or("Unknown"); let ship_name = kill
let value_line = format!("{} - {:.2}M ISK", ship_name, kill.total_value / 1_000_000f64); .victim
Text::new(&value_line, Point::new(text_x, current_y), style).draw(&mut self.display).ok(); .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; current_y += 16;
// System name // System name
Text::new(&kill.system_name, Point::new(text_x, current_y), style).draw(&mut self.display).ok(); 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) {
pub fn draw_loss_info(&mut self, kill: &KillInfo, x: i32, y: i32) {
let mut current_y = y; let mut current_y = y;
// Draw Alliance logo (64x64) if present // Draw Alliance logo (64x64) if present
if let Some(character) = &kill.victim.character { if let Some(character) = &kill.victim.character {
let bw_vec = rgb_to_bw_dithered(&character.portrait); let bw_vec = rgb_to_bw_dithered(&character.portrait);
let logo_raw = ImageRaw::<Color>::new(&bw_vec, character.portrait.width() as u32); 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(); Image::new(&logo_raw, Point::new(x, y))
.draw(&mut self.display)
.ok();
} }
// Draw Ship icon (64x64) if present // Draw Ship icon (64x64) if present
if let Some(ship) = &kill.victim.ship { if let Some(ship) = &kill.victim.ship {
let bw_vec = rgb_to_bw_dithered(&ship.icon); let bw_vec = rgb_to_bw_dithered(&ship.icon);
let logo_raw = ImageRaw::<Color>::new(&bw_vec, ship.icon.width() as u32); 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(); Image::new(&logo_raw, Point::new(x + 64 + 4, current_y))
.draw(&mut self.display)
.ok();
} }
let text_x = x + 64 + 64 + 8; let text_x = x + 64 + 64 + 8;
@@ -187,7 +211,6 @@ impl EPaper {
.map(|a| a.short.as_str()) .map(|a| a.short.as_str())
.unwrap_or(""); .unwrap_or("");
let char_name = kill let char_name = kill
.victim .victim
.character .character
@@ -196,24 +219,35 @@ impl EPaper {
.unwrap_or(""); .unwrap_or("");
let char_line = format!("{} [{}]", char_name, alliance_short); let char_line = format!("{} [{}]", char_name, alliance_short);
Text::new(&char_line, Point::new(text_x, current_y), style).draw(&mut self.display).ok(); Text::new(&char_line, Point::new(text_x, current_y), style)
.draw(&mut self.display)
.ok();
current_y += 16; current_y += 16;
// Ship name + total value // Ship name + total value
let ship_name = kill.victim.ship.as_ref().map(|s| s.name.as_str()).unwrap_or("Unknown"); let ship_name = kill
let value_line = format!("{} - {:.2}M ISK", ship_name, kill.total_value / 1_000_000f64); .victim
Text::new(&value_line, Point::new(text_x, current_y), style).draw(&mut self.display).ok(); .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; current_y += 16;
// System name // System name
Text::new(&kill.system_name, Point::new(text_x, current_y), style).draw(&mut self.display).ok(); 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> { fn rgb_to_bw_dithered(rgb: &RgbImage) -> Vec<u8> {
let w = rgb.width() as usize; let w = rgb.width() as usize;
let h = rgb.height() as usize; let h = rgb.height() as usize;
@@ -271,4 +305,4 @@ fn rgb_to_bw_dithered(rgb: &RgbImage) -> Vec<u8> {
} }
bits bits
} }

View File

@@ -1,6 +1,6 @@
//! SPI Commands for the Waveshare 7.5" E-Ink Display //! SPI Commands for the Waveshare 7.5" E-Ink Display
use crate::traits; use crate::epd::traits;
/// Epd7in5 commands /// Epd7in5 commands
/// ///
@@ -143,7 +143,7 @@ impl traits::Command for Command {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::traits::Command as CommandTrait; use crate::epd::traits::Command as CommandTrait;
#[test] #[test]
fn command_addr() { fn command_addr() {

View File

@@ -16,9 +16,9 @@ use embedded_hal::{
spi::SpiDevice, spi::SpiDevice,
}; };
use crate::color::Color; use crate::epd::color::Color;
use crate::interface::DisplayInterface; use crate::epd::interface::DisplayInterface;
use crate::traits::{InternalWiAdditions, RefreshLut, WaveshareDisplay}; use crate::epd::traits::{InternalWiAdditions, RefreshLut, WaveshareDisplay};
pub(crate) mod command; pub(crate) mod command;
use self::command::Command; use self::command::Command;
@@ -26,7 +26,7 @@ use crate::buffer_len;
/// Full size buffer for use with the 7in5 v2 EPD /// Full size buffer for use with the 7in5 v2 EPD
#[cfg(feature = "graphics")] #[cfg(feature = "graphics")]
pub type Display7in5 = crate::graphics::Display< pub type Display7in5 = crate::epd::graphics::Display<
WIDTH, WIDTH,
HEIGHT, HEIGHT,
false, false,

View File

@@ -1,6 +1,6 @@
//! Graphics Support for EPDs //! Graphics Support for EPDs
use crate::color::{ColorType, TriColor}; use crate::epd::color::{ColorType, TriColor};
use core::marker::PhantomData; use core::marker::PhantomData;
use embedded_graphics::prelude::*; use embedded_graphics::prelude::*;
@@ -59,12 +59,12 @@ pub struct Display<
} }
impl< impl<
const WIDTH: u32, const WIDTH: u32,
const HEIGHT: u32, const HEIGHT: u32,
const BWRBIT: bool, const BWRBIT: bool,
const BYTECOUNT: usize, const BYTECOUNT: usize,
COLOR: ColorType + PixelColor, COLOR: ColorType + PixelColor,
> Default for Display<WIDTH, HEIGHT, BWRBIT, BYTECOUNT, COLOR> > Default for Display<WIDTH, HEIGHT, BWRBIT, BYTECOUNT, COLOR>
{ {
/// Initialize display with the color '0', which may not be the same on all device. /// Initialize display with the color '0', which may not be the same on all device.
/// Many devices have a bit parameter polarity that should be changed if this is not the right /// Many devices have a bit parameter polarity that should be changed if this is not the right
@@ -87,12 +87,12 @@ impl<
/// For use with embedded_grahics /// For use with embedded_grahics
impl< impl<
const WIDTH: u32, const WIDTH: u32,
const HEIGHT: u32, const HEIGHT: u32,
const BWRBIT: bool, const BWRBIT: bool,
const BYTECOUNT: usize, const BYTECOUNT: usize,
COLOR: ColorType + PixelColor, COLOR: ColorType + PixelColor,
> DrawTarget for Display<WIDTH, HEIGHT, BWRBIT, BYTECOUNT, COLOR> > DrawTarget for Display<WIDTH, HEIGHT, BWRBIT, BYTECOUNT, COLOR>
{ {
type Color = COLOR; type Color = COLOR;
type Error = core::convert::Infallible; type Error = core::convert::Infallible;
@@ -110,12 +110,12 @@ impl<
/// For use with embedded_grahics /// For use with embedded_grahics
impl< impl<
const WIDTH: u32, const WIDTH: u32,
const HEIGHT: u32, const HEIGHT: u32,
const BWRBIT: bool, const BWRBIT: bool,
const BYTECOUNT: usize, const BYTECOUNT: usize,
COLOR: ColorType + PixelColor, COLOR: ColorType + PixelColor,
> OriginDimensions for Display<WIDTH, HEIGHT, BWRBIT, BYTECOUNT, COLOR> > OriginDimensions for Display<WIDTH, HEIGHT, BWRBIT, BYTECOUNT, COLOR>
{ {
fn size(&self) -> Size { fn size(&self) -> Size {
match self.rotation { match self.rotation {
@@ -126,12 +126,12 @@ impl<
} }
impl< impl<
const WIDTH: u32, const WIDTH: u32,
const HEIGHT: u32, const HEIGHT: u32,
const BWRBIT: bool, const BWRBIT: bool,
const BYTECOUNT: usize, const BYTECOUNT: usize,
COLOR: ColorType + PixelColor, COLOR: ColorType + PixelColor,
> Display<WIDTH, HEIGHT, BWRBIT, BYTECOUNT, COLOR> > Display<WIDTH, HEIGHT, BWRBIT, BYTECOUNT, COLOR>
{ {
/// get internal buffer to use it (to draw in epd) /// get internal buffer to use it (to draw in epd)
pub fn buffer(&self) -> &[u8] { pub fn buffer(&self) -> &[u8] {
@@ -354,10 +354,8 @@ fn set_pixel<COLOR: ColorType + PixelColor>(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::color::*; use crate::epd::color::*;
use embedded_graphics::{ use embedded_graphics::primitives::{Line, PrimitiveStyle};
primitives::{Line, PrimitiveStyle},
};
// test buffer length // test buffer length
#[test] #[test]

View File

@@ -1,4 +1,4 @@
use crate::traits::Command; use crate::epd::traits::Command;
use core::marker::PhantomData; use core::marker::PhantomData;
use embedded_hal::{delay::*, digital::*, spi::SpiDevice}; use embedded_hal::{delay::*, digital::*, spi::SpiDevice};

12
src/epd/mod.rs Normal file
View File

@@ -0,0 +1,12 @@
pub mod graphics;
pub mod traits;
pub mod color;
pub mod rect;
/// Interface for the physical connection between display and the controlling device
pub mod interface;
pub mod epd7in5_v2;

View File

@@ -111,9 +111,8 @@ impl Individual {
alli_id: u32, alli_id: u32,
ship_id: u32, ship_id: u32,
) -> Result<Individual, EsiError> { ) -> Result<Individual, EsiError> {
let character = if char_id != 0 { let character = if char_id != 0 {
client.get_character(char_id).ok() client.get_character(char_id).ok()
} else { } else {
None None
}; };

View File

@@ -1,101 +1,8 @@
//! A simple Driver for the [Waveshare](https://github.com/waveshare/e-Paper) E-Ink Displays via SPI pub mod epd;
//!
//! - Built using [`embedded-hal`] traits.
//! - Graphics support is added through [`embedded-graphics`]
//!
//! [`embedded-graphics`]: https://docs.rs/embedded-graphics/
//! [`embedded-hal`]: https://docs.rs/embedded-hal
//!
//!
//! # Example
//!
//!```rust, no_run
//!# use embedded_hal_mock::eh1::*;
//!# fn main() -> Result<(), embedded_hal::spi::ErrorKind> {
//!use embedded_graphics::{
//! pixelcolor::BinaryColor::On as Black, prelude::*, primitives::{Line, PrimitiveStyle},
//!};
//!use epd_waveshare::{epd1in54::*, prelude::*};
//!#
//!# let expectations = [];
//!# let mut spi = spi::Mock::new(&expectations);
//!# let expectations = [];
//!# let cs_pin = digital::Mock::new(&expectations);
//!# let busy_in = digital::Mock::new(&expectations);
//!# let dc = digital::Mock::new(&expectations);
//!# let rst = digital::Mock::new(&expectations);
//!# let mut delay = delay::NoopDelay::new();
//!
//!// Setup EPD
//!let mut epd = Epd1in54::new(&mut spi, busy_in, dc, rst, &mut delay, None)?;
//!
//!// Use display graphics from embedded-graphics
//!let mut display = Display1in54::default();
//!
//!// Use embedded graphics for drawing a line
//!
//!let _ = Line::new(Point::new(0, 120), Point::new(0, 295))
//! .into_styled(PrimitiveStyle::with_stroke(Color::Black, 1))
//! .draw(&mut display);
//!
//! // Display updated frame
//!epd.update_frame(&mut spi, &display.buffer(), &mut delay)?;
//!epd.display_frame(&mut spi, &mut delay)?;
//!
//!// Set the EPD to sleep
//!epd.sleep(&mut spi, &mut delay)?;
//!# Ok(())
//!# }
//!```
//!
//! # Other information and requirements
//!
//! - Buffersize: Wherever a buffer is used it always needs to be of the size: `width / 8 * length`,
//! where width and length being either the full e-ink size or the partial update window size
//!
//! ### SPI
//!
//! MISO is not connected/available. SPI_MODE_0 is used (CPHL = 0, CPOL = 0) with 8 bits per word, MSB first.
//!
//! Maximum speed tested by myself was 8Mhz but more should be possible (Ben Krasnow used 18Mhz with his implemenation)
//!
#[cfg(feature = "graphics")]
pub mod graphics;
pub mod traits;
pub mod color;
pub mod rect;
/// Interface for the physical connection between display and the controlling device
pub mod interface;
pub mod epd7in5_v2;
pub mod killinfo; pub mod killinfo;
pub mod model; pub mod model;
pub mod services; pub mod services;
pub mod type_a;
/// Includes everything important besides the chosen Display
pub mod prelude {
pub use crate::color::{Color, OctColor, TriColor};
pub use crate::traits::{
QuickRefresh, RefreshLut, WaveshareDisplay, WaveshareThreeColorDisplay,
};
pub use crate::SPI_MODE;
#[cfg(feature = "graphics")]
pub use crate::graphics::{Display, DisplayRotation};
}
/// Computes the needed buffer length. Takes care of rounding up in case width /// Computes the needed buffer length. Takes care of rounding up in case width
/// is not divisible by 8. /// is not divisible by 8.
/// ///

View File

@@ -1,52 +1,32 @@
pub mod graphics;
pub mod traits;
pub mod color;
pub mod rect;
/// Interface for the physical connection between display and the controlling device
pub mod interface;
pub mod epd7in5_v2;
pub mod display; pub mod display;
pub mod epaper;
pub mod epd;
pub mod killinfo; pub mod killinfo;
pub mod model; pub mod model;
pub mod services; pub mod services;
pub mod epaper;
pub mod type_a;
use crate::killinfo::KillInfo; use crate::killinfo::KillInfo;
use crate::services::esi_static::EsiClient; use crate::services::esi_static::EsiClient;
use crate::services::zkill::ZkillClient; use crate::services::zkill::ZkillClient;
pub const fn buffer_len(width: usize, height: usize) -> usize { pub const fn buffer_len(width: usize, height: usize) -> usize {
(width + 7) / 8 * height (width + 7) / 8 * height
} }
fn main() { fn main() {
let esi = EsiClient::new(); let esi = EsiClient::new();
let zkill = ZkillClient::new(); let zkill = ZkillClient::new();
let past_seconds = 60 * 60 * 24; let past_seconds = 60 * 60 * 24;
let my_corp_id = 98685373; let my_corp_id = 98685373;
let mut display = display::Display::new(); let mut display = display::Display::new();
let mut epaper = epaper::EPaper::new().expect("DisplayError"); let mut epaper = epaper::EPaper::new().expect("DisplayError");
display.clear(true); display.clear(true);
epaper.clear(true); epaper.clear(true);
epaper.flush().expect("flush error"); epaper.flush().expect("flush error");
let response = zkill let response = zkill
.get_corporation_kills(my_corp_id, past_seconds) .get_corporation_kills(my_corp_id, past_seconds)
.unwrap(); .unwrap();
@@ -58,15 +38,13 @@ fn main() {
.map(|r| builder.make_kill_info(&zkill, &esi, r).unwrap()) .map(|r| builder.make_kill_info(&zkill, &esi, r).unwrap())
.collect(); .collect();
for (i, k) in killmails.iter().enumerate() {
for (i,k) in killmails.iter().enumerate() {
let ii = i as i32; let ii = i as i32;
let y : i32 = ii * 60; let y: i32 = ii * 60;
display.draw_kill_info(k, 0, y); display.draw_kill_info(k, 0, y);
epaper.draw_kill_info(k, 0, y); epaper.draw_kill_info(k, 0, y);
} }
let response = zkill let response = zkill
.get_corporation_losses(my_corp_id, past_seconds) .get_corporation_losses(my_corp_id, past_seconds)
@@ -79,16 +57,14 @@ fn main() {
.map(|r| builder.make_kill_info(&zkill, &esi, r).unwrap()) .map(|r| builder.make_kill_info(&zkill, &esi, r).unwrap())
.collect(); .collect();
for (i,k) in killmails.iter().enumerate() { for (i, k) in killmails.iter().enumerate() {
let ii = i as i32; let ii = i as i32;
let y : i32 = ii * 60; let y: i32 = ii * 60;
display.draw_loss_info(k, 400, y); display.draw_loss_info(k, 400, y);
epaper.draw_loss_info(k, 400, y); epaper.draw_loss_info(k, 400, y);
} }
display.flush(); display.flush();
epaper.flush().expect("flush error"); epaper.flush().expect("flush error");
} }

View File

@@ -1,103 +0,0 @@
//! SPI Commands for the Waveshare 2.9" and 1.54" E-Ink Display
use crate::traits;
/// Epd1in54 and EPD2IN9 commands
///
/// Should rarely (never?) be needed directly.
///
/// For more infos about the addresses and what they are doing look into the pdfs
#[allow(dead_code)]
#[derive(Copy, Clone)]
pub(crate) enum Command {
/// Driver Output control
/// 3 Databytes:
/// A[7:0]
/// 0.. A[8]
/// 0.. B[2:0]
/// Default: Set A[8:0] = 0x127 and B[2:0] = 0x0
DriverOutputControl = 0x01,
GateDrivingVoltage = 0x03,
SourceDrivingVoltage = 0x04,
/// Booster Soft start control
/// 3 Databytes:
/// 1.. A[6:0]
/// 1.. B[6:0]
/// 1.. C[6:0]
/// Default: A[7:0] = 0xCF, B[7:0] = 0xCE, C[7:0] = 0x8D
BoosterSoftStartControl = 0x0C,
GateScanStartPosition = 0x0F,
//TODO: useful?
// GateScanStartPosition = 0x0F,
/// Deep Sleep Mode Control
/// 1 Databyte:
/// 0.. A[0]
/// Values:
/// A[0] = 0: Normal Mode (POR)
/// A[0] = 1: Enter Deep Sleep Mode
DeepSleepMode = 0x10,
// /// Data Entry mode setting
DataEntryModeSetting = 0x11,
SwReset = 0x12,
TemperatureSensorSelection = 0x18,
TemperatureSensorControl = 0x1A,
MasterActivation = 0x20,
DisplayUpdateControl1 = 0x21,
DisplayUpdateControl2 = 0x22,
WriteRam = 0x24,
WriteRam2 = 0x26,
WriteVcomRegister = 0x2C,
WriteLutRegister = 0x32,
WriteOtpSelection = 0x37,
SetDummyLinePeriod = 0x3A,
SetGateLineWidth = 0x3B,
BorderWaveformControl = 0x3C,
WriteLutRegisterEnd = 0x3f,
SetRamXAddressStartEndPosition = 0x44,
SetRamYAddressStartEndPosition = 0x45,
SetRamXAddressCounter = 0x4E,
SetRamYAddressCounter = 0x4F,
Nop = 0xFF,
}
impl traits::Command for Command {
/// Returns the address of the command
fn address(self) -> u8 {
self as u8
}
}
#[cfg(test)]
mod tests {
use super::Command;
use crate::traits::Command as CommandTrait;
#[test]
fn command_addr() {
assert_eq!(Command::DriverOutputControl.address(), 0x01);
assert_eq!(Command::SetRamXAddressCounter.address(), 0x4E);
assert_eq!(Command::Nop.address(), 0xFF);
}
}

View File

@@ -1,2 +0,0 @@
pub(crate) mod command;
pub(crate) mod constants;