From c90c10cf7ae29ec9b1f1578af2c8081d89642432 Mon Sep 17 00:00:00 2001 From: Adam Gausmann Date: Thu, 30 Oct 2025 20:06:14 -0500 Subject: [PATCH] HAL --- Cargo.lock | 27 ++++++++++ firmware/Cargo.toml | 1 + firmware/src/art.rs | 27 ++++++++++ firmware/src/assets/hal.tga | Bin 0 -> 269 bytes firmware/src/led_matrix.rs | 101 ++++++++++++++++++++++++++++++++++++ firmware/src/main.rs | 79 ++++------------------------ 6 files changed, 165 insertions(+), 70 deletions(-) create mode 100644 firmware/src/art.rs create mode 100644 firmware/src/assets/hal.tga create mode 100644 firmware/src/led_matrix.rs diff --git a/Cargo.lock b/Cargo.lock index 6f6ca5b..c86b5ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -767,6 +767,7 @@ dependencies = [ "mipidsi", "panic-probe", "rgb", + "tinytga", ] [[package]] @@ -808,6 +809,12 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c8dda44ff03a2f238717214da50f65d5a53b45cd213a7370424ffdb6fae815" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "mipidsi" version = "0.9.0" @@ -841,6 +848,16 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -1271,6 +1288,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tinytga" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "477839bd612acb4d0551915eaf6eef8cc1b3a9dd58e18e9c2b746c78614a25d5" +dependencies = [ + "embedded-graphics", + "nom", +] + [[package]] name = "typenum" version = "1.19.0" diff --git a/firmware/Cargo.toml b/firmware/Cargo.toml index 118de60..ce2b5b4 100644 --- a/firmware/Cargo.toml +++ b/firmware/Cargo.toml @@ -48,3 +48,4 @@ embedded-hal-bus = "0.3.0" embassy-futures = "0.1.2" heapless = "0.8.0" rgb = "0.8.52" +tinytga = "0.5.0" diff --git a/firmware/src/art.rs b/firmware/src/art.rs new file mode 100644 index 0000000..44886ab --- /dev/null +++ b/firmware/src/art.rs @@ -0,0 +1,27 @@ +use embedded_graphics::{image::Image, pixelcolor::Rgb888, prelude::*}; +use tinytga::Tga; + +pub struct Hal { + image_data: Tga<'static, Rgb888>, +} + +impl Hal { + pub fn new() -> Self { + Self { + image_data: Tga::from_slice(include_bytes!("assets/hal.tga")).unwrap(), + } + } +} + +impl Drawable for Hal { + type Color = Rgb888; + + type Output = (); + + fn draw(&self, target: &mut D) -> Result + where + D: DrawTarget, + { + Image::new(&self.image_data, Point::zero()).draw(target) + } +} diff --git a/firmware/src/assets/hal.tga b/firmware/src/assets/hal.tga new file mode 100644 index 0000000000000000000000000000000000000000..a6279188820b1ab3f78276510b6f9e6487b36cf9 GIT binary patch literal 269 zcmYk1tq#Ia428c1!LlbnA~B#)sF_Q$K!ETU92Sc~AV`)y0N@Y^USoo1E2q08aFZst z?bp*&$cQhcM@pxAk7-rHTi?p_n<62r$*p8#2_u8rt5-!^lvfVM*|->c69~CCBcRbm z(|Q@t2AjCTAMlp0j|+GhM+i Rgb888 { + Rgb888::new( + GAMMA8[color.r() as usize], + GAMMA8[color.g() as usize], + GAMMA8[color.b() as usize], + ) +} + +pub struct Serpentine { + pub size: Size, +} + +impl Serpentine { + fn map(&self, mut p: Point) -> Option { + if p.x < 0 || p.x as u32 >= self.size.width || p.y < 0 || p.y as u32 >= self.size.height { + return None; + } + + if p.y % 2 == 0 { + p.x = self.size.width as i32 - 1 - p.x; + } + + Some(p.y as usize * self.size.width as usize + p.x as usize) + } +} + +pub struct LedMatrix<'d> { + buffer: [RGB8; 320], + layout: Serpentine, + pio: PioWs2812<'d, PIO0, 0, 320>, +} + +impl<'d> LedMatrix<'d> { + pub fn new(layout: Serpentine, pio: PioWs2812<'d, PIO0, 0, 320>) -> Self { + Self { + buffer: [RGB8::default(); 320], + layout, + pio, + } + } + + pub async fn sync(&mut self) { + self.pio.write(&self.buffer).await; + } +} + +impl<'d> DrawTarget for LedMatrix<'d> { + type Color = Rgb888; + + type Error = Infallible; + + fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> + where + I: IntoIterator>, + { + for Pixel(point, color) in pixels { + if let Some(x) = self.layout.map(point).and_then(|i| self.buffer.get_mut(i)) { + let color = gamma(color); + // Map to 0-64 for brightness limiting + *x = RGB8::new( + color.r().div_ceil(2), + color.g().div_ceil(2), + color.b().div_ceil(2), + ); + } + } + + Ok(()) + } +} + +impl<'d> OriginDimensions for LedMatrix<'d> { + fn size(&self) -> Size { + self.layout.size + } +} diff --git a/firmware/src/main.rs b/firmware/src/main.rs index 1383dbd..9395339 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -1,7 +1,8 @@ #![no_std] #![no_main] -use core::convert::Infallible; +mod art; +mod led_matrix; use embassy_executor::Spawner; use embassy_futures::select::select_array; @@ -19,7 +20,9 @@ use heapless::String; use mipidsi::interface::SpiInterface; use mipidsi::models::ST7789; use mipidsi::options::Orientation; -use rgb::RGB8; + +use crate::art::Hal; +use crate::led_matrix::{LedMatrix, Serpentine}; use {defmt_rtt as _, panic_probe as _}; @@ -128,6 +131,7 @@ async fn main(spawner: Spawner) -> ! { ), ); led_surface.clear(Rgb888::BLACK).ok(); + /* Rectangle::new(Point::zero(), led_surface.size()) .into_styled( PrimitiveStyleBuilder::new() @@ -138,6 +142,9 @@ async fn main(spawner: Spawner) -> ! { ) .draw(&mut led_surface) .ok(); + */ + let hal = Hal::new(); + hal.draw(&mut led_surface).ok(); led_surface.sync().await; let mut render = |f_keys: [bool; 4]| { @@ -184,71 +191,3 @@ async fn dfu_button(mut btn_y: Input<'static>) { btn_y.wait_for_falling_edge().await; reset_to_usb_boot(0, 0); } - -struct Serpentine { - size: Size, -} - -impl Serpentine { - fn map(&self, mut p: Point) -> Option { - if p.x < 0 || p.x as u32 >= self.size.width || p.y < 0 || p.y as u32 >= self.size.height { - return None; - } - - if p.y % 2 == 0 { - p.x = self.size.width as i32 - 1 - p.x; - } - - Some(p.y as usize * self.size.width as usize + p.x as usize) - } -} - -struct LedMatrix<'d> { - buffer: [RGB8; 320], - layout: Serpentine, - pio: PioWs2812<'d, PIO0, 0, 320>, -} - -impl<'d> LedMatrix<'d> { - fn new(layout: Serpentine, pio: PioWs2812<'d, PIO0, 0, 320>) -> Self { - Self { - buffer: [RGB8::default(); 320], - layout, - pio, - } - } - - async fn sync(&mut self) { - self.pio.write(&self.buffer).await; - } -} - -impl<'d> DrawTarget for LedMatrix<'d> { - type Color = Rgb888; - - type Error = Infallible; - - fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> - where - I: IntoIterator>, - { - for Pixel(point, color) in pixels { - if let Some(x) = self.layout.map(point).and_then(|i| self.buffer.get_mut(i)) { - // Map to 0-64 for brightness limiting - *x = RGB8::new( - color.r().div_ceil(4), - color.g().div_ceil(4), - color.b().div_ceil(4), - ); - } - } - - Ok(()) - } -} - -impl<'d> OriginDimensions for LedMatrix<'d> { - fn size(&self) -> Size { - self.layout.size - } -}