Skip to content

Commit 700e658

Browse files
committed
fix(MSI Claw): use correct payload size for reports
1 parent a9c270f commit 700e658

File tree

1 file changed

+33
-12
lines changed

1 file changed

+33
-12
lines changed

src/drivers/msi_claw/driver.rs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// References:
22
// - https://github.com/zezba9000/MSI-Claw-Gamepad-Mode/blob/main/main.c
33
// - https://github.com/NeroReflex/hid-msi-claw-dkms/blob/main/hid-msi-claw.c
4-
use std::{error::Error, ffi::CString};
4+
use std::{error::Error, ffi::CString, time::Duration};
55

66
use hidapi::HidDevice;
77
use packed_struct::PackedStruct;
@@ -31,27 +31,29 @@ impl Driver {
3131
let path = CString::new(path)?;
3232
let api = hidapi::HidApi::new()?;
3333
let device = api.open_path(&path)?;
34+
device.set_blocking_mode(false)?;
3435

3536
Ok(Self { device })
3637
}
3738

38-
pub fn poll(&self) -> Result<(), Box<dyn Error + Send + Sync>> {
39+
pub fn poll(&self) -> Result<Option<PackedCommandReport>, Box<dyn Error + Send + Sync>> {
3940
let mut buf = [0; 8];
4041
let bytes_read = self.device.read(&mut buf[..])?;
42+
if bytes_read == 0 {
43+
return Ok(None);
44+
}
4145
let slice = &buf[..bytes_read];
4246

43-
if bytes_read > 0 {
44-
log::debug!("Got response bytes: {slice:?}");
45-
let report = PackedCommandReport::unpack(&buf)?;
46-
log::debug!("Response: {report}");
47+
log::debug!("Got response bytes: {slice:?}");
48+
let report = PackedCommandReport::unpack(&buf)?;
49+
log::debug!("Response: {report}");
4750

48-
if report.command == Command::GamepadModeAck {
49-
let mode: GamepadMode = report.arg1.into();
50-
log::debug!("Current gamepad mode: {mode:?}");
51-
}
51+
if report.command == Command::GamepadModeAck {
52+
let mode: GamepadMode = report.arg1.into();
53+
log::debug!("Current gamepad mode: {mode:?}");
5254
}
5355

54-
Ok(())
56+
Ok(Some(report))
5557
}
5658

5759
// Configure the device to be in the given mode
@@ -63,7 +65,26 @@ impl Driver {
6365
) -> Result<(), Box<dyn Error + Send + Sync>> {
6466
let report = PackedCommandReport::switch_mode(mode, mkeys);
6567
let data = report.pack()?;
66-
self.device.write(&data)?;
68+
69+
// The Claw appears to use a ring buffer of 64 bytes, so keep writing
70+
// the command until the ring buffer is full and an ACK response is
71+
// received. Attempts (buffer_size / report_size) number of times (8).
72+
for _ in 0..8 {
73+
// Write the SetMode command
74+
self.device.write(&data)?;
75+
std::thread::sleep(Duration::from_millis(50));
76+
77+
// Poll the device for an acknowlgement response
78+
let Some(report) = self.poll()? else {
79+
continue;
80+
};
81+
82+
// TODO: Validate that the device switched gamepad modes
83+
match report.command {
84+
Command::Ack | Command::GamepadModeAck => break,
85+
_ => break,
86+
}
87+
}
6788

6889
Ok(())
6990
}

0 commit comments

Comments
 (0)