mirror of
https://github.com/4yn/slidershim.git
synced 2025-02-21 20:39:34 +01:00
migrate to worker
This commit is contained in:
parent
7d5b552aec
commit
e64e68e9d9
31
src-tauri/src/bin/test_worker.rs
Normal file
31
src-tauri/src/bin/test_worker.rs
Normal file
@ -0,0 +1,31 @@
|
||||
extern crate slidershim;
|
||||
|
||||
use std::io;
|
||||
|
||||
use slidershim::slider_io::worker::{Job, Worker};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let worker = Worker::new(TestJob { data: 1 });
|
||||
|
||||
let mut input = String::new();
|
||||
let string = io::stdin().read_line(&mut input).unwrap();
|
||||
}
|
@ -4,7 +4,8 @@ use std::convert::TryFrom;
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DeviceMode {
|
||||
None,
|
||||
Tasoller { version: i64 },
|
||||
TasollerOne,
|
||||
TasollerTwo,
|
||||
Yuancon,
|
||||
Brokenithm { ground_only: bool },
|
||||
}
|
||||
@ -60,8 +61,8 @@ impl Config {
|
||||
raw: s.to_string(),
|
||||
device_mode: match v["deviceMode"].as_str().unwrap() {
|
||||
"none" => DeviceMode::None,
|
||||
"tasoller-one" => DeviceMode::Tasoller { version: 1 },
|
||||
"tasoller-two" => DeviceMode::Tasoller { version: 2 },
|
||||
"tasoller-one" => DeviceMode::TasollerOne,
|
||||
"tasoller-two" => DeviceMode::TasollerTwo,
|
||||
"yuancon" => DeviceMode::Yuancon,
|
||||
"brokenithm" => DeviceMode::Brokenithm { ground_only: false },
|
||||
"brokenithm-ground" => DeviceMode::Brokenithm { ground_only: true },
|
||||
|
@ -71,3 +71,12 @@ impl FullState {
|
||||
Arc::clone(&self.led_state)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for FullState {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
controller_state: Arc::clone(&self.controller_state),
|
||||
led_state: Arc::clone(&self.led_state),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,8 @@ impl DeviceThread {
|
||||
Self {
|
||||
thread: Some(match mode {
|
||||
DeviceMode::None => thread::spawn(|| {}),
|
||||
DeviceMode::Tasoller { .. } => thread::spawn(|| {}),
|
||||
DeviceMode::TasollerOne => thread::spawn(|| {}),
|
||||
DeviceMode::TasollerTwo => thread::spawn(|| {}),
|
||||
DeviceMode::Yuancon => thread::spawn(move || {
|
||||
hid::poll_controller(
|
||||
0x1973,
|
||||
|
170
src-tauri/src/slider_io/device_job.rs
Normal file
170
src-tauri/src/slider_io/device_job.rs
Normal file
@ -0,0 +1,170 @@
|
||||
use std::{error, ops::DerefMut, time::Duration};
|
||||
|
||||
use rusb::{self, DeviceHandle, GlobalContext};
|
||||
|
||||
use crate::slider_io::{
|
||||
config::DeviceMode,
|
||||
controller_state::{ControllerState, FullState, LedState},
|
||||
hid,
|
||||
worker::{Job, Worker},
|
||||
};
|
||||
|
||||
pub struct Buffer {
|
||||
pub data: [u8; 128],
|
||||
pub len: usize,
|
||||
}
|
||||
|
||||
impl Buffer {
|
||||
pub fn new() -> Self {
|
||||
Buffer {
|
||||
data: [0; 128],
|
||||
len: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn slice(&self) -> &[u8] {
|
||||
&self.data[0..self.len]
|
||||
}
|
||||
}
|
||||
|
||||
type HidReadCallback = fn(&Buffer, &mut ControllerState) -> ();
|
||||
type HidLedCallback = fn(&mut Buffer, &mut LedState) -> ();
|
||||
|
||||
pub struct HidDeviceJob {
|
||||
state: FullState,
|
||||
vid: u16,
|
||||
pid: u16,
|
||||
read_endpoint: u8,
|
||||
led_endpoint: u8,
|
||||
|
||||
read_callback: HidReadCallback,
|
||||
read_buf: Buffer,
|
||||
|
||||
led_callback: HidLedCallback,
|
||||
led_buf: Buffer,
|
||||
|
||||
handle: Option<DeviceHandle<GlobalContext>>,
|
||||
}
|
||||
|
||||
impl HidDeviceJob {
|
||||
fn new(
|
||||
state: FullState,
|
||||
vid: u16,
|
||||
pid: u16,
|
||||
read_endpoint: u8,
|
||||
led_endpoint: u8,
|
||||
read_callback: HidReadCallback,
|
||||
led_callback: HidLedCallback,
|
||||
) -> Self {
|
||||
Self {
|
||||
state,
|
||||
vid,
|
||||
pid,
|
||||
read_endpoint,
|
||||
led_endpoint,
|
||||
read_callback,
|
||||
read_buf: Buffer::new(),
|
||||
led_callback,
|
||||
led_buf: Buffer::new(),
|
||||
handle: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_config(mode: &DeviceMode, state: &FullState) -> Self {
|
||||
match mode {
|
||||
DeviceMode::Yuancon => Self::new(
|
||||
state.clone(),
|
||||
0x1973,
|
||||
0x2001,
|
||||
0x81,
|
||||
0x02,
|
||||
|buf, controller_state| {
|
||||
if buf.len != 34 {
|
||||
return;
|
||||
}
|
||||
|
||||
controller_state
|
||||
.ground_state
|
||||
.clone_from_slice(&buf.data[2..34]);
|
||||
for i in 0..6 {
|
||||
controller_state.air_state[i ^ 1] = if buf.data[0] & (1 << i) == 0 { 1 } else { 0 };
|
||||
}
|
||||
for i in 0..3 {
|
||||
controller_state.extra_state[i] = if buf.data[1] & (1 << i) == 0 { 1 } else { 0 };
|
||||
}
|
||||
},
|
||||
|buf, led_state| {
|
||||
if !led_state.dirty {
|
||||
return;
|
||||
}
|
||||
buf.len = 31 * 2;
|
||||
buf
|
||||
.data
|
||||
.chunks_mut(2)
|
||||
.take(31)
|
||||
.zip(led_state.led_state.chunks(3).rev())
|
||||
.for_each(|(buf_chunk, state_chunk)| {
|
||||
buf_chunk[0] = (state_chunk[0] << 3 & 0xe0) | (state_chunk[2] >> 3);
|
||||
buf_chunk[1] = (state_chunk[1] & 0xf8) | (state_chunk[0] >> 5);
|
||||
});
|
||||
led_state.dirty = false;
|
||||
},
|
||||
),
|
||||
_ => panic!("Not implemented"),
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_impl(&mut self) -> Result<(), Box<dyn error::Error>> {
|
||||
let mut handle = rusb::open_device_with_vid_pid(self.vid, self.pid).unwrap();
|
||||
if handle.kernel_driver_active(0).unwrap_or(false) {
|
||||
handle.detach_kernel_driver(0)?;
|
||||
}
|
||||
handle.set_active_configuration(1)?;
|
||||
handle.claim_interface(0)?;
|
||||
self.handle = Some(handle);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
const timeout: Duration = Duration::from_millis(20);
|
||||
|
||||
impl Job for HidDeviceJob {
|
||||
fn setup(&mut self) {
|
||||
self.setup_impl().unwrap();
|
||||
}
|
||||
|
||||
fn tick(&mut self) {
|
||||
// Input loop
|
||||
let handle = self.handle.as_mut().unwrap();
|
||||
|
||||
{
|
||||
let res = handle
|
||||
.read_interrupt(self.read_endpoint, &mut self.read_buf.data, timeout)
|
||||
.unwrap_or(0);
|
||||
self.read_buf.len = res;
|
||||
if self.read_buf.len != 0 {
|
||||
let mut controller_state_handle = self.state.controller_state.lock().unwrap();
|
||||
(self.read_callback)(&self.read_buf, controller_state_handle.deref_mut());
|
||||
}
|
||||
}
|
||||
|
||||
// Led loop
|
||||
{
|
||||
let mut led_state_handle = self.state.led_state.lock().unwrap();
|
||||
(self.led_callback)(&mut self.led_buf, led_state_handle.deref_mut());
|
||||
if self.led_buf.len != 0 {
|
||||
let res = handle
|
||||
.write_interrupt(self.led_endpoint, &self.led_buf.data, timeout)
|
||||
.unwrap_or(0);
|
||||
if res == self.led_buf.len + 1 {
|
||||
self.led_buf.len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn teardown(&mut self) {
|
||||
let handle = self.handle.as_mut().unwrap();
|
||||
handle.release_interface(0).ok();
|
||||
}
|
||||
}
|
@ -1,18 +1,21 @@
|
||||
use crate::slider_io::{
|
||||
config::Config, controller_state::FullState, device::DeviceThread, led::LedThread,
|
||||
config::Config, controller_state::FullState, device::DeviceThread, device_job::HidDeviceJob,
|
||||
led::LedThread, worker::Worker,
|
||||
};
|
||||
|
||||
pub struct Manager {
|
||||
state: FullState,
|
||||
config: Config,
|
||||
device_thread: DeviceThread,
|
||||
// device_thread: DeviceThread,
|
||||
device_worker: Worker,
|
||||
led_thread: LedThread,
|
||||
}
|
||||
|
||||
impl Manager {
|
||||
pub fn new(config: Config) -> Self {
|
||||
let state = FullState::new();
|
||||
let device_thread = DeviceThread::new(&state, config.device_mode.clone());
|
||||
// let device_thread = DeviceThread::new(&state, config.device_mode.clone());
|
||||
let device_worker = Worker::new(HidDeviceJob::from_config(&config.device_mode, &state));
|
||||
let led_thread = LedThread::new(&state, config.led_mode.clone());
|
||||
|
||||
println!("Starting manager with config: {:?}", config);
|
||||
@ -20,7 +23,8 @@ impl Manager {
|
||||
Self {
|
||||
state,
|
||||
config,
|
||||
device_thread,
|
||||
// device_thread,
|
||||
device_worker,
|
||||
led_thread,
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
pub mod config;
|
||||
pub mod controller_state;
|
||||
pub mod device;
|
||||
pub mod device_job;
|
||||
pub mod hid;
|
||||
pub mod keyboard;
|
||||
pub mod led;
|
||||
pub mod manager;
|
||||
pub mod output;
|
||||
pub mod worker;
|
||||
|
48
src-tauri/src/slider_io/worker.rs
Normal file
48
src-tauri/src/slider_io/worker.rs
Normal file
@ -0,0 +1,48 @@
|
||||
use std::{
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc,
|
||||
},
|
||||
thread,
|
||||
};
|
||||
|
||||
pub trait Job: Send {
|
||||
fn setup(&mut self);
|
||||
fn tick(&mut self);
|
||||
fn teardown(&mut self);
|
||||
}
|
||||
|
||||
pub struct Worker {
|
||||
thread: Option<thread::JoinHandle<()>>,
|
||||
stop_signal: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl Worker {
|
||||
pub fn new<T: 'static + Job>(mut job: T) -> Self {
|
||||
let stop_signal = Arc::new(AtomicBool::new(false));
|
||||
|
||||
let stop_signal_clone = Arc::clone(&stop_signal);
|
||||
Self {
|
||||
thread: Some(thread::spawn(move || {
|
||||
job.setup();
|
||||
loop {
|
||||
job.tick();
|
||||
if stop_signal_clone.load(Ordering::SeqCst) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
job.teardown();
|
||||
})),
|
||||
stop_signal,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Worker {
|
||||
fn drop(&mut self) {
|
||||
self.stop_signal.swap(true, Ordering::SeqCst);
|
||||
if self.thread.is_some() {
|
||||
self.thread.take().unwrap().join().ok();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user