diff --git a/src/color.rs b/src/color.rs index d1ef2c0..5ebae4c 100644 --- a/src/color.rs +++ b/src/color.rs @@ -96,7 +96,7 @@ pub fn merge_colors(from_color: Rgb, to_color: Rgb, factor: f32) -> Rgb { /// Builds a color ramp of length `length` of the (exclusive) bounds of `from_color` to `to_color` pub fn build_ramp(from_color: Rgb, to_color: Rgb, length: usize) -> Vec { - let offset = 1.0f32 / (length as f32 + 1.0f32); + let offset = 1.0_f32 / (length as f32 + 1.0_f32); let mut ret: Vec = vec![]; for step in 1..=length { ret.push(merge_colors(from_color, to_color, offset * step as f32)); diff --git a/src/main.rs b/src/main.rs index d619fe8..c176338 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,13 +56,16 @@ fn main() -> Result<(), ProgramError> { // I do not care if the console ui crashes let (g, h) = (tx.clone(), tx.clone()); - let _console_ui_handle = - thread::spawn(move || -> Result<(), ProgramError> { console_ui_loop(&g) }); + let _console_ui_handle = thread::spawn(move || -> Result<(), ProgramError> { + let ret = console_ui_loop(&g); + println!("Console ui dead: {:?}", ret); + ret + }); // I do not care if the web ui crashes let _web_ui_handle = thread::spawn(move || -> Result<(), io::Error> { let ret = webui::start(h); - println!("Webui dead"); + println!("Webui dead: {:?}", ret); ret // TODO: Do not join -- this is just because we are running on a computer with no spi env }) diff --git a/src/pattern/orb.rs b/src/pattern/orb.rs index ed3df14..32717c9 100644 --- a/src/pattern/orb.rs +++ b/src/pattern/orb.rs @@ -1,46 +1,64 @@ use super::Pattern; use crate::color::{self, Rgb}; use std::iter; +use std::collections::VecDeque; #[derive(Clone, Debug)] pub struct Orb { - lights_buf: Vec, + /// Buffer to manage the lights + lights_buf: VecDeque, + /// The color of the orb color: Rgb, + /// The width of the center of the orb center_width: u8, + /// The width of each side's backoff (fadeout) backoff_width: u8, + /// The total width of the orb, equal to center_width + 2*backoff_width total_width: u8, + /// True if the orb should bounce from left to right, otherwise it will wrap around bounces: bool, - step: isize, + /// The state of the program + step: usize, + /// The maximum number of steps for a given direction. The orb will turn around after this many steps + step_max: usize, + /// Direction of the orb. This can switch if `bounces` is true direction: bool, } impl Orb { pub const fn new(color: Rgb, center_width: u8, backoff_width: u8) -> Self { Self { - lights_buf: vec![], + lights_buf: VecDeque::new(), color, center_width, backoff_width, total_width: center_width + backoff_width * 2, bounces: false, step: 0, + step_max: 0, direction: true, } } } impl Pattern for Orb { fn step(&mut self) -> Result { - if self.direction { + if !self.bounces { + // If we don't bounce, then just wrap and we're done self.lights_buf.rotate_right(1); - self.step += 1; - } else { - self.lights_buf.rotate_left(1); - self.step -= 1; + return Ok(true); } - if step == 0 { - self.direction = true; - } else if self.lights_buf - self.step == self.total_width { - self.direction = false; + if self.direction { + self.lights_buf.rotate_right(1); + self.step = self.step.saturating_add(1); + } else { + self.lights_buf.rotate_left(1); + self.step = self.step.saturating_sub(1); + } + + if self.step == self.step_max || self.step == 0 { + self.direction = !self.direction; + // } else if self.lights_buf - self.step == self.total_width { + // self.direction = true; } Ok(true) @@ -62,6 +80,13 @@ impl Pattern for Orb { .take(num_lights.saturating_sub(self.total_width.into()).into()), ) .collect(); + + self.step_max = self + .lights_buf + .len() + .checked_sub(self.total_width.into()) + .unwrap_or(self.lights_buf.len()); + Ok(()) } fn get_strip(&self) -> &[Rgb] { diff --git a/src/webui.rs b/src/webui.rs index 2e8f969..c665c03 100644 --- a/src/webui.rs +++ b/src/webui.rs @@ -1,8 +1,8 @@ use crate::pattern; use crate::strip; -// use actix_web::web::JsonConfig; +use actix_web::error::{ErrorBadRequest, JsonPayloadError}; +use actix_web::web::JsonConfig; use actix_web::{post, web, App, HttpServer, Responder, Result}; -// use actix_web::error::InternalError; use actix_web_static_files; use pattern::PatternParameters; use std::io; @@ -12,21 +12,10 @@ include!(concat!(env!("OUT_DIR"), "/generated.rs")); use std::sync::mpsc::Sender; -// TODO: Pre-compute binary somehow? So do not have to unwrap -// #[derive(RustEmbed)] -// #[folder = "html/"] -// struct Asset; - struct AppState { strip_tx: Arc>>, } -// #[derive(Deserialize, Debug)] -// struct ColorForm { -// color: String, -// e: E -// } - #[post("/setcolor")] async fn set_color( data: web::Data, @@ -58,7 +47,12 @@ pub async fn start(tx: Sender) -> std::io::Result<()> { }) .service( web::scope("/api") - // .app_data(JsonConfig::default()) + .app_data( + JsonConfig::default().error_handler(|err: JsonPayloadError, _req| { + println!("JSON error: {:?}", err); + err.into() + }), + ) .service(set_color), ) .service(actix_web_static_files::ResourceFiles::new("/", generated))