SDL  2.0
SDL_hidapi_ps4.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 /* This driver supports both simplified reports and the extended input reports enabled by Steam.
22  Code and logic contributed by Valve Corporation under the SDL zlib license.
23 */
24 #include "../../SDL_internal.h"
25 
26 #ifdef SDL_JOYSTICK_HIDAPI
27 
28 #include "SDL_hints.h"
29 #include "SDL_events.h"
30 #include "SDL_timer.h"
31 #include "SDL_joystick.h"
32 #include "SDL_gamecontroller.h"
33 #include "../SDL_sysjoystick.h"
34 #include "SDL_hidapijoystick_c.h"
35 #include "SDL_hidapi_rumble.h"
36 
37 
38 #ifdef SDL_JOYSTICK_HIDAPI_PS4
39 
40 /* Define this if you want to log all packets from the controller */
41 /*#define DEBUG_PS4_PROTOCOL*/
42 
43 /* Define this if you want to log calibration data */
44 /*#define DEBUG_PS4_CALIBRATION*/
45 
46 #define GYRO_RES_PER_DEGREE 1024.0f
47 #define ACCEL_RES_PER_G 8192.0f
48 
49 #define LOAD16(A, B) (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8))
50 
51 typedef enum
52 {
53  k_EPS4ReportIdUsbState = 1,
54  k_EPS4ReportIdUsbEffects = 5,
55  k_EPS4ReportIdBluetoothState1 = 17,
56  k_EPS4ReportIdBluetoothState2 = 18,
57  k_EPS4ReportIdBluetoothState3 = 19,
58  k_EPS4ReportIdBluetoothState4 = 20,
59  k_EPS4ReportIdBluetoothState5 = 21,
60  k_EPS4ReportIdBluetoothState6 = 22,
61  k_EPS4ReportIdBluetoothState7 = 23,
62  k_EPS4ReportIdBluetoothState8 = 24,
63  k_EPS4ReportIdBluetoothState9 = 25,
64  k_EPS4ReportIdBluetoothEffects = 17,
65  k_EPS4ReportIdDisconnectMessage = 226,
66 } EPS4ReportId;
67 
68 typedef enum
69 {
70  k_ePS4FeatureReportIdGyroCalibration_USB = 0x02,
71  k_ePS4FeatureReportIdGyroCalibration_BT = 0x05,
72  k_ePS4FeatureReportIdSerialNumber = 0x12,
73 } EPS4FeatureReportID;
74 
75 typedef struct
76 {
77  Uint8 ucLeftJoystickX;
78  Uint8 ucLeftJoystickY;
79  Uint8 ucRightJoystickX;
80  Uint8 ucRightJoystickY;
81  Uint8 rgucButtonsHatAndCounter[ 3 ];
82  Uint8 ucTriggerLeft;
83  Uint8 ucTriggerRight;
84  Uint8 _rgucPad0[ 3 ];
85  Uint8 rgucGyroX[2];
86  Uint8 rgucGyroY[2];
87  Uint8 rgucGyroZ[2];
88  Uint8 rgucAccelX[2];
89  Uint8 rgucAccelY[2];
90  Uint8 rgucAccelZ[2];
91  Uint8 _rgucPad1[ 5 ];
92  Uint8 ucBatteryLevel;
93  Uint8 _rgucPad2[ 4 ];
94  Uint8 ucTouchpadCounter1;
95  Uint8 rgucTouchpadData1[ 3 ];
96  Uint8 ucTouchpadCounter2;
97  Uint8 rgucTouchpadData2[ 3 ];
98 } PS4StatePacket_t;
99 
100 typedef struct
101 {
102  Uint8 ucRumbleRight;
103  Uint8 ucRumbleLeft;
104  Uint8 ucLedRed;
105  Uint8 ucLedGreen;
106  Uint8 ucLedBlue;
107  Uint8 ucLedDelayOn;
108  Uint8 ucLedDelayOff;
109  Uint8 _rgucPad0[ 8 ];
110  Uint8 ucVolumeLeft;
111  Uint8 ucVolumeRight;
112  Uint8 ucVolumeMic;
113  Uint8 ucVolumeSpeaker;
114 } DS4EffectsState_t;
115 
116 typedef struct {
117  Sint16 bias;
118  float sensitivity;
119 } IMUCalibrationData;
120 
121 typedef struct {
122  SDL_bool is_dongle;
123  SDL_bool is_bluetooth;
124  SDL_bool official_controller;
125  SDL_bool audio_supported;
126  SDL_bool effects_supported;
127  SDL_bool report_sensors;
128  SDL_bool hardware_calibration;
129  IMUCalibrationData calibration[6];
130  int player_index;
131  Uint8 rumble_left;
132  Uint8 rumble_right;
133  SDL_bool color_set;
134  Uint8 led_red;
135  Uint8 led_green;
136  Uint8 led_blue;
137  Uint8 volume;
138  Uint32 last_volume_check;
139  PS4StatePacket_t last_state;
140 } SDL_DriverPS4_Context;
141 
142 
143 static SDL_bool
144 HIDAPI_DriverPS4_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
145 {
147 }
148 
149 static const char *
150 HIDAPI_DriverPS4_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
151 {
152  if (vendor_id == USB_VENDOR_SONY) {
153  return "PS4 Controller";
154  }
155  return NULL;
156 }
157 
158 static int ReadFeatureReport(hid_device *dev, Uint8 report_id, Uint8 *report, size_t length)
159 {
160  SDL_memset(report, 0, length);
161  report[0] = report_id;
162  return hid_get_feature_report(dev, report, length);
163 }
164 
165 static SDL_bool HIDAPI_DriverPS4_CanRumble(Uint16 vendor_id, Uint16 product_id)
166 {
167  /* The Razer Panthera fight stick hangs when trying to rumble */
168  if (vendor_id == USB_VENDOR_RAZER &&
169  (product_id == USB_PRODUCT_RAZER_PANTHERA || product_id == USB_PRODUCT_RAZER_PANTHERA_EVO)) {
170  return SDL_FALSE;
171  }
172  return SDL_TRUE;
173 }
174 
175 static void
176 SetLedsForPlayerIndex(DS4EffectsState_t *effects, int player_index)
177 {
178  /* This list is the same as what hid-sony.c uses in the Linux kernel.
179  The first 4 values correspond to what the PS4 assigns.
180  */
181  static const Uint8 colors[7][3] = {
182  { 0x00, 0x00, 0x40 }, /* Blue */
183  { 0x40, 0x00, 0x00 }, /* Red */
184  { 0x00, 0x40, 0x00 }, /* Green */
185  { 0x20, 0x00, 0x20 }, /* Pink */
186  { 0x02, 0x01, 0x00 }, /* Orange */
187  { 0x00, 0x01, 0x01 }, /* Teal */
188  { 0x01, 0x01, 0x01 } /* White */
189  };
190 
191  if (player_index >= 0) {
192  player_index %= SDL_arraysize(colors);
193  } else {
194  player_index = 0;
195  }
196 
197  effects->ucLedRed = colors[player_index][0];
198  effects->ucLedGreen = colors[player_index][1];
199  effects->ucLedBlue = colors[player_index][2];
200 }
201 
202 static SDL_bool
203 HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device)
204 {
206 }
207 
208 static int
209 HIDAPI_DriverPS4_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
210 {
211  return -1;
212 }
213 
214 static void
215 HIDAPI_DriverPS4_LoadCalibrationData(SDL_HIDAPI_Device *device)
216 {
217  SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
218  int i, tries, size;
219  SDL_bool have_data = SDL_FALSE;
221 
222  if (!ctx->official_controller) {
223 #ifdef DEBUG_PS4_CALIBRATION
224  SDL_Log("Not an official controller, ignoring calibration\n");
225 #endif
226  return;
227  }
228 
229  for( tries = 0; tries < 5; ++tries ) {
230  /* For Bluetooth controllers, this report switches them into advanced report mode */
231  size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdGyroCalibration_USB, data, sizeof(data));
232  if (size < 35) {
233 #ifdef DEBUG_PS4_CALIBRATION
234  SDL_Log("Short read of calibration data: %d, ignoring calibration\n", size);
235 #endif
236  return;
237  }
238 
239  if (ctx->is_bluetooth) {
240  size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdGyroCalibration_BT, data, sizeof(data));
241  if (size < 35) {
242 #ifdef DEBUG_PS4_CALIBRATION
243  SDL_Log("Short read of calibration data: %d, ignoring calibration\n", size);
244 #endif
245  return;
246  }
247  }
248 
249  /* In some cases this report returns all zeros. Usually immediately after connection with the PS4 Dongle */
250  for (i = 0; i < size; ++i) {
251  if (data[i]) {
252  have_data = SDL_TRUE;
253  break;
254  }
255  }
256  if (have_data) {
257  break;
258  }
259 
260  SDL_Delay(2);
261  }
262 
263  if (have_data) {
264  Sint16 sGyroPitchBias, sGyroYawBias, sGyroRollBias;
265  Sint16 sGyroPitchPlus, sGyroPitchMinus;
266  Sint16 sGyroYawPlus, sGyroYawMinus;
267  Sint16 sGyroRollPlus, sGyroRollMinus;
268  Sint16 sGyroSpeedPlus, sGyroSpeedMinus;
269 
270  Sint16 sAccXPlus, sAccXMinus;
271  Sint16 sAccYPlus, sAccYMinus;
272  Sint16 sAccZPlus, sAccZMinus;
273 
274  float flNumerator;
275  Sint16 sRange2g;
276 
277 #ifdef DEBUG_PS4_CALIBRATION
278  HIDAPI_DumpPacket("PS4 calibration packet: size = %d", data, size);
279 #endif
280 
281  sGyroPitchBias = LOAD16(data[1], data[2]);
282  sGyroYawBias = LOAD16(data[3], data[4]);
283  sGyroRollBias = LOAD16(data[5], data[6]);
284 
285  if (ctx->is_bluetooth || ctx->is_dongle) {
286  sGyroPitchPlus = LOAD16(data[7], data[8]);
287  sGyroYawPlus = LOAD16(data[9], data[10]);
288  sGyroRollPlus = LOAD16(data[11], data[12]);
289  sGyroPitchMinus = LOAD16(data[13], data[14]);
290  sGyroYawMinus = LOAD16(data[15], data[16]);
291  sGyroRollMinus = LOAD16(data[17], data[18]);
292  } else {
293  sGyroPitchPlus = LOAD16(data[7], data[8]);
294  sGyroPitchMinus = LOAD16(data[9], data[10]);
295  sGyroYawPlus = LOAD16(data[11], data[12]);
296  sGyroYawMinus = LOAD16(data[13], data[14]);
297  sGyroRollPlus = LOAD16(data[15], data[16]);
298  sGyroRollMinus = LOAD16(data[17], data[18]);
299  }
300 
301  sGyroSpeedPlus = LOAD16(data[19], data[20]);
302  sGyroSpeedMinus = LOAD16(data[21], data[22]);
303 
304  sAccXPlus = LOAD16(data[23], data[24]);
305  sAccXMinus = LOAD16(data[25], data[26]);
306  sAccYPlus = LOAD16(data[27], data[28]);
307  sAccYMinus = LOAD16(data[29], data[30]);
308  sAccZPlus = LOAD16(data[31], data[32]);
309  sAccZMinus = LOAD16(data[33], data[34]);
310 
311  flNumerator = (sGyroSpeedPlus + sGyroSpeedMinus) * GYRO_RES_PER_DEGREE;
312  ctx->calibration[0].bias = sGyroPitchBias;
313  ctx->calibration[0].sensitivity = flNumerator / (sGyroPitchPlus - sGyroPitchMinus);
314 
315  ctx->calibration[1].bias = sGyroYawBias;
316  ctx->calibration[1].sensitivity = flNumerator / (sGyroYawPlus - sGyroYawMinus);
317 
318  ctx->calibration[2].bias = sGyroRollBias;
319  ctx->calibration[2].sensitivity = flNumerator / (sGyroRollPlus - sGyroRollMinus);
320 
321  sRange2g = sAccXPlus - sAccXMinus;
322  ctx->calibration[3].bias = sAccXPlus - sRange2g / 2;
323  ctx->calibration[3].sensitivity = 2.0f * ACCEL_RES_PER_G / (float)sRange2g;
324 
325  sRange2g = sAccYPlus - sAccYMinus;
326  ctx->calibration[4].bias = sAccYPlus - sRange2g / 2;
327  ctx->calibration[4].sensitivity = 2.0f * ACCEL_RES_PER_G / (float)sRange2g;
328 
329  sRange2g = sAccZPlus - sAccZMinus;
330  ctx->calibration[5].bias = sAccZPlus - sRange2g / 2;
331  ctx->calibration[5].sensitivity = 2.0f * ACCEL_RES_PER_G / (float)sRange2g;
332 
333  ctx->hardware_calibration = SDL_TRUE;
334  for (i = 0; i < 6; ++i) {
335  float divisor = (i < 3 ? 64.0f : 1.0f);
336 #ifdef DEBUG_PS4_CALIBRATION
337  SDL_Log("calibration[%d] bias = %d, sensitivity = %f\n", i, ctx->calibration[i].bias, ctx->calibration[i].sensitivity);
338 #endif
339  /* Some controllers have a bad calibration */
340  if ((SDL_abs(ctx->calibration[i].bias) > 1024) || (SDL_fabs(1.0f - ctx->calibration[i].sensitivity / divisor) > 0.5f)) {
341 #ifdef DEBUG_PS4_CALIBRATION
342  SDL_Log("invalid calibration, ignoring\n");
343 #endif
344  ctx->hardware_calibration = SDL_FALSE;
345  }
346  }
347  } else {
348 #ifdef DEBUG_PS4_CALIBRATION
349  SDL_Log("Calibration data not available\n");
350 #endif
351  }
352 }
353 
354 static float
355 HIDAPI_DriverPS4_ApplyCalibrationData(SDL_DriverPS4_Context *ctx, int index, Sint16 value)
356 {
357  float result;
358 
359  if (ctx->hardware_calibration) {
360  IMUCalibrationData *calibration = &ctx->calibration[index];
361 
362  result = (value - calibration->bias) * calibration->sensitivity;
363  } else if (index < 3) {
364  result = value * 64.f;
365  } else {
366  result = value;
367  }
368 
369  /* Convert the raw data to the units expected by SDL */
370  if (index < 3) {
371  result = (result / GYRO_RES_PER_DEGREE) * (float)M_PI / 180.0f;
372  } else {
373  result = (result / ACCEL_RES_PER_G) * SDL_STANDARD_GRAVITY;
374  }
375  return result;
376 }
377 
378 static int
379 HIDAPI_DriverPS4_UpdateEffects(SDL_HIDAPI_Device *device)
380 {
381  SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
382  DS4EffectsState_t *effects;
383  Uint8 data[78];
384  int report_size, offset;
385 
386  if (!ctx->effects_supported) {
387  return SDL_Unsupported();
388  }
389 
390  SDL_zero(data);
391 
392  if (ctx->is_bluetooth) {
393  data[0] = k_EPS4ReportIdBluetoothEffects;
394  data[1] = 0xC0 | 0x04; /* Magic value HID + CRC, also sets interval to 4ms for samples */
395  data[3] = 0x03; /* 0x1 is rumble, 0x2 is lightbar, 0x4 is the blink interval */
396 
397  report_size = 78;
398  offset = 6;
399  } else {
400  data[0] = k_EPS4ReportIdUsbEffects;
401  data[1] = 0x07; /* Magic value */
402 
403  report_size = 32;
404  offset = 4;
405  }
406  effects = (DS4EffectsState_t *)&data[offset];
407 
408  effects->ucRumbleLeft = ctx->rumble_left;
409  effects->ucRumbleRight = ctx->rumble_right;
410 
411  /* Populate the LED state with the appropriate color from our lookup table */
412  if (ctx->color_set) {
413  effects->ucLedRed = ctx->led_red;
414  effects->ucLedGreen = ctx->led_green;
415  effects->ucLedBlue = ctx->led_blue;
416  } else {
417  SetLedsForPlayerIndex(effects, ctx->player_index);
418  }
419 
420  if (ctx->is_bluetooth) {
421  /* Bluetooth reports need a CRC at the end of the packet (at least on Linux) */
422  Uint8 ubHdr = 0xA2; /* hidp header is part of the CRC calculation */
423  Uint32 unCRC;
424  unCRC = SDL_crc32(0, &ubHdr, 1);
425  unCRC = SDL_crc32(unCRC, data, (size_t)(report_size - sizeof(unCRC)));
426  SDL_memcpy(&data[report_size - sizeof(unCRC)], &unCRC, sizeof(unCRC));
427  }
428 
429  if (SDL_HIDAPI_SendRumble(device, data, report_size) != report_size) {
430  return SDL_SetError("Couldn't send rumble packet");
431  }
432  return 0;
433 }
434 
435 static void
436 HIDAPI_DriverPS4_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
437 {
438  SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
439 
440  if (!ctx) {
441  return;
442  }
443 
444  ctx->player_index = player_index;
445 
446  /* This will set the new LED state based on the new player index */
447  HIDAPI_DriverPS4_UpdateEffects(device);
448 }
449 
450 static SDL_bool
451 HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
452 {
453  SDL_DriverPS4_Context *ctx;
454 
455  ctx = (SDL_DriverPS4_Context *)SDL_calloc(1, sizeof(*ctx));
456  if (!ctx) {
457  SDL_OutOfMemory();
458  return SDL_FALSE;
459  }
460 
461  device->dev = hid_open_path(device->path, 0);
462  if (!device->dev) {
463  SDL_free(ctx);
464  SDL_SetError("Couldn't open %s", device->path);
465  return SDL_FALSE;
466  }
467  device->context = ctx;
468 
469  /* Check for type of connection */
470  ctx->is_dongle = (device->vendor_id == USB_VENDOR_SONY && device->product_id == USB_PRODUCT_SONY_DS4_DONGLE);
471  if (ctx->is_dongle) {
472  ctx->is_bluetooth = SDL_FALSE;
473  ctx->official_controller = SDL_TRUE;
474  } else if (device->vendor_id == USB_VENDOR_SONY) {
476  int size;
477 
478  /* This will fail if we're on Bluetooth */
479  size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdSerialNumber, data, sizeof(data));
480  if (size >= 7) {
481  char serial[18];
482 
483  SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
484  data[6], data[5], data[4], data[3], data[2], data[1]);
485  joystick->serial = SDL_strdup(serial);
486  ctx->is_bluetooth = SDL_FALSE;
487  } else {
488  ctx->is_bluetooth = SDL_TRUE;
489  }
490  ctx->official_controller = SDL_TRUE;
491  } else {
492  /* Third party controllers appear to all be wired */
493  ctx->is_bluetooth = SDL_FALSE;
494  }
495 #ifdef DEBUG_PS4
496  SDL_Log("PS4 dongle = %s, bluetooth = %s\n", ctx->is_dongle ? "TRUE" : "FALSE", ctx->is_bluetooth ? "TRUE" : "FALSE");
497 #endif
498 
499  /* Check to see if audio is supported */
500  if (device->vendor_id == USB_VENDOR_SONY &&
501  (device->product_id == USB_PRODUCT_SONY_DS4_SLIM || device->product_id == USB_PRODUCT_SONY_DS4_DONGLE)) {
502  ctx->audio_supported = SDL_TRUE;
503  }
504 
505  if (HIDAPI_DriverPS4_CanRumble(device->vendor_id, device->product_id)) {
506  if (ctx->is_bluetooth) {
508  } else {
509  ctx->effects_supported = SDL_TRUE;
510  }
511  }
512 
513  /* Initialize player index (needed for setting LEDs) */
514  ctx->player_index = SDL_JoystickGetPlayerIndex(joystick);
515 
516  /* Initialize LED and effect state */
517  HIDAPI_DriverPS4_UpdateEffects(device);
518 
519  /* Initialize the joystick capabilities */
520  joystick->nbuttons = 16;
522  joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
523 
527 
528  return SDL_TRUE;
529 }
530 
531 static int
532 HIDAPI_DriverPS4_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
533 {
534  SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
535 
536  ctx->rumble_left = (low_frequency_rumble >> 8);
537  ctx->rumble_right = (high_frequency_rumble >> 8);
538 
539  return HIDAPI_DriverPS4_UpdateEffects(device);
540 }
541 
542 static int
543 HIDAPI_DriverPS4_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
544 {
545  return SDL_Unsupported();
546 }
547 
548 static SDL_bool
549 HIDAPI_DriverPS4_HasJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
550 {
551  return SDL_TRUE;
552 }
553 
554 static int
555 HIDAPI_DriverPS4_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
556 {
557  SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
558 
559  ctx->color_set = SDL_TRUE;
560  ctx->led_red = red;
561  ctx->led_green = green;
562  ctx->led_blue = blue;
563 
564  return HIDAPI_DriverPS4_UpdateEffects(device);
565 }
566 
567 static int
568 HIDAPI_DriverPS4_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
569 {
570  SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
571 
572  if (enabled) {
573  HIDAPI_DriverPS4_LoadCalibrationData(device);
574  }
575  ctx->report_sensors = enabled;
576 
577  return 0;
578 }
579 
580 static void
581 HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverPS4_Context *ctx, PS4StatePacket_t *packet)
582 {
583  static const float TOUCHPAD_SCALEX = 1.0f / 1920;
584  static const float TOUCHPAD_SCALEY = 1.0f / 920; /* This is noted as being 944 resolution, but 920 feels better */
585  Sint16 axis;
586  Uint8 touchpad_state;
587  int touchpad_x, touchpad_y;
588 
589  if (ctx->last_state.rgucButtonsHatAndCounter[0] != packet->rgucButtonsHatAndCounter[0]) {
590  {
591  Uint8 data = (packet->rgucButtonsHatAndCounter[0] >> 4);
592 
597  }
598  {
599  Uint8 data = (packet->rgucButtonsHatAndCounter[0] & 0x0F);
600  SDL_bool dpad_up = SDL_FALSE;
601  SDL_bool dpad_down = SDL_FALSE;
602  SDL_bool dpad_left = SDL_FALSE;
603  SDL_bool dpad_right = SDL_FALSE;
604 
605  switch (data) {
606  case 0:
607  dpad_up = SDL_TRUE;
608  break;
609  case 1:
610  dpad_up = SDL_TRUE;
611  dpad_right = SDL_TRUE;
612  break;
613  case 2:
614  dpad_right = SDL_TRUE;
615  break;
616  case 3:
617  dpad_right = SDL_TRUE;
618  dpad_down = SDL_TRUE;
619  break;
620  case 4:
621  dpad_down = SDL_TRUE;
622  break;
623  case 5:
624  dpad_left = SDL_TRUE;
625  dpad_down = SDL_TRUE;
626  break;
627  case 6:
628  dpad_left = SDL_TRUE;
629  break;
630  case 7:
631  dpad_up = SDL_TRUE;
632  dpad_left = SDL_TRUE;
633  break;
634  default:
635  break;
636  }
641  }
642  }
643 
644  if (ctx->last_state.rgucButtonsHatAndCounter[1] != packet->rgucButtonsHatAndCounter[1]) {
645  Uint8 data = packet->rgucButtonsHatAndCounter[1];
646 
653  }
654 
655  /* Some fightsticks, ex: Victrix FS Pro will only this these digital trigger bits and not the analog values so this needs to run whenever the
656  trigger is evaluated
657  */
658  if ((packet->rgucButtonsHatAndCounter[1] & 0x0C) != 0) {
659  Uint8 data = packet->rgucButtonsHatAndCounter[1];
660  packet->ucTriggerLeft = (data & 0x04) && packet->ucTriggerLeft == 0 ? 255 : packet->ucTriggerLeft;
661  packet->ucTriggerRight = (data & 0x08) && packet->ucTriggerRight == 0 ? 255 : packet->ucTriggerRight;
662  }
663 
664  if (ctx->last_state.rgucButtonsHatAndCounter[2] != packet->rgucButtonsHatAndCounter[2]) {
665  Uint8 data = (packet->rgucButtonsHatAndCounter[2] & 0x03);
666 
669  }
670 
671  axis = ((int)packet->ucTriggerLeft * 257) - 32768;
673  axis = ((int)packet->ucTriggerRight * 257) - 32768;
675  axis = ((int)packet->ucLeftJoystickX * 257) - 32768;
677  axis = ((int)packet->ucLeftJoystickY * 257) - 32768;
679  axis = ((int)packet->ucRightJoystickX * 257) - 32768;
681  axis = ((int)packet->ucRightJoystickY * 257) - 32768;
683 
684  if (packet->ucBatteryLevel & 0x10) {
685  joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
686  } else {
687  /* Battery level ranges from 0 to 10 */
688  int level = (packet->ucBatteryLevel & 0xF);
689  if (level == 0) {
690  joystick->epowerlevel = SDL_JOYSTICK_POWER_EMPTY;
691  } else if (level <= 2) {
692  joystick->epowerlevel = SDL_JOYSTICK_POWER_LOW;
693  } else if (level <= 7) {
694  joystick->epowerlevel = SDL_JOYSTICK_POWER_MEDIUM;
695  } else {
696  joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL;
697  }
698  }
699 
700  touchpad_state = ((packet->ucTouchpadCounter1 & 0x80) == 0) ? SDL_PRESSED : SDL_RELEASED;
701  touchpad_x = packet->rgucTouchpadData1[0] | (((int)packet->rgucTouchpadData1[1] & 0x0F) << 8);
702  touchpad_y = (packet->rgucTouchpadData1[1] >> 4) | ((int)packet->rgucTouchpadData1[2] << 4);
703  SDL_PrivateJoystickTouchpad(joystick, 0, 0, touchpad_state, touchpad_x * TOUCHPAD_SCALEX, touchpad_y * TOUCHPAD_SCALEY, touchpad_state ? 1.0f : 0.0f);
704 
705  touchpad_state = ((packet->ucTouchpadCounter2 & 0x80) == 0) ? SDL_PRESSED : SDL_RELEASED;
706  touchpad_x = packet->rgucTouchpadData2[0] | (((int)packet->rgucTouchpadData2[1] & 0x0F) << 8);
707  touchpad_y = (packet->rgucTouchpadData2[1] >> 4) | ((int)packet->rgucTouchpadData2[2] << 4);
708  SDL_PrivateJoystickTouchpad(joystick, 0, 1, touchpad_state, touchpad_x * TOUCHPAD_SCALEX, touchpad_y * TOUCHPAD_SCALEY, touchpad_state ? 1.0f : 0.0f);
709 
710  if (ctx->report_sensors) {
711  float data[3];
712 
713  data[0] = HIDAPI_DriverPS4_ApplyCalibrationData(ctx, 0, LOAD16(packet->rgucGyroX[0], packet->rgucGyroX[1]));
714  data[1] = HIDAPI_DriverPS4_ApplyCalibrationData(ctx, 1, LOAD16(packet->rgucGyroY[0], packet->rgucGyroY[1]));
715  data[2] = HIDAPI_DriverPS4_ApplyCalibrationData(ctx, 2, LOAD16(packet->rgucGyroZ[0], packet->rgucGyroZ[1]));
717 
718  data[0] = HIDAPI_DriverPS4_ApplyCalibrationData(ctx, 3, LOAD16(packet->rgucAccelX[0], packet->rgucAccelX[1]));
719  data[1] = HIDAPI_DriverPS4_ApplyCalibrationData(ctx, 4, LOAD16(packet->rgucAccelY[0], packet->rgucAccelY[1]));
720  data[2] = HIDAPI_DriverPS4_ApplyCalibrationData(ctx, 5, LOAD16(packet->rgucAccelZ[0], packet->rgucAccelZ[1]));
722  }
723 
724  SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state));
725 }
726 
727 static SDL_bool
728 HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device)
729 {
730  SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
731  SDL_Joystick *joystick = NULL;
733  int size;
734 
735  if (device->num_joysticks > 0) {
736  joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
737  }
738  if (!joystick) {
739  return SDL_FALSE;
740  }
741 
742  while ((size = hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
743 #ifdef DEBUG_PS4_PROTOCOL
744  HIDAPI_DumpPacket("PS4 packet: size = %d", data, size);
745 #endif
746  switch (data[0]) {
747  case k_EPS4ReportIdUsbState:
748  HIDAPI_DriverPS4_HandleStatePacket(joystick, device->dev, ctx, (PS4StatePacket_t *)&data[1]);
749  break;
750  case k_EPS4ReportIdBluetoothState1:
751  case k_EPS4ReportIdBluetoothState2:
752  case k_EPS4ReportIdBluetoothState3:
753  case k_EPS4ReportIdBluetoothState4:
754  case k_EPS4ReportIdBluetoothState5:
755  case k_EPS4ReportIdBluetoothState6:
756  case k_EPS4ReportIdBluetoothState7:
757  case k_EPS4ReportIdBluetoothState8:
758  case k_EPS4ReportIdBluetoothState9:
759  /* Bluetooth state packets have two additional bytes at the beginning, the first notes if HID is present */
760  if (data[1] & 0x80) {
761  HIDAPI_DriverPS4_HandleStatePacket(joystick, device->dev, ctx, (PS4StatePacket_t*)&data[3]);
762  }
763  break;
764  default:
765 #ifdef DEBUG_JOYSTICK
766  SDL_Log("Unknown PS4 packet: 0x%.2x\n", data[0]);
767 #endif
768  break;
769  }
770  }
771 
772  if (size < 0) {
773  /* Read error, device is disconnected */
775  }
776  return (size >= 0);
777 }
778 
779 static void
780 HIDAPI_DriverPS4_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
781 {
782  hid_close(device->dev);
783  device->dev = NULL;
784 
785  SDL_free(device->context);
786  device->context = NULL;
787 }
788 
789 static void
790 HIDAPI_DriverPS4_FreeDevice(SDL_HIDAPI_Device *device)
791 {
792 }
793 
795 {
797  SDL_TRUE,
798  HIDAPI_DriverPS4_IsSupportedDevice,
799  HIDAPI_DriverPS4_GetDeviceName,
800  HIDAPI_DriverPS4_InitDevice,
801  HIDAPI_DriverPS4_GetDevicePlayerIndex,
802  HIDAPI_DriverPS4_SetDevicePlayerIndex,
803  HIDAPI_DriverPS4_UpdateDevice,
804  HIDAPI_DriverPS4_OpenJoystick,
805  HIDAPI_DriverPS4_RumbleJoystick,
806  HIDAPI_DriverPS4_RumbleJoystickTriggers,
807  HIDAPI_DriverPS4_HasJoystickLED,
808  HIDAPI_DriverPS4_SetJoystickLED,
809  HIDAPI_DriverPS4_SetJoystickSensorsEnabled,
810  HIDAPI_DriverPS4_CloseJoystick,
811  HIDAPI_DriverPS4_FreeDevice,
812 };
813 
814 #endif /* SDL_JOYSTICK_HIDAPI_PS4 */
815 
816 #endif /* SDL_JOYSTICK_HIDAPI */
817 
818 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_SetError
#define SDL_memset
#define SDL_abs
#define SDL_JoystickGetPlayerIndex
#define SDL_crc32
#define SDL_fabs
#define SDL_JoystickFromInstanceID
#define SDL_free
#define SDL_strdup
#define SDL_Delay
#define SDL_GetHintBoolean
#define SDL_memcpy
#define SDL_Log
#define SDL_snprintf
#define SDL_calloc
#define SDL_OutOfMemory()
Definition: SDL_error.h:88
#define SDL_Unsupported()
Definition: SDL_error.h:89
#define SDL_RELEASED
Definition: SDL_events.h:49
#define SDL_PRESSED
Definition: SDL_events.h:50
@ SDL_CONTROLLER_AXIS_LEFTX
@ SDL_CONTROLLER_AXIS_TRIGGERRIGHT
@ SDL_CONTROLLER_AXIS_RIGHTY
@ SDL_CONTROLLER_AXIS_RIGHTX
@ SDL_CONTROLLER_AXIS_MAX
@ SDL_CONTROLLER_AXIS_TRIGGERLEFT
@ SDL_CONTROLLER_AXIS_LEFTY
@ SDL_CONTROLLER_BUTTON_B
@ SDL_CONTROLLER_BUTTON_BACK
@ SDL_CONTROLLER_BUTTON_LEFTSTICK
@ SDL_CONTROLLER_BUTTON_START
@ SDL_CONTROLLER_BUTTON_DPAD_LEFT
@ SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
@ SDL_CONTROLLER_BUTTON_DPAD_DOWN
@ SDL_CONTROLLER_BUTTON_DPAD_UP
@ SDL_CONTROLLER_BUTTON_LEFTSHOULDER
@ SDL_CONTROLLER_BUTTON_GUIDE
@ SDL_CONTROLLER_BUTTON_DPAD_RIGHT
@ SDL_CONTROLLER_BUTTON_X
@ SDL_CONTROLLER_BUTTON_RIGHTSTICK
@ SDL_CONTROLLER_BUTTON_Y
@ SDL_CONTROLLER_BUTTON_A
SDL_GameControllerType
@ SDL_CONTROLLER_TYPE_PS4
const GLubyte GLuint red
Definition: SDL_glfuncs.h:80
#define USB_PACKET_LENGTH
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4
void HIDAPI_DumpPacket(const char *prefix, Uint8 *data, int size)
SDL_bool HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID)
void HIDAPI_JoystickDisconnected(SDL_HIDAPI_Device *device, SDL_JoystickID joystickID)
#define SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE
A variable controlling whether extended input reports should be used for PS4 controllers when using t...
Definition: SDL_hints.h:631
#define SDL_HINT_JOYSTICK_HIDAPI_PS4
A variable controlling whether the HIDAPI driver for PS4 controllers should be used.
Definition: SDL_hints.h:605
int SDL_PrivateJoystickTouchpad(SDL_Joystick *joystick, int touchpad, int finger, Uint8 state, float x, float y, float pressure)
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
void SDL_PrivateJoystickAddTouchpad(SDL_Joystick *joystick, int nfingers)
int SDL_PrivateJoystickSensor(SDL_Joystick *joystick, SDL_SensorType type, const float *data, int num_values)
void SDL_PrivateJoystickAddSensor(SDL_Joystick *joystick, SDL_SensorType type)
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
@ SDL_JOYSTICK_POWER_FULL
Definition: SDL_joystick.h:103
@ SDL_JOYSTICK_POWER_MEDIUM
Definition: SDL_joystick.h:102
@ SDL_JOYSTICK_POWER_EMPTY
Definition: SDL_joystick.h:100
@ SDL_JOYSTICK_POWER_WIRED
Definition: SDL_joystick.h:104
@ SDL_JOYSTICK_POWER_LOW
Definition: SDL_joystick.h:101
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:81
GLint level
Definition: SDL_opengl.h:1572
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLbyte GLbyte blue
GLuint64EXT * result
GLfloat bias
GLintptr offset
GLuint index
GLuint divisor
GLuint const GLchar * name
GLsizeiptr size
GLuint GLsizei GLsizei * length
GLbyte green
GLsizei const GLfloat * value
#define SDL_STANDARD_GRAVITY
Definition: SDL_sensor.h:99
@ SDL_SENSOR_GYRO
Definition: SDL_sensor.h:74
@ SDL_SENSOR_ACCEL
Definition: SDL_sensor.h:73
uint16_t Uint16
Definition: SDL_stdinc.h:197
int16_t Sint16
Definition: SDL_stdinc.h:191
#define SDL_zero(x)
Definition: SDL_stdinc.h:426
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_TRUE
Definition: SDL_stdinc.h:170
@ SDL_FALSE
Definition: SDL_stdinc.h:169
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:121
uint8_t Uint8
Definition: SDL_stdinc.h:185
uint32_t Uint32
Definition: SDL_stdinc.h:209
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:163
EGLContext ctx
Definition: eglext.h:208
int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *device, unsigned char *data, size_t length, int milliseconds)
Read an Input report from a HID device with timeout.
int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length)
Get a feature report from a HID device.
HID_API_EXPORT hid_device *HID_API_CALL hid_open_path(const char *path, int bExclusive)
Open a HID device by its path name.
void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device)
Close a HID device.
struct hid_device_ hid_device
Definition: hidapi.h:54
static SDL_AudioDeviceID device
Definition: loopwave.c:37
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
SDL_Texture * axis
static int colors[7]
Definition: testgesture.c:41
static SDL_Joystick * joystick
Definition: testjoystick.c:37
#define USB_PRODUCT_RAZER_PANTHERA_EVO
Definition: usb_ids.h:41
#define USB_PRODUCT_RAZER_PANTHERA
Definition: usb_ids.h:40
#define USB_VENDOR_RAZER
Definition: usb_ids.h:35
#define USB_PRODUCT_SONY_DS4_SLIM
Definition: usb_ids.h:45
#define USB_VENDOR_SONY
Definition: usb_ids.h:34
#define USB_PRODUCT_SONY_DS4_DONGLE
Definition: usb_ids.h:44
typedef int(__stdcall *FARPROC)()