SDL_hidapi_ps5.c (35554B)
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 #include "../../SDL_internal.h" 22 23 #ifdef SDL_JOYSTICK_HIDAPI 24 25 #include "SDL_hints.h" 26 #include "SDL_events.h" 27 #include "SDL_timer.h" 28 #include "SDL_joystick.h" 29 #include "SDL_gamecontroller.h" 30 #include "../SDL_sysjoystick.h" 31 #include "SDL_hidapijoystick_c.h" 32 #include "SDL_hidapi_rumble.h" 33 34 35 #ifdef SDL_JOYSTICK_HIDAPI_PS5 36 37 /* Define this if you want to log all packets from the controller */ 38 /*#define DEBUG_PS5_PROTOCOL*/ 39 40 /* Define this if you want to log calibration data */ 41 /*#define DEBUG_PS5_CALIBRATION*/ 42 43 #define GYRO_RES_PER_DEGREE 1024.0f 44 #define ACCEL_RES_PER_G 8192.0f 45 #define BLUETOOTH_DISCONNECT_TIMEOUT_MS 500 46 47 #define LOAD16(A, B) (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8)) 48 49 typedef enum 50 { 51 k_EPS5ReportIdState = 0x01, 52 k_EPS5ReportIdUsbEffects = 0x02, 53 k_EPS5ReportIdBluetoothEffects = 0x31, 54 k_EPS5ReportIdBluetoothState = 0x31, 55 } EPS5ReportId; 56 57 typedef enum 58 { 59 k_EPS5FeatureReportIdCalibration = 0x05, 60 k_EPS5FeatureReportIdSerialNumber = 0x09, 61 } EPS5FeatureReportId; 62 63 typedef struct 64 { 65 Uint8 ucLeftJoystickX; 66 Uint8 ucLeftJoystickY; 67 Uint8 ucRightJoystickX; 68 Uint8 ucRightJoystickY; 69 Uint8 rgucButtonsHatAndCounter[3]; 70 Uint8 ucTriggerLeft; 71 Uint8 ucTriggerRight; 72 } PS5SimpleStatePacket_t; 73 74 typedef struct 75 { 76 Uint8 ucLeftJoystickX; /* 0 */ 77 Uint8 ucLeftJoystickY; /* 1 */ 78 Uint8 ucRightJoystickX; /* 2 */ 79 Uint8 ucRightJoystickY; /* 3 */ 80 Uint8 ucTriggerLeft; /* 4 */ 81 Uint8 ucTriggerRight; /* 5 */ 82 Uint8 ucCounter; /* 6 */ 83 Uint8 rgucButtonsAndHat[3]; /* 7 */ 84 Uint8 ucZero; /* 10 */ 85 Uint8 rgucPacketSequence[4]; /* 11 - 32 bit little endian */ 86 Uint8 rgucGyroX[2]; /* 15 */ 87 Uint8 rgucGyroY[2]; /* 17 */ 88 Uint8 rgucGyroZ[2]; /* 19 */ 89 Uint8 rgucAccelX[2]; /* 21 */ 90 Uint8 rgucAccelY[2]; /* 23 */ 91 Uint8 rgucAccelZ[2]; /* 25 */ 92 Uint8 rgucTimer1[4]; /* 27 - 32 bit little endian */ 93 Uint8 ucBatteryTemp; /* 31 */ 94 Uint8 ucTouchpadCounter1; /* 32 - high bit clear + counter */ 95 Uint8 rgucTouchpadData1[3]; /* 33 - X/Y, 12 bits per axis */ 96 Uint8 ucTouchpadCounter2; /* 36 - high bit clear + counter */ 97 Uint8 rgucTouchpadData2[3]; /* 37 - X/Y, 12 bits per axis */ 98 Uint8 rgucUnknown1[8]; /* 40 */ 99 Uint8 rgucTimer2[4]; /* 48 - 32 bit little endian */ 100 Uint8 ucBatteryLevel; /* 52 */ 101 Uint8 ucConnectState; /* 53 - 0x08 = USB, 0x01 = headphone */ 102 103 /* There's more unknown data at the end, and a 32-bit CRC on Bluetooth */ 104 } PS5StatePacket_t; 105 106 typedef struct 107 { 108 Uint8 ucEnableBits1; /* 0 */ 109 Uint8 ucEnableBits2; /* 1 */ 110 Uint8 ucRumbleRight; /* 2 */ 111 Uint8 ucRumbleLeft; /* 3 */ 112 Uint8 ucHeadphoneVolume; /* 4 */ 113 Uint8 ucSpeakerVolume; /* 5 */ 114 Uint8 ucMicrophoneVolume; /* 6 */ 115 Uint8 ucAudioEnableBits; /* 7 */ 116 Uint8 ucMicLightMode; /* 8 */ 117 Uint8 ucAudioMuteBits; /* 9 */ 118 Uint8 rgucRightTriggerEffect[11]; /* 10 */ 119 Uint8 rgucLeftTriggerEffect[11]; /* 21 */ 120 Uint8 rgucUnknown1[6]; /* 32 */ 121 Uint8 ucLedFlags; /* 38 */ 122 Uint8 rgucUnknown2[2]; /* 39 */ 123 Uint8 ucLedAnim; /* 41 */ 124 Uint8 ucLedBrightness; /* 42 */ 125 Uint8 ucPadLights; /* 43 */ 126 Uint8 ucLedRed; /* 44 */ 127 Uint8 ucLedGreen; /* 45 */ 128 Uint8 ucLedBlue; /* 46 */ 129 } DS5EffectsState_t; 130 131 typedef enum { 132 k_EDS5EffectNone, 133 k_EDS5EffectRumbleStart, 134 k_EDS5EffectRumble, 135 k_EDS5EffectLEDReset, 136 k_EDS5EffectLED, 137 k_EDS5EffectPadLights, 138 k_EDS5EffectMicLight, 139 } EDS5Effect; 140 141 typedef enum { 142 k_EDS5LEDResetStateNone, 143 k_EDS5LEDResetStatePending, 144 k_EDS5LEDResetStateComplete, 145 } EDS5LEDResetState; 146 147 typedef struct { 148 Sint16 bias; 149 float sensitivity; 150 } IMUCalibrationData; 151 152 typedef struct { 153 SDL_bool is_bluetooth; 154 SDL_bool report_sensors; 155 SDL_bool hardware_calibration; 156 IMUCalibrationData calibration[6]; 157 Uint32 last_packet; 158 int player_index; 159 Uint8 rumble_left; 160 Uint8 rumble_right; 161 SDL_bool color_set; 162 Uint8 led_red; 163 Uint8 led_green; 164 Uint8 led_blue; 165 EDS5LEDResetState led_reset_state; 166 union 167 { 168 PS5SimpleStatePacket_t simple; 169 PS5StatePacket_t state; 170 } last_state; 171 } SDL_DriverPS5_Context; 172 173 174 static SDL_bool 175 HIDAPI_DriverPS5_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) 176 { 177 return (type == SDL_CONTROLLER_TYPE_PS5) ? SDL_TRUE : SDL_FALSE; 178 } 179 180 static const char * 181 HIDAPI_DriverPS5_GetDeviceName(Uint16 vendor_id, Uint16 product_id) 182 { 183 if (vendor_id == USB_VENDOR_SONY) { 184 return "PS5 Controller"; 185 } 186 return NULL; 187 } 188 189 static int ReadFeatureReport(hid_device *dev, Uint8 report_id, Uint8 *report, size_t length) 190 { 191 SDL_memset(report, 0, length); 192 report[0] = report_id; 193 return hid_get_feature_report(dev, report, length); 194 } 195 196 static void 197 SetLedsForPlayerIndex(DS5EffectsState_t *effects, int player_index) 198 { 199 /* This list is the same as what hid-sony.c uses in the Linux kernel. 200 The first 4 values correspond to what the PS4 assigns. 201 */ 202 static const Uint8 colors[7][3] = { 203 { 0x00, 0x00, 0x40 }, /* Blue */ 204 { 0x40, 0x00, 0x00 }, /* Red */ 205 { 0x00, 0x40, 0x00 }, /* Green */ 206 { 0x20, 0x00, 0x20 }, /* Pink */ 207 { 0x02, 0x01, 0x00 }, /* Orange */ 208 { 0x00, 0x01, 0x01 }, /* Teal */ 209 { 0x01, 0x01, 0x01 } /* White */ 210 }; 211 212 if (player_index >= 0) { 213 player_index %= SDL_arraysize(colors); 214 } else { 215 player_index = 0; 216 } 217 218 effects->ucLedRed = colors[player_index][0]; 219 effects->ucLedGreen = colors[player_index][1]; 220 effects->ucLedBlue = colors[player_index][2]; 221 } 222 223 static SDL_bool 224 HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device) 225 { 226 return HIDAPI_JoystickConnected(device, NULL); 227 } 228 229 static int 230 HIDAPI_DriverPS5_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id) 231 { 232 return -1; 233 } 234 235 static void 236 HIDAPI_DriverPS5_LoadCalibrationData(SDL_HIDAPI_Device *device) 237 { 238 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; 239 int i, size; 240 Uint8 data[USB_PACKET_LENGTH]; 241 242 size = ReadFeatureReport(device->dev, k_EPS5FeatureReportIdCalibration, data, sizeof(data)); 243 if (size < 35) { 244 #ifdef DEBUG_PS5_CALIBRATION 245 SDL_Log("Short read of calibration data: %d, ignoring calibration\n", size); 246 #endif 247 return; 248 } 249 250 { 251 Sint16 sGyroPitchBias, sGyroYawBias, sGyroRollBias; 252 Sint16 sGyroPitchPlus, sGyroPitchMinus; 253 Sint16 sGyroYawPlus, sGyroYawMinus; 254 Sint16 sGyroRollPlus, sGyroRollMinus; 255 Sint16 sGyroSpeedPlus, sGyroSpeedMinus; 256 257 Sint16 sAccXPlus, sAccXMinus; 258 Sint16 sAccYPlus, sAccYMinus; 259 Sint16 sAccZPlus, sAccZMinus; 260 261 float flNumerator; 262 Sint16 sRange2g; 263 264 #ifdef DEBUG_PS5_CALIBRATION 265 HIDAPI_DumpPacket("PS5 calibration packet: size = %d", data, size); 266 #endif 267 268 sGyroPitchBias = LOAD16(data[1], data[2]); 269 sGyroYawBias = LOAD16(data[3], data[4]); 270 sGyroRollBias = LOAD16(data[5], data[6]); 271 272 sGyroPitchPlus = LOAD16(data[7], data[8]); 273 sGyroPitchMinus = LOAD16(data[9], data[10]); 274 sGyroYawPlus = LOAD16(data[11], data[12]); 275 sGyroYawMinus = LOAD16(data[13], data[14]); 276 sGyroRollPlus = LOAD16(data[15], data[16]); 277 sGyroRollMinus = LOAD16(data[17], data[18]); 278 279 sGyroSpeedPlus = LOAD16(data[19], data[20]); 280 sGyroSpeedMinus = LOAD16(data[21], data[22]); 281 282 sAccXPlus = LOAD16(data[23], data[24]); 283 sAccXMinus = LOAD16(data[25], data[26]); 284 sAccYPlus = LOAD16(data[27], data[28]); 285 sAccYMinus = LOAD16(data[29], data[30]); 286 sAccZPlus = LOAD16(data[31], data[32]); 287 sAccZMinus = LOAD16(data[33], data[34]); 288 289 flNumerator = (sGyroSpeedPlus + sGyroSpeedMinus) * GYRO_RES_PER_DEGREE; 290 ctx->calibration[0].bias = sGyroPitchBias; 291 ctx->calibration[0].sensitivity = flNumerator / (sGyroPitchPlus - sGyroPitchMinus); 292 293 ctx->calibration[1].bias = sGyroYawBias; 294 ctx->calibration[1].sensitivity = flNumerator / (sGyroYawPlus - sGyroYawMinus); 295 296 ctx->calibration[2].bias = sGyroRollBias; 297 ctx->calibration[2].sensitivity = flNumerator / (sGyroRollPlus - sGyroRollMinus); 298 299 sRange2g = sAccXPlus - sAccXMinus; 300 ctx->calibration[3].bias = sAccXPlus - sRange2g / 2; 301 ctx->calibration[3].sensitivity = 2.0f * ACCEL_RES_PER_G / (float)sRange2g; 302 303 sRange2g = sAccYPlus - sAccYMinus; 304 ctx->calibration[4].bias = sAccYPlus - sRange2g / 2; 305 ctx->calibration[4].sensitivity = 2.0f * ACCEL_RES_PER_G / (float)sRange2g; 306 307 sRange2g = sAccZPlus - sAccZMinus; 308 ctx->calibration[5].bias = sAccZPlus - sRange2g / 2; 309 ctx->calibration[5].sensitivity = 2.0f * ACCEL_RES_PER_G / (float)sRange2g; 310 311 ctx->hardware_calibration = SDL_TRUE; 312 for (i = 0; i < 6; ++i) { 313 float divisor = (i < 3 ? 64.0f : 1.0f); 314 #ifdef DEBUG_PS5_CALIBRATION 315 SDL_Log("calibration[%d] bias = %d, sensitivity = %f\n", i, ctx->calibration[i].bias, ctx->calibration[i].sensitivity); 316 #endif 317 /* Some controllers have a bad calibration */ 318 if ((SDL_abs(ctx->calibration[i].bias) > 1024) || (SDL_fabs(1.0f - ctx->calibration[i].sensitivity / divisor) > 0.5f)) { 319 #ifdef DEBUG_PS5_CALIBRATION 320 SDL_Log("invalid calibration, ignoring\n"); 321 #endif 322 ctx->hardware_calibration = SDL_FALSE; 323 } 324 } 325 } 326 } 327 328 static float 329 HIDAPI_DriverPS5_ApplyCalibrationData(SDL_DriverPS5_Context *ctx, int index, Sint16 value) 330 { 331 float result; 332 333 if (ctx->hardware_calibration) { 334 IMUCalibrationData *calibration = &ctx->calibration[index]; 335 336 result = (value - calibration->bias) * calibration->sensitivity; 337 } else if (index < 3) { 338 result = value * 64.f; 339 } else { 340 result = value; 341 } 342 343 /* Convert the raw data to the units expected by SDL */ 344 if (index < 3) { 345 result = (result / GYRO_RES_PER_DEGREE) * (float)M_PI / 180.0f; 346 } else { 347 result = (result / ACCEL_RES_PER_G) * SDL_STANDARD_GRAVITY; 348 } 349 return result; 350 } 351 352 static int 353 HIDAPI_DriverPS5_UpdateEffects(SDL_HIDAPI_Device *device, EDS5Effect effect) 354 { 355 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; 356 DS5EffectsState_t *effects; 357 Uint8 data[78]; 358 int report_size, offset; 359 Uint8 *pending_data; 360 int *pending_size; 361 int maximum_size; 362 363 364 SDL_zero(data); 365 366 if (ctx->is_bluetooth) { 367 data[0] = k_EPS5ReportIdBluetoothEffects; 368 data[1] = 0x02; /* Magic value */ 369 370 report_size = 78; 371 offset = 2; 372 } else { 373 data[0] = k_EPS5ReportIdUsbEffects; 374 375 report_size = 48; 376 offset = 1; 377 } 378 effects = (DS5EffectsState_t *)&data[offset]; 379 380 /* Make sure the Bluetooth connection sequence has completed before sending LED color change */ 381 if (effect == k_EDS5EffectLED && ctx->is_bluetooth) { 382 if (ctx->led_reset_state != k_EDS5LEDResetStateComplete) { 383 ctx->led_reset_state = k_EDS5LEDResetStatePending; 384 return 0; 385 } 386 } 387 388 if (ctx->rumble_left || ctx->rumble_right) { 389 effects->ucEnableBits1 |= 0x01; /* Enable rumble emulation */ 390 effects->ucEnableBits1 |= 0x02; /* Disable audio haptics */ 391 392 /* Shift to reduce effective rumble strength to match Xbox controllers */ 393 effects->ucRumbleLeft = ctx->rumble_left >> 1; 394 effects->ucRumbleRight = ctx->rumble_right >> 1; 395 } else { 396 /* Leaving emulated rumble bits off will restore audio haptics */ 397 } 398 399 switch (effect) { 400 case k_EDS5EffectRumbleStart: 401 effects->ucEnableBits1 |= 0x02; /* Disable audio haptics */ 402 break; 403 case k_EDS5EffectRumble: 404 /* Already handled above */ 405 break; 406 case k_EDS5EffectLEDReset: 407 effects->ucEnableBits2 |= 0x08; /* Reset LED state */ 408 break; 409 case k_EDS5EffectLED: 410 effects->ucEnableBits2 |= 0x04; /* Enable LED color */ 411 412 /* Populate the LED state with the appropriate color from our lookup table */ 413 if (ctx->color_set) { 414 effects->ucLedRed = ctx->led_red; 415 effects->ucLedGreen = ctx->led_green; 416 effects->ucLedBlue = ctx->led_blue; 417 } else { 418 SetLedsForPlayerIndex(effects, ctx->player_index); 419 } 420 break; 421 case k_EDS5EffectPadLights: 422 effects->ucEnableBits2 |= 0x10; /* Enable touchpad lights */ 423 424 effects->ucPadLights = 0x00; /* Bitmask, 0x1F enables all lights, 0x20 changes instantly instead of fade */ 425 break; 426 case k_EDS5EffectMicLight: 427 effects->ucEnableBits2 |= 0x01; /* Enable microphone light */ 428 429 effects->ucMicLightMode = 0; /* Bitmask, 0x00 = off, 0x01 = solid, 0x02 = pulse */ 430 break; 431 default: 432 break; 433 } 434 435 if (ctx->is_bluetooth) { 436 /* Bluetooth reports need a CRC at the end of the packet (at least on Linux) */ 437 Uint8 ubHdr = 0xA2; /* hidp header is part of the CRC calculation */ 438 Uint32 unCRC; 439 unCRC = SDL_crc32(0, &ubHdr, 1); 440 unCRC = SDL_crc32(unCRC, data, (size_t)(report_size - sizeof(unCRC))); 441 SDL_memcpy(&data[report_size - sizeof(unCRC)], &unCRC, sizeof(unCRC)); 442 } 443 444 if (SDL_HIDAPI_LockRumble() < 0) { 445 return -1; 446 } 447 448 /* See if we can update an existing pending request */ 449 if (SDL_HIDAPI_GetPendingRumbleLocked(device, &pending_data, &pending_size, &maximum_size)) { 450 DS5EffectsState_t *pending_effects = (DS5EffectsState_t *)&pending_data[offset]; 451 if (report_size == *pending_size && 452 effects->ucEnableBits1 == pending_effects->ucEnableBits1 && 453 effects->ucEnableBits2 == pending_effects->ucEnableBits2) { 454 /* We're simply updating the data for this request */ 455 SDL_memcpy(pending_data, data, report_size); 456 SDL_HIDAPI_UnlockRumble(); 457 return 0; 458 } 459 } 460 461 return SDL_HIDAPI_SendRumbleAndUnlock(device, data, report_size); 462 } 463 464 static void 465 HIDAPI_DriverPS5_SetBluetooth(SDL_HIDAPI_Device *device, SDL_bool is_bluetooth) 466 { 467 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; 468 469 if (ctx->is_bluetooth != is_bluetooth) { 470 ctx->is_bluetooth = is_bluetooth; 471 HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectLED); 472 } 473 } 474 475 static void 476 HIDAPI_DriverPS5_CheckPendingLEDReset(SDL_HIDAPI_Device *device) 477 { 478 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; 479 const PS5StatePacket_t *packet = &ctx->last_state.state; 480 481 /* Check the timer to make sure the Bluetooth connection LED animation is complete */ 482 const Uint32 connection_complete = 10000000; 483 Uint32 timer = ((Uint32)packet->rgucTimer1[0] << 0) | 484 ((Uint32)packet->rgucTimer1[1] << 8) | 485 ((Uint32)packet->rgucTimer1[2] << 16) | 486 ((Uint32)packet->rgucTimer1[3] << 24); 487 if (timer >= connection_complete) { 488 HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectLEDReset); 489 490 ctx->led_reset_state = k_EDS5LEDResetStateComplete; 491 492 HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectLED); 493 } 494 } 495 496 static void 497 HIDAPI_DriverPS5_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) 498 { 499 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; 500 501 if (!ctx) { 502 return; 503 } 504 505 ctx->player_index = player_index; 506 507 /* This will set the new LED state based on the new player index */ 508 HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectLED); 509 } 510 511 static SDL_bool 512 HIDAPI_DriverPS5_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 513 { 514 SDL_DriverPS5_Context *ctx; 515 Uint8 data[USB_PACKET_LENGTH]; 516 517 ctx = (SDL_DriverPS5_Context *)SDL_calloc(1, sizeof(*ctx)); 518 if (!ctx) { 519 SDL_OutOfMemory(); 520 return SDL_FALSE; 521 } 522 ctx->last_packet = SDL_GetTicks(); 523 524 device->dev = hid_open_path(device->path, 0); 525 if (!device->dev) { 526 SDL_free(ctx); 527 SDL_SetError("Couldn't open %s", device->path); 528 return SDL_FALSE; 529 } 530 device->context = ctx; 531 532 /* Read the serial number (Bluetooth address in reverse byte order) 533 This will also enable enhanced reports over Bluetooth 534 */ 535 if (ReadFeatureReport(device->dev, k_EPS5FeatureReportIdSerialNumber, data, sizeof(data)) >= 7) { 536 char serial[18]; 537 538 SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", 539 data[6], data[5], data[4], data[3], data[2], data[1]); 540 joystick->serial = SDL_strdup(serial); 541 } 542 543 /* Initialize player index (needed for setting LEDs) */ 544 ctx->player_index = SDL_JoystickGetPlayerIndex(joystick); 545 546 /* Initialize LED and effect state */ 547 HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectLED); 548 549 /* Initialize the joystick capabilities */ 550 joystick->nbuttons = 17; 551 joystick->naxes = SDL_CONTROLLER_AXIS_MAX; 552 553 SDL_PrivateJoystickAddTouchpad(joystick, 2); 554 SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO); 555 SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL); 556 557 return SDL_TRUE; 558 } 559 560 static int 561 HIDAPI_DriverPS5_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 562 { 563 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; 564 565 if (!ctx->rumble_left && !ctx->rumble_right) { 566 HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectRumbleStart); 567 } 568 569 ctx->rumble_left = (low_frequency_rumble >> 8); 570 ctx->rumble_right = (high_frequency_rumble >> 8); 571 572 return HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectRumble); 573 } 574 575 static int 576 HIDAPI_DriverPS5_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) 577 { 578 return SDL_Unsupported(); 579 } 580 581 static SDL_bool 582 HIDAPI_DriverPS5_HasJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 583 { 584 return SDL_FALSE; 585 } 586 587 static int 588 HIDAPI_DriverPS5_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) 589 { 590 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; 591 592 ctx->color_set = SDL_TRUE; 593 ctx->led_red = red; 594 ctx->led_green = green; 595 ctx->led_blue = blue; 596 597 return HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectLED); 598 } 599 600 static int 601 HIDAPI_DriverPS5_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled) 602 { 603 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; 604 605 if (enabled) { 606 HIDAPI_DriverPS5_LoadCalibrationData(device); 607 } 608 ctx->report_sensors = enabled; 609 610 return 0; 611 } 612 613 static void 614 HIDAPI_DriverPS5_HandleSimpleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverPS5_Context *ctx, PS5SimpleStatePacket_t *packet) 615 { 616 Sint16 axis; 617 618 if (ctx->last_state.simple.rgucButtonsHatAndCounter[0] != packet->rgucButtonsHatAndCounter[0]) { 619 { 620 Uint8 data = (packet->rgucButtonsHatAndCounter[0] >> 4); 621 622 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED); 623 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED); 624 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED); 625 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED); 626 } 627 { 628 Uint8 data = (packet->rgucButtonsHatAndCounter[0] & 0x0F); 629 SDL_bool dpad_up = SDL_FALSE; 630 SDL_bool dpad_down = SDL_FALSE; 631 SDL_bool dpad_left = SDL_FALSE; 632 SDL_bool dpad_right = SDL_FALSE; 633 634 switch (data) { 635 case 0: 636 dpad_up = SDL_TRUE; 637 break; 638 case 1: 639 dpad_up = SDL_TRUE; 640 dpad_right = SDL_TRUE; 641 break; 642 case 2: 643 dpad_right = SDL_TRUE; 644 break; 645 case 3: 646 dpad_right = SDL_TRUE; 647 dpad_down = SDL_TRUE; 648 break; 649 case 4: 650 dpad_down = SDL_TRUE; 651 break; 652 case 5: 653 dpad_left = SDL_TRUE; 654 dpad_down = SDL_TRUE; 655 break; 656 case 6: 657 dpad_left = SDL_TRUE; 658 break; 659 case 7: 660 dpad_up = SDL_TRUE; 661 dpad_left = SDL_TRUE; 662 break; 663 default: 664 break; 665 } 666 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down); 667 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up); 668 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right); 669 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left); 670 } 671 } 672 673 if (ctx->last_state.simple.rgucButtonsHatAndCounter[1] != packet->rgucButtonsHatAndCounter[1]) { 674 Uint8 data = packet->rgucButtonsHatAndCounter[1]; 675 676 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED); 677 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED); 678 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED); 679 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED); 680 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED); 681 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x80) ? SDL_PRESSED : SDL_RELEASED); 682 } 683 684 if (ctx->last_state.simple.rgucButtonsHatAndCounter[2] != packet->rgucButtonsHatAndCounter[2]) { 685 Uint8 data = (packet->rgucButtonsHatAndCounter[2] & 0x03); 686 687 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED); 688 SDL_PrivateJoystickButton(joystick, 15, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED); 689 } 690 691 axis = ((int)packet->ucTriggerLeft * 257) - 32768; 692 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis); 693 axis = ((int)packet->ucTriggerRight * 257) - 32768; 694 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis); 695 axis = ((int)packet->ucLeftJoystickX * 257) - 32768; 696 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis); 697 axis = ((int)packet->ucLeftJoystickY * 257) - 32768; 698 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis); 699 axis = ((int)packet->ucRightJoystickX * 257) - 32768; 700 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis); 701 axis = ((int)packet->ucRightJoystickY * 257) - 32768; 702 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis); 703 704 SDL_memcpy(&ctx->last_state.simple, packet, sizeof(ctx->last_state.simple)); 705 } 706 707 static void 708 HIDAPI_DriverPS5_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacket_t *packet) 709 { 710 static const float TOUCHPAD_SCALEX = 1.0f / 1920; 711 static const float TOUCHPAD_SCALEY = 1.0f / 1070; 712 Sint16 axis; 713 Uint8 touchpad_state; 714 int touchpad_x, touchpad_y; 715 716 if (ctx->last_state.state.rgucButtonsAndHat[0] != packet->rgucButtonsAndHat[0]) { 717 { 718 Uint8 data = (packet->rgucButtonsAndHat[0] >> 4); 719 720 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED); 721 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED); 722 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED); 723 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED); 724 } 725 { 726 Uint8 data = (packet->rgucButtonsAndHat[0] & 0x0F); 727 SDL_bool dpad_up = SDL_FALSE; 728 SDL_bool dpad_down = SDL_FALSE; 729 SDL_bool dpad_left = SDL_FALSE; 730 SDL_bool dpad_right = SDL_FALSE; 731 732 switch (data) { 733 case 0: 734 dpad_up = SDL_TRUE; 735 break; 736 case 1: 737 dpad_up = SDL_TRUE; 738 dpad_right = SDL_TRUE; 739 break; 740 case 2: 741 dpad_right = SDL_TRUE; 742 break; 743 case 3: 744 dpad_right = SDL_TRUE; 745 dpad_down = SDL_TRUE; 746 break; 747 case 4: 748 dpad_down = SDL_TRUE; 749 break; 750 case 5: 751 dpad_left = SDL_TRUE; 752 dpad_down = SDL_TRUE; 753 break; 754 case 6: 755 dpad_left = SDL_TRUE; 756 break; 757 case 7: 758 dpad_up = SDL_TRUE; 759 dpad_left = SDL_TRUE; 760 break; 761 default: 762 break; 763 } 764 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down); 765 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up); 766 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right); 767 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left); 768 } 769 } 770 771 if (ctx->last_state.state.rgucButtonsAndHat[1] != packet->rgucButtonsAndHat[1]) { 772 Uint8 data = packet->rgucButtonsAndHat[1]; 773 774 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED); 775 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED); 776 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED); 777 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED); 778 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED); 779 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x80) ? SDL_PRESSED : SDL_RELEASED); 780 } 781 782 if (ctx->last_state.state.rgucButtonsAndHat[2] != packet->rgucButtonsAndHat[2]) { 783 Uint8 data = packet->rgucButtonsAndHat[2]; 784 785 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED); 786 SDL_PrivateJoystickButton(joystick, 15, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED); 787 SDL_PrivateJoystickButton(joystick, 16, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED); 788 } 789 790 axis = ((int)packet->ucTriggerLeft * 257) - 32768; 791 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis); 792 axis = ((int)packet->ucTriggerRight * 257) - 32768; 793 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis); 794 axis = ((int)packet->ucLeftJoystickX * 257) - 32768; 795 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis); 796 axis = ((int)packet->ucLeftJoystickY * 257) - 32768; 797 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis); 798 axis = ((int)packet->ucRightJoystickX * 257) - 32768; 799 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis); 800 axis = ((int)packet->ucRightJoystickY * 257) - 32768; 801 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis); 802 803 if (packet->ucBatteryLevel & 0x10) { 804 /* 0x20 set means fully charged */ 805 SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_WIRED); 806 } else { 807 /* Battery level ranges from 0 to 10 */ 808 int level = (packet->ucBatteryLevel & 0xF); 809 if (level == 0) { 810 SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_EMPTY); 811 } else if (level <= 2) { 812 SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_LOW); 813 } else if (level <= 7) { 814 SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_MEDIUM); 815 } else { 816 SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_FULL); 817 } 818 } 819 820 touchpad_state = ((packet->ucTouchpadCounter1 & 0x80) == 0) ? SDL_PRESSED : SDL_RELEASED; 821 touchpad_x = packet->rgucTouchpadData1[0] | (((int)packet->rgucTouchpadData1[1] & 0x0F) << 8); 822 touchpad_y = (packet->rgucTouchpadData1[1] >> 4) | ((int)packet->rgucTouchpadData1[2] << 4); 823 SDL_PrivateJoystickTouchpad(joystick, 0, 0, touchpad_state, touchpad_x * TOUCHPAD_SCALEX, touchpad_y * TOUCHPAD_SCALEY, touchpad_state ? 1.0f : 0.0f); 824 825 touchpad_state = ((packet->ucTouchpadCounter2 & 0x80) == 0) ? SDL_PRESSED : SDL_RELEASED; 826 touchpad_x = packet->rgucTouchpadData2[0] | (((int)packet->rgucTouchpadData2[1] & 0x0F) << 8); 827 touchpad_y = (packet->rgucTouchpadData2[1] >> 4) | ((int)packet->rgucTouchpadData2[2] << 4); 828 SDL_PrivateJoystickTouchpad(joystick, 0, 1, touchpad_state, touchpad_x * TOUCHPAD_SCALEX, touchpad_y * TOUCHPAD_SCALEY, touchpad_state ? 1.0f : 0.0f); 829 830 if (ctx->report_sensors) { 831 float data[3]; 832 833 data[0] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 0, LOAD16(packet->rgucGyroX[0], packet->rgucGyroX[1])); 834 data[1] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 1, LOAD16(packet->rgucGyroY[0], packet->rgucGyroY[1])); 835 data[2] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 2, LOAD16(packet->rgucGyroZ[0], packet->rgucGyroZ[1])); 836 SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_GYRO, data, 3); 837 838 data[0] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 3, LOAD16(packet->rgucAccelX[0], packet->rgucAccelX[1])); 839 data[1] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 4, LOAD16(packet->rgucAccelY[0], packet->rgucAccelY[1])); 840 data[2] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 5, LOAD16(packet->rgucAccelZ[0], packet->rgucAccelZ[1])); 841 SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_ACCEL, data, 3); 842 } 843 844 SDL_memcpy(&ctx->last_state.state, packet, sizeof(ctx->last_state.state)); 845 } 846 847 static SDL_bool 848 HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device) 849 { 850 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; 851 SDL_Joystick *joystick = NULL; 852 Uint8 data[USB_PACKET_LENGTH*2]; 853 int size; 854 int packet_count = 0; 855 856 if (device->num_joysticks > 0) { 857 joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); 858 } 859 if (!joystick) { 860 return SDL_FALSE; 861 } 862 863 while ((size = hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) { 864 #ifdef DEBUG_PS5_PROTOCOL 865 HIDAPI_DumpPacket("PS5 packet: size = %d", data, size); 866 #endif 867 ++packet_count; 868 ctx->last_packet = SDL_GetTicks(); 869 870 switch (data[0]) { 871 case k_EPS5ReportIdState: 872 if (size == 10) { 873 HIDAPI_DriverPS5_SetBluetooth(device, SDL_TRUE); /* Simple state packet over Bluetooth */ 874 HIDAPI_DriverPS5_HandleSimpleStatePacket(joystick, device->dev, ctx, (PS5SimpleStatePacket_t *)&data[1]); 875 } else { 876 HIDAPI_DriverPS5_SetBluetooth(device, SDL_FALSE); 877 HIDAPI_DriverPS5_HandleStatePacket(joystick, device->dev, ctx, (PS5StatePacket_t *)&data[1]); 878 } 879 break; 880 case k_EPS5ReportIdBluetoothState: 881 HIDAPI_DriverPS5_SetBluetooth(device, SDL_TRUE); 882 HIDAPI_DriverPS5_HandleStatePacket(joystick, device->dev, ctx, (PS5StatePacket_t *)&data[2]); 883 if (ctx->led_reset_state == k_EDS5LEDResetStatePending) { 884 HIDAPI_DriverPS5_CheckPendingLEDReset(device); 885 } 886 break; 887 default: 888 #ifdef DEBUG_JOYSTICK 889 SDL_Log("Unknown PS5 packet: 0x%.2x\n", data[0]); 890 #endif 891 break; 892 } 893 } 894 895 if (ctx->is_bluetooth && packet_count == 0) { 896 /* Check to see if it looks like the device disconnected */ 897 if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->last_packet + BLUETOOTH_DISCONNECT_TIMEOUT_MS)) { 898 /* Send an empty output report to tickle the Bluetooth stack */ 899 HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectNone); 900 } 901 } 902 903 if (size < 0) { 904 /* Read error, device is disconnected */ 905 HIDAPI_JoystickDisconnected(device, joystick->instance_id); 906 } 907 return (size >= 0); 908 } 909 910 static void 911 HIDAPI_DriverPS5_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 912 { 913 hid_close(device->dev); 914 device->dev = NULL; 915 916 SDL_free(device->context); 917 device->context = NULL; 918 } 919 920 static void 921 HIDAPI_DriverPS5_FreeDevice(SDL_HIDAPI_Device *device) 922 { 923 } 924 925 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS5 = 926 { 927 SDL_HINT_JOYSTICK_HIDAPI_PS5, 928 SDL_TRUE, 929 HIDAPI_DriverPS5_IsSupportedDevice, 930 HIDAPI_DriverPS5_GetDeviceName, 931 HIDAPI_DriverPS5_InitDevice, 932 HIDAPI_DriverPS5_GetDevicePlayerIndex, 933 HIDAPI_DriverPS5_SetDevicePlayerIndex, 934 HIDAPI_DriverPS5_UpdateDevice, 935 HIDAPI_DriverPS5_OpenJoystick, 936 HIDAPI_DriverPS5_RumbleJoystick, 937 HIDAPI_DriverPS5_RumbleJoystickTriggers, 938 HIDAPI_DriverPS5_HasJoystickLED, 939 HIDAPI_DriverPS5_SetJoystickLED, 940 HIDAPI_DriverPS5_SetJoystickSensorsEnabled, 941 HIDAPI_DriverPS5_CloseJoystick, 942 HIDAPI_DriverPS5_FreeDevice, 943 }; 944 945 #endif /* SDL_JOYSTICK_HIDAPI_PS5 */ 946 947 #endif /* SDL_JOYSTICK_HIDAPI */ 948 949 /* vi: set ts=4 sw=4 expandtab: */