1
0
mirror of https://github.com/4yn/slidershim.git synced 2025-02-13 00:54:41 +01:00

diva draft

This commit is contained in:
4yn 2022-02-14 02:04:06 +08:00
parent 6bc462210f
commit 5865cd9d21
12 changed files with 334 additions and 198 deletions

View File

@ -5,41 +5,42 @@ use std::{future::Future, io, time::Duration};
use tokio::{select, time::sleep}; 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] #[async_trait]
// impl AsyncJob for CounterJob { impl AsyncHaltableJob for CounterJob {
// async fn run<F: Future<Output = ()> + Send>(self, stop_signal: F) { async fn run<F: Future<Output = ()> + Send>(self, stop_signal: F) {
// let job_a = async { let job_a = async {
// println!("Start job A"); println!("Start job A");
// let mut x = 0; let mut x = 0;
// loop { loop {
// x += 1; x += 1;
// println!("{}", x); println!("{}", x);
// sleep(Duration::from_millis(100)).await; sleep(Duration::from_millis(500)).await;
// } }
// }; };
// let job_b = async move { let job_b = async move {
// println!("Start job B"); println!("Start job B");
// stop_signal.await; stop_signal.await;
// println!("Stop signal hit at job B"); println!("Stop signal hit at job B");
// }; };
// select! { select! {
// _ = job_a => {}, _ = job_a => {},
// _ = job_b => {}, _ = job_b => {},
// } }
// } }
// } }
fn main() { #[tokio::main]
async fn main() {
env_logger::Builder::new() env_logger::Builder::new()
.filter_level(log::LevelFilter::Debug) .filter_level(log::LevelFilter::Debug)
.init(); .init();
// let worker = AsyncWorker::new("counter", CounterJob); let _worker = AsyncHaltableWorker::new("counter", CounterJob);
let mut input = String::new(); let mut input = String::new();
let string = io::stdin().read_line(&mut input).unwrap(); io::stdin().read_line(&mut input).unwrap();
} }

View File

@ -1,19 +1,20 @@
extern crate slider_io; 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::{ #[tokio::main]
// brokenithm::BrokenithmJob, controller_state::FullState, worker::AsyncWorker, async fn main() {
// };
fn main() {
env_logger::Builder::new() env_logger::Builder::new()
.filter_level(log::LevelFilter::Debug) .filter_level(log::LevelFilter::Debug)
.init(); .init();
// let worker = AsyncWorker::new("brokenithm", BrokenithmJob::new(FullState::new())); let state = SliderState::new();
let _worker = AsyncHaltableWorker::new("brokenithm", BrokenithmJob::new(&state, &false, &false));
let mut input = String::new(); let mut input = String::new();
let string = io::stdin().read_line(&mut input).unwrap(); io::stdin().read_line(&mut input).unwrap();
} }

View File

@ -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();
}

View File

@ -7,5 +7,5 @@ fn main() {
let res = available_ports(); let res = available_ports();
println!("{:?}", res); println!("{:?}", res);
let mut input = String::new(); let mut input = String::new();
let string = io::stdin().read_line(&mut input).unwrap(); io::stdin().read_line(&mut input).unwrap();
} }

View File

