114 lines
2.7 KiB
Rust
114 lines
2.7 KiB
Rust
use std::{
|
|
io,
|
|
sync::{Arc, Mutex},
|
|
thread,
|
|
time::{Duration, Instant},
|
|
};
|
|
|
|
use anyhow::{anyhow, Result};
|
|
use serialport::SerialPort;
|
|
|
|
use crate::fixtures::{DMXFixture, MovingHead};
|
|
|
|
const FPS: u32 = 50;
|
|
|
|
enum MCUResponse {
|
|
Sync,
|
|
Ack,
|
|
#[allow(dead_code)]
|
|
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>>,
|
|
movingheads: Arc<Mutex<[MovingHead; 4]>>,
|
|
) -> Result<()> {
|
|
let frame_time = Duration::from_secs_f64(1.0 / FPS as f64);
|
|
|
|
let mut dmx_buffer = [0u8; 512];
|
|
|
|
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,
|
|
}
|
|
}
|
|
|
|
'main: loop {
|
|
{
|
|
let running = running.lock().unwrap();
|
|
|
|
if !*running {
|
|
break Ok(());
|
|
}
|
|
}
|
|
|
|
let loop_start = Instant::now();
|
|
|
|
{
|
|
let movingheads = movingheads.lock().unwrap();
|
|
for head in movingheads.iter() {
|
|
head.render(&mut dmx_buffer);
|
|
}
|
|
}
|
|
|
|
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!");
|
|
}
|
|
}
|
|
}
|