From e4e69f4d511daf41c309d1a149df63f30880af02 Mon Sep 17 00:00:00 2001 From: Austen Adler Date: Sun, 28 May 2023 17:53:11 -0400 Subject: [PATCH] Start work on car rainbow --- common/src/pattern.rs | 6 ++ common/src/pattern/car_rainbow.rs | 99 +++++++++++++++++++++++++++++++ src/strip.rs | 2 +- webui/src/lib.rs | 2 +- 4 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 common/src/pattern/car_rainbow.rs diff --git a/common/src/pattern.rs b/common/src/pattern.rs index 871b166..b36013d 100644 --- a/common/src/pattern.rs +++ b/common/src/pattern.rs @@ -1,6 +1,7 @@ use crate::color::Rgb; use serde::{Deserialize, Serialize}; +pub mod car_rainbow; pub mod collide; pub mod fade; pub mod flashing; @@ -10,6 +11,7 @@ pub mod orb; pub mod slide; pub mod solid; pub mod visualizer; +pub use car_rainbow::{CarRainbow, CarRainbowParams}; pub use collide::{Collide, CollideParams}; pub use fade::{Fade, FadeParams}; pub use flashing::{Flashing, FlashingParams}; @@ -124,6 +126,7 @@ pub enum Parameters { Fade(FadeParams), MovingPixel(MovingPixelParams), MovingRainbow(MovingRainbowParams), + CarRainbow(CarRainbowParams), Orb(OrbParams), Solid(SolidParams), Visualizer(VisualizerParams), @@ -144,6 +147,7 @@ impl FormRender for Parameters { Self::Fade(ref p) => p.render(), Self::MovingPixel(ref p) => p.render(), Self::MovingRainbow(ref p) => p.render(), + Self::CarRainbow(ref p) => p.render(), Self::Orb(ref p) => p.render(), Self::Solid(ref p) => p.render(), Self::Visualizer(ref p) => p.render(), @@ -162,6 +166,7 @@ impl Parameters { "Fade", "MovingPixel", "MovingRainbow", + "CarRainbow", "Orb", "Flashing", ] @@ -174,6 +179,7 @@ impl Parameters { Self::Fade(ref p) => Box::new(Fade::new(p)), Self::MovingPixel(ref p) => Box::new(MovingPixel::new(p)), Self::MovingRainbow(ref p) => Box::new(MovingRainbow::new(p)), + Self::CarRainbow(ref p) => Box::new(CarRainbow::new(p)), Self::Orb(ref p) => Box::new(Orb::new(p)), Self::Solid(ref p) => Box::new(Solid::new(p)), Self::Visualizer(ref p) => Box::new(Visualizer::new(p)), diff --git a/common/src/pattern/car_rainbow.rs b/common/src/pattern/car_rainbow.rs new file mode 100644 index 0000000..7ec99ce --- /dev/null +++ b/common/src/pattern/car_rainbow.rs @@ -0,0 +1,99 @@ +use super::{ColorIterator, FormRender, InputRender, Pattern, PatternError, PatternResult}; +use crate::color::{self, Rgb, RAINBOW}; +use serde::{Deserialize, Serialize}; +use std::{collections::VecDeque, convert::TryFrom, iter}; + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct CarRainbowParams { + pub width: u8, + pub skip: u8, +} + +impl Default for CarRainbowParams { + fn default() -> Self { + Self { width: 8, skip: 4 } + } +} + +impl FormRender for CarRainbowParams { + fn render(&self) -> String { + [ + self.width.render("width", None), + self.skip.render("skip", None), + ] + .concat() + } +} + +#[derive(Clone, Debug)] +pub struct CarRainbow { + lights_buf: VecDeque, + /// The index to split, if Rainbow from the inside out + split_index: usize, + skip: u8, + width: u8, +} +impl Default for CarRainbow { + fn default() -> Self { + Self::new(&CarRainbowParams::default()) + } +} +impl CarRainbow { + pub fn new(params: &CarRainbowParams) -> Self { + Self { + lights_buf: VecDeque::new(), + skip: params.skip, + width: params.width, + split_index: 0, + } + } +} +impl Pattern for CarRainbow { + fn step(&mut self) -> PatternResult { + self.lights_buf.rotate_left(1); + // TODO: Not sure if we should go forward or backwards + // if self.forward { + // self.lights_buf.rotate_left(1); + // } else { + // self.lights_buf.rotate_right(1); + // } + Ok(true) + } + fn init(&mut self, num_lights: u16) -> PatternResult<()> { + if !(1..=255).contains(&num_lights) { + return Err(PatternError::LightCount); + } + if self.width < 1 { + return Err(PatternError::LightCount); + } + + // (width + skip) * RAINBOW.len() + let length_factor = u16::from(self.width) + .checked_add(self.skip.into()) + .ok_or(PatternError::ArithmeticError)? + .saturating_mul(u16::try_from(RAINBOW.len()).or(Err(PatternError::ArithmeticError))?); + // The length of the buffer + // Always a factor of length_factor + let buf_length = color::min_with_factor(num_lights, length_factor)?; + + self.split_index = (num_lights / 2_u16) as usize; + + self.lights_buf = RAINBOW + .iter() + .flat_map(|&x| { + iter::repeat(x) + .take(self.width.into()) + .chain(iter::repeat(color::BLACK).take(self.skip.into())) + }) + .cycle() + .take(buf_length.into()) + .collect(); + + Ok(()) + } + fn get_strip(&self) -> ColorIterator { + let forward_lights = self.lights_buf.iter().take(self.split_index); + let backward_lights = self.lights_buf.iter().take(self.split_index).rev(); + Box::new(forward_lights.chain(backward_lights)) + } +} diff --git a/src/strip.rs b/src/strip.rs index 44baf05..21f1b5f 100644 --- a/src/strip.rs +++ b/src/strip.rs @@ -5,7 +5,6 @@ use common::{ pattern::{self, Pattern}, strip::Message, }; -use tracing::{error, info}; use std::{ cmp, ops::Add, @@ -14,6 +13,7 @@ use std::{ thread, time::{Duration, Instant}, }; +use tracing::{error, info}; use ws2818_rgb_led_spi_driver::{adapter_gen::Ws28xxAdapter, adapter_spi::Ws28xxSpiAdapter}; /// Maximum number of lights allowed diff --git a/webui/src/lib.rs b/webui/src/lib.rs index 407ca27..7b231ce 100644 --- a/webui/src/lib.rs +++ b/webui/src/lib.rs @@ -3,8 +3,8 @@ use actix_web::HttpResponse; use actix_web_actors::ws; use common::{error, pattern, strip}; use live_view::{LiveView, StateSocket, Template}; -use template::{AppTemplate, ControlTemplate}; use std::str::FromStr; +use template::{AppTemplate, ControlTemplate}; use actix_web::{ error::{ErrorInternalServerError, JsonPayloadError, UrlencodedError},