Implement beat detection -> dmx output
This commit is contained in:
118
beat_detection/src/dmx_controller.rs
Normal file
118
beat_detection/src/dmx_controller.rs
Normal 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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user