Files
4yn_slidershim/src-slider_io/src/device/device.rs
T
2022-02-12 23:23:22 +08:00

297 lines
7.5 KiB
Rust

use log::{error, info};
use rusb::{self, DeviceHandle, GlobalContext};
use std::{
error::Error,
mem::swap,
ops::{Deref, DerefMut},
time::Duration,
};
use crate::{
controller_state::{ControllerState, FullState, LedState},
shared::{
utils::{Buffer, ShimError},
worker::ThreadJob,
},
};
use super::config::HardwareSpec;
type HidReadCallback = fn(&Buffer, &mut ControllerState) -> ();
type HidLedCallback = fn(&mut Buffer, &LedState) -> ();
enum WriteType {
Bulk,
Interrupt,
}
pub struct HidDeviceJob {
state: FullState,
vid: u16,
pid: u16,
read_endpoint: u8,
led_endpoint: u8,
read_callback: HidReadCallback,
read_buf: Buffer,
last_read_buf: Buffer,
led_write_type: WriteType,
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_type: WriteType,
led_callback: HidLedCallback,
) -> Self {
Self {
state,
vid,
pid,
read_endpoint,
led_endpoint,
read_callback,
read_buf: Buffer::new(),
last_read_buf: Buffer::new(),
led_write_type: led_type,
led_callback,
led_buf: Buffer::new(),
handle: None,
}
}
pub fn from_config(state: &FullState, spec: &HardwareSpec) -> Self {
match spec {
HardwareSpec::TasollerOne => Self::new(
state.clone(),
0x1ccf,
0x2333,
0x84,
0x03,
|buf, controller_state| {
if buf.len != 11 {
return;
}
let bits: Vec<u8> = buf
.data
.iter()
.flat_map(|x| (0..8).map(move |i| ((x) >> i) & 1))
.collect();
for i in 0..32 {
controller_state.ground_state[i] = bits[34 + i] * 255;
}
controller_state.flip_vert();
controller_state.air_state.copy_from_slice(&bits[28..34]);
controller_state.extra_state[0..2].copy_from_slice(&bits[26..28]);
},
WriteType::Bulk,
|buf, led_state| {
buf.len = 240;
buf.data[0] = 'B' as u8;
buf.data[1] = 'L' as u8;
buf.data[2] = '\x00' as u8;
for (buf_chunk, state_chunk) in buf.data[3..96]
.chunks_mut(3)
.take(31)
.zip(led_state.led_state.chunks(3).rev())
{
buf_chunk[0] = state_chunk[1];
buf_chunk[1] = state_chunk[0];
buf_chunk[2] = state_chunk[2];
}
buf.data[96..240].fill(0);
},
),
HardwareSpec::TasollerTwo => Self::new(
state.clone(),
0x1ccf,
0x2333,
0x84,
0x03,
|buf, controller_state| {
if buf.len != 36 {
return;
}
controller_state
.ground_state
.copy_from_slice(&buf.data[4..36]);
controller_state.flip_vert();
let bits: Vec<u8> = (0..8).map(|x| (buf.data[3] >> x) & 1).collect();
controller_state.air_state.copy_from_slice(&bits[0..6]);
controller_state.extra_state[0..2].copy_from_slice(&bits[6..8]);
},
WriteType::Bulk,
|buf, led_state| {
buf.len = 240;
buf.data[0] = 'B' as u8;
buf.data[1] = 'L' as u8;
buf.data[2] = '\x00' as u8;
for (buf_chunk, state_chunk) in buf.data[3..96]
.chunks_mut(3)
.take(31)
.zip(led_state.led_state.chunks(3).rev())
{
buf_chunk[0] = state_chunk[1];
buf_chunk[1] = state_chunk[0];
buf_chunk[2] = state_chunk[2];
}
buf.data[96..240].fill(0);
},
),
HardwareSpec::Yuancon => Self::new(
state.clone(),
0x1973,
0x2001,
0x81,
0x02,
|buf, controller_state| {
if buf.len != 34 {
return;
}
controller_state
.ground_state
.copy_from_slice(&buf.data[2..34]);
for i in 0..6 {
controller_state.air_state[i ^ 1] = (buf.data[0] >> i) & 1;
}
for i in 0..3 {
controller_state.extra_state[2 - i] = (buf.data[1] >> i) & 1;
}
},
WriteType::Interrupt,
|buf, led_state| {
buf.len = 31 * 2;
for (buf_chunk, state_chunk) in buf
.data
.chunks_mut(2)
.take(31)
.zip(led_state.led_state.chunks(3).rev())
{
buf_chunk[0] = (state_chunk[0] << 3 & 0xe0) | (state_chunk[2] >> 3);
buf_chunk[1] = (state_chunk[1] & 0xf8) | (state_chunk[0] >> 5);
}
},
),
}
}
fn get_handle(&mut self) -> Result<(), Box<dyn Error>> {
info!("Device finding vid {} pid {}", self.vid, self.pid);
let handle = rusb::open_device_with_vid_pid(self.vid, self.pid);
if handle.is_none() {
error!("Device not found");
return Err(Box::new(ShimError));
}
let mut handle = handle.unwrap();
info!("Device found {:?}", handle);
if handle.kernel_driver_active(0).unwrap_or(false) {
info!("Device detaching kernel driver");
handle.detach_kernel_driver(0)?;
}
info!("Device setting configuration");
handle.set_active_configuration(1)?;
info!("Device claiming interface");
handle.claim_interface(0)?;
self.handle = Some(handle);
Ok(())
}
}
const TIMEOUT: Duration = Duration::from_millis(20);
impl ThreadJob for HidDeviceJob {
fn setup(&mut self) -> bool {
match self.get_handle() {
Ok(_) => {
info!("Device OK");
true
}
Err(e) => {
error!("Device setup failed: {}", e);
false
}
}
}
fn tick(&mut self) -> bool {
// Input loop
let handle = self.handle.as_mut().unwrap();
let mut work = false;
{
let res = handle
.read_interrupt(self.read_endpoint, &mut self.read_buf.data, TIMEOUT)
.map_err(|e| {
// debug!("Device read error {}", &e);
e
})
.unwrap_or(0);
self.read_buf.len = res;
// debug!("{:?}", self.read_buf.slice());
// if self.read_buf.len != 0 {
if (self.read_buf.len != 0) && (self.read_buf.slice() != self.last_read_buf.slice()) {
work = true;
let mut controller_state_handle = self.state.controller_state.lock();
(self.read_callback)(&self.read_buf, controller_state_handle.deref_mut());
swap(&mut self.read_buf, &mut self.last_read_buf);
}
}
// Led loop
{
{
let mut led_state_handle = self.state.led_state.lock();
if led_state_handle.dirty {
(self.led_callback)(&mut self.led_buf, led_state_handle.deref());
led_state_handle.dirty = false;
}
}
if self.led_buf.len != 0 {
let res = (match self.led_write_type {
WriteType::Bulk => handle.write_bulk(self.led_endpoint, self.led_buf.slice(), TIMEOUT),
WriteType::Interrupt => {
handle.write_interrupt(self.led_endpoint, &self.led_buf.slice(), TIMEOUT)
}
})
.map_err(|e| {
// debug!("Device write error {}", e);
e
})
.unwrap_or(0);
if res == self.led_buf.len + 1 {
// work = true;
self.led_buf.len = 0;
}
}
}
work
}
}
impl Drop for HidDeviceJob {
fn drop(&mut self) {
if let Some(handle) = self.handle.as_mut() {
handle.release_interface(0).ok();
}
}
}