1
0
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:
4yn 2022-01-29 01:10:12 +08:00
parent 7d5b552aec
commit e64e68e9d9
9 changed files with 274 additions and 8 deletions

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

View File

@ -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 },

View File

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

View File

@ -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,

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

View File

@ -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,
}
}

View File

@ -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;

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