feat; add device status
This commit is contained in:
parent
883c72ff24
commit
526a78428b
@ -6,6 +6,7 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
chrono = "0.4.26"
|
||||||
config = "0.13.3"
|
config = "0.13.3"
|
||||||
ctrlc = "3.4.0"
|
ctrlc = "3.4.0"
|
||||||
env_logger = "0.10.0"
|
env_logger = "0.10.0"
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
use crate::point::Point;
|
|
||||||
|
|
||||||
mod helios;
|
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::device::helios::HeliosDevice;
|
||||||
use crate::errors::LJResult;
|
use crate::errors::LJResult;
|
||||||
|
use crate::point::Point;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
self.protocol_version,
|
self.protocol_version,
|
||||||
@ -18,22 +20,40 @@ self.fullness,
|
|||||||
self.point_rate,
|
self.point_rate,
|
||||||
self.point_count
|
self.point_count
|
||||||
*/
|
*/
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Copy, Clone)]
|
||||||
pub struct Status {
|
pub enum PlaybackState {
|
||||||
pub active: bool,
|
IDLE = 0,
|
||||||
pub last_traced_at: String,
|
PREPARE,
|
||||||
pub properties: Vec<String>
|
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<String>,
|
||||||
|
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 {
|
pub trait Device {
|
||||||
fn status( &self ) -> Status;
|
fn status(&self) -> Status;
|
||||||
fn draw(
|
fn draw(
|
||||||
&mut self,
|
&mut self,
|
||||||
frame: Vec<Point>,
|
frame: Vec<Point>,
|
||||||
speed: u32,
|
speed: u32,
|
||||||
) -> LJResult<()> ;
|
) -> LJResult<()>;
|
||||||
fn stop(&mut self) -> LJResult<()>;
|
fn stop(&mut self) -> LJResult<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn device_factory(config: &Conf) -> LJResult<Box<dyn Device>> {
|
pub fn device_factory(config: &Conf) -> LJResult<Box<dyn Device>> {
|
||||||
|
@ -11,13 +11,16 @@ use helios_dac::{
|
|||||||
// Point as HeliosPoint,
|
// Point as HeliosPoint,
|
||||||
};
|
};
|
||||||
use crate::conf::HeliosConf;
|
use crate::conf::HeliosConf;
|
||||||
use crate::device::{Device, Status};
|
use crate::device::{Device, Status, PlaybackState};
|
||||||
use crate::errors::{LJError, LJResult};
|
use crate::errors::{LJError, LJResult};
|
||||||
use crate::point::Point;
|
use crate::point::Point;
|
||||||
|
|
||||||
pub struct HeliosDevice {
|
pub struct HeliosDevice {
|
||||||
pub conf: HeliosConf,
|
pub conf: HeliosConf,
|
||||||
dac: NativeHeliosDac,
|
dac: NativeHeliosDac,
|
||||||
|
sent_points: u16,
|
||||||
|
state: PlaybackState,
|
||||||
|
lack: String
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HeliosDevice {
|
impl HeliosDevice {
|
||||||
@ -29,16 +32,20 @@ impl HeliosDevice {
|
|||||||
return Err(Box::new(LJError::HeliosDeviceMissing));
|
return Err(Box::new(LJError::HeliosDeviceMissing));
|
||||||
};
|
};
|
||||||
let dac = device.open()?;
|
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 {
|
impl Device for HeliosDevice {
|
||||||
fn status(&self) -> Status {
|
fn status(&self) -> Status {
|
||||||
|
|
||||||
|
let lack = self.lack.clone();
|
||||||
Status {
|
Status {
|
||||||
active: true,
|
|
||||||
last_traced_at: "now".to_string(),
|
last_traced_at: "now".to_string(),
|
||||||
properties: vec!["foo".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<Point>,
|
line: Vec<Point>,
|
||||||
speed: u32,
|
speed: u32,
|
||||||
) -> LJResult<()> {
|
) -> LJResult<()> {
|
||||||
while let Ok(DeviceStatus::NotReady) = self.dac.status() {
|
while let Ok(DeviceStatus::NotReady) = self.dac.status() {}
|
||||||
}
|
|
||||||
|
|
||||||
let points: Vec<helios_dac::Point> = line.into_iter().map(|p| p.into()).collect();
|
let points: Vec<helios_dac::Point> = 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.dac.write_frame(frame.clone())?;
|
||||||
|
self.sent_points = points.len() as u16;
|
||||||
|
self.state = PlaybackState::PLAYING;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ fn run_all() -> LJResult<()> {
|
|||||||
info!("{:?}", config);
|
info!("{:?}", config);
|
||||||
|
|
||||||
// Setup Redis Service
|
// 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
|
// Setup handler for interrupt Signals
|
||||||
let running = Arc::new(AtomicBool::new(true));
|
let running = Arc::new(AtomicBool::new(true));
|
||||||
@ -65,6 +65,7 @@ fn run_all() -> LJResult<()> {
|
|||||||
|
|
||||||
// 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())?;
|
||||||
let order = rs.get_order(config.laser_id)?;
|
let order = rs.get_order(config.laser_id)?;
|
||||||
if order != Order::Draw {
|
if order != Order::Draw {
|
||||||
info!("Order: {:?}", order);
|
info!("Order: {:?}", order);
|
||||||
|
@ -1,76 +1,99 @@
|
|||||||
use redis::{Client, Commands, Connection};
|
use redis::{Client, Commands, Connection};
|
||||||
use ron::de::from_str;
|
use ron::de::from_str;
|
||||||
use crate::errors::{LJError,LJResult};
|
use crate::device::Status;
|
||||||
|
use crate::errors::{LJError, LJResult};
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Order {
|
pub enum Order {
|
||||||
Draw = 0,
|
Draw = 0,
|
||||||
Edh, //homography
|
Edh,
|
||||||
Black,
|
//homography
|
||||||
Grid,
|
Black,
|
||||||
Resampler,
|
Grid,
|
||||||
ClientKey,
|
Resampler,
|
||||||
Intensity,
|
ClientKey,
|
||||||
Kpps,
|
Intensity,
|
||||||
ColorBalance,
|
Kpps,
|
||||||
|
ColorBalance,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<u8> for Order {
|
impl TryFrom<u8> for Order {
|
||||||
type Error = String;
|
type Error = String;
|
||||||
|
|
||||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
use Order::*;
|
use Order::*;
|
||||||
|
|
||||||
if value > 8 {
|
if value > 8 {
|
||||||
return Err("order out of range".to_string());
|
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 type Line = Vec<(f32, f32, u32)>;
|
||||||
|
|
||||||
pub struct RedisCtrl {
|
pub struct RedisCtrl {
|
||||||
pub client: Client,
|
pub client: Client,
|
||||||
pub connection: Connection,
|
pub connection: Connection,
|
||||||
|
laser_id: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RedisCtrl {
|
impl RedisCtrl {
|
||||||
pub fn new(url: &str) -> LJResult<Self> {
|
pub fn new(url: &str, laser_id: &u8) -> LJResult<Self> {
|
||||||
let client = Client::open(url)
|
let client = Client::open(url)
|
||||||
.map_err(LJError::RedisConnect)?;
|
.map_err(LJError::RedisConnect)?;
|
||||||
let connection = client.get_connection()
|
let connection = client.get_connection()
|
||||||
.map_err(LJError::RedisConnect)?;
|
.map_err(LJError::RedisConnect)?;
|
||||||
Ok(RedisCtrl { client, connection })
|
Ok(RedisCtrl { client, connection, laser_id: *laser_id })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&mut self, key: &str) -> LJResult<Line> {
|
pub fn get(&mut self, key: &str) -> LJResult<Line> {
|
||||||
let val: String = self.connection.get(key)?;
|
let val: String = self.connection.get(key)?;
|
||||||
let line: Line = from_str(&val)?;
|
let line: Line = from_str(&val)?;
|
||||||
Ok(line)
|
Ok(line)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_order(&mut self, id: u8) -> LJResult<Order> {
|
pub fn set(&mut self, key: String, value: String) -> LJResult<()> {
|
||||||
let path = format!("/order/{id}");
|
self.connection.set(key, value)?;
|
||||||
let val: u8 = self.connection.get(path.clone())?;
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
if val == 1 || val >= 4 {
|
pub fn get_order(&mut self, id: u8) -> LJResult<Order> {
|
||||||
self.connection.set(path, 0)?;
|
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(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user