Skip to content

Commit

Permalink
Add full hot-plug support for the adapter
Browse files Browse the repository at this point in the history
  • Loading branch information
amatho committed Sep 13, 2022
1 parent 2630616 commit 9679efc
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 23 deletions.
46 changes: 31 additions & 15 deletions src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -40,11 +45,11 @@ pub fn start_read_thread() {
});
}

pub struct GCAdapter {
pub struct GcAdapter {
handle: DeviceHandle<GlobalContext>,
}

impl Debug for GCAdapter {
impl Debug for GcAdapter {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
Expand All @@ -56,7 +61,7 @@ impl Debug for GCAdapter {
}
}

impl GCAdapter {
impl GcAdapter {
pub fn new() -> Result<Self, rusb::Error> {
let device = rusb::devices()?
.iter()
Expand Down Expand Up @@ -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),
}
}
}
Expand Down
13 changes: 5 additions & 8 deletions tests/input.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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");
Expand All @@ -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)
Expand Down

0 comments on commit 9679efc

Please sign in to comment.