From 5865cd9d21a3ae60d569e25c6863e1ff8f905cf3 Mon Sep 17 00:00:00 2001 From: 4yn Date: Mon, 14 Feb 2022 02:04:06 +0800 Subject: [PATCH] diva draft --- src-slider_io/src/bin/test_async.rs | 69 +++++++------- src-slider_io/src/bin/test_brokenithm.rs | 25 ++--- src-slider_io/src/bin/test_diva.rs | 27 ++++++ src-slider_io/src/bin/test_serial.rs | 8 +- src-slider_io/src/bin/test_usb.rs | 111 ++++++++++++----------- src-slider_io/src/bin/test_worker.rs | 54 ++++++----- src-slider_io/src/context.rs | 84 +++++++++-------- src-slider_io/src/device/diva.rs | 100 +++++++++++++++----- src-slider_io/src/lib.rs | 18 ++-- src-slider_io/src/shared/mod.rs | 1 + src-slider_io/src/shared/serial.rs | 31 +++++++ src-tauri/Cargo.lock | 4 +- 12 files changed, 334 insertions(+), 198 deletions(-) create mode 100644 src-slider_io/src/bin/test_diva.rs create mode 100644 src-slider_io/src/shared/serial.rs diff --git a/src-slider_io/src/bin/test_async.rs b/src-slider_io/src/bin/test_async.rs index ca685db..10d3893 100644 --- a/src-slider_io/src/bin/test_async.rs +++ b/src-slider_io/src/bin/test_async.rs @@ -5,41 +5,42 @@ use std::{future::Future, io, time::Duration}; use tokio::{select, time::sleep}; -// use slidershim::slider_io::worker::{AsyncJob, AsyncWorker}; +use slider_io::shared::worker::{AsyncHaltableJob, AsyncHaltableWorker}; -// struct CounterJob; +struct CounterJob; -// #[async_trait] -// impl AsyncJob for CounterJob { -// async fn run + Send>(self, stop_signal: F) { -// let job_a = async { -// println!("Start job A"); -// let mut x = 0; -// loop { -// x += 1; -// println!("{}", x); -// sleep(Duration::from_millis(100)).await; -// } -// }; -// let job_b = async move { -// println!("Start job B"); -// stop_signal.await; -// println!("Stop signal hit at job B"); -// }; +#[async_trait] +impl AsyncHaltableJob for CounterJob { + async fn run + Send>(self, stop_signal: F) { + let job_a = async { + println!("Start job A"); + let mut x = 0; + loop { + x += 1; + println!("{}", x); + sleep(Duration::from_millis(500)).await; + } + }; + let job_b = async move { + println!("Start job B"); + stop_signal.await; + println!("Stop signal hit at job B"); + }; -// select! { -// _ = job_a => {}, -// _ = job_b => {}, -// } -// } -// } - -fn main() { - env_logger::Builder::new() - .filter_level(log::LevelFilter::Debug) - .init(); - - // let worker = AsyncWorker::new("counter", CounterJob); - let mut input = String::new(); - let string = io::stdin().read_line(&mut input).unwrap(); + select! { + _ = job_a => {}, + _ = job_b => {}, + } + } +} + +#[tokio::main] +async fn main() { + env_logger::Builder::new() + .filter_level(log::LevelFilter::Debug) + .init(); + + let _worker = AsyncHaltableWorker::new("counter", CounterJob); + let mut input = String::new(); + io::stdin().read_line(&mut input).unwrap(); } diff --git a/src-slider_io/src/bin/test_brokenithm.rs b/src-slider_io/src/bin/test_brokenithm.rs index a1276d7..65511d4 100644 --- a/src-slider_io/src/bin/test_brokenithm.rs +++ b/src-slider_io/src/bin/test_brokenithm.rs @@ -1,19 +1,20 @@ extern crate slider_io; -use std::{io, time::Duration}; +use std::io; -use tokio::time::sleep; +use slider_io::{ + device::brokenithm::BrokenithmJob, shared::worker::AsyncHaltableWorker, state::SliderState, +}; -// use slidershim::slider_io::{ -// brokenithm::BrokenithmJob, controller_state::FullState, worker::AsyncWorker, -// }; +#[tokio::main] +async fn main() { + env_logger::Builder::new() + .filter_level(log::LevelFilter::Debug) + .init(); -fn main() { - env_logger::Builder::new() - .filter_level(log::LevelFilter::Debug) - .init(); + let state = SliderState::new(); - // let worker = AsyncWorker::new("brokenithm", BrokenithmJob::new(FullState::new())); - let mut input = String::new(); - let string = io::stdin().read_line(&mut input).unwrap(); + let _worker = AsyncHaltableWorker::new("brokenithm", BrokenithmJob::new(&state, &false, &false)); + let mut input = String::new(); + io::stdin().read_line(&mut input).unwrap(); } diff --git a/src-slider_io/src/bin/test_diva.rs b/src-slider_io/src/bin/test_diva.rs new file mode 100644 index 0000000..77285d3 --- /dev/null +++ b/src-slider_io/src/bin/test_diva.rs @@ -0,0 +1,27 @@ +extern crate slider_io; + +use std::io; + +use slider_io::{ + device::diva, + shared::{utils::LoopTimer, worker::ThreadWorker}, + state::SliderState, +}; + +fn main() { + env_logger::Builder::new() + .filter_level(log::LevelFilter::Debug) + .init(); + + let state = SliderState::new(); + + let timer = LoopTimer::new(); + let _worker = ThreadWorker::new( + "d", + diva::DivaSliderJob::new(&state, &"COM5".to_string()), + timer, + ); + + let mut input = String::new(); + io::stdin().read_line(&mut input).unwrap(); +} diff --git a/src-slider_io/src/bin/test_serial.rs b/src-slider_io/src/bin/test_serial.rs index 8ab7d74..23c9ee8 100644 --- a/src-slider_io/src/bin/test_serial.rs +++ b/src-slider_io/src/bin/test_serial.rs @@ -4,8 +4,8 @@ use serialport::available_ports; use std::io; fn main() { - let res = available_ports(); - println!("{:?}", res); - let mut input = String::new(); - let string = io::stdin().read_line(&mut input).unwrap(); + let res = available_ports(); + println!("{:?}", res); + let mut input = String::new(); + io::stdin().read_line(&mut input).unwrap(); } diff --git a/src-slider_io/src/bin/test_usb.rs b/src-slider_io/src/bin/test_usb.rs index ec1be49..1e1f390 100644 --- a/src-slider_io/src/bin/test_usb.rs +++ b/src-slider_io/src/bin/test_usb.rs @@ -2,63 +2,72 @@ extern crate slider_io; use std::io; -// use slidershim::slider_io::{Config, Context}; +use slider_io::config::Config; fn main() { - env_logger::Builder::new() - .filter_level(log::LevelFilter::Debug) - .init(); + env_logger::Builder::new() + .filter_level(log::LevelFilter::Debug) + .init(); - // voltex? - // let config = Config::from_str( - // r#"{ - // "deviceMode": "yuancon", - // "outputMode": "gamepad-voltex", - // "keyboardSensitivity": 50, - // "ledMode": "reactive-voltex", - // "ledSensitivity": 50 - // }"#, - // ) - // .unwrap(); + // voltex? + let config = Config::from_str( + r#"{ + "deviceMode": "yuancon", + "outputMode": "gamepad-voltex", + "outputPolling": "60", + "keyboardSensitivity": 50, + "ledMode": "reactive-voltex", + "ledSensitivity": 50 + }"#, + ) + .unwrap(); + println!("{:?}", config); - // serial? - // let config = Config::from_str( - // r#"{ - // "deviceMode": "yuancon", - // "outputMode": "kb-32-tasoller", - // "keyboardSensitivity": 50, - // "ledMode": "serial", - // "ledSerialPort": "COM5" - // }"#, - // ) - // .unwrap(); + // serial? + let config = Config::from_str( + r#"{ + "deviceMode": "yuancon", + "outputMode": "kb-32-tasoller", + "outputPolling": "60", + "keyboardSensitivity": 50, + "ledMode": "serial", + "ledSerialPort": "COM5" + }"#, + ) + .unwrap(); + println!("{:?}", config); - // basic - // let config = Config::from_str( - // r#"{ - // "deviceMode": "yuancon", - // "outputMode": "kb-32-tasoller", - // "keyboardSensitivity": 50,fdwdfp1 - // "ledMode": "reactive-8", - // "ledSensitivity": 50 - // }"#, - // ) - // .unwrap(); + // basic + let config = Config::from_str( + r#"{ + "deviceMode": "yuancon", + "outputMode": "kb-32-tasoller", + "keyboardSensitivity": 50, + "outputPolling": "60", + "ledMode": "reactive-8", + "ledSensitivity": 50 + }"#, + ) + .unwrap(); + println!("{:?}", config); - // tasoller/ - // let config = Config::from_str( - // r#"{ - // "deviceMode": "tasoller-two", - // "outputMode": "kb-32-tasoller", - // "keyboardSensitivity": 50, - // "ledMode": "reactive-8", - // "ledSensitivity": 50 - // }"#, - // ) - // .unwrap(); + // tasoller/ + let config = Config::from_str( + r#"{ + "deviceMode": "tasoller-two", + "outputMode": "kb-32-tasoller", + "outputPolling": "60", + "keyboardSensitivity": 50, + "ledMode": "reactive-8", + "ledSensitivity": 50 + }"#, + ) + .unwrap(); - // let manager = Context::new(config); + println!("{:?}", config); - let mut input = String::new(); - let string = io::stdin().read_line(&mut input).unwrap(); + // let manager = Context::new(config); + + let mut input = String::new(); + io::stdin().read_line(&mut input).unwrap(); } diff --git a/src-slider_io/src/bin/test_worker.rs b/src-slider_io/src/bin/test_worker.rs index 0fd9aca..d773eae 100644 --- a/src-slider_io/src/bin/test_worker.rs +++ b/src-slider_io/src/bin/test_worker.rs @@ -1,31 +1,41 @@ extern crate slider_io; -use std::io; +use std::{io, thread::sleep, time::Duration}; -// use slidershim::slider_io::worker::{Job, Worker}; +use slider_io::shared::{ + utils::LoopTimer, + worker::{ThreadJob, ThreadWorker}, +}; -// struct TestJob { -// data: i64, -// } +struct TestJob { + data: i64, +} -// impl Job for TestJob { -// fn setup(&mut self) { -// self.data = 10; -// println!("setup {}", self.data); -// } -// fn tick(&mut self) { -// self.data -= 1; -// println!("tick {}", self.data); -// } -// fn teardown(&mut self) { -// self.data = 11; -// println!("teardown {}", self.data); -// } -// } +impl ThreadJob for TestJob { + fn setup(&mut self) -> bool { + self.data = 0; + println!("setup {}", self.data); + true + } + fn tick(&mut self) -> bool { + self.data += 1; + println!("tick {}", self.data); + sleep(Duration::from_millis(500)); + true + } +} + +impl Drop for TestJob { + fn drop(&mut self) { + self.data = -1; + println!("teardown {}", self.data); + } +} fn main() { - // let worker = Worker::new(TestJob { data: 1 }); + let timer = LoopTimer::new(); + let _worker = ThreadWorker::new("j", TestJob { data: 1 }, timer); - let mut input = String::new(); - let string = io::stdin().read_line(&mut input).unwrap(); + let mut input = String::new(); + io::stdin().read_line(&mut input).unwrap(); } diff --git a/src-slider_io/src/context.rs b/src-slider_io/src/context.rs index 6c66d0e..2a4559a 100644 --- a/src-slider_io/src/context.rs +++ b/src-slider_io/src/context.rs @@ -19,6 +19,7 @@ pub struct Context { state: SliderState, config: Config, device_thread_worker: Option, + device_async_worker: Option, device_async_haltable_worker: Option, output_worker: Option, lights_worker: Option, @@ -35,43 +36,47 @@ impl Context { let state = SliderState::new(); let mut timers = vec![]; - let (device_worker, brokenithm_worker) = match &config.device_mode { - DeviceMode::None => (None, None), - DeviceMode::Brokenithm { - ground_only, - lights_enabled, - } => ( - None, - Some(AsyncHaltableWorker::new( - "brokenithm", - BrokenithmJob::new(&state, ground_only, lights_enabled), - )), - ), - DeviceMode::Hardware { spec } => ( - { - let timer = LoopTimer::new(); - timers.push(("d", timer.fork())); - Some(ThreadWorker::new( - "device", - HidJob::from_config(&state, spec), - timer, - )) - }, - None, - ), - DeviceMode::DivaSlider { port } => ( - { - let timer = LoopTimer::new(); - timers.push(("d", timer.fork())); - Some(ThreadWorker::new( - "diva", - DivaSliderJob::new(&state, port), - timer, - )) - }, - None, - ), - }; + let (device_thread_worker, device_async_worker, device_async_haltable_worker) = + match &config.device_mode { + DeviceMode::None => (None, None, None), + DeviceMode::Brokenithm { + ground_only, + lights_enabled, + } => ( + None, + None, + Some(AsyncHaltableWorker::new( + "brokenithm", + BrokenithmJob::new(&state, ground_only, lights_enabled), + )), + ), + DeviceMode::Hardware { spec } => ( + { + let timer = LoopTimer::new(); + timers.push(("d", timer.fork())); + Some(ThreadWorker::new( + "device", + HidJob::from_config(&state, spec), + timer, + )) + }, + None, + None, + ), + DeviceMode::DivaSlider { port } => ( + { + let timer = LoopTimer::new(); + timers.push(("d", timer.fork())); + Some(ThreadWorker::new( + "diva", + DivaSliderJob::new(&state, port), + timer, + )) + }, + None, + None, + ), + }; let output_worker = match &config.output_mode { OutputMode::None => None, _ => { @@ -100,8 +105,9 @@ impl Context { Self { state, config, - device_thread_worker: device_worker, - device_async_haltable_worker: brokenithm_worker, + device_thread_worker, + device_async_worker, + device_async_haltable_worker, output_worker, lights_worker, timers, diff --git a/src-slider_io/src/device/diva.rs b/src-slider_io/src/device/diva.rs index e8cbc2b..a449195 100644 --- a/src-slider_io/src/device/diva.rs +++ b/src-slider_io/src/device/diva.rs @@ -1,8 +1,17 @@ use log::{error, info}; -use serialport::SerialPort; -use std::{collections::VecDeque, num::Wrapping, thread::sleep, time::Duration}; +use serialport::{COMPort, SerialPort}; +use std::{ + collections::VecDeque, + io::{Read, Write}, + num::Wrapping, + thread::sleep, + time::Duration, +}; -use crate::{shared::worker::ThreadJob, state::SliderState}; +use crate::{ + shared::{serial::ReadWriteTimeout, worker::ThreadJob}, + state::SliderState, +}; struct DivaPacket { command: u8, @@ -98,15 +107,20 @@ impl DivaDeserializer { } fn deserialize(&mut self, data: &[u8], out: &mut VecDeque) { + // println!("Found data"); for c in data { match c { 0xff => { self.packet = DivaPacket::new(); self.packet.checksum = Wrapping(0xff); self.state = DivaDeserializerState::ExpectCommand; + self.escape = 0; + + // println!("{} open", c); } 0xfd => { self.escape = 1; + // println!("esc {}", c); } c => { let c = c + self.escape; @@ -117,6 +131,8 @@ impl DivaDeserializer { DivaDeserializerState::ExpectCommand => { self.packet.command = c; self.state = DivaDeserializerState::ExpectLen; + + // println!("cmd {}", c); } DivaDeserializerState::ExpectLen => { self.len = c; @@ -125,6 +141,7 @@ impl DivaDeserializer { 0 => DivaDeserializerState::ExpectChecksum, _ => DivaDeserializerState::ExpectData, }; + // println!("len {}", c); } DivaDeserializerState::ExpectData => { self.packet.data.push(c); @@ -133,8 +150,11 @@ impl DivaDeserializer { if self.len == 0 { self.state = DivaDeserializerState::ExpectChecksum; } + + // println!("data {}", c); } DivaDeserializerState::ExpectChecksum => { + // println!("checksum {} {:?}", c, self.packet.checksum); debug_assert!(self.packet.checksum == Wrapping(0)); if self.packet.checksum == Wrapping(0) { out.push_back(DivaPacket::new()); @@ -163,7 +183,7 @@ pub struct DivaSliderJob { port: String, packets: VecDeque, deserializer: DivaDeserializer, - serial_port: Option>, + serial_port: Option, bootstrap: DivaSliderBootstrap, } @@ -187,10 +207,13 @@ impl ThreadJob for DivaSliderJob { self.port.as_str(), 115200 ); - match serialport::new(&self.port, 152000).open() { - Ok(serial_port_buf) => { + match serialport::new(&self.port, 152000).open_native() { + Ok(serial_port) => { info!("Serial port opened"); - self.serial_port = Some(serial_port_buf); + serial_port + .set_read_write_timeout(Duration::from_millis(3)) + .ok(); + self.serial_port = Some(serial_port); true } Err(e) => { @@ -208,53 +231,81 @@ impl ThreadJob for DivaSliderJob { let bytes_avail = serial_port.bytes_to_read().unwrap_or(0); if bytes_avail > 0 { let mut read_buf = vec![0 as u8; bytes_avail as usize]; - serial_port.read_exact(&mut read_buf).ok(); + serial_port.read(&mut read_buf).ok(); self.deserializer.deserialize(&read_buf, &mut self.packets); work = true; } match self.bootstrap { DivaSliderBootstrap::Init => { - println!("Diva sending init"); + info!("Diva sending init"); let mut reset_packet = DivaPacket::from_bytes(0x10, &[]); - serial_port.write(reset_packet.serialize()).ok(); - println!("Diva sent init"); + match serial_port.write(reset_packet.serialize()) { + Ok(_) => { + info!("Diva sent init"); - self.bootstrap = DivaSliderBootstrap::AwaitReset; - work = true; + self.bootstrap = DivaSliderBootstrap::AwaitReset; + work = true; + } + Err(e) => { + error!("Diva send init error {}", e); + } + } + + // Wait for flush + sleep(Duration::from_millis(100)); } DivaSliderBootstrap::AwaitReset => { + while self.packets.len() > 1 { + self.packets.pop_front(); + } if let Some(ack_packet) = self.packets.pop_front() { info!( - "Diva slider ack reset {:?} {:?}", + "Diva ack reset {:?} {:?}", ack_packet.command, ack_packet.data ); let mut info_packet = DivaPacket::from_bytes(0xf0, &[]); - serial_port.write(info_packet.serialize()).ok(); - self.bootstrap = DivaSliderBootstrap::AwaitInfo; - work = true; + match serial_port.write(info_packet.serialize()) { + Ok(_) => { + info!("Diva sent info"); + + self.bootstrap = DivaSliderBootstrap::AwaitInfo; + work = true; + } + Err(e) => { + error!("Diva send info error {}", e); + } + } } } DivaSliderBootstrap::AwaitInfo => { if let Some(ack_packet) = self.packets.pop_front() { info!( - "Diva slider ack info {:?} {:?}", + "Diva ack info {:?} {:?}", ack_packet.command, ack_packet.data ); let mut start_packet = DivaPacket::from_bytes(0x03, &[]); - serial_port.write(start_packet.serialize()).ok(); - self.bootstrap = DivaSliderBootstrap::AwaitStart; - work = true; + match serial_port.write(start_packet.serialize()) { + Ok(_) => { + info!("Diva sent start"); + + self.bootstrap = DivaSliderBootstrap::AwaitStart; + work = true; + } + Err(e) => { + error!("Diva send start error {}", e); + } + } } } DivaSliderBootstrap::AwaitStart => { if let Some(ack_packet) = self.packets.pop_front() { info!( - "Diva slider ack start {:?} {:?}", + "Diva ack start {:?} {:?}", ack_packet.command, ack_packet.data ); @@ -301,16 +352,15 @@ impl ThreadJob for DivaSliderJob { impl Drop for DivaSliderJob { fn drop(&mut self) { - println!("Dropping diva"); match self.bootstrap { DivaSliderBootstrap::AwaitStart | DivaSliderBootstrap::ReadLoop => { - info!("Diva slider sending stop"); - let serial_port = self.serial_port.as_mut().unwrap(); let mut stop_packet = DivaPacket::from_bytes(0x04, &[]); serial_port.write(stop_packet.serialize()).ok(); } _ => {} }; + info!("Diva serial port closed"); + // println!("Diva slider dropped"); } } diff --git a/src-slider_io/src/lib.rs b/src-slider_io/src/lib.rs index 8632020..5819d2d 100644 --- a/src-slider_io/src/lib.rs +++ b/src-slider_io/src/lib.rs @@ -5,18 +5,18 @@ #![feature(div_duration)] #![feature(more_qualified_paths)] -mod config; -mod shared; -mod state; +pub mod config; +pub mod shared; +pub mod state; -mod device; -mod lighting; -mod output; +pub mod device; +pub mod lighting; +pub mod output; -mod system; +pub mod system; -mod context; -mod manager; +pub mod context; +pub mod manager; pub use config::Config; pub use manager::Manager; diff --git a/src-slider_io/src/shared/mod.rs b/src-slider_io/src/shared/mod.rs index 1e54333..3f68fc7 100644 --- a/src-slider_io/src/shared/mod.rs +++ b/src-slider_io/src/shared/mod.rs @@ -1,3 +1,4 @@ +pub mod serial; pub mod utils; pub mod voltex; pub mod worker; diff --git a/src-slider_io/src/shared/serial.rs b/src-slider_io/src/shared/serial.rs new file mode 100644 index 0000000..2c49868 --- /dev/null +++ b/src-slider_io/src/shared/serial.rs @@ -0,0 +1,31 @@ +use serialport::COMPort; +use std::{os::windows::prelude::AsRawHandle, time::Duration}; + +use winapi::{ + shared::minwindef::DWORD, + um::{commapi::SetCommTimeouts, winbase::COMMTIMEOUTS}, +}; + +pub trait ReadWriteTimeout { + fn set_read_write_timeout(&self, timeout: Duration) -> Result<(), ()>; +} + +impl ReadWriteTimeout for COMPort { + fn set_read_write_timeout(&self, timeout: Duration) -> Result<(), ()> { + let milliseconds = timeout.as_secs() * 1000 + timeout.subsec_nanos() as u64 / 1_000_000; + + let mut timeouts = COMMTIMEOUTS { + ReadIntervalTimeout: 0, + ReadTotalTimeoutMultiplier: 0, + ReadTotalTimeoutConstant: milliseconds as DWORD, + WriteTotalTimeoutMultiplier: 0, + WriteTotalTimeoutConstant: milliseconds as DWORD, + }; + + if unsafe { SetCommTimeouts(self.as_raw_handle(), &mut timeouts) } == 0 { + return Err(()); + } + + Ok(()) + } +} diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 8278fd5..cd39df9 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1628,9 +1628,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.114" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0005d08a8f7b65fb8073cb697aa0b12b631ed251ce73d862ce50eeb52ce3b50" +checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c" [[package]] name = "libudev"