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
66use hidapi:: HidDevice ;
77use 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