From ff96bdf6fa91a2dd7f3278b829b69898859c3160 Mon Sep 17 00:00:00 2001 From: alban Date: Mon, 24 Jul 2023 17:28:18 +0200 Subject: [PATCH 1/5] fix: etherdream example --- examples/etherdream.rs | 2 +- examples/test.rs | 46 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 examples/test.rs diff --git a/examples/etherdream.rs b/examples/etherdream.rs index 75d888c..c521b0b 100644 --- a/examples/etherdream.rs +++ b/examples/etherdream.rs @@ -129,7 +129,7 @@ impl Iterator for SineWave { _ => (std::u16::MAX, std::u16::MAX, std::u16::MAX), }; let x_min = std::i16::MIN; - let x_max = std::i16::MAX; + let x_max = std::i8::MAX as i16; let x = (x_min as f32 + fract * (x_max as f32 - x_min as f32)) as i16; let y = (amp * x_max as f32) as i16; let control = 0; diff --git a/examples/test.rs b/examples/test.rs new file mode 100644 index 0000000..b8fb5f3 --- /dev/null +++ b/examples/test.rs @@ -0,0 +1,46 @@ +/// +/// $ cargo run --example simple_client +/// + +use redis::{ + //RedisResult, + Client, + Commands, + Connection, +}; + +use std::time::Instant; + +fn do_something() -> redis::RedisResult<()> { + let client = Client::open("redis://127.0.0.1/")?; + let mut con: Connection = client.get_connection()?; + let start = Instant::now(); + + loop { + let elapsed = start.elapsed(); + let time = 60.0 * elapsed.as_millis() as f32 / 1000.0; + + let mut v: Vec<(f32, f32, u32)> = vec![]; + + for i in 0..128 { + let a = (time + i as f32) / 128.0 * std::f32::consts::PI * 2.0; + let r = 1200.0 + (a * 5.0).cos() * (500.0 * (time / 5.0).cos()); + + let x = a.cos() * r; + let y = a.sin() * r; + let col = if i % 8 < 4 { + 0x000000ff + } else { + 0x00ff0000 + }; + v.push((x, y, col)); + } + // println!("{:?}", v); + let _ = con.set("/pl/0/0", format!("{:?}", v))?; + } + // Ok(()) +} + +fn main() { + _ = do_something(); +} From 3ce346306f15569f8d191140e734f0db73d86cc0 Mon Sep 17 00:00:00 2001 From: alban Date: Mon, 24 Jul 2023 17:29:33 +0200 Subject: [PATCH 2/5] feat: add helios to etherdream transformer --- src/conf.rs | 5 ++++- src/transformer.rs | 2 ++ src/transformer/helios_to_etherdream.rs | 27 +++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/transformer/helios_to_etherdream.rs diff --git a/src/conf.rs b/src/conf.rs index 2996c7d..4ddf686 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -48,7 +48,9 @@ pub enum TransformConf { #[serde(rename = "grid")] Grid(transformer::Grid), #[serde(rename = "homography")] - Homography(transformer::Homography) + Homography(transformer::Homography), + #[serde(rename = "helios_to_etherdream")] + HeliosToEtherdream(transformer::HeliosToEtherdream), } @@ -73,6 +75,7 @@ impl Conf { TransformConf::FlipV(r) => Box::new(*r), TransformConf::Grid(r) => Box::new(*r), TransformConf::Homography(r) => Box::new(*r), + TransformConf::HeliosToEtherdream(r) => Box::new(*r), }; v.push(t); } diff --git a/src/transformer.rs b/src/transformer.rs index aa25291..2b9465f 100644 --- a/src/transformer.rs +++ b/src/transformer.rs @@ -6,6 +6,7 @@ mod flip_horizontal; mod flip_vertical; mod grid; mod homography; +mod helios_to_etherdream; use crate::point::Point; use crate::worldstate::WorldState; @@ -18,6 +19,7 @@ pub use flip_horizontal::FlipHorizontal; pub use flip_vertical::FlipVertical; pub use grid::Grid; pub use self::homography::Homography; +pub use helios_to_etherdream::HeliosToEtherdream; pub trait Transformers { fn apply( diff --git a/src/transformer/helios_to_etherdream.rs b/src/transformer/helios_to_etherdream.rs new file mode 100644 index 0000000..1891d5d --- /dev/null +++ b/src/transformer/helios_to_etherdream.rs @@ -0,0 +1,27 @@ +use crate::transformer::Transformers; +use crate::point::Point; +use crate::worldstate::WorldState; + +use serde::{Serialize, Deserialize}; + +/// Converts helios Geometry to Helios +#[allow(dead_code)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy)] +pub struct HeliosToEtherdream { +} + +impl Transformers for HeliosToEtherdream { + fn apply(&self, point_list: &[Point], _ws: &WorldState) -> Vec { + // debug!("list helios {:?}", point_list); + let out = point_list.iter().map(|pt| { + Point { + x: 8.0 * (pt.x - 2047.0), + y: 8.0 * (pt.y - 2047.0), + ..*pt + } + }).collect(); + // debug!("list etherdream {:?}", out); + out + } +} + From 6f04925ea5e56f8d6bc8b0ea0c53086b25753129 Mon Sep 17 00:00:00 2001 From: alban Date: Mon, 24 Jul 2023 17:34:06 +0200 Subject: [PATCH 3/5] feat: add framerate with fixed value for now (20Hz) --- src/framerate.rs | 39 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/main.rs | 6 ++++++ 3 files changed, 46 insertions(+) create mode 100644 src/framerate.rs diff --git a/src/framerate.rs b/src/framerate.rs new file mode 100644 index 0000000..dbab25b --- /dev/null +++ b/src/framerate.rs @@ -0,0 +1,39 @@ +use log::{debug, warn}; +use std::time::{Duration, Instant}; +use crate::errors::LJResult; +use std::{thread}; + +/// Converts helios Geometry to Helios +#[derive(Debug, Clone, Copy)] +pub struct Framerate { + prev_trace_time: Instant, + fps: u8, +} + +impl Framerate { + pub fn new() -> LJResult { + Ok(Framerate { + prev_trace_time: Instant::now(), + fps: 20, + }) + } + pub fn handle_time(&mut self) -> LJResult<()> { + let frame_time = 1000000000 / self.fps as u128; + let now = Instant::now(); + // How long since last loop ? + let nanotime_spent = self.prev_trace_time.elapsed().as_nanos(); + // Diw it go too fast? If so : sleep a bit + if frame_time > nanotime_spent { + let nanotime_towait = frame_time - nanotime_spent; + let dur = Duration::new(0, (nanotime_towait as f32 * 0.9) as u32); + // debug!("{:?} - {:?} : {:?}", nanotime_towait, self.prev_trace_time, now ); + thread::sleep(dur); + debug!("Framerate OK"); + } else { + warn!("Frame longer than expected {:?} > {:?}", nanotime_spent, frame_time, ); + } + + self.prev_trace_time = now; + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 9048f40..ac3d833 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,3 +5,4 @@ pub mod device; pub mod point; pub mod transformer; pub mod worldstate; +pub mod framerate; diff --git a/src/main.rs b/src/main.rs index 62067a8..c1ba308 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ mod point; mod transformer; mod device; mod worldstate; +mod framerate; use device::device_factory; use std::sync::atomic::{AtomicBool, Ordering}; @@ -21,6 +22,7 @@ use transformer::Transformers; use log::{LevelFilter, info, /* warn, */ error}; use env_logger::Builder; use worldstate::WorldState; +use framerate::Framerate; const DEFAULT_CONF_FILE: &str = "settings.toml"; @@ -68,9 +70,13 @@ fn run_all() -> LJResult<()> { // Setup geometry transformers on points lists let transformers = config.get_transformers(); + // Setup framerate limiter + let mut framerate_handler = Framerate::new()?; + // Dispatch based on redis requests while running.load(Ordering::SeqCst) { rs.set_status(tracer.status())?; + let _ = framerate_handler.handle_time()?; let order = rs.get_order(config.laser_id)?; match order { Order::Draw | Order::Black | Order::Grid => { From 514f4cc7c9183ba61e3d1602c1c304ded6039220 Mon Sep 17 00:00:00 2001 From: alban Date: Mon, 24 Jul 2023 17:35:15 +0200 Subject: [PATCH 4/5] fix: etherdream should work with device trait adjustments --- src/device.rs | 2 +- src/device/etherdream.rs | 116 +++++++++++++++++++++++---------------- src/device/helios.rs | 2 +- 3 files changed, 70 insertions(+), 50 deletions(-) diff --git a/src/device.rs b/src/device.rs index 6cbf0d5..cf83dba 100644 --- a/src/device.rs +++ b/src/device.rs @@ -42,7 +42,7 @@ pub struct Status { pub last_traced_at: String, pub properties: Vec, pub playback_state: PlaybackState, - pub capacity: u16, + pub capacity: usize, pub lack: String, } diff --git a/src/device/etherdream.rs b/src/device/etherdream.rs index e4ea6a6..b9e3cab 100644 --- a/src/device/etherdream.rs +++ b/src/device/etherdream.rs @@ -1,16 +1,20 @@ -use std::time; +#[warn(unused_imports)] +use log::{ debug, info, warn}; + use std::net::SocketAddr; +use std::thread::sleep; use ether_dream::dac::stream::{CommunicationError, connect}; use ether_dream::dac::{Playback, Stream}; use chrono::{DateTime, Utc}; -use std::time::SystemTime; +use std::time; +use std::time::{Duration, SystemTime}; use crate::conf::EtherDreamConf; use crate::device::{Device, Status, PlaybackState}; use crate::errors::{LJError, LJResult}; use crate::point::{Color, Point}; use ether_dream::protocol::{DacBroadcast, DacResponse}; -use log::{debug, info, warn}; + #[warn(dead_code)] pub struct EtherdreamDevice { @@ -114,14 +118,20 @@ impl EtherdreamDevice { Ok(stream) } - fn points_capacity(&self) -> u16 { + fn points_capacity(&self) -> usize { /*** Determine the number of points needed to fill the DAC. ***/ // Fixme thread 'main' panicked at 'attempt to subtract with overflow', src/device/etherdream.rs:144:24 - let n_points = self.dac.buffer_capacity as u16 - self.stream.dac().dac.status.buffer_fullness as u16 - 1; + let n_points = self.dac.buffer_capacity as usize - self.stream.dac().dac.status.buffer_fullness as usize - 1; n_points } + + fn ping(&mut self) -> LJResult<()> { + + Ok(self.stream.queue_commands().ping().submit()?) + + } } impl Device for EtherdreamDevice { @@ -135,62 +145,72 @@ impl Device for EtherdreamDevice { let now: DateTime = now.into(); let now = now.to_rfc3339(); - let status = Status { + Status { last_traced_at: now, properties: vec!["foo".to_string()], playback_state, capacity: self.points_capacity(), lack: self.dac_response.to_string(), - }; + } // debug!("Dac Status: {:?} ", status ); // debug!("Etherdream Dac {:?} ", self.dac ); - debug!("Stream dac{:?}", self.stream.dac()); - status + // debug!("Stream dac{:?}", self.stream.dac()); + // status } fn draw(&mut self, line: Vec, _speed: u32, ) -> LJResult<()> { - let n_points = self.points_capacity(); - // let n_points = &line.len(); - debug!("Etherdream::device draw Generating {:?} points", n_points); - - - match self.stream - .queue_commands() - .data( - line.into_iter() - .map(|point| point.into()) - .take(n_points as usize) - ) - // .data(sine_wave.by_ref().take(n_points as usize)) - - .submit() { - Err(err) => { - // We should account for - // 'Broken pipe (os error 32)' - // Connection reset by peer (os error 104) - self.dac_response = match err { - CommunicationError::Io(err) => { - warn!("IO ERROR while drawing: '{}'",err); - DacResponse::ACK - } - CommunicationError::Protocol(err) => { - warn!("Protocol ERROR while drawing: '{}'",err); - DacResponse::ACK - } - CommunicationError::Response(err) => { - warn!("Response ERROR while drawing: '{}'",err); - err.response.response - } - }; + let chunk_size = 64; + let points_iter = line.into_iter(); + for chunk in points_iter.as_slice().chunks(chunk_size){ + debug!("New chunk length: {:?}", chunk.len()); + loop { + let capacity = self.points_capacity(); + if chunk.len() > capacity as usize { + debug!("Sleep, capacity : {:?}", capacity); + // Sleep for 1/100th of a sec + sleep(Duration::new( 0, 10000000)); + self.ping(); + } else { + break; + } } - Ok(_) => { - self.dac_response = DacResponse::ACK; - debug!("Draw is ok"); - } - }; + debug!("drawing"); + match self.stream + .queue_commands() + .data( + chunk.into_iter() + .map(|point| (*point).into()) + .take(chunk_size as usize) + ) + .submit() { + Err(err) => { + // We should account for + // 'Broken pipe (os error 32)' + // Connection reset by peer (os error 104) + self.dac_response = match err { + CommunicationError::Io(err) => { + warn!("IO ERROR while drawing: '{}'",err); + DacResponse::ACK + } + CommunicationError::Protocol(err) => { + warn!("Protocol ERROR while drawing: '{}'",err); + DacResponse::ACK + } + CommunicationError::Response(err) => { + warn!("Response ERROR while drawing: '{}'",err); + err.response.response + } + }; + } + Ok(_) => { + self.dac_response = DacResponse::ACK; + // debug!("Draw is ok"); + } + }; + } Ok(()) } @@ -274,7 +294,7 @@ impl Iterator for SineWave { u1, u2, }; - debug!("{:?}",p); + // debug!("{:?}",p); self.point += 1; Some(p) } diff --git a/src/device/helios.rs b/src/device/helios.rs index 0971aeb..9106243 100644 --- a/src/device/helios.rs +++ b/src/device/helios.rs @@ -57,7 +57,7 @@ impl Device for HeliosDevice { last_traced_at: self.last_traced_at.clone(), properties: vec!["foo".to_string()], playback_state: self.state, - capacity: self.sent_points, + capacity: self.sent_points as usize, lack, } } From 22d7d3c718c8db551871565f73ee9fdcdfa24aa6 Mon Sep 17 00:00:00 2001 From: alban Date: Mon, 24 Jul 2023 17:35:39 +0200 Subject: [PATCH 5/5] fix: i in point for etherdream is meh --- src/point.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/point.rs b/src/point.rs index 6ce6268..273bfbc 100644 --- a/src/point.rs +++ b/src/point.rs @@ -1,5 +1,6 @@ use ether_dream::protocol::DacPoint; + #[derive(Debug, Clone, Copy, Default, PartialEq)] pub struct Point { pub x: f32, @@ -48,10 +49,10 @@ impl From for DacPoint { fn from(pt: Point) -> DacPoint { let control = 0; let (u1, u2) = (0, 0); - let i = 255; + let i = 0; let x = pt.x.clamp(-32000.0, 32000.0); let y = pt.y.clamp(-32000.0, 32000.0); - DacPoint { + let pt = DacPoint { control, x: x as i16, y: y as i16, @@ -61,6 +62,8 @@ impl From for DacPoint { b: (pt.color.b as u16) * 255, u1, u2, - } + }; + // debug!("point {:?}", pt); + pt } }