201 lines
4.6 KiB
Rust
201 lines
4.6 KiB
Rust
///
|
|
/// Configure udev:
|
|
/// https://github.com/Grix/helios_dac/blob/master/docs/udev_rules_for_linux.md
|
|
///
|
|
mod redis_ctrl;
|
|
mod conf;
|
|
mod errors;
|
|
mod point;
|
|
mod transformer;
|
|
mod device;
|
|
mod worldstate;
|
|
mod framerate;
|
|
|
|
use device::device_factory;
|
|
use std::sync::atomic::{AtomicBool, Ordering};
|
|
use std::sync::Arc;
|
|
use redis_ctrl::{RedisCtrl, Order};
|
|
use conf::Conf;
|
|
use errors::LJResult;
|
|
use point::{Point, Color};
|
|
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";
|
|
|
|
pub fn main() {
|
|
match run_all() {
|
|
Ok(()) => {}
|
|
Err(err) => {
|
|
error!("Error: {}", err);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
fn run_all() -> LJResult<()> {
|
|
// Setup handler for interrupt Signals
|
|
let running = Arc::new(AtomicBool::new(true));
|
|
let r = running.clone();
|
|
ctrlc::set_handler(move || {
|
|
r.store(false, Ordering::SeqCst);
|
|
})?;
|
|
|
|
// Setup configuration file and set up logs
|
|
let filename = std::env::args().nth(1).unwrap_or_else(|| {
|
|
DEFAULT_CONF_FILE.to_string()
|
|
});
|
|
|
|
let config = Conf::new(&filename);
|
|
init_logging(&config);
|
|
let config = config?;
|
|
info!("*** Starting up ***");
|
|
|
|
info!("{:?}", config);
|
|
|
|
// Setup Redis Service
|
|
let mut rs = RedisCtrl::new(&config.redis_url, &config.laser_id)?;
|
|
|
|
let mut world_state = rs.init_world_state().unwrap();
|
|
info!("WorldState: {:?}", world_state);
|
|
|
|
|
|
// Setup Laser Device based on conf
|
|
let mut tracer = device_factory(&config)?;
|
|
world_state.grid = tracer.grid();
|
|
|
|
// 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 => {
|
|
// 0 : Draw Normal point list
|
|
// 2 : Draw BLACK point list
|
|
// 3 : Draw GRID point list
|
|
world_state.draw_black = order == Order::Black;
|
|
world_state.draw_grid = order == Order::Grid;
|
|
let frame = get_next_frame(
|
|
&config,
|
|
&transformers,
|
|
&mut rs,
|
|
&world_state,
|
|
)?;
|
|
// For now, draw all the time
|
|
tracer.draw(frame, world_state.kpps)?;
|
|
}
|
|
Order::Intensity => {
|
|
// 6 : Max Intensity Change = reread redis key /intensity
|
|
world_state.intensity = rs.get_int("intensity")?
|
|
.try_into()?;
|
|
}
|
|
Order::Edh => {
|
|
// 1 : Get the new EDH = reread redis key /EDH/lasernumber
|
|
world_state.edh = rs.get_edh()?;
|
|
}
|
|
Order::Kpps => {
|
|
// 7 : kpps change = reread redis key /kpps
|
|
world_state.kpps = rs.get_int("kpps")?;
|
|
}
|
|
Order::ClientKey => {
|
|
world_state.client_key = rs.get_client_key()?;
|
|
}
|
|
Order::ColorBalance => {
|
|
let (r, g, b) = rs.get_color_balance()?;
|
|
world_state.color_balance = Color { r, g, b };
|
|
}
|
|
Order::Resampler => {
|
|
world_state.resampler = rs.get_resampler()?;
|
|
}
|
|
_ => {
|
|
// 9 : poweroff LJ
|
|
info!("Order: {:?}", order);
|
|
}
|
|
}
|
|
}
|
|
|
|
info!("Exiting, stoping device.");
|
|
tracer.stop()?;
|
|
Ok(())
|
|
}
|
|
|
|
fn init_logging(config: &LJResult<Conf>) {
|
|
if let Ok(ref config) = config {
|
|
let level = if config.debug {
|
|
LevelFilter::Debug
|
|
} else {
|
|
LevelFilter::Info
|
|
};
|
|
let mut builder = Builder::from_default_env();
|
|
builder
|
|
.filter(None, level)
|
|
.init();
|
|
info!("Debug mode enabled from configuration file");
|
|
return;
|
|
}
|
|
info!("Logging level inherited from env");
|
|
env_logger::init();
|
|
}
|
|
|
|
fn get_next_frame(
|
|
config: &Conf,
|
|
transformers: &[Box<dyn Transformers>],
|
|
rs: &mut RedisCtrl,
|
|
world_state: &WorldState,
|
|
) -> LJResult<Vec<Point>> {
|
|
let format_key = format!("{}{}",
|
|
world_state.client_key,
|
|
config.laser_id);
|
|
|
|
// Handle the grid case
|
|
|
|
let mut line: Vec<Point> = if world_state.draw_grid {
|
|
world_state.grid.clone()
|
|
} else {
|
|
let redis_line = rs.get_line(&format_key)?;
|
|
redis_line.into_iter()
|
|
.map(|tpl| tpl.into())
|
|
.collect()
|
|
};
|
|
|
|
for transformer in transformers {
|
|
line = transformer.apply(&line, world_state);
|
|
}
|
|
|
|
// info!("Draw Black -> {}", world_state.draw_black);
|
|
// info!("Draw Grid -> {}", world_state.draw_grid);
|
|
|
|
// LIMITER and BLACK
|
|
line = line.into_iter()
|
|
.map(|p| {
|
|
let color = if world_state.draw_black {
|
|
Color { r: 0, g: 0, b: 0 }
|
|
} else {
|
|
Color {
|
|
r: p.color.r.min(world_state.intensity),
|
|
g: p.color.g.min(world_state.intensity),
|
|
b: p.color.b.min(world_state.intensity),
|
|
}
|
|
};
|
|
Point {
|
|
color,
|
|
..p
|
|
}
|
|
})
|
|
.collect();
|
|
|
|
//info!("Line: {:?}", line);
|
|
Ok(line)
|
|
}
|
|
|