init: set your eyes

This commit is contained in:
alban 2023-07-24 23:32:18 +02:00
commit cc9966bf73
10 changed files with 285 additions and 0 deletions

24
src/conf.rs Normal file
View file

@ -0,0 +1,24 @@
use std::error::Error;
use config::Config;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Conf {
pub debug: bool,
pub laser_id: u8,
pub client_id: u8,
pub redis_url: String,
pub framerate: u8,
}
impl Conf {
pub fn new(path: &str) -> Result<Conf, Box<dyn Error>> {
let settings = Config::builder()
.add_source(config::File::with_name(path))
.build()?;
let conf: Conf = settings.try_deserialize()?;
Ok(conf)
}
}

20
src/draw.rs Normal file
View file

@ -0,0 +1,20 @@
// This is where you can put your custom code
use crate::{Color, Point};
const RADIUS: f32 = 2000.0;
const X_CENTER: f32 = 2047.0;
const Y_CENTER: f32 = 2047.0;
pub fn draw() -> Result<Vec<Point>, Box<dyn std::error::Error>> {
let mut v: Vec<Point> = vec![];
for i in 0..128 {
let a = i as f32 / 128.0 * std::f32::consts::PI * 2.0;
v.push(Point {
x: (X_CENTER + a.cos() * RADIUS) as f32,
y: (Y_CENTER + a.sin() * RADIUS) as f32,
color: Color { r: 255, g: 255, b: 255 },
});
}
Ok(v)
}

38
src/framerate.rs Normal file
View file

@ -0,0 +1,38 @@
use log::{debug, warn};
use std::time::{Duration, Instant};
use std::{thread};
/// Converts helios Geometry to Helios
#[derive(Debug, Clone, Copy)]
pub struct Framerate {
prev_trace_time: Instant,
framerate: u8,
}
impl Framerate {
pub fn new(framerate: u8) -> Result<Self, Box<dyn std::error::Error>> {
Ok(Framerate {
prev_trace_time: Instant::now(),
framerate,
})
}
pub fn handle_time(&mut self) -> Result<(), Box<dyn std::error::Error>> {
let frame_time = 1000000000 / self.framerate 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 slower than expected {:?} > {:?}", nanotime_spent, frame_time, );
}
self.prev_trace_time = now;
Ok(())
}
}

19
src/logs.rs Normal file
View file

@ -0,0 +1,19 @@
use env_logger::Builder;
use log::LevelFilter;
use crate::Conf;
pub fn init_logging(config: &Result<Conf, Box<dyn std::error::Error>>) {
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();
return;
}
env_logger::init();
}

66
src/main.rs Normal file
View file

@ -0,0 +1,66 @@
///
/// Configure udev:
/// https://github.com/Grix/helios_dac/blob/master/docs/udev_rules_for_linux.md
///
mod conf;
mod point;
mod draw;
mod logs;
mod framerate;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use conf::Conf;
use point::{Point, Color};
use log::{info, /* warn, */ error};
use redis::{Client, Commands, Connection};
use logs::init_logging;
const DEFAULT_CONF_FILE: &str = "settings.toml";
pub fn main() {
match run_all() {
Ok(()) => {}
Err(err) => {
error!("Error: {}", err);
}
}
}
fn run_all() -> Result<(), Box<dyn std::error::Error>> {
// 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?;
let client = Client::open(config.redis_url.clone())?;
let mut con: Connection = client.get_connection()?;
let mut framerate_handler = framerate::Framerate::new( config.framerate )?;
info!("*** Starting up ***");
info!("{:?}", config);
// Dispatch based on redis requests
while running.load(Ordering::SeqCst) {
let _ = framerate_handler.handle_time();
let points_list: Vec<Point> = draw::draw()?;
let v: Vec<(f32, f32, u32)> = points_list.iter().map(|pt| {
(pt.x, pt.y, u32::from(pt.color))
}
).collect();
// println!("{:?}", v);
let _ = con.set(format!("/pl/{}/{}", config.client_id, config.laser_id), format!("{:?}", v))?;
}
Ok(())
}

40
src/point.rs Normal file
View file

@ -0,0 +1,40 @@
pub type Line = Vec<(f32, f32, u32)>;
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub struct Point {
pub x: f32,
pub y: f32,
pub color: Color,
}
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub struct Color {
pub r: u8,
pub g: u8,
pub b: u8,
}
impl From<Color> for u32 {
fn from(value: Color) -> Self {
let r = value.r as u32;
let g = value.g as u32;
let b = (value.b) as u32;
(r << 16) + (g << 8) + b
}
}
impl From<(f32, f32, u32)> for Point {
fn from((x, y, color): (f32, f32, u32)) -> Point {
let r = (color >> 16) as u8;
let g = ((color >> 8) & 255) as u8;
let b = (color & 255) as u8;
Point { x, y, color: Color { r, g, b } }
}
}
impl From<Point> for (f32, f32, u32) {
fn from(pt : Point ) -> (f32, f32, u32) {
(pt.x,pt.y,pt.color.into())
}
}