use std::{io, thread};
use serial_arbiter::*;
use std::time::*;
fn main() -> io::Result<()> {
let port = Arbiter::new();
let rpm = 5.0;
let pwr = 0.1;
let mut id = 1;
let mut angle;
let mut now = Instant::now() - Duration::from_secs(1);
let mut print_time = Instant::now();
let start = Instant::now();
loop {
port.close();
if let Err(err) = port.open("/dev/tty-usb-to-led-1") {
println!("Cannot connecto: {err}");
thread::sleep(Duration::from_secs(1));
continue;
}
loop {
let elapsed = now.elapsed();
now = Instant::now();
if now >= print_time {
eprintln!("Frequency: {} Hz", (1.0 / elapsed.as_secs_f32()).floor());
print_time = now + Duration::from_secs(1);
}
id += 1;
angle = start.elapsed().as_secs_f32().rem_euclid(1.0) * rpm;
let request = make_request(id, angle, pwr);
let deadline = Instant::now() + Duration::from_millis(100);
if let Err(err) = port.transmit_str(&request, deadline) {
println!("Cannot transmitto: {err}");
thread::sleep(Duration::from_secs(1));
break;
}
let deadline = Instant::now() + Duration::from_millis(1);
if let Err(err) = port.receive_string(deadline) {
println!("Cannot recivio: {err}");
thread::sleep(Duration::from_secs(1));
break;
}
}
}
}
fn make_request(id: usize, angle: f32, power: f32) -> String {
let mut pixels = [0; 12];
let sprite = get_pixel_index(angle);
pixels[sprite.i0] = (power * 255.0 * (1.0 - sprite.ratio)).round() as u8;
pixels[sprite.i1] = (power * 255.0 * sprite.ratio).round() as u8;
let mut channels = [0; 36];
for i in 0..pixels.len() {
channels[3 * i + 1] = pixels[i];
}
let request = format!("{}\n", r#"{"jsonrpc":"2.0","id":{id},"method":"set_pixels","params":{channels}}"#);
let request = request.replace("{id}", &id.to_string());
let request = request.replace("{channels}", &format!("{channels:?}"));
request
}
#[derive(Debug, PartialEq, PartialOrd)]
struct PixelIndex {
i0: usize,
i1: usize,
ratio: f32,
}
fn get_pixel_index(angle: f32) -> PixelIndex {
let a = 12.0 * angle.rem_euclid(1.0);
let i0 = a.floor() as usize;
let i1 = if i0 < 11 { i0 + 1 } else { 0 };
let ratio = a.rem_euclid(1.0);
PixelIndex { i0, i1, ratio }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_getting_pixel_index() {
let p = 1.0 / 12.0;
assert_eq!(get_pixel_index(p * 0.00), PixelIndex { i0: 0, i1: 1, ratio: 0.00 });
assert_eq!(get_pixel_index(p * 1.00), PixelIndex { i0: 1, i1: 2, ratio: 0.00 });
assert_eq!(get_pixel_index(p * 2.00), PixelIndex { i0: 2, i1: 3, ratio: 0.00 });
assert_eq!(get_pixel_index(p * 3.00), PixelIndex { i0: 3, i1: 4, ratio: 0.00 });
assert_eq!(get_pixel_index(p * 3.50), PixelIndex { i0: 3, i1: 4, ratio: 0.50000024 });
assert_eq!(get_pixel_index(p * 3.75), PixelIndex { i0: 3, i1: 4, ratio: 0.75 });
assert_eq!(get_pixel_index(p * 6.00), PixelIndex { i0: 6, i1: 7, ratio: 0.00 });
assert_eq!(get_pixel_index(p * 8.11), PixelIndex { i0: 8, i1: 9, ratio: 0.11000061 });
assert_eq!(get_pixel_index(p * 8.44), PixelIndex { i0: 8, i1: 9, ratio: 0.43999958 });
assert_eq!(get_pixel_index(p * 8.99), PixelIndex { i0: 8, i1: 9, ratio: 0.9899998 });
assert_eq!(get_pixel_index(p * 11.0), PixelIndex { i0: 11, i1: 0, ratio: 0.00 });
assert_eq!(get_pixel_index(p * 11.9), PixelIndex { i0: 11, i1: 0, ratio: 0.8999996 });
assert_eq!(get_pixel_index(p * 12.0), PixelIndex { i0: 0, i1: 1, ratio: 0.00 });
}
}