From ac0133f358cc5a6725b79868f2e6137b74d13131 Mon Sep 17 00:00:00 2001 From: tobinio Date: Sun, 26 Jul 2026 13:28:26 +0200 Subject: [PATCH] smooth color --- firmware/src/color.rs | 53 +++++++++++++++++++++++++++++++++++ firmware/src/main.rs | 65 +++++++------------------------------------ 2 files changed, 63 insertions(+), 55 deletions(-) create mode 100644 firmware/src/color.rs diff --git a/firmware/src/color.rs b/firmware/src/color.rs new file mode 100644 index 0000000..daf59fd --- /dev/null +++ b/firmware/src/color.rs @@ -0,0 +1,53 @@ +use packets::Color; + +#[derive(Debug, Clone, Default, PartialEq)] +pub struct FullColor { + pub r: f32, + pub g: f32, + pub b: f32, + pub w: f32, +} + +impl FullColor { + pub const fn new(r: u8, g: u8, b: u8, w: u8) -> Self { + Self { + r: r as f32 / 255.0, + g: g as f32 / 255.0, + b: b as f32 / 255.0, + w: w as f32 / 255.0, + } + } + + pub fn from_color(color: Color) -> Self { + let white_out = color.0.min(color.1).min(color.2); + let red_out = color.0 - white_out; + let green_out = color.1 - white_out; + let blue_out = color.2 - white_out; + + Self::new(red_out, green_out, blue_out, white_out) + } + + pub fn with_brightness(&self, brightness: f32) -> Self { + let b = brightness.clamp(0.0, 1.0); + + FullColor { + r: self.r * b, + g: self.g * b, + b: self.b * b, + w: self.w * b, + } + } + + pub fn lerp(color_1: &FullColor, color_2: &FullColor, percent: f32) -> FullColor { + let t = percent.clamp(0.0, 1.0); + + let lerp = |a: f32, b: f32| -> f32 { a + (b - a) * t }; + + FullColor { + r: lerp(color_1.r, color_2.r), + g: lerp(color_1.g, color_2.g), + b: lerp(color_1.b, color_2.b), + w: lerp(color_1.w, color_2.w), + } + } +} diff --git a/firmware/src/main.rs b/firmware/src/main.rs index bcd5c19..6c0051f 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -24,16 +24,18 @@ use embassy_executor::Spawner; use log::info; use esp_backtrace as _; -use packets::{Color, State}; +use packets::State; use static_cell::StaticCell; use crate::clock::CLOCK; +use crate::color::FullColor; use crate::communication::{RegisterEventChannel, listen_register_events, listen_updates}; use crate::sun::calculate_current_color; extern crate alloc; pub mod clock; +pub mod color; pub mod communication; pub mod sun; pub mod tcp; @@ -203,54 +205,6 @@ pub async fn handle_sun( } } -// TODO: swap to use f32 -#[derive(Debug, Clone, Default, PartialEq)] -pub struct FullColor { - pub r: u8, - pub g: u8, - pub b: u8, - pub w: u8, -} - -impl FullColor { - pub const fn new(r: u8, g: u8, b: u8, w: u8) -> Self { - Self { r, g, b, w } - } - - pub fn from_color(color: Color) -> Self { - let white_out = color.0.min(color.1).min(color.2); - let red_out = color.0 - white_out; - let green_out = color.1 - white_out; - let blue_out = color.2 - white_out; - - Self::new(red_out, green_out, blue_out, white_out) - } - - pub fn with_brightness(&self, brightness: f32) -> Self { - let b = brightness.clamp(0.0, 1.0); - - FullColor { - r: (self.r as f32 * b) as u8, - g: (self.g as f32 * b) as u8, - b: (self.b as f32 * b) as u8, - w: (self.w as f32 * b) as u8, - } - } - - fn lerp(color_1: &FullColor, color_2: &FullColor, percent: f32) -> FullColor { - let t = percent.clamp(0.0, 1.0); - - let lerp_u8 = |a: u8, b: u8| -> u8 { (a as f32 + (b as f32 - a as f32) * t) as u8 }; - - FullColor { - r: lerp_u8(color_1.r, color_2.r), - g: lerp_u8(color_1.g, color_2.g), - b: lerp_u8(color_1.b, color_2.b), - w: lerp_u8(color_1.w, color_2.w), - } - } -} - pub type UpdateColorEventChannel = Channel; pub type UpdateColorEventSender = Sender<'static, NoopRawMutex, FullColor, 1>; pub type UpdateColorEventReceiver = Receiver<'static, NoopRawMutex, FullColor, 1>; @@ -266,8 +220,9 @@ pub async fn handle_color( white_pin: AnyPin<'static>, ) { let clock_cfg = PeripheralClockConfig::with_frequency(Rate::from_mhz(40)).unwrap(); + const PERIOD: u16 = 999; let timer_clock_cfg = clock_cfg - .timer_clock_with_frequency(255, PwmWorkingMode::Increase, Rate::from_khz(20)) + .timer_clock_with_frequency(PERIOD, PwmWorkingMode::Increase, Rate::from_khz(20)) .unwrap(); let mut mcpwm0 = McPwm::new(mcpwm0, clock_cfg); @@ -305,12 +260,12 @@ pub async fn handle_color( info!("received color_event: {:?}", color); - //TODO: do human brightness conversion + let gamma_correct = |x: f32| -> f32 { x * x }; - pwm_red_pin.set_timestamp((color.r) as u16); - pwm_green_pin.set_timestamp((color.g) as u16); - pwm_blue_pin.set_timestamp((color.b) as u16); - pwm_white_pin.set_timestamp((color.w) as u16); + pwm_red_pin.set_timestamp((gamma_correct(color.r) * PERIOD as f32) as u16); + pwm_green_pin.set_timestamp((gamma_correct(color.g) * PERIOD as f32) as u16); + pwm_blue_pin.set_timestamp((gamma_correct(color.b) * PERIOD as f32) as u16); + pwm_white_pin.set_timestamp((gamma_correct(color.w) * PERIOD as f32) as u16); prev_color = color; } -- 2.51.2