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(),
}
}
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 {
@ -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 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 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 {
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::rom_data::reset_to_usb_boot;
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_time::{Delay, Duration, Instant, Ticker, Timer};
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 mipidsi::interface::SpiInterface;
use mipidsi::models::ST7789;
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 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,
Hal,
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]
async fn controller_task(buttons: Buttons) {
@ -179,6 +228,8 @@ async fn controller_task(buttons: Buttons) {
let mut stable_chord = 0;
let mut pending_chord = 0;
let mut led_config = LedConfig::default();
loop {
let state = buttons.read();
let new_chord = state.chord();
@ -204,18 +255,29 @@ async fn controller_task(buttons: Buttons) {
match stable_chord {
0x1 => {
// blank display
LED_CONFIG_SIGNAL.signal(LedConfig::Blank);
led_config.pattern = LedPattern::Blank;
LED_CONFIG_SIGNAL.signal(led_config);
}
0x2 => {
// 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 => {
// 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>) {
let hal = Hal::new();
let eyes = HappyEyes::new();
let mut rainbow = Rainbow {
// rate: Duration::from_secs(10),
// width: 300,
let mut rainbow_slow = Rainbow {
rate: Duration::from_secs(10),
width: 300,
elapsed: Duration::from_secs(0),
};
let mut rainbow_fast = Rainbow {
rate: Duration::from_secs(1),
width: 80,
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 start = Instant::now();
let mut led_config = LedConfig::Blank;
let mut led_config = LedConfig::default();
loop {
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() {
led_config = new_config;
}
led_surface.clear(Rgb888::BLACK).ok();
match led_config {
LedConfig::Blank => {}
LedConfig::Hal => {
hal.draw(&mut led_surface).ok();
}
LedConfig::Happy => {
eyes.draw(&mut RainbowFilter {
inner_target: &mut led_surface,
rainbow: &rainbow,
})
.ok();
}
match led_config.pattern {
LedPattern::Blank => {}
LedPattern::Hal => match led_config.hal {
HalConfig::Red => {
hal.draw(&mut led_surface).ok();
}
HalConfig::Blue => {
hal.draw(&mut ColorMapFilter {
inner_target: &mut led_surface,
filter: |color| Rgb888::new(color.b(), color.g(), color.r() / 2),
})
.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;
ticker.next().await;