Start work on car rainbow

This commit is contained in:
Austen Adler 2023-05-28 17:53:11 -04:00
parent 4781506ff9
commit e4e69f4d51
4 changed files with 107 additions and 2 deletions

View File

@ -1,6 +1,7 @@
use crate::color::Rgb; use crate::color::Rgb;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub mod car_rainbow;
pub mod collide; pub mod collide;
pub mod fade; pub mod fade;
pub mod flashing; pub mod flashing;
@ -10,6 +11,7 @@ pub mod orb;
pub mod slide; pub mod slide;
pub mod solid; pub mod solid;
pub mod visualizer; pub mod visualizer;
pub use car_rainbow::{CarRainbow, CarRainbowParams};
pub use collide::{Collide, CollideParams}; pub use collide::{Collide, CollideParams};
pub use fade::{Fade, FadeParams}; pub use fade::{Fade, FadeParams};
pub use flashing::{Flashing, FlashingParams}; pub use flashing::{Flashing, FlashingParams};
@ -124,6 +126,7 @@ pub enum Parameters {
Fade(FadeParams), Fade(FadeParams),
MovingPixel(MovingPixelParams), MovingPixel(MovingPixelParams),
MovingRainbow(MovingRainbowParams), MovingRainbow(MovingRainbowParams),
CarRainbow(CarRainbowParams),
Orb(OrbParams), Orb(OrbParams),
Solid(SolidParams), Solid(SolidParams),
Visualizer(VisualizerParams), Visualizer(VisualizerParams),
@ -144,6 +147,7 @@ impl FormRender for Parameters {
Self::Fade(ref p) => p.render(), Self::Fade(ref p) => p.render(),
Self::MovingPixel(ref p) => p.render(), Self::MovingPixel(ref p) => p.render(),
Self::MovingRainbow(ref p) => p.render(), Self::MovingRainbow(ref p) => p.render(),
Self::CarRainbow(ref p) => p.render(),
Self::Orb(ref p) => p.render(), Self::Orb(ref p) => p.render(),
Self::Solid(ref p) => p.render(), Self::Solid(ref p) => p.render(),
Self::Visualizer(ref p) => p.render(), Self::Visualizer(ref p) => p.render(),
@ -162,6 +166,7 @@ impl Parameters {
"Fade", "Fade",
"MovingPixel", "MovingPixel",
"MovingRainbow", "MovingRainbow",
"CarRainbow",
"Orb", "Orb",
"Flashing", "Flashing",
] ]
@ -174,6 +179,7 @@ impl Parameters {
Self::Fade(ref p) => Box::new(Fade::new(p)), Self::Fade(ref p) => Box::new(Fade::new(p)),
Self::MovingPixel(ref p) => Box::new(MovingPixel::new(p)), Self::MovingPixel(ref p) => Box::new(MovingPixel::new(p)),
Self::MovingRainbow(ref p) => Box::new(MovingRainbow::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::Orb(ref p) => Box::new(Orb::new(p)),
Self::Solid(ref p) => Box::new(Solid::new(p)), Self::Solid(ref p) => Box::new(Solid::new(p)),
Self::Visualizer(ref p) => Box::new(Visualizer::new(p)), Self::Visualizer(ref p) => Box::new(Visualizer::new(p)),

View File

@ -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<Rgb>,
/// 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<bool> {
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))
}
}

View File

@ -5,7 +5,6 @@ use common::{
pattern::{self, Pattern}, pattern::{self, Pattern},
strip::Message, strip::Message,
}; };
use tracing::{error, info};
use std::{ use std::{
cmp, cmp,
ops::Add, ops::Add,
@ -14,6 +13,7 @@ use std::{
thread, thread,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use tracing::{error, info};
use ws2818_rgb_led_spi_driver::{adapter_gen::Ws28xxAdapter, adapter_spi::Ws28xxSpiAdapter}; use ws2818_rgb_led_spi_driver::{adapter_gen::Ws28xxAdapter, adapter_spi::Ws28xxSpiAdapter};
/// Maximum number of lights allowed /// Maximum number of lights allowed

View File

@ -3,8 +3,8 @@ use actix_web::HttpResponse;
use actix_web_actors::ws; use actix_web_actors::ws;
use common::{error, pattern, strip}; use common::{error, pattern, strip};
use live_view::{LiveView, StateSocket, Template}; use live_view::{LiveView, StateSocket, Template};
use template::{AppTemplate, ControlTemplate};
use std::str::FromStr; use std::str::FromStr;
use template::{AppTemplate, ControlTemplate};
use actix_web::{ use actix_web::{
error::{ErrorInternalServerError, JsonPayloadError, UrlencodedError}, error::{ErrorInternalServerError, JsonPayloadError, UrlencodedError},