Compare commits

..

No commits in common. "main" and "ftdi" have entirely different histories.
main ... ftdi

15 changed files with 152 additions and 318 deletions

126
Cargo.lock generated
View file

@ -1,16 +1,17 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 3
[[package]] [[package]]
name = "ELApse" name = "ELApse"
version = "0.1.5" version = "0.1.5"
dependencies = [ dependencies = [
"clap", "clap",
"ftdi-embedded-hal",
"image", "image",
"piston",
"piston2d-graphics 0.45.0",
"piston_window", "piston_window",
"rgb", "rand",
"unreal_asset", "unreal_asset",
"url", "url",
] ]
@ -540,32 +541,6 @@ version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "embedded-hal"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"
dependencies = [
"nb 0.1.3",
"void",
]
[[package]]
name = "embedded-hal"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89"
[[package]]
name = "embedded-hal-nb"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605"
dependencies = [
"embedded-hal 1.0.0",
"nb 1.1.0",
]
[[package]] [[package]]
name = "enum_dispatch" name = "enum_dispatch"
version = "0.3.13" version = "0.3.13"
@ -658,29 +633,6 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "ftdi-embedded-hal"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e328c2738c104e2649586bda4baabf376825db50014eb0d41bee74fb6064deb"
dependencies = [
"embedded-hal 0.2.7",
"embedded-hal 1.0.0",
"embedded-hal-nb",
"ftdi-mpsse",
"libftd2xx",
"nb 1.1.0",
]
[[package]]
name = "ftdi-mpsse"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7cfcda69930a8d2fdcdd7ffb9234fe4c79a8c73934ed4904327d77bfb5078a"
dependencies = [
"static_assertions",
]
[[package]] [[package]]
name = "funty" name = "funty"
version = "2.0.0" version = "2.0.0"
@ -1024,28 +976,6 @@ version = "0.2.158"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
[[package]]
name = "libftd2xx"
version = "0.32.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f20d68b3138aaabb97edc3db8ed8f418d60f8abd2a7d8220d562906fb38ff08e"
dependencies = [
"ftdi-mpsse",
"libftd2xx-ffi",
"log",
"paste",
"static_assertions",
]
[[package]]
name = "libftd2xx-ffi"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40bed7f53ea45282e0e4f1361d1a8094e62abe0ccfd9a6dbf7e3db932b2789ce"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "libfuzzer-sys" name = "libfuzzer-sys"
version = "0.4.7" version = "0.4.7"
@ -1189,21 +1119,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fce7b49e1e6d8aa67232ef1c4c936c0af58756eb2db6f65c40bacb39035e7f42" checksum = "fce7b49e1e6d8aa67232ef1c4c936c0af58756eb2db6f65c40bacb39035e7f42"
[[package]]
name = "nb"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
dependencies = [
"nb 1.1.0",
]
[[package]]
name = "nb"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
[[package]] [[package]]
name = "ndk" name = "ndk"
version = "0.7.0" version = "0.7.0"
@ -1518,7 +1433,7 @@ dependencies = [
"gfx", "gfx",
"piston-gfx_texture", "piston-gfx_texture",
"piston-shaders_graphics2d", "piston-shaders_graphics2d",
"piston2d-graphics", "piston2d-graphics 0.44.0",
"shader_version", "shader_version",
] ]
@ -1537,6 +1452,19 @@ dependencies = [
"vecmath", "vecmath",
] ]
[[package]]
name = "piston2d-graphics"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efa81d40c7b656d270fdbfeef8c531cc04493a001937f5a7d0c5cdb3db2b1469"
dependencies = [
"interpolation",
"piston-texture",
"piston-viewport",
"read_color",
"vecmath",
]
[[package]] [[package]]
name = "piston_window" name = "piston_window"
version = "0.132.0" version = "0.132.0"
@ -1548,7 +1476,7 @@ dependencies = [
"piston", "piston",
"piston-texture", "piston-texture",
"piston2d-gfx_graphics", "piston2d-gfx_graphics",
"piston2d-graphics", "piston2d-graphics 0.44.0",
"pistoncore-glutin_window", "pistoncore-glutin_window",
"shader_version", "shader_version",
] ]
@ -1858,9 +1786,9 @@ checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]] [[package]]
name = "rgb" name = "rgb"
version = "0.8.52" version = "0.8.50"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c6a884d2998352bb4daf0183589aec883f16a6da1f4dde84d8e2e9a5409a1ce" checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
] ]
@ -2026,12 +1954,6 @@ dependencies = [
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]] [[package]]
name = "strict-num" name = "strict-num"
version = "0.1.1" version = "0.1.1"
@ -2342,12 +2264,6 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.11.0+wasi-snapshot-preview1" version = "0.11.0+wasi-snapshot-preview1"

View file

@ -9,16 +9,14 @@ readme = "README.md"
[dependencies] [dependencies]
clap = { version = "4.5.17", features = ["derive"] } clap = { version = "4.5.17", features = ["derive"] }
ftdi-embedded-hal = { version = "0.22.0", features = ["libftd2xx"] }
image = "0.25.2" image = "0.25.2"
piston = "1.0.0"
piston2d-graphics = "0.45.0"
piston_window = "0.132.0" piston_window = "0.132.0"
rgb = "0.8.52" rand = "0.8.5"
unreal_asset = "0.1.16" unreal_asset = "0.1.16"
url = "2.5.2" url = "2.5.2"
[profile.dev]
opt-level = 3
# The profile that 'cargo dist' will build with # The profile that 'cargo dist' will build with
[profile.dist] [profile.dist]
inherits = "release" inherits = "release"

