From 08b0b655ed14e3d405c2ef04dd51a33b04337cc2 Mon Sep 17 00:00:00 2001 From: Niklas Kapelle Date: Sun, 15 Oct 2023 18:19:55 +0200 Subject: [PATCH] led value interpolation for flashed --- src/led.rs | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 64 ++++++--------------------------- src/state.rs | 16 +++++++++ 3 files changed, 127 insertions(+), 53 deletions(-) create mode 100644 src/led.rs create mode 100644 src/state.rs diff --git a/src/led.rs b/src/led.rs new file mode 100644 index 0000000..da0ba36 --- /dev/null +++ b/src/led.rs @@ -0,0 +1,100 @@ +use super::state::State; +use std::{sync::atomic::Ordering, thread}; + +fn build_led_package(len: u32, color: (u8, u8, u8)) -> Vec { + let mut packet: Vec = vec![1, 1]; + + // loop through leds + for i in 0..len { + packet.push(i as u8); + packet.push(color.0); + packet.push(color.1); + packet.push(color.2); + } + + return packet; +} + +const FLASHED_X2: f64 = 0.00003113; +const FLASHED_X1: f64 = -0.17396053; +const FLASHED_X0: f64 = 244.51964267; + +fn interpolate_flashed(time: u64) -> u8 { + if time == 0 { + return 0; + } + + let y = FLASHED_X2 * (time as f64).powi(2) + FLASHED_X1 * (time as f64) + FLASHED_X0; + + return y.min(255.0).round() as u8; +} + +fn resolve_time_from_flashed(flashed: u8) -> u64 { + let discriminant = FLASHED_X1.powi(2) - 4.0 * FLASHED_X2 * (FLASHED_X0 - flashed as f64); + + let x = (-FLASHED_X1 - discriminant.sqrt()) / (2.0 * FLASHED_X2); + return x as u64; +} + +pub fn led_loop(fps: u32, addr: &str, len: u32, state: State) { + let socket = std::net::UdpSocket::bind("0.0.0.0:0").unwrap(); + let sleep_time: u64 = (1000 / fps).into(); + + let mut last_up_flashed: u8 = 0; // Used to detect changes in upstream flashed + let mut interpolated_flashed: u8; + let mut time_since_last_flashed: u64 = 0; + + loop { + thread::sleep(std::time::Duration::from_millis(sleep_time)); + + let upstream_flashed = u8::try_from(state.flashed.load(Ordering::Relaxed)).unwrap_or(0); + + // Count the time since the flash started to fade + if upstream_flashed > 0 && upstream_flashed < 255 { + time_since_last_flashed += sleep_time; + } + + if upstream_flashed == last_up_flashed { + // Upstream value hasn't changed + + if upstream_flashed == 255 { + // Flash is at max + interpolated_flashed = 255; + } else if upstream_flashed == 0 { + // Flash is off + interpolated_flashed = 0; + } else { + // Flash is fading + interpolated_flashed = interpolate_flashed(time_since_last_flashed); + } + } else { + // Upstream value has changed + + time_since_last_flashed = resolve_time_from_flashed(upstream_flashed); + interpolated_flashed = upstream_flashed; + last_up_flashed = upstream_flashed; + } + + if upstream_flashed > 0 || interpolated_flashed > 0 { + println!("{},{}", upstream_flashed, interpolated_flashed); + } + + let pack = build_led_package( + len, + ( + interpolated_flashed, + interpolated_flashed, + interpolated_flashed, + ), + ); + socket.send_to(&pack, addr).unwrap(); + + // let planted = state.bomb_planted.load(Ordering::Relaxed); + + // if planted { + // let packet = build_led_package(len, (255, 0, 0)); + // socket.send_to(&packet, addr).unwrap(); + // continue; + // } + } +} diff --git a/src/main.rs b/src/main.rs index 3abf78c..8ee9a76 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,32 +1,17 @@ #[macro_use] extern crate rocket; -use std::sync::atomic::AtomicBool; -use std::sync::atomic::AtomicU16; use std::sync::atomic::Ordering; -use std::sync::Arc; use rocket::serde::json::{json, Json, Value}; +use state::State; use std::thread; mod gamestate; - -#[derive(Clone)] -struct State { - flashed: Arc, - bomb_planted: Arc, -} - -impl State { - fn new() -> State { - State { - flashed: Arc::new(AtomicU16::new(0)), - bomb_planted: Arc::new(AtomicBool::new(false)), - } - } -} +mod led; +mod state; #[post("/gsi", data = "")] -fn gsi(data: Json, gobal_state: &rocket::State) -> Value { +fn gsi(data: Json, gobal_state: &rocket::State) -> Value { let flashed = match &data.player { Some(player) => match &player.state { Some(state) => state.flashed, @@ -53,20 +38,6 @@ fn gsi(data: Json, gobal_state: &rocket::State) json!({ "status": "ok"}) } -fn build_led_package(len: u32, color: (u8, u8, u8)) -> Vec { - let mut packet: Vec = vec![1, 1]; - - // loop through leds - for i in 0..len { - packet.push(i as u8); - packet.push(color.0); - packet.push(color.1); - packet.push(color.2); - } - - return packet; -} - #[launch] fn rocket() -> _ { let state: State = State::new(); @@ -74,26 +45,13 @@ fn rocket() -> _ { let addr = "192.168.0.59:21324"; thread::spawn(move || { - let socket = std::net::UdpSocket::bind("0.0.0.0:0").unwrap(); - loop { - thread::sleep(std::time::Duration::from_millis(50)); - - let flashed = u8::try_from(state_clone.flashed.load(Ordering::Relaxed)).unwrap_or(0); - if flashed > 0 { - let packet = build_led_package(36, (flashed, flashed, flashed)); - socket.send_to(&packet, addr).unwrap(); - continue; - } - - let planted = state_clone.bomb_planted.load(Ordering::Relaxed); - - if planted { - let packet = build_led_package(36, (255, 0, 0)); - socket.send_to(&packet, addr).unwrap(); - continue; - } - } + led::led_loop(30,addr,36, state_clone); }); - rocket::build().manage(state).mount("/", routes![gsi]) + let figment = rocket::figment::Figment::from(rocket::Config::default()) + .merge(("log_level", "critical")); + + rocket::custom(figment) + .manage(state) + .mount("/", routes![gsi]) } diff --git a/src/state.rs b/src/state.rs new file mode 100644 index 0000000..aa87095 --- /dev/null +++ b/src/state.rs @@ -0,0 +1,16 @@ +use std::sync::{atomic::{AtomicU16, AtomicBool}, Arc}; + +#[derive(Clone)] +pub struct State { + pub flashed: Arc, + pub bomb_planted: Arc, +} + +impl State { + pub fn new() -> State { + State { + flashed: Arc::new(AtomicU16::new(0)), + bomb_planted: Arc::new(AtomicBool::new(false)), + } + } +} \ No newline at end of file