@@ -3,6 +3,7 @@ use std::cmp;
3
3
use anyhow:: Result ;
4
4
use hidapi:: { DeviceInfo , HidApi } ;
5
5
use log:: error;
6
+ use log:: info;
6
7
use serde:: { Deserialize , Serialize } ;
7
8
8
9
use crate :: controller:: Status ;
@@ -38,6 +39,15 @@ const DS_STATUS_BATTERY_CAPACITY: u8 = 0b1111;
38
39
const DS_STATUS_CHARGING : u8 = 0b1111 << 4 ;
39
40
const DS_STATUS_CHARGING_SHIFT : u8 = 4 ;
40
41
42
+ // DualShock3
43
+ pub const DS3_PRODUCT_ID : u16 = 0x0268 ;
44
+
45
+ const DS3_INPUT_REPORT : u8 = 0x01 ;
46
+ const DS3_INPUT_REPORT_SIZE : usize = 49 ;
47
+ const DS3_INPUT_REPORT_BATTERY_OFFSET : usize = 30 ;
48
+ const DS3_INPUT_REPORT_BATTERY_CHARGING : u8 = 0xee ;
49
+ const DS3_INPUT_REPORT_CHARGING_BIT : u8 = 0x01 ;
50
+
41
51
#[ repr( C , packed) ]
42
52
#[ derive( Copy , Clone , Debug , Deserialize ) ]
43
53
struct DualSenseTouchPoint {
@@ -245,6 +255,76 @@ fn get_battery_status(charging_status: u8, battery_data: u8) -> BatteryInfo {
245
255
}
246
256
}
247
257
258
+ pub fn parse_dualshock3_controller_data (
259
+ device_info : & DeviceInfo ,
260
+ hidapi : & HidApi ,
261
+ name : & str ,
262
+ ) -> Result < Controller > {
263
+ let mut controller = Controller :: from_hidapi ( device_info, name, 0 , Status :: Unknown ) ;
264
+ let device = device_info. open_device ( hidapi) ?;
265
+
266
+ // Read data from device_info
267
+ // If the DualShock 3 controller is not "activated", if its LEDs are blinking, it will not
268
+ // respond to reads, so we will timeout after 5s
269
+ let mut buf = [ 0u8 ; DS3_INPUT_REPORT_SIZE ] ;
270
+ let res = device. read_timeout ( & mut buf[ ..] , 2000 ) ?;
271
+
272
+ if res == 0 {
273
+ info ! ( "Inactive DualShock 3 controller" ) ;
274
+ return Ok ( controller) ;
275
+ }
276
+
277
+ if buf[ 1 ] == 0xff {
278
+ /* Comment coppied from the linux driver at drivers/hid/hid-sony.c
279
+ * When connected via Bluetooth the Sixaxis occasionally sends
280
+ * a report with the second byte 0xff and the rest zeroed.
281
+ *
282
+ * This report does not reflect the actual state of the
283
+ * controller must be ignored to avoid generating false input
284
+ * events.
285
+ */
286
+ return Ok ( controller) ;
287
+ }
288
+
289
+ let battery_data: u8 ;
290
+ if buf[ 0 ] == DS3_INPUT_REPORT && res == DS3_INPUT_REPORT_SIZE
291
+ {
292
+ battery_data = buf[ DS3_INPUT_REPORT_BATTERY_OFFSET ] ;
293
+ } else {
294
+ error ! ( "Unhandled report ID: {}" , buf[ 0 ] ) ;
295
+ return Ok ( controller) ;
296
+ }
297
+
298
+ let battery_status = get_ds3_battery_status ( battery_data) ;
299
+ controller. capacity = battery_status. capacity ;
300
+ controller. status = battery_status. status ;
301
+
302
+ Ok ( controller)
303
+ }
304
+
305
+ fn get_ds3_battery_status ( battery_data : u8 ) -> BatteryInfo {
306
+ /*
307
+ * This code was based on the linux driver for this controller.
308
+ * sixaxis_parse_report() from drivers/hid/hid-sony.c
309
+ */
310
+
311
+ let mut battery_info = BatteryInfo { capacity : 75 , status : Status :: Unknown } ;
312
+ if battery_data >= DS3_INPUT_REPORT_BATTERY_CHARGING {
313
+ //if the controller is charging, it does not report exact battery capacity
314
+ battery_info. status = match battery_data & DS3_INPUT_REPORT_CHARGING_BIT {
315
+ 0 => Status :: Charging ,
316
+ _ => { battery_info. capacity = 100 ; Status :: Unknown } ,
317
+ } ;
318
+ } else {
319
+ let index: usize = if battery_data <= 5 { battery_data. into ( ) } else { 5 } ;
320
+ let dualshock3_battery_capacity_values = [ 0 , 1 , 25 , 50 , 75 , 100 ] ;
321
+ battery_info. capacity = dualshock3_battery_capacity_values[ index] ;
322
+ battery_info. status = Status :: Discharging ;
323
+ }
324
+
325
+ battery_info
326
+ }
327
+
248
328
#[ cfg( test) ]
249
329
mod tests {
250
330
use crate :: api:: playstation:: { DualSenseInputReport , DS_INPUT_REPORT_USB_SIZE } ;
0 commit comments