Fill in remaining color settings

This commit is contained in:
Adam Gausmann 2025-11-01 20:28:10 -05:00
parent 3e1245260d
commit 3cc0d6aaad
2 changed files with 149 additions and 30 deletions

View file

@ -37,6 +37,17 @@ impl HappyEyes {
image_data: Bmp::from_slice(include_bytes!("assets/eye1.bmp")).unwrap(), image_data: Bmp::from_slice(include_bytes!("assets/eye1.bmp")).unwrap(),
} }
} }
pub fn draw_colored<D: DrawTarget<Color = Rgb888>>(
&self,
target: &mut D,
color: Rgb888,
) -> Result<(), D::Error> {
self.draw(&mut ColorMapFilter {
inner_target: target,
filter: |c| mix(c, color),
})
}
} }
impl Drawable for HappyEyes { impl Drawable for HappyEyes {
@ -122,12 +133,19 @@ impl<'a, D: Dimensions> Dimensions for RainbowFilter<'a, D> {
} }
} }
pub struct ColorMapFilter<'a, D> { pub struct ColorMapFilter<'a, D, F>
where
F: FnMut(Rgb888) -> Rgb888,
{
pub inner_target: &'a mut D, pub inner_target: &'a mut D,
pub filter: fn(Rgb888) -> Rgb888, pub filter: F,
} }
impl<'a, D: DrawTarget<Color = Rgb888>> DrawTarget for ColorMapFilter<'a, D> { impl<'a, D, F> DrawTarget for ColorMapFilter<'a, D, F>
where
D: DrawTarget<Color = Rgb888>,
F: FnMut(Rgb888) -> Rgb888,
{
type Color = D::Color; type Color = D::Color;
type Error = D::Error; type Error = D::Error;
@ -143,7 +161,10 @@ impl<'a, D: DrawTarget<Color = Rgb888>> DrawTarget for ColorMapFilter<'a, D> {
} }
} }
impl<'a, D: Dimensions> Dimensions for ColorMapFilter<'a, D> { impl<'a, D: Dimensions, F> Dimensions for ColorMapFilter<'a, D, F>
where
F: FnMut(Rgb888) -> Rgb888,
{
fn bounding_box(&self) -> Rectangle { fn bounding_box(&self) -> Rectangle {
self.inner_target.bounding_box() self.inner_target.bounding_box()
} }

View file

@ -15,17 +15,17 @@ use embassy_rp::pio_programs::ws2812::{PioWs2812, PioWs2812Program};
use embassy_rp::pwm::{self, Pwm}; use embassy_rp::pwm::{self, Pwm};
use embassy_rp::rom_data::reset_to_usb_boot; use embassy_rp::rom_data::reset_to_usb_boot;
use embassy_rp::spi::{self, Blocking, Spi}; use embassy_rp::spi::{self, Blocking, Spi};
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_rp::spinlock_mutex::SpinlockRawMutex;
use embassy_sync::signal::Signal; use embassy_sync::signal::Signal;
use embassy_time::{Delay, Duration, Instant, Ticker, Timer}; use embassy_time::{Delay, Duration, Instant, Ticker, Timer};
use embedded_graphics::pixelcolor::Rgb888; use embedded_graphics::pixelcolor::Rgb888;
use embedded_graphics::prelude::{DrawTarget, Drawable, RgbColor, Size}; use embedded_graphics::prelude::{DrawTarget, Drawable, RgbColor, Size, WebColors};
use embedded_hal_bus::spi::ExclusiveDevice; use embedded_hal_bus::spi::ExclusiveDevice;
use mipidsi::interface::SpiInterface; use mipidsi::interface::SpiInterface;
use mipidsi::models::ST7789; use mipidsi::models::ST7789;
use mipidsi::options::Orientation; use mipidsi::options::Orientation;
use crate::art::{Hal, HappyEyes, Rainbow, RainbowFilter}; use crate::art::{ColorMapFilter, Hal, HappyEyes, Rainbow, RainbowFilter};
use crate::led_matrix::{LedMatrix, Serpentine}; use crate::led_matrix::{LedMatrix, Serpentine};
use defmt_rtt as _; use defmt_rtt as _;
@ -164,13 +164,62 @@ impl ButtonStates {
} }
} }
enum LedConfig { #[derive(Clone, Copy, Default)]
struct LedConfig {
pattern: LedPattern,
hal: HalConfig,
happy: HappyConfig,
}
#[derive(Clone, Copy, PartialEq, Default)]
enum LedPattern {
#[default]
Blank, Blank,
Hal, Hal,
Happy, Happy,
} }
static LED_CONFIG_SIGNAL: Signal<CriticalSectionRawMutex, LedConfig> = Signal::new(); #[derive(Clone, Copy, PartialEq, Default)]
enum HalConfig {
#[default]
Red,
Blue,
}
impl HalConfig {
fn next(self) -> Self {
match self {
HalConfig::Red => HalConfig::Blue,
HalConfig::Blue => HalConfig::Red,
}
}
}
#[derive(Clone, Copy, PartialEq, Default)]
enum HappyConfig {
Green,
Blue,
#[default]
Purple,
Pink,
RainbowSlow,
RainbowFast,
}
impl HappyConfig {
fn next(self) -> Self {
match self {
HappyConfig::Green => HappyConfig::Blue,
HappyConfig::Blue => HappyConfig::Purple,
HappyConfig::Purple => HappyConfig::Pink,
HappyConfig::Pink => HappyConfig::RainbowSlow,
HappyConfig::RainbowSlow => HappyConfig::RainbowFast,
HappyConfig::RainbowFast => HappyConfig::Green,
}
}
}
static LED_CONFIG_SIGNAL: Signal<SpinlockRawMutex<0>, LedConfig> = Signal::new();
#[embassy_executor::task] #[embassy_executor::task]
async fn controller_task(buttons: Buttons) { async fn controller_task(buttons: Buttons) {
@ -179,6 +228,8 @@ async fn controller_task(buttons: Buttons) {
let mut stable_chord = 0; let mut stable_chord = 0;
let mut pending_chord = 0; let mut pending_chord = 0;
let mut led_config = LedConfig::default();
loop { loop {
let state = buttons.read(); let state = buttons.read();
let new_chord = state.chord(); let new_chord = state.chord();
@ -204,18 +255,29 @@ async fn controller_task(buttons: Buttons) {
match stable_chord { match stable_chord {
0x1 => { 0x1 => {
// blank display // blank display
LED_CONFIG_SIGNAL.signal(LedConfig::Blank); led_config.pattern = LedPattern::Blank;
LED_CONFIG_SIGNAL.signal(led_config);
} }
0x2 => { 0x2 => {
// happy // happy
LED_CONFIG_SIGNAL.signal(LedConfig::Happy); if led_config.pattern == LedPattern::Happy {
led_config.happy = led_config.happy.next();
} else {
led_config.pattern = LedPattern::Happy;
}
LED_CONFIG_SIGNAL.signal(led_config);
} }
0x4 => { 0x4 => {
// hal // hal
LED_CONFIG_SIGNAL.signal(LedConfig::Hal); if led_config.pattern == LedPattern::Hal {
led_config.hal = led_config.hal.next();
} else {
led_config.pattern = LedPattern::Hal;
}
LED_CONFIG_SIGNAL.signal(led_config);
} }
_ => { _ => {
// unknown pattern // unknown chord
} }
} }
@ -230,9 +292,12 @@ async fn controller_task(buttons: Buttons) {
async fn led_task(mut led_surface: LedMatrix<'static>) { async fn led_task(mut led_surface: LedMatrix<'static>) {
let hal = Hal::new(); let hal = Hal::new();
let eyes = HappyEyes::new(); let eyes = HappyEyes::new();
let mut rainbow = Rainbow { let mut rainbow_slow = Rainbow {
// rate: Duration::from_secs(10), rate: Duration::from_secs(10),
// width: 300, width: 300,
elapsed: Duration::from_secs(0),
};
let mut rainbow_fast = Rainbow {
rate: Duration::from_secs(1), rate: Duration::from_secs(1),
width: 80, width: 80,
elapsed: Duration::from_secs(0), elapsed: Duration::from_secs(0),
@ -241,29 +306,62 @@ async fn led_task(mut led_surface: LedMatrix<'static>) {
let mut ticker = Ticker::every(Duration::from_hz(30)); let mut ticker = Ticker::every(Duration::from_hz(30));
let start = Instant::now(); let start = Instant::now();
let mut led_config = LedConfig::Blank; let mut led_config = LedConfig::default();
loop { loop {
let elapsed = start.elapsed(); let elapsed = start.elapsed();
rainbow.elapsed = elapsed; rainbow_slow.elapsed = elapsed;
rainbow_fast.elapsed = elapsed;
if let Some(new_config) = LED_CONFIG_SIGNAL.try_take() { if let Some(new_config) = LED_CONFIG_SIGNAL.try_take() {
led_config = new_config; led_config = new_config;
} }
led_surface.clear(Rgb888::BLACK).ok(); led_surface.clear(Rgb888::BLACK).ok();
match led_config { match led_config.pattern {
LedConfig::Blank => {} LedPattern::Blank => {}
LedConfig::Hal => { LedPattern::Hal => match led_config.hal {
hal.draw(&mut led_surface).ok(); HalConfig::Red => {
} hal.draw(&mut led_surface).ok();
LedConfig::Happy => { }
eyes.draw(&mut RainbowFilter { HalConfig::Blue => {
inner_target: &mut led_surface, hal.draw(&mut ColorMapFilter {
rainbow: &rainbow, inner_target: &mut led_surface,
}) filter: |color| Rgb888::new(color.b(), color.g(), color.r() / 2),
.ok(); })
} .ok();
}
},
LedPattern::Happy => match led_config.happy {
HappyConfig::Green => {
eyes.draw_colored(&mut led_surface, Rgb888::GREEN).ok();
}
HappyConfig::Blue => {
eyes.draw_colored(&mut led_surface, Rgb888::BLUE).ok();
}
HappyConfig::Purple => {
eyes.draw_colored(&mut led_surface, Rgb888::new(172, 20, 172))
.ok();
}
HappyConfig::Pink => {
eyes.draw_colored(&mut led_surface, Rgb888::CSS_HOT_PINK)
.ok();
}
HappyConfig::RainbowSlow => {
eyes.draw(&mut RainbowFilter {
inner_target: &mut led_surface,
rainbow: &rainbow_slow,
})
.ok();
}
HappyConfig::RainbowFast => {
eyes.draw(&mut RainbowFilter {
inner_target: &mut led_surface,
rainbow: &rainbow_fast,
})
.ok();
}
},
} }
led_surface.sync().await; led_surface.sync().await;
ticker.next().await; ticker.next().await;