From 9679efc53505ec034e48c8e47e1cb03d9ab524f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amandus=20S=C3=B8ve=20Thorsrud?= Date: Tue, 13 Sep 2022 14:59:19 +0200 Subject: [PATCH] Add full hot-plug support for the adapter --- src/adapter.rs | 46 +++++++++++++++++++++++++++++++--------------- tests/input.rs | 13 +++++-------- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/adapter.rs b/src/adapter.rs index 792c485..cf7d9cf 100644 --- a/src/adapter.rs +++ b/src/adapter.rs @@ -19,18 +19,23 @@ pub fn start_read_thread() { debug_print!(M64Message::Info, "Adapter thread started"); debug_print!(M64Message::Info, "Trying to connect to GameCube adapter..."); - let gc_adapter = loop { - if let Ok(gc) = GCAdapter::new() { - break gc; - } - - thread::park_timeout(Duration::from_secs(1)); - }; + let mut gc_adapter = GcAdapter::blocking_connect(); debug_print!(M64Message::Info, "Found a GameCube adapter"); while IS_INIT.load(Ordering::Acquire) { - *ADAPTER_STATE.buf.lock().unwrap() = gc_adapter.read(); + match gc_adapter.read() { + Ok(buf) => *ADAPTER_STATE.buf.lock().unwrap() = buf, + Err(rusb::Error::NoDevice) => { + debug_print!( + M64Message::Info, + "Adapter disconnected, trying to reconnect..." + ); + gc_adapter = GcAdapter::blocking_connect(); + debug_print!(M64Message::Info, "Adapter reconnected"); + } + Err(e) => panic!("error while reading from adapter: {:?}", e), + } // Gives a polling rate of approx. 1000 Hz thread::park_timeout(Duration::from_millis(1)); @@ -40,11 +45,11 @@ pub fn start_read_thread() { }); } -pub struct GCAdapter { +pub struct GcAdapter { handle: DeviceHandle, } -impl Debug for GCAdapter { +impl Debug for GcAdapter { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, @@ -56,7 +61,7 @@ impl Debug for GCAdapter { } } -impl GCAdapter { +impl GcAdapter { pub fn new() -> Result { let device = rusb::devices()? .iter() @@ -87,18 +92,29 @@ impl GCAdapter { handle.claim_interface(0)?; handle.write_interrupt(ENDPOINT_OUT, &[0x13], Duration::from_millis(16))?; - Ok(GCAdapter { handle }) + Ok(GcAdapter { handle }) + } + + /// Continuously try to connect to the adapter + pub fn blocking_connect() -> Self { + loop { + if let Ok(gc) = GcAdapter::new() { + break gc; + } + + thread::park_timeout(Duration::from_secs(1)); + } } - pub fn read(&self) -> [u8; READ_LEN] { + pub fn read(&self) -> rusb::Result<[u8; READ_LEN]> { let mut buf = [0; READ_LEN]; match self .handle .read_interrupt(ENDPOINT_IN, &mut buf, Duration::from_millis(16)) { - Ok(_) | Err(rusb::Error::Timeout) => buf, - Err(e) => panic!("error while reading from adapter: {:?}", e), + Ok(_) | Err(rusb::Error::Timeout) => Ok(buf), + Err(e) => Err(e), } } } diff --git a/tests/input.rs b/tests/input.rs index 5009267..c2d89ff 100644 --- a/tests/input.rs +++ b/tests/input.rs @@ -1,8 +1,5 @@ -use mupen64plus_input_gca::adapter::{AdapterState, Channel, ControllerState, GCAdapter}; -use std::{ - io::Write, - time::{Duration, Instant}, -}; +use mupen64plus_input_gca::adapter::{AdapterState, ControllerState, GcAdapter}; +use std::time::{Duration, Instant}; fn all_controller_states<'a>( state: &'a AdapterState, @@ -42,11 +39,11 @@ fn any(state: ControllerState) -> bool { fn receives_input() { const ERR: &str = "make sure the adapter is connected, and press the input(s) you want to test"; - let adapter = GCAdapter::new().expect(ERR); + let adapter = GcAdapter::new().expect(ERR); let started = Instant::now(); let mut state = AdapterState::new(); - state.set_buf(adapter.read()); + state.set_buf(adapter.read().unwrap()); if !(0..4).map(|i| state.is_connected(i)).any(|b| b) { eprintln!("no controllers detected, but might be a false negative"); @@ -58,7 +55,7 @@ fn receives_input() { break; } - state.set_buf(adapter.read()); + state.set_buf(adapter.read().unwrap()); if let Some((i, _)) = (0..4) .map(|i| (i, any(state.controller_state(i)))) .find(|(_, a)| *a)