From 4f959d217de25d2176f4c486a4fb5099480784f5 Mon Sep 17 00:00:00 2001 From: BlackDragon Date: Sun, 3 Aug 2025 18:51:35 +0200 Subject: [PATCH] Replace array_chunks feature and refactoring --- Cargo.lock | 14 ++---- Cargo.toml | 4 +- rust-toolchain.toml | 2 - src/input.rs | 61 -------------------------- src/input/file.rs | 29 +++++++++++++ src/input/mod.rs | 5 +++ src/input/realtimeudp.rs | 20 +++++++++ src/input/stdin.rs | 39 +++++++++++++++++ src/main.rs | 17 ++++---- src/output.rs | 91 --------------------------------------- src/output/ft2dxx.rs | 40 +++++++++++++++++ src/output/mod.rs | 5 +++ src/output/piston.rs | 34 +++++++++++++++ src/output/realtimeudp.rs | 26 +++++++++++ src/parser.rs | 2 +- 15 files changed, 213 insertions(+), 176 deletions(-) delete mode 100644 rust-toolchain.toml delete mode 100644 src/input.rs create mode 100644 src/input/file.rs create mode 100644 src/input/mod.rs create mode 100644 src/input/realtimeudp.rs create mode 100644 src/input/stdin.rs delete mode 100644 src/output.rs create mode 100644 src/output/ft2dxx.rs create mode 100644 src/output/mod.rs create mode 100644 src/output/piston.rs create mode 100644 src/output/realtimeudp.rs diff --git a/Cargo.lock b/Cargo.lock index 7d1ba60..ea6bc68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "ELApse" @@ -10,6 +10,7 @@ dependencies = [ "ftdi-embedded-hal", "image", "piston_window", + "rgb", "unreal_asset", "url", ] @@ -1857,9 +1858,9 @@ checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rgb" -version = "0.8.50" +version = "0.8.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" +checksum = "0c6a884d2998352bb4daf0183589aec883f16a6da1f4dde84d8e2e9a5409a1ce" dependencies = [ "bytemuck", ] @@ -2297,13 +2298,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "usbintled" -version = "0.1.0" -dependencies = [ - "ELApse", -] - [[package]] name = "utf8parse" version = "0.2.2" diff --git a/Cargo.toml b/Cargo.toml index a468c77..bea2079 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ clap = { version = "4.5.17", features = ["derive"] } ftdi-embedded-hal = { version = "0.22.0", features = ["libftd2xx"] } image = "0.25.2" piston_window = "0.132.0" +rgb = "0.8.52" unreal_asset = "0.1.16" url = "2.5.2" @@ -23,9 +24,6 @@ opt-level = 3 inherits = "release" lto = "thin" -[workspace] -members = ["usbintled"] - # Config for 'cargo dist' [workspace.metadata.dist] # The preferred cargo-dist version to use in CI (Cargo.toml SemVer syntax) diff --git a/rust-toolchain.toml b/rust-toolchain.toml deleted file mode 100644 index 5d56faf..0000000 --- a/rust-toolchain.toml +++ /dev/null @@ -1,2 +0,0 @@ -[toolchain] -channel = "nightly" diff --git a/src/input.rs b/src/input.rs deleted file mode 100644 index e3651f5..0000000 --- a/src/input.rs +++ /dev/null @@ -1,61 +0,0 @@ -#![allow(non_camel_case_types)] -use std::{io::Read, net::UdpSocket, sync::mpsc::{self, Receiver, Sender}, thread, time::{Duration, Instant}}; -use crate::{ parser, fileparser }; - -pub fn stdin(tx: Sender>) { - let (stdintx, stdinrx): (Sender>, Receiver>) = mpsc::channel(); - thread::spawn( move || { - let mut buf = [0; 1500]; - let mut e = std::io::stdin().lock(); - loop { - let amt = e.read(&mut buf).unwrap(); - if buf[..amt].to_vec().len() > 0 { - let _ = stdintx.send(buf[..amt].to_vec()); - } - } - }); - thread::spawn( move || { - loop { - // let amt = e.read(&mut buf).unwrap(); - match stdinrx.recv_timeout(Duration::from_millis(500)) { - Ok(d) => { - let r: Vec<[f32; 4]> = parser::parseleds(d, parser::ParserOptions::default().mirror(true).double(true).offset(15)); - let _ = tx.send(r); - }, - Err(_) => { - std::process::exit(0); - }, - }; - } - }); -} - -pub fn realtimeudp(tx: Sender>,bindaddr: String) { - thread::spawn( move || { - let socket = UdpSocket::bind(bindaddr).unwrap(); - let mut buf = [0; 1500]; - loop { - let (amt, _src) = socket.recv_from(&mut buf).unwrap(); - let r = parser::parseleds(buf[..amt].to_vec(), parser::ParserOptions::default().stripheader(2)); - let _ = tx.send(r); - } - }); -} - -pub fn file(tx: Sender>, path: String) { - thread::spawn( move || { - let Ok(rawbytes) = fileparser::parse(&path) else { - println!("File not found"); - std::process::exit(1) - }; - for frame in rawbytes.chunks(720) { - let st = Instant::now(); - let r = parser::parseleds(frame.to_vec(), parser::ParserOptions::default().mirror(true).double(true).offset(15)); - let _ = tx.send(r); - if Duration::from_secs_f32(1.0/60.0) > st.elapsed() { - thread::sleep(Duration::from_secs_f32(1.0/60.0)-st.elapsed()); - }; - } - std::process::exit(0); - }); -} diff --git a/src/input/file.rs b/src/input/file.rs new file mode 100644 index 0000000..fe6809a --- /dev/null +++ b/src/input/file.rs @@ -0,0 +1,29 @@ +#![allow(non_camel_case_types)] +use std::{sync::mpsc::Sender, thread, time::{Duration, Instant}}; +use crate::{fileparser, input::Input, parser}; + +impl Input { + pub fn file(tx: Sender>, path: String) { + thread::spawn(move || { + let Ok(rawbytes) = fileparser::parse(&path) else { + println!("File not found"); + std::process::exit(1) + }; + for frame in rawbytes.chunks(720) { + let st = Instant::now(); + let r = parser::parseleds( + frame.to_vec(), + parser::ParserOptions::default() + .mirror(true) + .double(true) + .offset(15), + ); + let _ = tx.send(r); + if Duration::from_secs_f32(1.0 / 60.0) > st.elapsed() { + thread::sleep(Duration::from_secs_f32(1.0 / 60.0) - st.elapsed()); + }; + } + std::process::exit(0); + }); + } +} diff --git a/src/input/mod.rs b/src/input/mod.rs new file mode 100644 index 0000000..d55c709 --- /dev/null +++ b/src/input/mod.rs @@ -0,0 +1,5 @@ +mod file; +mod realtimeudp; +mod stdin; + +pub struct Input; \ No newline at end of file diff --git a/src/input/realtimeudp.rs b/src/input/realtimeudp.rs new file mode 100644 index 0000000..017a693 --- /dev/null +++ b/src/input/realtimeudp.rs @@ -0,0 +1,20 @@ +#![allow(non_camel_case_types)] +use std::{net::UdpSocket, sync::mpsc::Sender, thread}; +use crate::{input::Input, parser}; + +impl Input { + pub fn realtimeudp(tx: Sender>, bindaddr: String) { + thread::spawn(move || { + let socket = UdpSocket::bind(bindaddr).unwrap(); + let mut buf = [0; 1500]; + loop { + let (amt, _src) = socket.recv_from(&mut buf).unwrap(); + let r = parser::parseleds( + buf[..amt].to_vec(), + parser::ParserOptions::default().stripheader(2), + ); + let _ = tx.send(r); + } + }); + } +} diff --git a/src/input/stdin.rs b/src/input/stdin.rs new file mode 100644 index 0000000..97e2327 --- /dev/null +++ b/src/input/stdin.rs @@ -0,0 +1,39 @@ +#![allow(non_camel_case_types)] +use std::{io::Read, sync::mpsc::{self, Receiver, Sender}, thread, time::Duration}; +use crate::{input::Input, parser}; + +impl Input { + pub fn stdin(tx: Sender>) { + let (stdintx, stdinrx): (Sender>, Receiver>) = mpsc::channel(); + thread::spawn(move || { + let mut buf = [0; 1500]; + let mut e = std::io::stdin().lock(); + loop { + let amt = e.read(&mut buf).unwrap(); + if buf[..amt].to_vec().len() > 0 { + let _ = stdintx.send(buf[..amt].to_vec()); + } + } + }); + thread::spawn(move || { + loop { + // let amt = e.read(&mut buf).unwrap(); + match stdinrx.recv_timeout(Duration::from_millis(500)) { + Ok(d) => { + let r: Vec<[f32; 4]> = parser::parseleds( + d, + parser::ParserOptions::default() + .mirror(true) + .double(true) + .offset(15), + ); + let _ = tx.send(r); + } + Err(_) => { + std::process::exit(0); + } + }; + } + }); + } +} diff --git a/src/main.rs b/src/main.rs index a1bc929..947cd29 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,3 @@ -#![feature(array_chunks)] mod input; mod output; mod parser; @@ -8,6 +7,8 @@ mod fileparser; use std::sync::mpsc::{self, Receiver, Sender}; use clap::Parser; use url::Url; +use crate::output::Output; +use crate::input::Input; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] @@ -25,15 +26,15 @@ fn main() { let args = Args::parse(); let (tx, rx): (Sender>, Receiver>) = mpsc::channel(); match args.input.as_str() { - "-" | "stdin" => input::stdin(tx), + "-" | "stdin" => Input::stdin(tx), _ => { match Url::parse(&args.input) { Ok(o) => { match o.scheme() { "udp" => { - input::realtimeudp(tx, utils::get_host(o)); + Input::realtimeudp(tx, utils::get_host(o)); }, - "file" => input::file(tx, o.path().to_owned()), + "file" => Input::file(tx, o.path().to_owned()), _ => { println!("Unrecognized uri scheme"); std::process::exit(1); @@ -41,19 +42,19 @@ fn main() { } }, Err(_) => { - input::file(tx, args.input); + Input::file(tx, args.input); }, }; } } match args.output.as_str() { - "piston" => output::piston(rx), - "ftd2xx" => output::ft2dxx(rx), + "piston" => Output::piston(rx), + "ftd2xx" => Output::ft2dxx(rx), _ => { match Url::parse(&args.output) { Ok(o) => { match o.scheme() { - "udp" => output::realtimeudp(rx,utils::get_host(o)), + "udp" => Output::realtimeudp(rx,utils::get_host(o)), _ => { println!("Unrecognized uri scheme"); std::process::exit(1); diff --git a/src/output.rs b/src/output.rs deleted file mode 100644 index 55916d0..0000000 --- a/src/output.rs +++ /dev/null @@ -1,91 +0,0 @@ -#![allow(non_camel_case_types)] - -use piston_window::*; -use piston_window::graphics::math::Scalar; -use std::{net::UdpSocket, sync::mpsc::Receiver, time::Duration}; - -use ftdi_embedded_hal::eh0::prelude::_embedded_hal_blocking_spi_Write; -use ftdi_embedded_hal::{self as hal, libftd2xx}; - -use crate::utils::{compare, offset}; - -pub fn piston(rx: Receiver>) { - let mut window: PistonWindow = - WindowSettings::new("ELApse", [800, 800]) - .transparent(true) - .exit_on_esc(true).build().unwrap(); - while let Some(e) = window.next() { - let r = match rx.recv_timeout(Duration::from_millis(66)) { - Ok(e) => e, - Err(_) => vec![[0.02, 0.02, 0.02, 1.0]; 480], - }; - - let size = window.size(); - let wh = compare(size.height, size.width)*0.75; - window.draw_2d(&e, |c, g, _device| { - for e in 1..9 { - for i in 0..60 { - let rwh = wh*(1.0-(e as f64*0.06)); - circle_arc(r[i*8+(e-1)], rwh/32.0, Scalar::deg_to_rad(offset((((360/60)*i)) as i16, 360, 90) as f64), Scalar::deg_to_rad(offset((((360/60)*i)+6) as i16, 360, 90) as f64), [(size.width/2.0)-(rwh/2.0), (size.height/2.0)-(rwh/2.0), rwh, rwh], c.transform, g); - } - } - }); - } -} - -pub fn realtimeudp(rx: Receiver>, addr: String) { - let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); - loop { - let leds = rx.recv().unwrap(); - let mut packet: Vec = vec![2, 2]; - for led in leds { - packet.push((led[0]*255.0) as u8); - packet.push((led[1]*255.0) as u8); - packet.push((led[2]*255.0) as u8); - } - match socket.send_to(&packet, &addr) { - Ok(_) => (), - Err(err) => { - println!("Error while sending trying to send data: {}", err); - std::process::exit(1); - }, - }; - } -} - -pub fn ft2dxx(rx: Receiver>) { - let device = libftd2xx::Ft232h::with_description("Single RS232-HS").unwrap(); - println!("Connected to FT232H"); - - let hal = hal::FtHal::init_freq(device, 3_000_000).unwrap(); - let mut spi = hal.spi().unwrap(); - - // led stuff - loop { - let leds = rx.recv().unwrap(); - let mut fdata: Vec = Vec::new(); - for led in leds { - let sled = [led[1],led[0],led[2]]; //Shift colors (be gone when I make a color struct) - for i in 0..3 { - let mut data = (sled[i].clone()*255.0) as u8; - let patterns = [0b1000_1000, 0b1000_1110, 0b11101000, 0b11101110]; - for _ in 0..4 { - let bits = (data & 0b1100_0000) >> 6; - fdata.push(patterns[bits as usize]); - data <<= 2; - } - } - } - let _ = spi.write(&fdata); - // for _ in 0..140 { - // spi.write(std::array::from_ref(&0)).unwrap(); - // } - } -} - -#[derive(clap::ValueEnum, Clone, Debug)] -pub enum Output { - piston, - realtimeudp, - ft2dxx, -} \ No newline at end of file diff --git a/src/output/ft2dxx.rs b/src/output/ft2dxx.rs new file mode 100644 index 0000000..dc41ed6 --- /dev/null +++ b/src/output/ft2dxx.rs @@ -0,0 +1,40 @@ +#![allow(non_camel_case_types)] + +use std::sync::mpsc::Receiver; + +use ftdi_embedded_hal::eh0::prelude::_embedded_hal_blocking_spi_Write; +use ftdi_embedded_hal::{self as hal, libftd2xx}; + +use crate::output::Output; + +impl Output { + pub fn ft2dxx(rx: Receiver>) { + let device = libftd2xx::Ft232h::with_description("Single RS232-HS").unwrap(); + println!("Connected to FT232H"); + + let hal = hal::FtHal::init_freq(device, 3_000_000).unwrap(); + let mut spi = hal.spi().unwrap(); + + // led stuff + loop { + let leds = rx.recv().unwrap(); + let mut fdata: Vec = Vec::new(); + for led in leds { + let sled = [led[1], led[0], led[2]]; //Shift colors (be gone when I make a color struct) + for i in 0..3 { + let mut data = (sled[i].clone() * 255.0) as u8; + let patterns = [0b1000_1000, 0b1000_1110, 0b11101000, 0b11101110]; + for _ in 0..4 { + let bits = (data & 0b1100_0000) >> 6; + fdata.push(patterns[bits as usize]); + data <<= 2; + } + } + } + let _ = spi.write(&fdata); + // for _ in 0..140 { + // spi.write(std::array::from_ref(&0)).unwrap(); + // } + } + } +} diff --git a/src/output/mod.rs b/src/output/mod.rs new file mode 100644 index 0000000..ba7dbb1 --- /dev/null +++ b/src/output/mod.rs @@ -0,0 +1,5 @@ +mod ft2dxx; +mod piston; +mod realtimeudp; + +pub struct Output; \ No newline at end of file diff --git a/src/output/piston.rs b/src/output/piston.rs new file mode 100644 index 0000000..baa41b9 --- /dev/null +++ b/src/output/piston.rs @@ -0,0 +1,34 @@ +#![allow(non_camel_case_types)] + +use piston_window::*; +use piston_window::graphics::math::Scalar; +use std::{sync::mpsc::Receiver, time::Duration}; + +use crate::output::Output; +use crate::utils::{compare, offset}; + +impl Output { + pub fn piston(rx: Receiver>) { + let mut window: PistonWindow = + WindowSettings::new("ELApse", [800, 800]) + .transparent(true) + .exit_on_esc(true).build().unwrap(); + while let Some(e) = window.next() { + let r = match rx.recv_timeout(Duration::from_millis(66)) { + Ok(e) => e, + Err(_) => vec![[0.02, 0.02, 0.02, 1.0]; 480], + }; + + let size = window.size(); + let wh = compare(size.height, size.width)*0.75; + window.draw_2d(&e, |c, g, _device| { + for e in 1..9 { + for i in 0..60 { + let rwh = wh*(1.0-(e as f64*0.06)); + circle_arc(r[i*8+(e-1)], rwh/32.0, Scalar::deg_to_rad(offset((((360/60)*i)) as i16, 360, 90) as f64), Scalar::deg_to_rad(offset((((360/60)*i)+6) as i16, 360, 90) as f64), [(size.width/2.0)-(rwh/2.0), (size.height/2.0)-(rwh/2.0), rwh, rwh], c.transform, g); + } + } + }); + } + } +} diff --git a/src/output/realtimeudp.rs b/src/output/realtimeudp.rs new file mode 100644 index 0000000..706ce3e --- /dev/null +++ b/src/output/realtimeudp.rs @@ -0,0 +1,26 @@ +#![allow(non_camel_case_types)] +use std::{net::UdpSocket, sync::mpsc::Receiver}; + +use crate::output::Output; + +impl Output { + pub fn realtimeudp(rx: Receiver>, addr: String) { + let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); + loop { + let leds = rx.recv().unwrap(); + let mut packet: Vec = vec![2, 2]; + for led in leds { + packet.push((led[0] * 255.0) as u8); + packet.push((led[1] * 255.0) as u8); + packet.push((led[2] * 255.0) as u8); + } + match socket.send_to(&packet, &addr) { + Ok(_) => (), + Err(err) => { + println!("Error while sending trying to send data: {}", err); + std::process::exit(1); + } + }; + } + } +} diff --git a/src/parser.rs b/src/parser.rs index 6dbb229..3a887e4 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -34,7 +34,7 @@ pub fn parseleds(mut data: Vec, options: ParserOptions) -> Vec<[f32; 4]> { if data.len() < expectedlen { data.append(&mut vec![5; expectedlen-out.len()]); } - for x in data.array_chunks::<3>() { + for x in data.as_chunks::<3>().0.iter() { out.push([utils::scaleu8tof32(x[0]), utils::scaleu8tof32(x[1]), utils::scaleu8tof32(x[2]), 1.0]); if options.double && !options.mirror { out.push(out.last().unwrap().clone());