Compare commits

..

5 Commits

Author SHA1 Message Date
alban
22d7d3c718 fix: i in point for etherdream is meh 2023-07-24 17:35:39 +02:00
alban
514f4cc7c9 fix: etherdream should work with device trait adjustments 2023-07-24 17:35:15 +02:00
alban
6f04925ea5 feat: add framerate with fixed value for now (20Hz) 2023-07-24 17:34:06 +02:00
alban
3ce346306f feat: add helios to etherdream transformer 2023-07-24 17:29:33 +02:00
alban
ff96bdf6fa fix: etherdream example 2023-07-24 17:28:18 +02:00
12 changed files with 202 additions and 55 deletions

View File

@ -129,7 +129,7 @@ impl Iterator for SineWave {
_ => (std::u16::MAX, std::u16::MAX, std::u16::MAX), _ => (std::u16::MAX, std::u16::MAX, std::u16::MAX),
}; };
let x_min = std::i16::MIN; 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 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 y = (amp * x_max as f32) as i16;
let control = 0; let control = 0;

46
examples/test.rs Normal file
View File

@ -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();
}

View File

@ -48,7 +48,9 @@ pub enum TransformConf {
#[serde(rename = "grid")] #[serde(rename = "grid")]
Grid(transformer::Grid), Grid(transformer::Grid),
#[serde(rename = "homography")] #[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::FlipV(r) => Box::new(*r),
TransformConf::Grid(r) => Box::new(*r), TransformConf::Grid(r) => Box::new(*r),
TransformConf::Homography(r) => Box::new(*r), TransformConf::Homography(r) => Box::new(*r),
TransformConf::HeliosToEtherdream(r) => Box::new(*r),
}; };
v.push(t); v.push(t);
} }

View File

@ -42,7 +42,7 @@ pub struct Status {
pub last_traced_at: String, pub last_traced_at: String,
pub properties: Vec<String>, pub properties: Vec<String>,
pub playback_state: PlaybackState, pub playback_state: PlaybackState,
pub capacity: u16, pub capacity: usize,
pub lack: String, pub lack: String,
} }

View File

