From 55b7c2970cda6614fdb4227c6b323afe7413ffd7 Mon Sep 17 00:00:00 2001 From: sawyer bristol Date: Mon, 30 Jun 2025 19:37:55 -0600 Subject: [PATCH] add status bar to console --- Cargo.lock | 7 ++- Cargo.toml | 2 +- src/display.rs | 157 +++++++++++++++++++++++++------------------------ 3 files changed, 84 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fe98260..4d75097 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1006,9 +1006,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "indexmap" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", "hashbrown", @@ -1730,10 +1730,11 @@ dependencies = [ [[package]] name = "st7365p-lcd" version = "0.10.0" -source = "git+https://github.com/legitcamper/st7365p-lcd-rs#d751e8d30f1a3f964ffe05e4bb16f82112fbefce" +source = "git+https://github.com/legitcamper/st7365p-lcd-rs?branch=async#9f8da568ff695a00afb6b8b8cf9573fad408a66f" dependencies = [ "embedded-graphics-core", "embedded-hal 1.0.0", + "embedded-hal-async", "nb 1.1.0", ] diff --git a/Cargo.toml b/Cargo.toml index 5a9425d..dcca01b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,7 +71,7 @@ defmt-rtt = "0.4.2" embedded-graphics = { version = "0.8.1" } embedded-sdmmc = { git = "https://github.com/Be-ing/embedded-sdmmc-rs", branch = "bisync", default-features = false } -st7365p-lcd = { git = "https://github.com/legitcamper/st7365p-lcd-rs" } +st7365p-lcd = { git = "https://github.com/legitcamper/st7365p-lcd-rs", branch = "async" } static_cell = "2.1.1" bitflags = "2.9.1" diff --git a/src/display.rs b/src/display.rs index fe3f2b0..553c555 100644 --- a/src/display.rs +++ b/src/display.rs @@ -1,27 +1,42 @@ use embassy_rp::{ gpio::{Level, Output}, peripherals::{PIN_13, PIN_14, PIN_15, SPI1}, - spi::{Blocking, Spi}, + spi::{Async, Spi}, }; use embassy_time::{Delay, Timer}; -use embedded_graphics::{ - Drawable, Pixel, - pixelcolor::{Rgb565, raw::RawU16}, - prelude::{DrawTarget, OriginDimensions, Point, Primitive, RawData, RgbColor, Size}, - primitives::{PrimitiveStyle, Rectangle}, -}; use embedded_hal_bus::spi::ExclusiveDevice; -use st7365p_lcd::{Orientation, ST7365P}; +use st7365p_lcd::{FrameBuffer, Orientation, ST7365P}; + +use arrform::{ArrForm, arrform}; +use embedded_graphics::{ + Drawable, + draw_target::DrawTarget, + mono_font::{ + MonoTextStyle, + ascii::{FONT_6X10, FONT_9X15, FONT_10X20}, + }, + object_chain::Chain, + pixelcolor::Rgb565, + prelude::{Point, RgbColor, Size}, + primitives::Rectangle, + text::Text, +}; +use embedded_layout::{ + align::{horizontal, vertical}, + layout::linear::LinearLayout, + prelude::*, +}; + +pub const SCREEN_WIDTH: usize = 320; +pub const SCREEN_HEIGHT: usize = 320; + +pub const STATUS_BAR_WIDTH: usize = 320; +pub const STATUS_BAR_HEIGHT: usize = 40; #[embassy_executor::task] -pub async fn display_task( - spi: Spi<'static, SPI1, Blocking>, - cs: PIN_13, - data: PIN_14, - reset: PIN_15, -) { +pub async fn display_task(spi: Spi<'static, SPI1, Async>, cs: PIN_13, data: PIN_14, reset: PIN_15) { let spi_device = ExclusiveDevice::new(spi, Output::new(cs, Level::Low), Delay).unwrap(); - let mut display = ST7365P::new( + let display = ST7365P::new( spi_device, Output::new(data, Level::Low), Some(Output::new(reset, Level::High)), @@ -30,84 +45,70 @@ pub async fn display_task( 320, 320, ); - display.init(&mut Delay).unwrap(); - display.set_orientation(&Orientation::Landscape).unwrap(); - let mut virtual_display = VirtualDisplay::new(display, 320 / 2, 320 / 2); - - let thin_stroke = PrimitiveStyle::with_stroke(Rgb565::RED, 20); - - Rectangle::new(Point::new(10, 10), Size::new(100, 100)) - .into_styled(thin_stroke) - .draw(&mut virtual_display) + display.init(&mut Delay).await.unwrap(); + display + .set_orientation(&Orientation::Landscape) + .await .unwrap(); + let mut framebuffer = FrameBuffer::new(display); + + let mut ui = UI::new(); + ui.draw_status_bar(&mut framebuffer); + loop { + framebuffer.draw().await.unwrap(); Timer::after_millis(500).await; } } -/// simple abstraction over real display & resolution to reduce frame buffer size -/// by cutting the resolution by 1/4 -struct VirtualDisplay { - display: ST7365P< - ExclusiveDevice, Output<'static>, Delay>, - Output<'static>, - Output<'static>, - >, - width: u32, - height: u32, +pub struct UI { + pub status_bar: StatusBar, } -impl VirtualDisplay { - pub fn new( - display: ST7365P< - ExclusiveDevice, Output<'static>, Delay>, - Output<'static>, - Output<'static>, - >, - new_width: u32, - new_height: u32, - ) -> Self { +impl UI { + pub fn new() -> Self { Self { - display, - width: new_width, - height: new_height, + status_bar: StatusBar { + battery: 100, + backlight: 100, + volume: 100, + }, } } -} -impl DrawTarget for VirtualDisplay { - type Color = Rgb565; - type Error = (); + pub fn draw_status_bar>(&mut self, target: &mut D) { + let text_style = MonoTextStyle::new(&FONT_9X15, Rgb565::WHITE); - fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> - where - I: IntoIterator>, - { - for Pixel(coord, color) in pixels.into_iter() { - // Check bounds on the *virtual* (already reduced) resolution - if coord.x >= 0 - && coord.y >= 0 - && coord.x < self.width as i32 - && coord.y < self.height as i32 - { - let px = coord.x as u16 * 2; - let py = coord.y as u16 * 2; - let raw_color = RawU16::from(color).into_inner(); - - // Draw the 2x2 block on the underlying hardware - self.display.set_pixel(px, py, raw_color)?; - self.display.set_pixel(px + 1, py, raw_color)?; - self.display.set_pixel(px, py + 1, raw_color)?; - self.display.set_pixel(px + 1, py + 1, raw_color)?; - } - } - Ok(()) + let status_bar = Rectangle::new( + Point::new(0, 0), + Size::new(STATUS_BAR_WIDTH as u32, STATUS_BAR_HEIGHT as u32), + ); + let _ = LinearLayout::horizontal( + Chain::new(Text::new( + arrform!(20, "Bat: {}", self.status_bar.battery).as_str(), + Point::zero(), + text_style, + )) + .append(Text::new( + arrform!(20, "Lght: {}", self.status_bar.backlight).as_str(), + Point::zero(), + text_style, + )) + .append(Text::new( + arrform!(20, "Vol: {}", self.status_bar.volume).as_str(), + Point::zero(), + text_style, + )), + ) + .arrange() + .align_to(&status_bar, horizontal::Center, vertical::Center) + .draw(target); } } -impl OriginDimensions for VirtualDisplay { - fn size(&self) -> Size { - Size::new(self.width, self.height) - } +pub struct StatusBar { + pub battery: u8, + pub backlight: u8, + pub volume: u8, }