2
rust-toolchain.toml Normal file
View file

@ -0,0 +1,2 @@
[toolchain]
channel = "nightly"

61
src/input.rs Normal file
View file

@ -0,0 +1,61 @@
#![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<Vec<[f32; 4]>>) {
let (stdintx, stdinrx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = 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<Vec<[f32; 4]>>,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<Vec<[f32; 4]>>, 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);
});
}

View file

@ -1,29 +0,0 @@
#![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<Vec<[f32; 4]>>, 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);
});
}
}

View file

@ -1,5 +0,0 @@
mod file;
mod realtimeudp;
mod stdin;
pub struct Input;

View file

@ -1,20 +0,0 @@
#![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<Vec<[f32; 4]>>, 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);
}
});
}
}

View file

@ -1,39 +0,0 @@
#![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<Vec<[f32; 4]>>) {
let (stdintx, stdinrx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = 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);
}
};
}
});
}
}

View file

@ -1,3 +1,4 @@
#![feature(array_chunks)]
mod input; mod input;
mod output; mod output;
mod parser; mod parser;
@ -7,8 +8,6 @@ mod fileparser;
use std::sync::mpsc::{self, Receiver, Sender}; use std::sync::mpsc::{self, Receiver, Sender};
use clap::Parser; use clap::Parser;
use url::Url; use url::Url;
use crate::output::Output;
use crate::input::Input;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(version, about, long_about = None)] #[command(version, about, long_about = None)]
@ -26,15 +25,15 @@ fn main() {
let args = Args::parse(); let args = Args::parse();
let (tx, rx): (Sender<Vec<[f32; 4]>>, Receiver<Vec<[f32; 4]>>) = mpsc::channel(); let (tx, rx): (Sender<Vec<[f32; 4]>>, Receiver<Vec<[f32; 4]>>) = mpsc::channel();
match args.input.as_str() { match args.input.as_str() {
"-" | "stdin" => Input::stdin(tx), "-" | "stdin" => input::stdin(tx),
_ => { _ => {
match Url::parse(&args.input) { match Url::parse(&args.input) {
Ok(o) => { Ok(o) => {
match o.scheme() { match o.scheme() {
"udp" => { "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"); println!("Unrecognized uri scheme");
std::process::exit(1); std::process::exit(1);
@ -42,19 +41,18 @@ fn main() {
} }
}, },
Err(_) => { Err(_) => {
Input::file(tx, args.input); input::file(tx, args.input);
}, },
}; };
} }
} }
match args.output.as_str() { match args.output.as_str() {
"piston" => Output::piston(rx), "piston" => output::piston(rx),
"ftd2xx" => Output::ft2dxx(rx),
_ => { _ => {
match Url::parse(&args.output) { match Url::parse(&args.output) {
Ok(o) => { Ok(o) => {
match o.scheme() { match o.scheme() {
"udp" => Output::realtimeudp(rx,utils::get_host(o)), "udp" => output::realtimeudp(rx,utils::get_host(o)),
_ => { _ => {
println!("Unrecognized uri scheme"); println!("Unrecognized uri scheme");
std::process::exit(1); std::process::exit(1);

57
src/output.rs Normal file
View file

@ -0,0 +1,57 @@
#![allow(non_camel_case_types)]
use piston_window::*;
use piston_window::graphics::math::Scalar;
use std::{net::UdpSocket, sync::mpsc::Receiver, time::Duration};
use crate::utils::{compare, offset};
pub fn piston(rx: Receiver<Vec<[f32; 4]>>) {
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<Vec<[f32; 4]>>, addr: String) {
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
loop {
let leds = rx.recv().unwrap();
let mut packet: Vec<u8> = 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);
},
};
}
}
#[derive(clap::ValueEnum, Clone, Debug)]
pub enum Output {
piston,
realtimeudp,
}

View file

@ -1,40 +0,0 @@
#![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<Vec<[f32; 4]>>) {
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<u8> = 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();
// }
}
}
}

View file

@ -1,5 +0,0 @@
mod ft2dxx;
mod piston;
mod realtimeudp;
pub struct Output;

View file

@ -1,34 +0,0 @@
#![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<Vec<[f32; 4]>>) {
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);
}
}
});
}
}
}

View file

@ -1,26 +0,0 @@
#![allow(non_camel_case_types)]
use std::{net::UdpSocket, sync::mpsc::Receiver};
use crate::output::Output;
impl Output {
pub fn realtimeudp(rx: Receiver<Vec<[f32; 4]>>, addr: String) {
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
loop {
let leds = rx.recv().unwrap();
let mut packet: Vec<u8> = 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);
}
};
}
}
}

View file

@ -34,7 +34,7 @@ pub fn parseleds(mut data: Vec<u8>, options: ParserOptions) -> Vec<[f32; 4]> {
if data.len() < expectedlen { if data.len() < expectedlen {
data.append(&mut vec![5; expectedlen-out.len()]); data.append(&mut vec![5; expectedlen-out.len()]);
} }
for x in data.as_chunks::<3>().0.iter() { for x in data.array_chunks::<3>() {
out.push([utils::scaleu8tof32(x[0]), utils::scaleu8tof32(x[1]), utils::scaleu8tof32(x[2]), 1.0]); out.push([utils::scaleu8tof32(x[0]), utils::scaleu8tof32(x[1]), utils::scaleu8tof32(x[2]), 1.0]);
if options.double && !options.mirror { if options.double && !options.mirror {
out.push(out.last().unwrap().clone()); out.push(out.last().unwrap().clone());