@ -1,16 +1,20 @@
use std::time; #[warn(unused_imports)]
use log::{ debug, info, warn};
use std::net::SocketAddr; use std::net::SocketAddr;
use std::thread::sleep;
use ether_dream::dac::stream::{CommunicationError, connect}; use ether_dream::dac::stream::{CommunicationError, connect};
use ether_dream::dac::{Playback, Stream}; use ether_dream::dac::{Playback, Stream};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use std::time::SystemTime; use std::time;
use std::time::{Duration, SystemTime};
use crate::conf::EtherDreamConf; use crate::conf::EtherDreamConf;
use crate::device::{Device, Status, PlaybackState}; use crate::device::{Device, Status, PlaybackState};
use crate::errors::{LJError, LJResult}; use crate::errors::{LJError, LJResult};
use crate::point::{Color, Point}; use crate::point::{Color, Point};
use ether_dream::protocol::{DacBroadcast, DacResponse}; use ether_dream::protocol::{DacBroadcast, DacResponse};
use log::{debug, info, warn};
#[warn(dead_code)] #[warn(dead_code)]
pub struct EtherdreamDevice { pub struct EtherdreamDevice {
@ -114,14 +118,20 @@ impl EtherdreamDevice {
Ok(stream) Ok(stream)
} }
fn points_capacity(&self) -> u16 { fn points_capacity(&self) -> usize {
/*** /***
Determine the number of points needed to fill the DAC. 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 // 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 n_points
} }
fn ping(&mut self) -> LJResult<()> {
Ok(self.stream.queue_commands().ping().submit()?)
}
} }
impl Device for EtherdreamDevice { impl Device for EtherdreamDevice {
@ -135,62 +145,72 @@ impl Device for EtherdreamDevice {
let now: DateTime<Utc> = now.into(); let now: DateTime<Utc> = now.into();
let now = now.to_rfc3339(); let now = now.to_rfc3339();
let status = Status { Status {
last_traced_at: now, last_traced_at: now,
properties: vec!["foo".to_string()], properties: vec!["foo".to_string()],
playback_state, playback_state,
capacity: self.points_capacity(), capacity: self.points_capacity(),
lack: self.dac_response.to_string(), lack: self.dac_response.to_string(),
}; }
// debug!("Dac Status: {:?} ", status ); // debug!("Dac Status: {:?} ", status );
// debug!("Etherdream Dac {:?} ", self.dac ); // debug!("Etherdream Dac {:?} ", self.dac );
debug!("Stream dac{:?}", self.stream.dac()); // debug!("Stream dac{:?}", self.stream.dac());
status // status
} }
fn draw(&mut self, fn draw(&mut self,
line: Vec<Point>, line: Vec<Point>,
_speed: u32, _speed: u32,
) -> LJResult<()> { ) -> LJResult<()> {
let n_points = self.points_capacity(); let chunk_size = 64;
// let n_points = &line.len(); let points_iter = line.into_iter();
debug!("Etherdream::device draw Generating {:?} points", n_points); for chunk in points_iter.as_slice().chunks(chunk_size){
debug!("New chunk length: {:?}", chunk.len());
loop {
match self.stream let capacity = self.points_capacity();
.queue_commands() if chunk.len() > capacity as usize {
.data( debug!("Sleep, capacity : {:?}", capacity);
line.into_iter() // Sleep for 1/100th of a sec
.map(|point| point.into()) sleep(Duration::new( 0, 10000000));
.take(n_points as usize) self.ping();
) } else {
// .data(sine_wave.by_ref().take(n_points as usize)) break;
}
.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(_) => { debug!("drawing");
self.dac_response = DacResponse::ACK; match self.stream
debug!("Draw is ok"); .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(()) Ok(())
} }
@ -274,7 +294,7 @@ impl Iterator for SineWave {
u1, u1,
u2, u2,
}; };
debug!("{:?}",p); // debug!("{:?}",p);
self.point += 1; self.point += 1;
Some(p) Some(p)
} }

View File

@ -57,7 +57,7 @@ impl Device for HeliosDevice {
last_traced_at: self.last_traced_at.clone(), last_traced_at: self.last_traced_at.clone(),
properties: vec!["foo".to_string()], properties: vec!["foo".to_string()],
playback_state: self.state, playback_state: self.state,
capacity: self.sent_points, capacity: self.sent_points as usize,
lack, lack,
} }
} }

39
src/framerate.rs Normal file
View File

@ -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<Self> {
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(())
}
}

View File

@ -5,3 +5,4 @@ pub mod device;
pub mod point; pub mod point;
pub mod transformer; pub mod transformer;
pub mod worldstate; pub mod worldstate;
pub mod framerate;

View File

@ -9,6 +9,7 @@ mod point;
mod transformer; mod transformer;
mod device; mod device;
mod worldstate; mod worldstate;
mod framerate;
use device::device_factory; use device::device_factory;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
@ -21,6 +22,7 @@ use transformer::Transformers;
use log::{LevelFilter, info, /* warn, */ error}; use log::{LevelFilter, info, /* warn, */ error};
use env_logger::Builder; use env_logger::Builder;
use worldstate::WorldState; use worldstate::WorldState;
use framerate::Framerate;
const DEFAULT_CONF_FILE: &str = "settings.toml"; const DEFAULT_CONF_FILE: &str = "settings.toml";
@ -68,9 +70,13 @@ fn run_all() -> LJResult<()> {
// Setup geometry transformers on points lists // Setup geometry transformers on points lists
let transformers = config.get_transformers(); let transformers = config.get_transformers();
// Setup framerate limiter
let mut framerate_handler = Framerate::new()?;
// Dispatch based on redis requests // Dispatch based on redis requests
while running.load(Ordering::SeqCst) { while running.load(Ordering::SeqCst) {
rs.set_status(tracer.status())?; rs.set_status(tracer.status())?;
let _ = framerate_handler.handle_time()?;
let order = rs.get_order(config.laser_id)?; let order = rs.get_order(config.laser_id)?;
match order { match order {
Order::Draw | Order::Black | Order::Grid => { Order::Draw | Order::Black | Order::Grid => {

View File

@ -1,5 +1,6 @@
use ether_dream::protocol::DacPoint; use ether_dream::protocol::DacPoint;
#[derive(Debug, Clone, Copy, Default, PartialEq)] #[derive(Debug, Clone, Copy, Default, PartialEq)]
pub struct Point { pub struct Point {
pub x: f32, pub x: f32,
@ -48,10 +49,10 @@ impl From<Point> for DacPoint {
fn from(pt: Point) -> DacPoint { fn from(pt: Point) -> DacPoint {
let control = 0; let control = 0;
let (u1, u2) = (0, 0); let (u1, u2) = (0, 0);
let i = 255; let i = 0;
let x = pt.x.clamp(-32000.0, 32000.0); let x = pt.x.clamp(-32000.0, 32000.0);
let y = pt.y.clamp(-32000.0, 32000.0); let y = pt.y.clamp(-32000.0, 32000.0);
DacPoint { let pt = DacPoint {
control, control,
x: x as i16, x: x as i16,
y: y as i16, y: y as i16,
@ -61,6 +62,8 @@ impl From<Point> for DacPoint {
b: (pt.color.b as u16) * 255, b: (pt.color.b as u16) * 255,
u1, u1,
u2, u2,
} };
// debug!("point {:?}", pt);
pt
} }
} }

View File

@ -6,6 +6,7 @@ mod flip_horizontal;
mod flip_vertical; mod flip_vertical;
mod grid; mod grid;
mod homography; mod homography;
mod helios_to_etherdream;
use crate::point::Point; use crate::point::Point;
use crate::worldstate::WorldState; use crate::worldstate::WorldState;
@ -18,6 +19,7 @@ pub use flip_horizontal::FlipHorizontal;
pub use flip_vertical::FlipVertical; pub use flip_vertical::FlipVertical;
pub use grid::Grid; pub use grid::Grid;
pub use self::homography::Homography; pub use self::homography::Homography;
pub use helios_to_etherdream::HeliosToEtherdream;
pub trait Transformers { pub trait Transformers {
fn apply( fn apply(

View File

@ -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<Point> {
// 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
}
}