forked from protonphoton/lj_templates_rust
init: set your eyes
This commit is contained in:
commit
cc9966bf73
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
debug/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||||
|
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||||
|
Cargo.lock
|
||||||
|
|
||||||
|
# These are backup files generated by rustfmt
|
||||||
|
**/*.rs.bk
|
||||||
|
|
||||||
|
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
# Configuration file
|
||||||
|
settings.*
|
||||||
|
|
||||||
|
.idea
|
17
Cargo.toml
Normal file
17
Cargo.toml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
[package]
|
||||||
|
name = "lj_templates_rust"
|
||||||
|
version = "0.1.0"
|
||||||
|
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"
|
||||||
|
log = "0.4.18"
|
||||||
|
redis = "0.23.0"
|
||||||
|
toml = "0.7.4"
|
||||||
|
serde = { version = "1.0.163", features = ["derive"] }
|
25
README.md
Normal file
25
README.md
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# LJ Template for Rust
|
||||||
|
|
||||||
|
**This project is a basic program for building rust programs compatible with the protonphoton LJ project.**
|
||||||
|
|
||||||
|
Use this code as a basis and let the laser points be with you.
|
||||||
|
|
||||||
|
**Crash course**
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
$ git clone https://git.interhacker.space/protonphoton/lj_templates_rust && cd lj_templates_rust
|
||||||
|
|
||||||
|
# Create a settings file, see the content for more details including redis server url
|
||||||
|
$ cp copyme.settings.toml settings.toml && $EDITOR settings.toml
|
||||||
|
|
||||||
|
# Run the projet
|
||||||
|
$ cargo run
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Associate projects
|
||||||
|
|
||||||
|
**The LJ rust tracer projet and the nannou visualiser might be of help to simulate your project.**
|
||||||
|
|
||||||
|
Todo: make a full tutorial for that
|
17
copyme.settings.toml
Normal file
17
copyme.settings.toml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# file: settings.toml
|
||||||
|
# Rename me !
|
||||||
|
|
||||||
|
# The main key of your laser in LJ
|
||||||
|
laser_id = 0
|
||||||
|
|
||||||
|
# Your client id in LJ
|
||||||
|
client_id = 0
|
||||||
|
|
||||||
|
# Activate for more debug
|
||||||
|
debug = true
|
||||||
|
|
||||||
|
# How many Frames Per Second
|
||||||
|
framerate = 20
|
||||||
|
|
||||||
|
# Redis URL as redis://IP:port/
|
||||||
|
redis_url = "redis://127.0.0.1:6379/"
|
24
src/conf.rs
Normal file
24
src/conf.rs
Normal 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
20
src/draw.rs
Normal 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
38
src/framerate.rs
Normal 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
19
src/logs.rs
Normal 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
66
src/main.rs
Normal 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
40
src/point.rs
Normal 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())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user