From 2dfc051ef9a6f92239a3548d6d34b740226d3d97 Mon Sep 17 00:00:00 2001 From: alemidev Date: Fri, 12 Aug 2022 23:33:43 +0200 Subject: [PATCH] fix: use correct lib, draw some initial gui --- Cargo.toml | 2 +- src/main.rs | 153 ++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 138 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 60b0ad2..3b87955 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ panic-halt = "0.2.0" ufmt = "0.1.0" nb = "1" embedded-hal = "0.2.3" -sh1106 = "0.4" +ssd1306 = "0.7" embedded-graphics = "0.7" [dependencies.arduino-hal] diff --git a/src/main.rs b/src/main.rs index 4d74a23..f0a4f0a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,9 +5,15 @@ use packet::PacketId; use panic_halt as _; use embedded_hal::serial::Read; +use embedded_graphics::{ + mono_font::{ascii::FONT_4X6, MonoTextStyle}, + pixelcolor::BinaryColor, + prelude::*, + text::Text, primitives::{PrimitiveStyleBuilder, Rectangle, PrimitiveStyle}, +}; -use arduino_hal::simple_pwm::{IntoPwmPin, Prescaler, Timer1Pwm, Timer2Pwm}; -use sh1106::{prelude::GraphicsMode, Builder}; +use arduino_hal::{simple_pwm::{IntoPwmPin, Prescaler, Timer1Pwm, Timer2Pwm}, I2c}; +use ssd1306::{prelude::*, I2CDisplayInterface, Ssd1306, mode::BufferedGraphicsMode}; mod packet; mod utils; @@ -15,6 +21,15 @@ mod utils; use crate::packet::PacketBuilder; use crate::utils::FourLedDisplay; +type Display = Ssd1306, DisplaySize128x64, BufferedGraphicsMode>; + +struct DisplayStyle<'a> { + border_style: PrimitiveStyle, + text_style: MonoTextStyle<'a, BinaryColor>, + bar_style: PrimitiveStyle, + background_style: PrimitiveStyle, +} + #[arduino_hal::entry] fn main() -> ! { // init board peripherals @@ -38,35 +53,54 @@ fn main() -> ! { let mut serial = arduino_hal::default_serial!(dp, pins, 57600); led_load.set_high(); - led_rx.set_high(); - led_tx.set_high(); + led_tx.set_low(); + led_rx.set_low(); + + let style = DisplayStyle { + border_style: PrimitiveStyleBuilder::new() + .stroke_width(1) + .stroke_color(BinaryColor::On) + .build(), + text_style: MonoTextStyle::new(&FONT_4X6, BinaryColor::On), + bar_style: PrimitiveStyleBuilder::new() + .stroke_color(BinaryColor::On) + .fill_color(BinaryColor::On) + .build(), + background_style: PrimitiveStyleBuilder::new() + .stroke_color(BinaryColor::Off) + .fill_color(BinaryColor::Off) + .build(), + }; // prepare display - let mut display: GraphicsMode<_> = Builder::new().with_size(sh1106::prelude::DisplaySize::Display128x64).connect_i2c(i2c).into(); - cpu_leds.set(1, 255); + let interface = I2CDisplayInterface::new(i2c); + let mut display = Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0).into_buffered_graphics_mode(); display.init().unwrap(); + cpu_leds.set(1, 255); + + display.clear(); + display.flush().unwrap(); cpu_leds.set(2, 255); - let mut flip : u8 = 0; - for x in 0..128 { - for y in 0..64 { - cpu_leds.set(3, if flip == 0 { 0 } else { 255 }); - display.set_pixel(x, y, flip); - flip = !flip; - } - } + draw_ui(&mut display, &style); cpu_leds.set(3, 255); display.flush().unwrap(); cpu_leds.set(4, 255); led_load.set_low(); - led_tx.set_low(); - led_rx.set_low(); let mut pkt_builder = PacketBuilder::new(); + // TODO put these in a struct + let mut cpu1 : u8 = 0; + let mut cpu2 : u8 = 0; + let mut cpu3 : u8 = 0; + let mut cpu4 : u8 = 0; + let mut tx : u8 = 0; + let mut rx : u8 = 0; + arduino_hal::delay_ms(25); cpu_leds.set_all(0); loop { // main loop @@ -87,12 +121,22 @@ fn main() -> ! { PacketId::SetLedsPacket => { if let Some(payload) = pkt.payload && payload.len() == 4 { cpu_leds.set_many(payload[0], payload[1], payload[2], payload[3]); + if payload[0] != cpu1 { draw_cpu_bar(&mut display, 1, payload[0], &style); } + if payload[1] != cpu2 { draw_cpu_bar(&mut display, 2, payload[1], &style); } + if payload[2] != cpu3 { draw_cpu_bar(&mut display, 3, payload[2], &style); } + if payload[3] != cpu4 { draw_cpu_bar(&mut display, 4, payload[3], &style); } + cpu1 = payload[0]; cpu2 = payload[1]; cpu3 = payload[2]; cpu4 = payload[3]; + display.flush().unwrap(); } }, PacketId::NetStatePacket => { if let Some(payload) = pkt.payload && payload.len() == 2 { if payload[0] == 0 { led_tx.set_low() } else { led_tx.set_high() }; if payload[1] == 0 { led_rx.set_low() } else { led_rx.set_high() }; + if payload[0] != tx { draw_network_bar(&mut display, NetDirection::TX, payload[0], &style) } + if payload[1] != rx { draw_network_bar(&mut display, NetDirection::RX, payload[1], &style) } + tx = payload[0]; rx = payload[1]; + display.flush().unwrap(); } }, _ => {}, // TODO log it? @@ -106,3 +150,80 @@ fn main() -> ! { } } +fn byte_to_height(val: u8, max: u8) -> u32 { + // let t = (val >> 2) as u32; // TODO this is a cheap ass solution with awful precision!!! + // return if t > max as u32 { max as u32 } else { t }; + return ((val as f32 / 255.0) * max as f32) as u32; // TODO get rid of floating point operations! +} + +fn draw_ui(display: &mut Display, style: &DisplayStyle) { + Rectangle::new(Point::new(0, 0), Size::new(128, 64)) + .into_styled(style.border_style) + .draw(display) + .unwrap(); + + Text::new("CPU1", Point::new(2, 6), style.text_style).draw(display).unwrap(); + Text::new("CPU2", Point::new(22, 6), style.text_style).draw(display).unwrap(); + Text::new("CPU3", Point::new(42, 6), style.text_style).draw(display).unwrap(); + Text::new("CPU4", Point::new(62, 6), style.text_style).draw(display).unwrap(); + Text::new("TX", Point::new(104, 6), style.text_style).draw(display).unwrap(); + Text::new("RX", Point::new(116, 6), style.text_style).draw(display).unwrap(); + +} + +fn draw_cpu_bar(display: &mut Display, index: u8, value: u8, style: &DisplayStyle) { + let x = 2 + ((index - 1) * 20); + let height = byte_to_height(value, 54); + Rectangle::new(Point::new(x as i32, 8), Size::new(15, 54 - (height-1) as u32)) + .into_styled(style.background_style) + .draw(display) + .unwrap(); + Rectangle::new(Point::new(x as i32, (62 - height) as i32), Size::new(15, 1 + height as u32)) + .into_styled(style.bar_style) + .draw(display) + .unwrap(); +} + +enum NetDirection { + TX, RX +} + +fn draw_network_bar(display: &mut Display, direction: NetDirection, value: u8, style: &DisplayStyle) { + let x = match direction { NetDirection::TX => 104, NetDirection::RX => 116 }; + let height = byte_to_height(value, 54); + Rectangle::new(Point::new(x as i32, 8), Size::new(10, 54 - (height-1) as u32)) + .into_styled(style.background_style) + .draw(display) + .unwrap(); + Rectangle::new(Point::new(x as i32, (62 - height) as i32), Size::new(10, 1 + height as u32)) + .into_styled(style.bar_style) + .draw(display) + .unwrap(); +} + +fn _draw_all(display: &mut Display, cpu1: u8, cpu2: u8, cpu3: u8, cpu4: u8, tx: u8, rx: u8, style: &DisplayStyle) { + draw_ui(display, style); + + draw_cpu_bar(display, 1, cpu1, style); + draw_cpu_bar(display, 2, cpu2, style); + draw_cpu_bar(display, 3, cpu3, style); + draw_cpu_bar(display, 4, cpu4, style); + + draw_network_bar(display, NetDirection::TX, tx, style); + draw_network_bar(display, NetDirection::RX, rx, style); + + display.flush().unwrap(); +} + +fn _display_grid(display: &mut Display, cpu_leds: &mut FourLedDisplay) { + let mut flip : bool = false; + for y in 0..64 { + for x in 0..128 { + cpu_leds.set(3, if flip { 0 } else { 255 }); + display.set_pixel(x, y, flip); + flip = !flip; + } + flip = !flip; + } + display.flush().unwrap(); +}