forked from beerpsi/chuniio-yubideck
Support hotplugging (maybe)?
This commit is contained in:
parent
bfea435bfc
commit
0115888309
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -13,7 +13,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aimeio-yubideck"
|
||||
version = "0.1.2"
|
||||
version = "0.1.3"
|
||||
dependencies = [
|
||||
"cfg_aliases",
|
||||
"faster-hex",
|
||||
@ -89,7 +89,7 @@ checksum = "77e53693616d3075149f4ead59bdeecd204ac6b8192d8969757601b74bddf00f"
|
||||
|
||||
[[package]]
|
||||
name = "chuniio-yubideck"
|
||||
version = "0.1.2"
|
||||
version = "0.1.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cfg-if 1.0.0",
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "aimeio-yubideck"
|
||||
version = "0.1.2"
|
||||
version = "0.1.3"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "chuniio-yubideck"
|
||||
version = "0.1.2"
|
||||
version = "0.1.3"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
@ -9,6 +9,7 @@ use std::{
|
||||
atomic::Ordering,
|
||||
Mutex,
|
||||
},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use ::log::error;
|
||||
@ -24,16 +25,13 @@ use yubideck_common::{create_shared_memory, init_logger, INPUT_SHMEM_SIZE, OUTPU
|
||||
|
||||
static mut INPUT_SHMEM: Option<Rc<Shmem>> = None;
|
||||
static mut OUTPUT_SHMEM: Option<Rc<Mutex<Shmem>>> = None;
|
||||
pub static DEVICE_POLLING_INTERVAL: Duration = Duration::from_millis(100);
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(chuni, chusanapp))] {
|
||||
use std::{
|
||||
sync::{OnceLock, atomic::AtomicBool},
|
||||
thread::{self, JoinHandle},
|
||||
time::Duration,
|
||||
};
|
||||
use std::{sync::{atomic::AtomicBool, RwLock}, thread};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use anyhow::Result;
|
||||
use ::log::info;
|
||||
use rusb::{DeviceHandle, GlobalContext};
|
||||
|
||||
@ -41,8 +39,7 @@ cfg_if::cfg_if! {
|
||||
|
||||
const TIMEOUT: Duration = Duration::from_millis(20);
|
||||
|
||||
static DEVICE: OnceLock<DeviceHandle<GlobalContext>> = OnceLock::new();
|
||||
static mut SLIDER_THREAD: OnceLock<JoinHandle<()>> = OnceLock::new();
|
||||
static DEVICE: RwLock<Option<DeviceHandle<GlobalContext>>> = RwLock::new(None);
|
||||
static SLIDER_ACTIVE: AtomicBool = AtomicBool::new(false);
|
||||
}
|
||||
}
|
||||
@ -128,10 +125,7 @@ pub extern "C" fn chuni_io_jvs_init() -> HRESULT {
|
||||
|
||||
#[cfg(not(amdaemon))]
|
||||
{
|
||||
if let Err(e) = yubideck_init() {
|
||||
error!("Could not initialize YubiDeck: {e:#?}");
|
||||
return E_FAIL;
|
||||
}
|
||||
thread::spawn(yubideck_init);
|
||||
}
|
||||
|
||||
S_OK
|
||||
@ -228,14 +222,15 @@ pub unsafe extern "C" fn chuni_io_slider_start(callback: *const c_void) {
|
||||
return;
|
||||
}
|
||||
|
||||
if SLIDER_THREAD.get().is_some() {
|
||||
if SLIDER_ACTIVE.load(Ordering::SeqCst) {
|
||||
return;
|
||||
}
|
||||
|
||||
SLIDER_ACTIVE.store(true, Ordering::Relaxed);
|
||||
|
||||
let callback = std::mem::transmute::<_, SliderCallbackFn>(callback);
|
||||
let thread = thread::spawn(move || {
|
||||
|
||||
thread::spawn(move || {
|
||||
let Some(input_shmem) = (unsafe { &INPUT_SHMEM }) else {
|
||||
return;
|
||||
};
|
||||
@ -251,8 +246,6 @@ pub unsafe extern "C" fn chuni_io_slider_start(callback: *const c_void) {
|
||||
thread::sleep(Duration::from_nanos(1_000_000));
|
||||
}
|
||||
});
|
||||
|
||||
SLIDER_THREAD.set(thread).unwrap();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -262,13 +255,7 @@ pub extern "C" fn chuni_io_slider_start(_callback: *const c_void) {}
|
||||
#[no_mangle]
|
||||
#[cfg(any(chuni, chusanapp))]
|
||||
pub extern "C" fn chuni_io_slider_stop() {
|
||||
let Some(thread) = (unsafe { SLIDER_THREAD.take() }) else {
|
||||
return;
|
||||
};
|
||||
|
||||
SLIDER_ACTIVE.store(false, Ordering::Relaxed);
|
||||
|
||||
thread.join().expect("Couldn't join slider input thread");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -282,7 +269,8 @@ pub unsafe extern "C" fn chuni_io_slider_set_leds(rgb: *const u8) {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(device) = DEVICE.get() else { return };
|
||||
let device_rg = DEVICE.read().unwrap();
|
||||
let Some(device) = device_rg.as_ref().map(|z| z) else { return };
|
||||
let Some(out_shmem) = &OUTPUT_SHMEM else {
|
||||
error!("OUTPUT_SHMEM is unset.");
|
||||
return;
|
||||
@ -333,7 +321,8 @@ pub extern "C" fn chuni_io_led_init() -> HRESULT {
|
||||
#[no_mangle]
|
||||
#[cfg(any(chuni, chusanapp))]
|
||||
pub unsafe extern "C" fn chuni_io_led_set_colors(board: u8, rgb: *const u8) {
|
||||
let Some(device) = DEVICE.get() else { return };
|
||||
let device_rg = DEVICE.read().unwrap();
|
||||
let Some(device) = device_rg.as_ref().map(|z| z) else { return };
|
||||
let Some(out_shmem) = &OUTPUT_SHMEM else {
|
||||
error!("OUTPUT_SHMEM is unset.");
|
||||
return;
|
||||
@ -372,26 +361,39 @@ pub extern "C" fn chuni_io_led_set_colors(_rgb: *const u8) {}
|
||||
|
||||
#[cfg(any(chuni, chusanapp))]
|
||||
fn yubideck_init() -> Result<()> {
|
||||
let Some(mut device) = rusb::open_device_with_vid_pid(0x1973, 0x2001) else {
|
||||
return Err(anyhow!("YubiDeck not found."));
|
||||
};
|
||||
{
|
||||
let mut global_device = DEVICE.write().unwrap();
|
||||
*global_device = None;
|
||||
}
|
||||
|
||||
device.set_active_configuration(1)?;
|
||||
device.claim_interface(0)?;
|
||||
DEVICE
|
||||
.set(device)
|
||||
.map_err(|e| anyhow!("Cannot store device handle: {e:#?}"))?;
|
||||
info!("Waiting for device...");
|
||||
|
||||
thread::spawn(input_thread_proc);
|
||||
loop {
|
||||
let Some(mut device) =
|
||||
rusb::open_device_with_vid_pid(0x1973, 0x2001)
|
||||
else {
|
||||
thread::sleep(DEVICE_POLLING_INTERVAL);
|
||||
continue;
|
||||
};
|
||||
|
||||
Ok(())
|
||||
device.set_active_configuration(1)?;
|
||||
device.claim_interface(0)?;
|
||||
|
||||
let mut global_device = DEVICE.write().unwrap();
|
||||
*global_device = Some(device);
|
||||
|
||||
thread::spawn(input_thread_proc);
|
||||
|
||||
return Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(chuni, chusanapp))]
|
||||
fn input_thread_proc() {
|
||||
info!("Input thread started");
|
||||
|
||||
let device = DEVICE.get().unwrap();
|
||||
let device_rg = DEVICE.read().unwrap();
|
||||
let Some(device) = device_rg.as_ref().map(|z| z) else { return };
|
||||
|
||||
let mut input_shmem = match create_shared_memory("YubideckInput", INPUT_SHMEM_SIZE, true) {
|
||||
Ok(s) => s,
|
||||
@ -413,7 +415,19 @@ fn input_thread_proc() {
|
||||
|
||||
loop {
|
||||
if let Err(e) = device.read_interrupt(0x81, usb_in, TIMEOUT) {
|
||||
error!("Failed to read data from YubiDeck: {e:#}");
|
||||
match e {
|
||||
rusb::Error::NoDevice | rusb::Error::Io => {
|
||||
error!("Controller disconnected.");
|
||||
|
||||
usb_in.iter_mut().for_each(|m| *m = 0);
|
||||
|
||||
// Spawn a thread polling for a connection again
|
||||
thread::spawn(yubideck_init);
|
||||
|
||||
return;
|
||||
}
|
||||
_ => error!("Failed to read data from YubiDeck: {e:#}"),
|
||||
}
|
||||
}
|
||||
|
||||
// Update reader LED data
|
||||
|
Loading…
Reference in New Issue
Block a user