From 71fabde38565a6af515231fdc9f036703d918257 Mon Sep 17 00:00:00 2001 From: alban Date: Thu, 20 Jul 2023 21:11:57 +0200 Subject: [PATCH 1/4] fix: Resampler should have correct type --- src/redis_ctrl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/redis_ctrl.rs b/src/redis_ctrl.rs index 9b4bb4a..4fdcdde 100644 --- a/src/redis_ctrl.rs +++ b/src/redis_ctrl.rs @@ -45,7 +45,7 @@ impl TryFrom for Order { } pub type Line = Vec<(f32, f32, u32)>; -pub type Resampler = Vec<(f32,f32)>; +pub type Resampler = Vec>; pub struct RedisCtrl { pub client: Client, From 810a3677de4b640449c5449a48ecc3b725926747 Mon Sep 17 00:00:00 2001 From: alban Date: Thu, 20 Jul 2023 21:12:17 +0200 Subject: [PATCH 2/4] fix: populate redis general geometry --- examples/populate_redis.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/populate_redis.rs b/examples/populate_redis.rs index a1d43fe..307acd6 100644 --- a/examples/populate_redis.rs +++ b/examples/populate_redis.rs @@ -22,7 +22,7 @@ fn do_something() -> redis::RedisResult<()> { let _ = con.set("/EDH/0", "[[1.0, 0.0, 0.0],\n [ 0.0, 1.0, 0.0],\n [ 0.0, 0.0, 1.0]]")?; let _ = con.set("/kpps/0", "5000")?; let _ = con.set("/intensity/0", "255")?; - let _ = con.set("/pl/0/0", "[(-300, 300, 0), (-300, -300, 65280), (300, -300, 65280), (300, 300, 65280), (-300, 300, 65280)]")?; + let _ = con.set("/pl/0/0", "[(1000, 2000, 0), (1000, 1000, 65535), (2000, 1000, 65535), (2000, 2000, 65535), (1000, 2000, 65535)]")?; Ok(()) } From f45b9e5748aaa40da2111c5f621e2e85969c003b Mon Sep 17 00:00:00 2001 From: alban Date: Thu, 20 Jul 2023 21:12:34 +0200 Subject: [PATCH 3/4] fix: dac/etherdream should work --- examples/etherdream.rs | 235 ++++++++++++++++++++------------------- src/device/etherdream.rs | 90 +++++++++++++-- src/point.rs | 7 +- 3 files changed, 204 insertions(+), 128 deletions(-) diff --git a/examples/etherdream.rs b/examples/etherdream.rs index e174a88..75d888c 100644 --- a/examples/etherdream.rs +++ b/examples/etherdream.rs @@ -3,148 +3,149 @@ extern crate ether_dream; use ether_dream::dac; fn main() { - println!("Listening for an Ether Dream DAC..."); + println!("Listening for an Ether Dream DAC..."); - let (dac_broadcast, source_addr) = ether_dream::recv_dac_broadcasts() - .expect("failed to bind to UDP socket") - .filter_map(Result::ok) - .next() - .unwrap(); - let mac_address = dac::MacAddress(dac_broadcast.mac_address); + let (dac_broadcast, source_addr) = ether_dream::recv_dac_broadcasts() + .expect("failed to bind to UDP socket") + .filter_map(Result::ok) + .next() + .unwrap(); + let mac_address = dac::MacAddress(dac_broadcast.mac_address); - println!( - "Discovered DAC \"{}\" at \"{}\"! Connecting...", - mac_address, source_addr - ); + println!( + "Discovered DAC \"{}\" at \"{}\"! Connecting...", + mac_address, source_addr + ); - // Establish the TCP connection. - let mut stream = dac::stream::connect(&dac_broadcast, source_addr.ip().clone()).unwrap(); + // Establish the TCP connection. + let mut stream = dac::stream::connect(&dac_broadcast, source_addr.ip().clone()).unwrap(); - // If we want to create an animation (in our case a moving sine wave) we need a frame rate. - let frames_per_second = 60.0; - // Lets use the DAC at an eighth the maximum scan rate. - let points_per_second = stream.dac().max_point_rate / 32; - // Determine the number of points per frame given our target frame and point rates. - let points_per_frame = (points_per_second as f32 / frames_per_second) as u16; + // If we want to create an animation (in our case a moving sine wave) we need a frame rate. + let frames_per_second = 60.0; + // Lets use the DAC at an eighth the maximum scan rate. + let points_per_second = stream.dac().max_point_rate / 32; + // Determine the number of points per frame given our target frame and point rates. + let points_per_frame = (points_per_second as f32 / frames_per_second) as u16; - println!( - "Preparing for playback:\n\tframe_hz: {}\n\tpoint_hz: {}\n\tpoints_per_frame: {}\n", - frames_per_second, points_per_second, points_per_frame - ); + println!( + "Preparing for playback:\n\tframe_hz: {}\n\tpoint_hz: {}\n\tpoints_per_frame: {}\n", + frames_per_second, points_per_second, points_per_frame + ); - // Prepare the DAC's playback engine and await the repsonse. - stream - .queue_commands() - .prepare_stream() - .submit() - .err() - .map(|err| { - eprintln!( - "err occurred when submitting PREPARE_STREAM \ + // Prepare the DAC's playback engine and await the repsonse. + stream + .queue_commands() + .prepare_stream() + .submit() + .err() + .map(|err| { + eprintln!( + "err occurred when submitting PREPARE_STREAM \ command and listening for response: {}", - err - ); - }); + err + ); + }); - println!("Beginning playback!"); + println!("Beginning playback!"); - // The sine wave used to generate points. - let mut sine_wave = SineWave { - point: 0, - points_per_frame, - frames_per_second, - }; + // The sine wave used to generate points. + let mut sine_wave = SineWave { + point: 0, + points_per_frame, + frames_per_second, + }; - // Queue the initial frame and tell the DAC to begin producing output. - let n_points = points_to_generate(stream.dac()); - stream - .queue_commands() - .data(sine_wave.by_ref().take(n_points)) - .begin(0, points_per_second) - .submit() - .err() - .map(|err| { - eprintln!( - "err occurred when submitting initial DATA and BEGIN \ + // Queue the initial frame and tell the DAC to begin producing output. + let n_points = points_to_generate(stream.dac()); + stream + .queue_commands() + .data(sine_wave.by_ref().take(n_points)) + .begin(0, points_per_second) + .submit() + .err() + .map(|err| { + eprintln!( + "err occurred when submitting initial DATA and BEGIN \ commands and listening for response: {}", - err - ); - }); + err + ); + }); + eprintln!("Stream dac{:?}", stream.dac()); - // Loop and continue to send points forever. - loop { - // Determine how many points the DAC can currently receive. - let n_points = points_to_generate(stream.dac()); - if let Err(err) = stream - .queue_commands() - .data(sine_wave.by_ref().take(n_points)) - .submit() - { - eprintln!( - "err occurred when submitting DATA command and listening \ + // Loop and continue to send points forever. + loop { + // Determine how many points the DAC can currently receive. + let n_points = points_to_generate(stream.dac()); + if let Err(err) = stream + .queue_commands() + .data(sine_wave.by_ref().take(n_points)) + .submit() + { + eprintln!( + "err occurred when submitting DATA command and listening \ for response: {}", - err - ); - break; - } - } + err + ); + break; + } + } - // Tell the DAC to stop producing output and return to idle. Wait for the response. - // - // Note that the DAC is commanded to stop on `Drop` if this is not called and any errors - // produced are ignored. - stream - .queue_commands() - .stop() - .submit() - .expect("err occurred when submitting STOP command and listening for response"); + // Tell the DAC to stop producing output and return to idle. Wait for the response. + // + // Note that the DAC is commanded to stop on `Drop` if this is not called and any errors + // produced are ignored. + stream + .queue_commands() + .stop() + .submit() + .expect("err occurred when submitting STOP command and listening for response"); } // Determine the number of points needed to fill the DAC. fn points_to_generate(dac: ðer_dream::dac::Dac) -> usize { - dac.buffer_capacity as usize - 1 - dac.status.buffer_fullness as usize + dac.buffer_capacity as usize - 1 - dac.status.buffer_fullness as usize } // An iterator that endlessly generates a sine wave of DAC points. // // The sine wave oscillates at a rate of once per second. struct SineWave { - point: u32, - points_per_frame: u16, - frames_per_second: f32, + point: u32, + points_per_frame: u16, + frames_per_second: f32, } impl Iterator for SineWave { - type Item = ether_dream::protocol::DacPoint; - fn next(&mut self) -> Option { - let coloured_points_per_frame = self.points_per_frame - 1; - let i = (self.point % self.points_per_frame as u32) as u16; - let hz = 1.0; - let fract = i as f32 / coloured_points_per_frame as f32; - let phase = (self.point as f32 / coloured_points_per_frame as f32) / self.frames_per_second; - let amp = (hz * (fract + phase) * 2.0 * std::f32::consts::PI).sin(); - let (r, g, b) = match i { - i if i == coloured_points_per_frame || i < 13 => (0, 0, 0), - _ => (std::u16::MAX, std::u16::MAX, std::u16::MAX), - }; - let x_min = std::i16::MIN; - let x_max = std::i16::MAX; - 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; - let (u1, u2) = (0, 0); - let p = ether_dream::protocol::DacPoint { - control, - x, - y, - i, - r, - g, - b, - u1, - u2, - }; - self.point += 1; - Some(p) - } + type Item = ether_dream::protocol::DacPoint; + fn next(&mut self) -> Option { + let coloured_points_per_frame = self.points_per_frame - 1; + let i = (self.point % self.points_per_frame as u32) as u16; + let hz = 1.0; + let fract = i as f32 / coloured_points_per_frame as f32; + let phase = (self.point as f32 / coloured_points_per_frame as f32) / self.frames_per_second; + let amp = (hz * (fract + phase) * 2.0 * std::f32::consts::PI).sin(); + let (r, g, b) = match i { + i if i == coloured_points_per_frame || i < 13 => (0, 0, 0), + _ => (std::u16::MAX, std::u16::MAX, std::u16::MAX), + }; + let x_min = std::i16::MIN; + let x_max = std::i16::MAX; + 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; + let (u1, u2) = (0, 0); + let p = ether_dream::protocol::DacPoint { + control, + x, + y, + i, + r, + g, + b, + u1, + u2, + }; + self.point += 1; + Some(p) + } } \ No newline at end of file diff --git a/src/device/etherdream.rs b/src/device/etherdream.rs index 86b6a6b..6d1e626 100644 --- a/src/device/etherdream.rs +++ b/src/device/etherdream.rs @@ -71,6 +71,7 @@ impl EtherdreamDevice { Err(Box::new(LJError::EtherdreamConnectError(err))) } Ok((dac, source_addr)) => { + info!("Trying to open TCP stream..."); let stream = EtherdreamDevice::get_tcp_stream(&dac, &source_addr)?; info!("Finished configuring DAC and TCP stream."); Ok((dac, source_addr, stream)) @@ -87,18 +88,29 @@ impl EtherdreamDevice { Err(err) => warn!("err occurred when submitting PREPARE_STREAM command and listening for response: {}",err), Ok(_) => info!("Prepared Stream.") } - let begin_list = vec![ - DacPoint { control: 0, x: 0, y: 0, i: 255, r: 0, g: 0, b: 0, u1: 0, u2: 0 }, - ]; + // If we want to create an animation (in our case a moving sine wave) we need a frame rate. + let frames_per_second = 60.0; + // Lets use the DAC at an eighth the maximum scan rate. let points_per_second = stream.dac().max_point_rate / 32; + // Determine the number of points per frame given our target frame and point rates. + let points_per_frame = (points_per_second as f32 / frames_per_second) as u16; + + let mut sine_wave = SineWave { + point: 0, + points_per_frame, + frames_per_second, + }; + match stream .queue_commands() - .data(begin_list.into_iter().take(1 as usize)) + .data(sine_wave.by_ref().take(400)) + // .data(begin_list.into_iter().take(400 as usize)) .begin(0, points_per_second) .submit() { Err(err) => warn!("err occurred when submitting first data: {}",err), Ok(_) => info!("Sent first data to Etherdream.") } + Ok(stream) } @@ -130,9 +142,9 @@ impl Device for EtherdreamDevice { capacity: self.points_capacity(), lack: self.dac_response.to_string(), }; - // info!("Dac Status: {:?} ", status ); - // info!("Etherdream Dac {:?} ", self.dac ); - // info!("Stream dac{:?}", self.stream.dac()); + // debug!("Dac Status: {:?} ", status ); + // debug!("Etherdream Dac {:?} ", self.dac ); + debug!("Stream dac{:?}", self.stream.dac()); status } @@ -143,6 +155,17 @@ impl Device for EtherdreamDevice { let n_points = self.points_capacity(); // let n_points = &line.len(); debug!("Etherdream::device draw Generating {:?} points", n_points); + let frames_per_second = 60.0; + // Lets use the DAC at an eighth the maximum scan rate. + let points_per_second = self.stream.dac().max_point_rate / 32; + // Determine the number of points per frame given our target frame and point rates. + let points_per_frame = (points_per_second as f32 / frames_per_second) as u16; + + let mut sine_wave = SineWave { + point: 0, + points_per_frame, + frames_per_second, + }; match self.stream .queue_commands() .data( @@ -151,6 +174,8 @@ impl Device for EtherdreamDevice { // .take(line.len() as usize) .take(n_points as usize) ) + // .data(sine_wave.by_ref().take(n_points as usize)) + .submit() { Err(err) => { // We should account for @@ -170,7 +195,6 @@ impl Device for EtherdreamDevice { err.response.response } }; - } Ok(_) => { self.dac_response = DacResponse::ACK; @@ -220,3 +244,53 @@ impl Device for EtherdreamDevice { ] } } + +// Determine the number of points needed to fill the DAC. +fn points_to_generate(dac: ðer_dream::dac::Dac) -> usize { + dac.buffer_capacity as usize - 1 - dac.status.buffer_fullness as usize +} + +// An iterator that endlessly generates a sine wave of DAC points. +// +// The sine wave oscillates at a rate of once per second. +struct SineWave { + point: u32, + points_per_frame: u16, + frames_per_second: f32, +} + +impl Iterator for SineWave { + type Item = ether_dream::protocol::DacPoint; + fn next(&mut self) -> Option { + let coloured_points_per_frame = self.points_per_frame - 1; + let i = (self.point % self.points_per_frame as u32) as u16; + let hz = 1.0; + let fract = i as f32 / coloured_points_per_frame as f32; + let phase = (self.point as f32 / coloured_points_per_frame as f32) / self.frames_per_second; + let amp = (hz * (fract + phase) * 2.0 * std::f32::consts::PI).sin(); + let (r, g, b) = match i { + i if i == coloured_points_per_frame || i < 13 => (0, 0, 0), + _ => (std::u16::MAX, std::u16::MAX, std::u16::MAX), + }; + let x_min = std::i16::MIN; + let x_max = std::i16::MAX; + 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; + let (u1, u2) = (0, 0); + let p = ether_dream::protocol::DacPoint { + control, + x, + y, + i, + r, + g, + b, + u1, + u2, + }; + debug!("{:?}",p); + self.point += 1; + Some(p) + } +} \ No newline at end of file diff --git a/src/point.rs b/src/point.rs index 1298905..9f88f43 100644 --- a/src/point.rs +++ b/src/point.rs @@ -1,4 +1,5 @@ use ether_dream::protocol::DacPoint; +use log::debug; fn clamp(val: f32, min: f32, max: f32) -> f32 { if val < min { @@ -67,9 +68,9 @@ impl From for DacPoint { x: x as i16, y: y as i16, i, - r: pt.color.r.into(), - g: pt.color.g.into(), - b: pt.color.b.into(), + r: (pt.color.r as u16) * 255, + g: (pt.color.g as u16) * 255, + b: (pt.color.b as u16) * 255, u1, u2, } From e148a1ec5eefa9e7dab03966e39042967961339f Mon Sep 17 00:00:00 2001 From: alban Date: Thu, 20 Jul 2023 21:34:23 +0200 Subject: [PATCH 4/4] fix: cleanup for errors --- src/device/etherdream.rs | 19 ++----------------- src/device/helios.rs | 9 +++++++-- src/point.rs | 16 ++-------------- src/redis_ctrl.rs | 2 ++ 4 files changed, 13 insertions(+), 33 deletions(-) diff --git a/src/device/etherdream.rs b/src/device/etherdream.rs index 6d1e626..e4ea6a6 100644 --- a/src/device/etherdream.rs +++ b/src/device/etherdream.rs @@ -9,7 +9,7 @@ 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, DacPoint, DacResponse}; +use ether_dream::protocol::{DacBroadcast, DacResponse}; use log::{debug, info, warn}; #[warn(dead_code)] @@ -155,23 +155,13 @@ impl Device for EtherdreamDevice { let n_points = self.points_capacity(); // let n_points = &line.len(); debug!("Etherdream::device draw Generating {:?} points", n_points); - let frames_per_second = 60.0; - // Lets use the DAC at an eighth the maximum scan rate. - let points_per_second = self.stream.dac().max_point_rate / 32; - // Determine the number of points per frame given our target frame and point rates. - let points_per_frame = (points_per_second as f32 / frames_per_second) as u16; - let mut sine_wave = SineWave { - point: 0, - points_per_frame, - frames_per_second, - }; + match self.stream .queue_commands() .data( line.into_iter() .map(|point| point.into()) - // .take(line.len() as usize) .take(n_points as usize) ) // .data(sine_wave.by_ref().take(n_points as usize)) @@ -245,11 +235,6 @@ impl Device for EtherdreamDevice { } } -// Determine the number of points needed to fill the DAC. -fn points_to_generate(dac: ðer_dream::dac::Dac) -> usize { - dac.buffer_capacity as usize - 1 - dac.status.buffer_fullness as usize -} - // An iterator that endlessly generates a sine wave of DAC points. // // The sine wave oscillates at a rate of once per second. diff --git a/src/device/helios.rs b/src/device/helios.rs index 19a346c..0971aeb 100644 --- a/src/device/helios.rs +++ b/src/device/helios.rs @@ -1,3 +1,4 @@ +use std::time::SystemTime; /// /// Configure udev: /// https://github.com/Grix/helios_dac/blob/master/docs/udev_rules_for_linux.md @@ -14,7 +15,7 @@ use crate::conf::HeliosConf; use crate::device::{Device, Status, PlaybackState}; use crate::errors::{LJError, LJResult}; use crate::point::{Color, Point}; -use chrono::Utc; +use chrono::{DateTime, Utc}; pub struct HeliosDevice { pub conf: HeliosConf, @@ -34,13 +35,17 @@ impl HeliosDevice { return Err(Box::new(LJError::HeliosDeviceMissing)); }; let dac = device.open()?; + let now = SystemTime::now(); + let now: DateTime = now.into(); + let last_traced_at = now.to_rfc3339(); + Ok(Self { conf: (*conf).clone(), dac, sent_points: 0, state: PlaybackState::PREPARE, lack: "".to_string(), - last_traced_at: "1985-04-12T23:20:50.52Z".to_string(), + last_traced_at, }) } } diff --git a/src/point.rs b/src/point.rs index 9f88f43..6ce6268 100644 --- a/src/point.rs +++ b/src/point.rs @@ -1,15 +1,4 @@ use ether_dream::protocol::DacPoint; -use log::debug; - -fn clamp(val: f32, min: f32, max: f32) -> f32 { - if val < min { - return min; - } - if val > max { - return max; - } - val -} #[derive(Debug, Clone, Copy, Default, PartialEq)] pub struct Point { @@ -56,13 +45,12 @@ impl From for helios_dac::Point { } impl From for DacPoint { - fn from(pt: Point) -> DacPoint { let control = 0; let (u1, u2) = (0, 0); let i = 255; - let x = clamp(pt.x, -32000 as f32, 32000 as f32); - let y = clamp(pt.y, -32000 as f32, 32000 as f32); + let x = pt.x.clamp(-32000.0, 32000.0); + let y = pt.y.clamp(-32000.0, 32000.0); DacPoint { control, x: x as i16, diff --git a/src/redis_ctrl.rs b/src/redis_ctrl.rs index 4fdcdde..03d7cba 100644 --- a/src/redis_ctrl.rs +++ b/src/redis_ctrl.rs @@ -17,6 +17,7 @@ pub enum Order { Intensity, Kpps, ColorBalance, + PowerOff } impl TryFrom for Order { @@ -39,6 +40,7 @@ impl TryFrom for Order { 6 => Intensity, 7 => Kpps, 8 => ColorBalance, + 9 => PowerOff, _ => unreachable!() }) }