diff --git a/Cargo.toml b/Cargo.toml index 18f311d..9789221 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +chrono = "0.4.26" config = "0.13.3" ctrlc = "3.4.0" env_logger = "0.10.0" diff --git a/src/device.rs b/src/device.rs index d85d95a..0947bf2 100644 --- a/src/device.rs +++ b/src/device.rs @@ -1,10 +1,12 @@ -use crate::point::Point; mod helios; -use crate::conf::{Conf, DacFamily, /*EtherDreamConf, HeliosConf*/}; +use std::fmt; +use crate::conf::{Conf, DacFamily /*EtherDreamConf, HeliosConf*/}; use crate::device::helios::HeliosDevice; use crate::errors::LJResult; +use crate::point::Point; +use serde::Serialize; /* self.protocol_version, @@ -18,22 +20,40 @@ self.fullness, self.point_rate, self.point_count */ - - -pub struct Status { - pub active: bool, - pub last_traced_at: String, - pub properties: Vec +#[repr(u8)] +#[derive(Debug, PartialEq, Serialize, Copy, Clone)] +pub enum PlaybackState { + IDLE = 0, + PREPARE, + PLAYING, +} +impl fmt::Display for PlaybackState { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self) + } } +#[derive(Debug)] +pub struct Status { + pub last_traced_at: String, + pub properties: Vec, + pub playback_state: PlaybackState, + pub capacity: u16, + pub lack: String +} + +// /lstt/lasernumber etherdream last_status.playback_state (0: idle 1: prepare 2: playing) +// /cap/lasernumber number of empty points sent to fill etherdream buffer (up to 1799) +// /lack/lasernumber "a": ACK "F": Full "I": invalid. 64 or 35 for no connection. + pub trait Device { - fn status( &self ) -> Status; - fn draw( - &mut self, - frame: Vec, - speed: u32, - ) -> LJResult<()> ; - fn stop(&mut self) -> LJResult<()>; + fn status(&self) -> Status; + fn draw( + &mut self, + frame: Vec, + speed: u32, + ) -> LJResult<()>; + fn stop(&mut self) -> LJResult<()>; } pub fn device_factory(config: &Conf) -> LJResult> { diff --git a/src/device/helios.rs b/src/device/helios.rs index f607bb8..2e1041c 100644 --- a/src/device/helios.rs +++ b/src/device/helios.rs @@ -11,13 +11,16 @@ use helios_dac::{ // Point as HeliosPoint, }; use crate::conf::HeliosConf; -use crate::device::{Device, Status}; +use crate::device::{Device, Status, PlaybackState}; use crate::errors::{LJError, LJResult}; use crate::point::Point; pub struct HeliosDevice { pub conf: HeliosConf, dac: NativeHeliosDac, + sent_points: u16, + state: PlaybackState, + lack: String } impl HeliosDevice { @@ -29,16 +32,20 @@ impl HeliosDevice { return Err(Box::new(LJError::HeliosDeviceMissing)); }; let dac = device.open()?; - Ok(Self { conf: (*conf).clone(), dac }) + Ok(Self { conf: (*conf).clone(), dac, sent_points: 0, state: PlaybackState::IDLE, lack: "".to_string() }) } } impl Device for HeliosDevice { fn status(&self) -> Status { + + let lack = self.lack.clone(); Status { - active: true, last_traced_at: "now".to_string(), properties: vec!["foo".to_string()], + playback_state: self.state, + capacity: self.sent_points, + lack, } } @@ -46,12 +53,13 @@ impl Device for HeliosDevice { line: Vec, speed: u32, ) -> LJResult<()> { - while let Ok(DeviceStatus::NotReady) = self.dac.status() { - } + while let Ok(DeviceStatus::NotReady) = self.dac.status() {} let points: Vec = line.into_iter().map(|p| p.into()).collect(); - let frame = Frame::new(speed, points); + let frame = Frame::new(speed, points.clone()); self.dac.write_frame(frame.clone())?; + self.sent_points = points.len() as u16; + self.state = PlaybackState::PLAYING; Ok(()) } diff --git a/src/main.rs b/src/main.rs index 020dce3..2cf7953 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,7 +45,7 @@ fn run_all() -> LJResult<()> { info!("{:?}", config); // Setup Redis Service - let mut rs = RedisCtrl::new(&config.redis_url)?; + let mut rs = RedisCtrl::new(&config.redis_url, &config.laser_id)?; // Setup handler for interrupt Signals let running = Arc::new(AtomicBool::new(true)); @@ -65,6 +65,7 @@ fn run_all() -> LJResult<()> { // Dispatch based on redis requests while running.load(Ordering::SeqCst) { + rs.set_status( tracer.status())?; let order = rs.get_order(config.laser_id)?; if order != Order::Draw { info!("Order: {:?}", order); diff --git a/src/redis_ctrl.rs b/src/redis_ctrl.rs index 7ae8d9f..448ed43 100644 --- a/src/redis_ctrl.rs +++ b/src/redis_ctrl.rs @@ -1,76 +1,99 @@ use redis::{Client, Commands, Connection}; use ron::de::from_str; -use crate::errors::{LJError,LJResult}; +use crate::device::Status; +use crate::errors::{LJError, LJResult}; #[repr(u8)] #[derive(Debug, PartialEq)] pub enum Order { - Draw = 0, - Edh, //homography - Black, - Grid, - Resampler, - ClientKey, - Intensity, - Kpps, - ColorBalance, + Draw = 0, + Edh, + //homography + Black, + Grid, + Resampler, + ClientKey, + Intensity, + Kpps, + ColorBalance, } impl TryFrom for Order { - type Error = String; + type Error = String; - fn try_from(value: u8) -> Result { - use Order::*; + fn try_from(value: u8) -> Result { + use Order::*; - if value > 8 { - return Err("order out of range".to_string()); + if value > 8 { + return Err("order out of range".to_string()); + } + + Ok(match value { + 0 => Draw, + 1 => Edh, + 2 => Black, + 3 => Grid, + 4 => Resampler, + 5 => ClientKey, + 6 => Intensity, + 7 => Kpps, + 8 => ColorBalance, + _ => unreachable!() + }) } - - Ok(match value { - 0 => Draw, - 1 => Edh, - 2 => Black, - 3 => Grid, - 4 => Resampler, - 5 => ClientKey, - 6 => Intensity, - 7 => Kpps, - 8 => ColorBalance, - _ => unreachable!() - }) - } } pub type Line = Vec<(f32, f32, u32)>; pub struct RedisCtrl { - pub client: Client, - pub connection: Connection, + pub client: Client, + pub connection: Connection, + laser_id: u8, } impl RedisCtrl { - pub fn new(url: &str) -> LJResult { - let client = Client::open(url) - .map_err(LJError::RedisConnect)?; - let connection = client.get_connection() - .map_err(LJError::RedisConnect)?; - Ok(RedisCtrl { client, connection }) - } + pub fn new(url: &str, laser_id: &u8) -> LJResult { + let client = Client::open(url) + .map_err(LJError::RedisConnect)?; + let connection = client.get_connection() + .map_err(LJError::RedisConnect)?; + Ok(RedisCtrl { client, connection, laser_id: *laser_id }) + } - pub fn get(&mut self, key: &str) -> LJResult { - let val: String = self.connection.get(key)?; - let line: Line = from_str(&val)?; - Ok(line) - } + pub fn get(&mut self, key: &str) -> LJResult { + let val: String = self.connection.get(key)?; + let line: Line = from_str(&val)?; + Ok(line) + } - pub fn get_order(&mut self, id: u8) -> LJResult { - let path = format!("/order/{id}"); - let val: u8 = self.connection.get(path.clone())?; + pub fn set(&mut self, key: String, value: String) -> LJResult<()> { + self.connection.set(key, value)?; + Ok(()) + } - if val == 1 || val >= 4 { - self.connection.set(path, 0)?; - } + pub fn get_order(&mut self, id: u8) -> LJResult { + let path = format!("/order/{id}"); + let val: u8 = self.connection.get(path.clone())?; - Ok(val.try_into()?) - } + if val == 1 || val >= 4 { + self.connection.set(path, 0)?; + } + + Ok(val.try_into()?) + } + + /** + /lstt/lasernumber etherdream last_status.playback_state (0: idle 1: prepare 2: playing) + /cap/lasernumber number of empty points sent to fill etherdream buffer (up to 1799) + /lack/lasernumber "a": ACK "F": Full "I": invalid. 64 or 35 for no connection. + **/ + pub fn set_status(&mut self, status: Status) -> LJResult<()> { + let lstt_key = format!("/lstt/{}", self.laser_id); + let cap_key = format!("/cap/{}", self.laser_id); + let lack_key = format!("/lack/{}", self.laser_id); + self.set(lstt_key, status.playback_state.to_string())?; + self.set(cap_key, status.capacity.to_string())?; + self.set(lack_key, status.lack.to_string())?; + Ok(()) + } }