Implement beat detection -> dmx output

This commit is contained in:
2021-10-27 22:44:51 +02:00
parent b0fecde639
commit 9f07172f60
5 changed files with 233 additions and 17 deletions

View File

@@ -0,0 +1,118 @@
use std::{io, sync::{Arc, Mutex}, thread, time::{Duration, Instant}};
use anyhow::{anyhow, Result};
use palette::{Hsl, IntoColor, Pixel, Srgb};
use serialport::SerialPort;
use crate::fixtures::{DMXFixture, MovingHead};
const FPS: u32 = 50;
enum MCUResponse {
Sync,
Ack,
Info { num_pkts: u32 },
}
fn poll_response(ser: &mut dyn SerialPort) -> Result<MCUResponse> {
let mut read_buffer = vec![0u8; 32];
let bytes_read;
loop {
match ser.read(read_buffer.as_mut_slice()) {
Ok(t) => {
bytes_read = t;
break;
}
Err(ref e) if e.kind() == io::ErrorKind::TimedOut => continue,
Err(e) => Err(e),
}?
}
let response = std::str::from_utf8(&read_buffer[..bytes_read])?;
match response.trim() {
"Sync." => Ok(MCUResponse::Sync),
"Ack." => Ok(MCUResponse::Ack),
s if s.starts_with("Info") => Ok(MCUResponse::Info { num_pkts: 69 }),
s => Err(anyhow!("Unknown response: \"{}\"", s)),
}
}
pub fn controller_thread(running: Arc<Mutex<bool>>, brightness: Arc<Mutex<f32>>) -> Result<()> {
let frame_time = Duration::from_secs_f64(1.0 / FPS as f64);
let hsl_cycle = 12 * FPS;
let mut dmx_buffer = [0u8; 512];
let mut movinghead = MovingHead::new(1);
let mut ser = serialport::new("/dev/ttyUSB0", 500_000)
.timeout(Duration::from_millis(10))
.open()?;
// wait for initial sync
loop {
match poll_response(&mut *ser) {
Ok(MCUResponse::Sync) => break,
_ => continue,
}
}
let mut t = 0;
'main: loop {
{
let running = running.lock().unwrap();
if !*running {
break Ok(());
}
}
let loop_start = Instant::now();
let hsl: Srgb = Hsl::new(360.0 * (t as f32 / hsl_cycle as f32), 1.0, 0.5).into_color();
let [r, g, b]: [u8; 3] = hsl.into_format().into_raw();
movinghead.rgbw = (r, g, b, 0);
movinghead.dimmer = {
let brightness = brightness.lock().unwrap();
0.2 + 0.8 * *brightness
};
movinghead.render(&mut dmx_buffer);
t += 1;
t %= hsl_cycle;
let write_result = ser.write(&dmx_buffer);
if write_result.is_err() {
loop {
match poll_response(&mut *ser) {
Ok(MCUResponse::Sync) => continue 'main,
_ => continue,
}
}
}
loop {
match poll_response(&mut *ser) {
Ok(MCUResponse::Ack) => break,
Ok(MCUResponse::Info { .. }) | Err(_) => continue,
Ok(MCUResponse::Sync) => continue 'main,
}
}
let loop_time = loop_start.elapsed();
if loop_time < frame_time {
thread::sleep(frame_time - loop_time);
} else {
println!("loop took too long!");
}
}
}