@ -2,7 +2,7 @@ extern crate slider_io;
use std::io; use std::io;
// use slidershim::slider_io::{Config, Context}; use slider_io::config::Config;
fn main() { fn main() {
env_logger::Builder::new() env_logger::Builder::new()
@ -10,55 +10,64 @@ fn main() {
.init(); .init();
// voltex? // voltex?
// let config = Config::from_str( let config = Config::from_str(
// r#"{ r#"{
// "deviceMode": "yuancon", "deviceMode": "yuancon",
// "outputMode": "gamepad-voltex", "outputMode": "gamepad-voltex",
// "keyboardSensitivity": 50, "outputPolling": "60",
// "ledMode": "reactive-voltex", "keyboardSensitivity": 50,
// "ledSensitivity": 50 "ledMode": "reactive-voltex",
// }"#, "ledSensitivity": 50
// ) }"#,
// .unwrap(); )
.unwrap();
println!("{:?}", config);
// serial? // serial?
// let config = Config::from_str( let config = Config::from_str(
// r#"{ r#"{
// "deviceMode": "yuancon", "deviceMode": "yuancon",
// "outputMode": "kb-32-tasoller", "outputMode": "kb-32-tasoller",
// "keyboardSensitivity": 50, "outputPolling": "60",
// "ledMode": "serial", "keyboardSensitivity": 50,
// "ledSerialPort": "COM5" "ledMode": "serial",
// }"#, "ledSerialPort": "COM5"
// ) }"#,
// .unwrap(); )
.unwrap();
println!("{:?}", config);
// basic // basic
// let config = Config::from_str( let config = Config::from_str(
// r#"{ r#"{
// "deviceMode": "yuancon", "deviceMode": "yuancon",
// "outputMode": "kb-32-tasoller", "outputMode": "kb-32-tasoller",
// "keyboardSensitivity": 50,fdwdfp1 "keyboardSensitivity": 50,
// "ledMode": "reactive-8", "outputPolling": "60",
// "ledSensitivity": 50 "ledMode": "reactive-8",
// }"#, "ledSensitivity": 50
// ) }"#,
// .unwrap(); )
.unwrap();
println!("{:?}", config);
// tasoller/ // tasoller/
// let config = Config::from_str( let config = Config::from_str(
// r#"{ r#"{
// "deviceMode": "tasoller-two", "deviceMode": "tasoller-two",
// "outputMode": "kb-32-tasoller", "outputMode": "kb-32-tasoller",
// "keyboardSensitivity": 50, "outputPolling": "60",
// "ledMode": "reactive-8", "keyboardSensitivity": 50,
// "ledSensitivity": 50 "ledMode": "reactive-8",
// }"#, "ledSensitivity": 50
// ) }"#,
// .unwrap(); )
.unwrap();
println!("{:?}", config);
// let manager = Context::new(config); // let manager = Context::new(config);
let mut input = String::new(); let mut input = String::new();
let string = io::stdin().read_line(&mut input).unwrap(); io::stdin().read_line(&mut input).unwrap();
} }

View File

@ -1,31 +1,41 @@
extern crate slider_io; 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 { struct TestJob {
// data: i64, data: i64,
// } }
// impl Job for TestJob { impl ThreadJob for TestJob {
// fn setup(&mut self) { fn setup(&mut self) -> bool {
// self.data = 10; self.data = 0;
// println!("setup {}", self.data); println!("setup {}", self.data);
// } true
// fn tick(&mut self) { }
// self.data -= 1; fn tick(&mut self) -> bool {
// println!("tick {}", self.data); self.data += 1;
// } println!("tick {}", self.data);
// fn teardown(&mut self) { sleep(Duration::from_millis(500));
// self.data = 11; true
// println!("teardown {}", self.data); }
// } }
// }
impl Drop for TestJob {
fn drop(&mut self) {
self.data = -1;
println!("teardown {}", self.data);
}
}
fn main() { 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 mut input = String::new();
let string = io::stdin().read_line(&mut input).unwrap(); io::stdin().read_line(&mut input).unwrap();
} }

View File

@ -19,6 +19,7 @@ pub struct Context {
state: SliderState, state: SliderState,
config: Config, config: Config,
device_thread_worker: Option<ThreadWorker>, device_thread_worker: Option<ThreadWorker>,
device_async_worker: Option<AsyncWorker>,
device_async_haltable_worker: Option<AsyncHaltableWorker>, device_async_haltable_worker: Option<AsyncHaltableWorker>,
output_worker: Option<AsyncWorker>, output_worker: Option<AsyncWorker>,
lights_worker: Option<AsyncWorker>, lights_worker: Option<AsyncWorker>,
@ -35,12 +36,14 @@ impl Context {
let state = SliderState::new(); let state = SliderState::new();
let mut timers = vec![]; let mut timers = vec![];
let (device_worker, brokenithm_worker) = match &config.device_mode { let (device_thread_worker, device_async_worker, device_async_haltable_worker) =
DeviceMode::None => (None, None), match &config.device_mode {
DeviceMode::None => (None, None, None),
DeviceMode::Brokenithm { DeviceMode::Brokenithm {
ground_only, ground_only,
lights_enabled, lights_enabled,
} => ( } => (
None,
None, None,
Some(AsyncHaltableWorker::new( Some(AsyncHaltableWorker::new(
"brokenithm", "brokenithm",
@ -58,6 +61,7 @@ impl Context {
)) ))
}, },
None, None,
None,
), ),
DeviceMode::DivaSlider { port } => ( DeviceMode::DivaSlider { port } => (
{ {
@ -70,6 +74,7 @@ impl Context {
)) ))
}, },
None, None,
None,
), ),
}; };
let output_worker = match &config.output_mode { let output_worker = match &config.output_mode {
@ -100,8 +105,9 @@ impl Context {
Self { Self {
state, state,
config, config,
device_thread_worker: device_worker, device_thread_worker,
device_async_haltable_worker: brokenithm_worker, device_async_worker,
device_async_haltable_worker,
output_worker, output_worker,
lights_worker, lights_worker,
timers, timers,

View File

@ -1,8 +1,17 @@
use log::{error, info}; use log::{error, info};
use serialport::SerialPort; use serialport::{COMPort, SerialPort};
use std::{collections::VecDeque, num::Wrapping, thread::sleep, time::Duration}; 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 { struct DivaPacket {
command: u8, command: u8,
@ -98,15 +107,20 @@ impl DivaDeserializer {
} }
fn deserialize(&mut self, data: &[u8], out: &mut VecDeque<DivaPacket>) { fn deserialize(&mut self, data: &[u8], out: &mut VecDeque<DivaPacket>) {
// println!("Found data");
for c in data { for c in data {
match c { match c {
0xff => { 0xff => {
self.packet = DivaPacket::new(); self.packet = DivaPacket::new();
self.packet.checksum = Wrapping(0xff); self.packet.checksum = Wrapping(0xff);
self.state = DivaDeserializerState::ExpectCommand; self.state = DivaDeserializerState::ExpectCommand;
self.escape = 0;
// println!("{} open", c);
} }
0xfd => { 0xfd => {
self.escape = 1; self.escape = 1;
// println!("esc {}", c);
} }
c => { c => {
let c = c + self.escape; let c = c + self.escape;
@ -117,6 +131,8 @@ impl DivaDeserializer {
DivaDeserializerState::ExpectCommand => { DivaDeserializerState::ExpectCommand => {
self.packet.command = c; self.packet.command = c;
self.state = DivaDeserializerState::ExpectLen; self.state = DivaDeserializerState::ExpectLen;
// println!("cmd {}", c);
} }
DivaDeserializerState::ExpectLen => { DivaDeserializerState::ExpectLen => {
self.len = c; self.len = c;
@ -125,6 +141,7 @@ impl DivaDeserializer {
0 => DivaDeserializerState::ExpectChecksum, 0 => DivaDeserializerState::ExpectChecksum,
_ => DivaDeserializerState::ExpectData, _ => DivaDeserializerState::ExpectData,
}; };
// println!("len {}", c);
} }
DivaDeserializerState::ExpectData => { DivaDeserializerState::ExpectData => {
self.packet.data.push(c); self.packet.data.push(c);
@ -133,8 +150,11 @@ impl DivaDeserializer {
if self.len == 0 { if self.len == 0 {
self.state = DivaDeserializerState::ExpectChecksum; self.state = DivaDeserializerState::ExpectChecksum;
} }
// println!("data {}", c);
} }
DivaDeserializerState::ExpectChecksum => { DivaDeserializerState::ExpectChecksum => {
// println!("checksum {} {:?}", c, self.packet.checksum);
debug_assert!(self.packet.checksum == Wrapping(0)); debug_assert!(self.packet.checksum == Wrapping(0));
if self.packet.checksum == Wrapping(0) { if self.packet.checksum == Wrapping(0) {
out.push_back(DivaPacket::new()); out.push_back(DivaPacket::new());
@ -163,7 +183,7 @@ pub struct DivaSliderJob {
port: String, port: String,
packets: VecDeque<DivaPacket>, packets: VecDeque<DivaPacket>,
deserializer: DivaDeserializer, deserializer: DivaDeserializer,
serial_port: Option<Box<dyn SerialPort>>, serial_port: Option<COMPort>,
bootstrap: DivaSliderBootstrap, bootstrap: DivaSliderBootstrap,
} }
@ -187,10 +207,13 @@ impl ThreadJob for DivaSliderJob {
self.port.as_str(), self.port.as_str(),
115200 115200
); );
match serialport::new(&self.port, 152000).open() { match serialport::new(&self.port, 152000).open_native() {
Ok(serial_port_buf) => { Ok(serial_port) => {
info!("Serial port opened"); 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 true
} }
Err(e) => { Err(e) => {
@ -208,53 +231,81 @@ impl ThreadJob for DivaSliderJob {
let bytes_avail = serial_port.bytes_to_read().unwrap_or(0); let bytes_avail = serial_port.bytes_to_read().unwrap_or(0);
if bytes_avail > 0 { if bytes_avail > 0 {
let mut read_buf = vec![0 as u8; bytes_avail as usize]; 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); self.deserializer.deserialize(&read_buf, &mut self.packets);
work = true; work = true;
} }
match self.bootstrap { match self.bootstrap {
DivaSliderBootstrap::Init => { DivaSliderBootstrap::Init => {
println!("Diva sending init"); info!("Diva sending init");
let mut reset_packet = DivaPacket::from_bytes(0x10, &[]); let mut reset_packet = DivaPacket::from_bytes(0x10, &[]);
serial_port.write(reset_packet.serialize()).ok(); match serial_port.write(reset_packet.serialize()) {
println!("Diva sent init"); Ok(_) => {
info!("Diva sent init");
self.bootstrap = DivaSliderBootstrap::AwaitReset; self.bootstrap = DivaSliderBootstrap::AwaitReset;
work = true; work = true;
} }
Err(e) => {
error!("Diva send init error {}", e);
}
}
// Wait for flush
sleep(Duration::from_millis(100));
}
DivaSliderBootstrap::AwaitReset => { DivaSliderBootstrap::AwaitReset => {
while self.packets.len() > 1 {
self.packets.pop_front();
}
if let Some(ack_packet) = self.packets.pop_front() { if let Some(ack_packet) = self.packets.pop_front() {
info!( info!(
"Diva slider ack reset {:?} {:?}", "Diva ack reset {:?} {:?}",
ack_packet.command, ack_packet.data ack_packet.command, ack_packet.data
); );
let mut info_packet = DivaPacket::from_bytes(0xf0, &[]); let mut info_packet = DivaPacket::from_bytes(0xf0, &[]);
serial_port.write(info_packet.serialize()).ok();
match serial_port.write(info_packet.serialize()) {
Ok(_) => {
info!("Diva sent info");
self.bootstrap = DivaSliderBootstrap::AwaitInfo; self.bootstrap = DivaSliderBootstrap::AwaitInfo;
work = true; work = true;
} }
Err(e) => {
error!("Diva send info error {}", e);
}
}
}
} }
DivaSliderBootstrap::AwaitInfo => { DivaSliderBootstrap::AwaitInfo => {
if let Some(ack_packet) = self.packets.pop_front() { if let Some(ack_packet) = self.packets.pop_front() {
info!( info!(
"Diva slider ack info {:?} {:?}", "Diva ack info {:?} {:?}",
ack_packet.command, ack_packet.data ack_packet.command, ack_packet.data
); );
let mut start_packet = DivaPacket::from_bytes(0x03, &[]); let mut start_packet = DivaPacket::from_bytes(0x03, &[]);
serial_port.write(start_packet.serialize()).ok();
match serial_port.write(start_packet.serialize()) {
Ok(_) => {
info!("Diva sent start");
self.bootstrap = DivaSliderBootstrap::AwaitStart; self.bootstrap = DivaSliderBootstrap::AwaitStart;
work = true; work = true;
} }
Err(e) => {
error!("Diva send start error {}", e);
}
}
}
} }
DivaSliderBootstrap::AwaitStart => { DivaSliderBootstrap::AwaitStart => {
if let Some(ack_packet) = self.packets.pop_front() { if let Some(ack_packet) = self.packets.pop_front() {
info!( info!(
"Diva slider ack start {:?} {:?}", "Diva ack start {:?} {:?}",
ack_packet.command, ack_packet.data ack_packet.command, ack_packet.data
); );
@ -301,16 +352,15 @@ impl ThreadJob for DivaSliderJob {
impl Drop for DivaSliderJob { impl Drop for DivaSliderJob {
fn drop(&mut self) { fn drop(&mut self) {
println!("Dropping diva");
match self.bootstrap { match self.bootstrap {
DivaSliderBootstrap::AwaitStart | DivaSliderBootstrap::ReadLoop => { DivaSliderBootstrap::AwaitStart | DivaSliderBootstrap::ReadLoop => {
info!("Diva slider sending stop");
let serial_port = self.serial_port.as_mut().unwrap(); let serial_port = self.serial_port.as_mut().unwrap();
let mut stop_packet = DivaPacket::from_bytes(0x04, &[]); let mut stop_packet = DivaPacket::from_bytes(0x04, &[]);
serial_port.write(stop_packet.serialize()).ok(); serial_port.write(stop_packet.serialize()).ok();
} }
_ => {} _ => {}
}; };
info!("Diva serial port closed");
// println!("Diva slider dropped");
} }
} }

View File

@ -5,18 +5,18 @@
#![feature(div_duration)] #![feature(div_duration)]
#![feature(more_qualified_paths)] #![feature(more_qualified_paths)]
mod config; pub mod config;
mod shared; pub mod shared;
mod state; pub mod state;
mod device; pub mod device;
mod lighting; pub mod lighting;
mod output; pub mod output;
mod system; pub mod system;
mod context; pub mod context;
mod manager; pub mod manager;
pub use config::Config; pub use config::Config;
pub use manager::Manager; pub use manager::Manager;

View File

@ -1,3 +1,4 @@
pub mod serial;
pub mod utils; pub mod utils;
pub mod voltex; pub mod voltex;
pub mod worker; pub mod worker;

View File

@ -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(())
}
}

4
src-tauri/Cargo.lock generated
View File

@ -1628,9 +1628,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.114" version = "0.2.117"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0005d08a8f7b65fb8073cb697aa0b12b631ed251ce73d862ce50eeb52ce3b50" checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c"
[[package]] [[package]]
name = "libudev" name = "libudev"