Atlas - SDL_hidapi_ps5.c

Home / ext / SDL / src / joystick / hidapi Lines: 1 | Size: 61226 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 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_c.h" 26#include "../SDL_sysjoystick.h" 27#include "SDL_hidapijoystick_c.h" 28#include "SDL_hidapi_rumble.h" 29 30#ifdef SDL_JOYSTICK_HIDAPI_PS5 31 32// Define this if you want to log all packets from the controller 33#if 0 34#define DEBUG_PS5_PROTOCOL 35#endif 36 37// Define this if you want to log calibration data 38#if 0 39#define DEBUG_PS5_CALIBRATION 40#endif 41 42#define GYRO_RES_PER_DEGREE 1024.0f 43#define ACCEL_RES_PER_G 8192.0f 44#define BLUETOOTH_DISCONNECT_TIMEOUT_MS 500 45 46#define LOAD16(A, B) (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8)) 47#define LOAD32(A, B, C, D) ((((Uint32)(A)) << 0) | \ 48 (((Uint32)(B)) << 8) | \ 49 (((Uint32)(C)) << 16) | \ 50 (((Uint32)(D)) << 24)) 51 52enum 53{ 54 SDL_GAMEPAD_BUTTON_PS5_TOUCHPAD = 11, 55 SDL_GAMEPAD_BUTTON_PS5_MICROPHONE, 56 SDL_GAMEPAD_BUTTON_PS5_LEFT_FUNCTION, 57 SDL_GAMEPAD_BUTTON_PS5_RIGHT_FUNCTION, 58 SDL_GAMEPAD_BUTTON_PS5_LEFT_PADDLE, 59 SDL_GAMEPAD_BUTTON_PS5_RIGHT_PADDLE 60}; 61 62typedef enum 63{ 64 k_EPS5ReportIdState = 0x01, 65 k_EPS5ReportIdUsbEffects = 0x02, 66 k_EPS5ReportIdBluetoothEffects = 0x31, 67 k_EPS5ReportIdBluetoothState = 0x31, 68} EPS5ReportId; 69 70typedef enum 71{ 72 k_EPS5FeatureReportIdCapabilities = 0x03, 73 k_EPS5FeatureReportIdCalibration = 0x05, 74 k_EPS5FeatureReportIdSerialNumber = 0x09, 75 k_EPS5FeatureReportIdFirmwareInfo = 0x20, 76} EPS5FeatureReportId; 77 78typedef struct 79{ 80 Uint8 ucLeftJoystickX; 81 Uint8 ucLeftJoystickY; 82 Uint8 ucRightJoystickX; 83 Uint8 ucRightJoystickY; 84 Uint8 rgucButtonsHatAndCounter[3]; 85 Uint8 ucTriggerLeft; 86 Uint8 ucTriggerRight; 87} PS5SimpleStatePacket_t; 88 89typedef struct 90{ 91 Uint8 ucLeftJoystickX; // 0 92 Uint8 ucLeftJoystickY; // 1 93 Uint8 ucRightJoystickX; // 2 94 Uint8 ucRightJoystickY; // 3 95 Uint8 ucTriggerLeft; // 4 96 Uint8 ucTriggerRight; // 5 97 Uint8 ucCounter; // 6 98 Uint8 rgucButtonsAndHat[4]; // 7 99 Uint8 rgucPacketSequence[4]; // 11 - 32 bit little endian 100 Uint8 rgucGyroX[2]; // 15 101 Uint8 rgucGyroY[2]; // 17 102 Uint8 rgucGyroZ[2]; // 19 103 Uint8 rgucAccelX[2]; // 21 104 Uint8 rgucAccelY[2]; // 23 105 Uint8 rgucAccelZ[2]; // 25 106 Uint8 rgucSensorTimestamp[4]; // 27 - 16/32 bit little endian 107 108} PS5StatePacketCommon_t; 109 110typedef struct 111{ 112 Uint8 ucLeftJoystickX; // 0 113 Uint8 ucLeftJoystickY; // 1 114 Uint8 ucRightJoystickX; // 2 115 Uint8 ucRightJoystickY; // 3 116 Uint8 ucTriggerLeft; // 4 117 Uint8 ucTriggerRight; // 5 118 Uint8 ucCounter; // 6 119 Uint8 rgucButtonsAndHat[4]; // 7 120 Uint8 rgucPacketSequence[4]; // 11 - 32 bit little endian 121 Uint8 rgucGyroX[2]; // 15 122 Uint8 rgucGyroY[2]; // 17 123 Uint8 rgucGyroZ[2]; // 19 124 Uint8 rgucAccelX[2]; // 21 125 Uint8 rgucAccelY[2]; // 23 126 Uint8 rgucAccelZ[2]; // 25 127 Uint8 rgucSensorTimestamp[4]; // 27 - 32 bit little endian 128 Uint8 ucSensorTemp; // 31 129 Uint8 ucTouchpadCounter1; // 32 - high bit clear + counter 130 Uint8 rgucTouchpadData1[3]; // 33 - X/Y, 12 bits per axis 131 Uint8 ucTouchpadCounter2; // 36 - high bit clear + counter 132 Uint8 rgucTouchpadData2[3]; // 37 - X/Y, 12 bits per axis 133 Uint8 rgucUnknown1[8]; // 40 134 Uint8 rgucTimer2[4]; // 48 - 32 bit little endian 135 Uint8 ucBatteryLevel; // 52 136 Uint8 ucConnectState; // 53 - 0x08 = USB, 0x01 = headphone 137 138 // There's more unknown data at the end, and a 32-bit CRC on Bluetooth 139} PS5StatePacket_t; 140 141typedef struct 142{ 143 Uint8 ucLeftJoystickX; // 0 144 Uint8 ucLeftJoystickY; // 1 145 Uint8 ucRightJoystickX; // 2 146 Uint8 ucRightJoystickY; // 3 147 Uint8 ucTriggerLeft; // 4 148 Uint8 ucTriggerRight; // 5 149 Uint8 ucCounter; // 6 150 Uint8 rgucButtonsAndHat[4]; // 7 151 Uint8 rgucPacketSequence[4]; // 11 - 32 bit little endian 152 Uint8 rgucGyroX[2]; // 15 153 Uint8 rgucGyroY[2]; // 17 154 Uint8 rgucGyroZ[2]; // 19 155 Uint8 rgucAccelX[2]; // 21 156 Uint8 rgucAccelY[2]; // 23 157 Uint8 rgucAccelZ[2]; // 25 158 Uint8 rgucSensorTimestamp[2]; // 27 - 16 bit little endian 159 Uint8 ucBatteryLevel; // 29 160 Uint8 ucUnknown; // 30 161 Uint8 ucTouchpadCounter1; // 31 - high bit clear + counter 162 Uint8 rgucTouchpadData1[3]; // 32 - X/Y, 12 bits per axis 163 Uint8 ucTouchpadCounter2; // 35 - high bit clear + counter 164 Uint8 rgucTouchpadData2[3]; // 36 - X/Y, 12 bits per axis 165 166 // There's more unknown data at the end, and a 32-bit CRC on Bluetooth 167} PS5StatePacketAlt_t; 168 169typedef struct 170{ 171 Uint8 ucEnableBits1; // 0 172 Uint8 ucEnableBits2; // 1 173 Uint8 ucRumbleRight; // 2 174 Uint8 ucRumbleLeft; // 3 175 Uint8 ucHeadphoneVolume; // 4 176 Uint8 ucSpeakerVolume; // 5 177 Uint8 ucMicrophoneVolume; // 6 178 Uint8 ucAudioEnableBits; // 7 179 Uint8 ucMicLightMode; // 8 180 Uint8 ucAudioMuteBits; // 9 181 Uint8 rgucRightTriggerEffect[11]; // 10 182 Uint8 rgucLeftTriggerEffect[11]; // 21 183 Uint8 rgucUnknown1[6]; // 32 184 Uint8 ucEnableBits3; // 38 185 Uint8 rgucUnknown2[2]; // 39 186 Uint8 ucLedAnim; // 41 187 Uint8 ucLedBrightness; // 42 188 Uint8 ucPadLights; // 43 189 Uint8 ucLedRed; // 44 190 Uint8 ucLedGreen; // 45 191 Uint8 ucLedBlue; // 46 192} DS5EffectsState_t; 193 194typedef enum 195{ 196 k_EDS5EffectRumbleStart = (1 << 0), 197 k_EDS5EffectRumble = (1 << 1), 198 k_EDS5EffectLEDReset = (1 << 2), 199 k_EDS5EffectLED = (1 << 3), 200 k_EDS5EffectPadLights = (1 << 4), 201 k_EDS5EffectMicLight = (1 << 5) 202} EDS5Effect; 203 204typedef enum 205{ 206 k_EDS5LEDResetStateNone, 207 k_EDS5LEDResetStatePending, 208 k_EDS5LEDResetStateComplete, 209} EDS5LEDResetState; 210 211typedef struct 212{ 213 Sint16 bias; 214 float sensitivity; 215} IMUCalibrationData; 216 217/* Rumble hint mode: 218 * "0": enhanced features are never used 219 * "1": enhanced features are always used 220 * "auto": enhanced features are advertised to the application, but SDL doesn't touch the controller state unless the application explicitly requests it. 221 */ 222typedef enum 223{ 224 PS5_ENHANCED_REPORT_HINT_OFF, 225 PS5_ENHANCED_REPORT_HINT_ON, 226 PS5_ENHANCED_REPORT_HINT_AUTO 227} HIDAPI_PS5_EnhancedReportHint; 228 229typedef struct 230{ 231 SDL_HIDAPI_Device *device; 232 SDL_Joystick *joystick; 233 bool is_nacon_dongle; 234 bool use_alternate_report; 235 bool sensors_supported; 236 bool lightbar_supported; 237 bool vibration_supported; 238 bool playerled_supported; 239 bool touchpad_supported; 240 bool effects_supported; 241 HIDAPI_PS5_EnhancedReportHint enhanced_report_hint; 242 bool enhanced_reports; 243 bool enhanced_mode; 244 bool enhanced_mode_available; 245 bool report_sensors; 246 bool report_touchpad; 247 bool report_battery; 248 bool hardware_calibration; 249 IMUCalibrationData calibration[6]; 250 Uint16 firmware_version; 251 Uint64 last_packet; 252 int player_index; 253 bool player_lights; 254 bool enhanced_rumble; 255 Uint8 rumble_left; 256 Uint8 rumble_right; 257 bool color_set; 258 Uint8 led_red; 259 Uint8 led_green; 260 Uint8 led_blue; 261 EDS5LEDResetState led_reset_state; 262 Uint64 sensor_ticks; 263 Uint32 last_tick; 264 union 265 { 266 PS5SimpleStatePacket_t simple; 267 PS5StatePacketCommon_t state; 268 PS5StatePacketAlt_t alt_state; 269 PS5StatePacket_t full_state; 270 Uint8 data[64]; 271 } last_state; 272} SDL_DriverPS5_Context; 273 274static bool HIDAPI_DriverPS5_InternalSendJoystickEffect(SDL_DriverPS5_Context *ctx, const void *effect, int size, bool application_usage); 275 276static void HIDAPI_DriverPS5_RegisterHints(SDL_HintCallback callback, void *userdata) 277{ 278 SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS5, callback, userdata); 279} 280 281static void HIDAPI_DriverPS5_UnregisterHints(SDL_HintCallback callback, void *userdata) 282{ 283 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS5, callback, userdata); 284} 285 286static bool HIDAPI_DriverPS5_IsEnabled(void) 287{ 288 return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS5, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT)); 289} 290 291static int ReadFeatureReport(SDL_hid_device *dev, Uint8 report_id, Uint8 *report, size_t length) 292{ 293 SDL_memset(report, 0, length); 294 report[0] = report_id; 295 return SDL_hid_get_feature_report(dev, report, length); 296} 297 298static bool HIDAPI_DriverPS5_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol) 299{ 300 Uint8 data[USB_PACKET_LENGTH]; 301 int size; 302 303 if (type == SDL_GAMEPAD_TYPE_PS5) { 304 return true; 305 } 306 307 if (HIDAPI_SupportsPlaystationDetection(vendor_id, product_id)) { 308 if (device && device->dev) { 309 size = ReadFeatureReport(device->dev, k_EPS5FeatureReportIdCapabilities, data, sizeof(data)); 310 if (size == 48 && data[2] == 0x28) { 311 // Supported third party controller 312 return true; 313 } else { 314 return false; 315 } 316 } else { 317 // Might be supported by this driver, enumerate and find out 318 return true; 319 } 320 } 321 return false; 322} 323 324static void SetLedsForPlayerIndex(DS5EffectsState_t *effects, int player_index) 325{ 326 /* This list is the same as what hid-sony.c uses in the Linux kernel. 327 The first 4 values correspond to what the PS4 assigns. 328 */ 329 static const Uint8 colors[7][3] = { 330 { 0x00, 0x00, 0x40 }, // Blue 331 { 0x40, 0x00, 0x00 }, // Red 332 { 0x00, 0x40, 0x00 }, // Green 333 { 0x20, 0x00, 0x20 }, // Pink 334 { 0x20, 0x10, 0x00 }, // Orange 335 { 0x00, 0x10, 0x10 }, // Teal 336 { 0x10, 0x10, 0x10 } // White 337 }; 338 339 if (player_index >= 0) { 340 player_index %= SDL_arraysize(colors); 341 } else { 342 player_index = 0; 343 } 344 345 effects->ucLedRed = colors[player_index][0]; 346 effects->ucLedGreen = colors[player_index][1]; 347 effects->ucLedBlue = colors[player_index][2]; 348} 349 350static void SetLightsForPlayerIndex(DS5EffectsState_t *effects, int player_index) 351{ 352 static const Uint8 lights[] = { 353 0x04, 354 0x0A, 355 0x15, 356 0x1B, 357 0x1F 358 }; 359 360 if (player_index >= 0) { 361 // Bitmask, 0x1F enables all lights, 0x20 changes instantly instead of fade 362 player_index %= SDL_arraysize(lights); 363 effects->ucPadLights = lights[player_index] | 0x20; 364 } else { 365 effects->ucPadLights = 0x00; 366 } 367} 368 369static bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device) 370{ 371 SDL_DriverPS5_Context *ctx; 372 Uint8 data[USB_PACKET_LENGTH * 2]; 373 int size; 374 char serial[18]; 375 SDL_JoystickType joystick_type = SDL_JOYSTICK_TYPE_GAMEPAD; 376 377 ctx = (SDL_DriverPS5_Context *)SDL_calloc(1, sizeof(*ctx)); 378 if (!ctx) { 379 return false; 380 } 381 ctx->device = device; 382 383 device->context = ctx; 384 385 if (device->serial && SDL_strlen(device->serial) == 12) { 386 int i, j; 387 388 j = -1; 389 for (i = 0; i < 12; i += 2) { 390 j += 1; 391 SDL_memmove(&serial[j], &device->serial[i], 2); 392 j += 2; 393 serial[j] = '-'; 394 } 395 serial[j] = '\0'; 396 } else { 397 serial[0] = '\0'; 398 } 399 400 // Read a report to see what mode we're in 401 size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 16); 402#ifdef DEBUG_PS5_PROTOCOL 403 if (size > 0) { 404 HIDAPI_DumpPacket("PS5 first packet: size = %d", data, size); 405 } else { 406 SDL_Log("PS5 first packet: size = %d", size); 407 } 408#endif 409 if (size == 64) { 410 // Connected over USB 411 ctx->enhanced_reports = true; 412 } else if (size > 0 && data[0] == k_EPS5ReportIdBluetoothEffects) { 413 // Connected over Bluetooth, using enhanced reports 414 ctx->enhanced_reports = true; 415 } else { 416 // Connected over Bluetooth, using simple reports (DirectInput enabled) 417 } 418 419 if (device->vendor_id == USB_VENDOR_SONY && ctx->enhanced_reports) { 420 /* Read the serial number (Bluetooth address in reverse byte order) 421 This will also enable enhanced reports over Bluetooth 422 */ 423 if (ReadFeatureReport(device->dev, k_EPS5FeatureReportIdSerialNumber, data, sizeof(data)) >= 7) { 424 (void)SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", 425 data[6], data[5], data[4], data[3], data[2], data[1]); 426 } 427 428 /* Read the firmware version 429 This will also enable enhanced reports over Bluetooth 430 */ 431 if (ReadFeatureReport(device->dev, k_EPS5FeatureReportIdFirmwareInfo, data, USB_PACKET_LENGTH) >= 46) { 432 ctx->firmware_version = (Uint16)data[44] | ((Uint16)data[45] << 8); 433 } 434 } 435 436 if (device->vendor_id == USB_VENDOR_SONY) { 437 if (device->product_id == USB_PRODUCT_SONY_DS5_EDGE || 438 ctx->firmware_version == 0 || // Assume that it's updated firmware over Bluetooth 439 ctx->firmware_version >= 0x0224) { 440 ctx->enhanced_rumble = true; 441 } 442 } 443 444 // Get the device capabilities 445 if (device->vendor_id == USB_VENDOR_SONY) { 446 ctx->sensors_supported = true; 447 ctx->lightbar_supported = true; 448 ctx->vibration_supported = true; 449 ctx->playerled_supported = true; 450 ctx->touchpad_supported = true; 451 } else { 452 // Third party controller capability request 453 size = ReadFeatureReport(device->dev, k_EPS5FeatureReportIdCapabilities, data, sizeof(data)); 454 if (size == 48 && data[2] == 0x28) { 455 Uint8 capabilities = data[4]; 456 Uint8 capabilities2 = data[20]; 457 Uint8 device_type = data[5]; 458 459#ifdef DEBUG_PS5_PROTOCOL 460 HIDAPI_DumpPacket("PS5 capabilities: size = %d", data, size); 461#endif 462 if (capabilities & 0x02) { 463 ctx->sensors_supported = true; 464 } 465 if (capabilities & 0x04) { 466 ctx->lightbar_supported = true; 467 } 468 if (capabilities & 0x08) { 469 ctx->vibration_supported = true; 470 } 471 if (capabilities & 0x40) { 472 ctx->touchpad_supported = true; 473 } 474 if (capabilities2 & 0x80) { 475 ctx->playerled_supported = true; 476 } 477 478 switch (device_type) { 479 case 0x00: 480 joystick_type = SDL_JOYSTICK_TYPE_GAMEPAD; 481 break; 482 case 0x01: 483 joystick_type = SDL_JOYSTICK_TYPE_GUITAR; 484 break; 485 case 0x02: 486 joystick_type = SDL_JOYSTICK_TYPE_DRUM_KIT; 487 break; 488 case 0x06: 489 joystick_type = SDL_JOYSTICK_TYPE_WHEEL; 490 break; 491 case 0x07: 492 joystick_type = SDL_JOYSTICK_TYPE_ARCADE_STICK; 493 break; 494 case 0x08: 495 joystick_type = SDL_JOYSTICK_TYPE_FLIGHT_STICK; 496 break; 497 default: 498 joystick_type = SDL_JOYSTICK_TYPE_UNKNOWN; 499 break; 500 } 501 502 ctx->use_alternate_report = true; 503 504 if (device->vendor_id == USB_VENDOR_NACON_ALT && 505 (device->product_id == USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS5_WIRED || 506 device->product_id == USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS5_WIRELESS)) { 507 // This doesn't report vibration capability, but it can do rumble 508 ctx->vibration_supported = true; 509 } 510 } else if (device->vendor_id == USB_VENDOR_RAZER && 511 (device->product_id == USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_PS5_WIRED || 512 device->product_id == USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_PS5_WIRELESS)) { 513 // The Razer Wolverine V2 Pro doesn't respond to the detection protocol, but has a touchpad and sensors and no vibration 514 ctx->sensors_supported = true; 515 ctx->touchpad_supported = true; 516 ctx->use_alternate_report = true; 517 } else if (device->vendor_id == USB_VENDOR_RAZER && 518 device->product_id == USB_PRODUCT_RAZER_KITSUNE) { 519 // The Razer Kitsune doesn't respond to the detection protocol, but has a touchpad 520 joystick_type = SDL_JOYSTICK_TYPE_ARCADE_STICK; 521 ctx->touchpad_supported = true; 522 ctx->use_alternate_report = true; 523 } 524 } 525 ctx->effects_supported = (ctx->lightbar_supported || ctx->vibration_supported || ctx->playerled_supported); 526 527 if (device->vendor_id == USB_VENDOR_NACON_ALT && 528 device->product_id == USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS5_WIRELESS) { 529 ctx->is_nacon_dongle = true; 530 } 531 532 device->joystick_type = joystick_type; 533 device->type = SDL_GAMEPAD_TYPE_PS5; 534 if (device->vendor_id == USB_VENDOR_SONY) { 535 if (SDL_IsJoystickDualSenseEdge(device->vendor_id, device->product_id)) { 536 HIDAPI_SetDeviceName(device, "DualSense Edge Wireless Controller"); 537 } else { 538 HIDAPI_SetDeviceName(device, "DualSense Wireless Controller"); 539 } 540 } 541 HIDAPI_SetDeviceSerial(device, serial); 542 543 if (ctx->is_nacon_dongle) { 544 // We don't know if this is connected yet, wait for reports 545 return true; 546 } 547 548 // Prefer the USB device over the Bluetooth device 549 if (device->is_bluetooth) { 550 if (HIDAPI_HasConnectedUSBDevice(device->serial)) { 551 return true; 552 } 553 } else { 554 HIDAPI_DisconnectBluetoothDevice(device->serial); 555 } 556 return HIDAPI_JoystickConnected(device, NULL); 557} 558 559static int HIDAPI_DriverPS5_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id) 560{ 561 return -1; 562} 563 564static void HIDAPI_DriverPS5_LoadCalibrationData(SDL_HIDAPI_Device *device) 565{ 566 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; 567 int i, size; 568 Uint8 data[USB_PACKET_LENGTH]; 569 570 size = ReadFeatureReport(device->dev, k_EPS5FeatureReportIdCalibration, data, sizeof(data)); 571 if (size < 35) { 572#ifdef DEBUG_PS5_CALIBRATION 573 SDL_Log("Short read of calibration data: %d, ignoring calibration", size); 574#endif 575 return; 576 } 577 578 { 579 Sint16 sGyroPitchBias, sGyroYawBias, sGyroRollBias; 580 Sint16 sGyroPitchPlus, sGyroPitchMinus; 581 Sint16 sGyroYawPlus, sGyroYawMinus; 582 Sint16 sGyroRollPlus, sGyroRollMinus; 583 Sint16 sGyroSpeedPlus, sGyroSpeedMinus; 584 585 Sint16 sAccXPlus, sAccXMinus; 586 Sint16 sAccYPlus, sAccYMinus; 587 Sint16 sAccZPlus, sAccZMinus; 588 589 float flNumerator; 590 Sint16 sRange2g; 591 592#ifdef DEBUG_PS5_CALIBRATION 593 HIDAPI_DumpPacket("PS5 calibration packet: size = %d", data, size); 594#endif 595 596 sGyroPitchBias = LOAD16(data[1], data[2]); 597 sGyroYawBias = LOAD16(data[3], data[4]); 598 sGyroRollBias = LOAD16(data[5], data[6]); 599 600 sGyroPitchPlus = LOAD16(data[7], data[8]); 601 sGyroPitchMinus = LOAD16(data[9], data[10]); 602 sGyroYawPlus = LOAD16(data[11], data[12]); 603 sGyroYawMinus = LOAD16(data[13], data[14]); 604 sGyroRollPlus = LOAD16(data[15], data[16]); 605 sGyroRollMinus = LOAD16(data[17], data[18]); 606 607 sGyroSpeedPlus = LOAD16(data[19], data[20]); 608 sGyroSpeedMinus = LOAD16(data[21], data[22]); 609 610 sAccXPlus = LOAD16(data[23], data[24]); 611 sAccXMinus = LOAD16(data[25], data[26]); 612 sAccYPlus = LOAD16(data[27], data[28]); 613 sAccYMinus = LOAD16(data[29], data[30]); 614 sAccZPlus = LOAD16(data[31], data[32]); 615 sAccZMinus = LOAD16(data[33], data[34]); 616 617 flNumerator = (sGyroSpeedPlus + sGyroSpeedMinus) * GYRO_RES_PER_DEGREE; 618 ctx->calibration[0].bias = sGyroPitchBias; 619 ctx->calibration[0].sensitivity = flNumerator / (sGyroPitchPlus - sGyroPitchMinus); 620 621 ctx->calibration[1].bias = sGyroYawBias; 622 ctx->calibration[1].sensitivity = flNumerator / (sGyroYawPlus - sGyroYawMinus); 623 624 ctx->calibration[2].bias = sGyroRollBias; 625 ctx->calibration[2].sensitivity = flNumerator / (sGyroRollPlus - sGyroRollMinus); 626 627 sRange2g = sAccXPlus - sAccXMinus; 628 ctx->calibration[3].bias = sAccXPlus - sRange2g / 2; 629 ctx->calibration[3].sensitivity = 2.0f * ACCEL_RES_PER_G / (float)sRange2g; 630 631 sRange2g = sAccYPlus - sAccYMinus; 632 ctx->calibration[4].bias = sAccYPlus - sRange2g / 2; 633 ctx->calibration[4].sensitivity = 2.0f * ACCEL_RES_PER_G / (float)sRange2g; 634 635 sRange2g = sAccZPlus - sAccZMinus; 636 ctx->calibration[5].bias = sAccZPlus - sRange2g / 2; 637 ctx->calibration[5].sensitivity = 2.0f * ACCEL_RES_PER_G / (float)sRange2g; 638 639 ctx->hardware_calibration = true; 640 for (i = 0; i < 6; ++i) { 641 float divisor = (i < 3 ? 64.0f : 1.0f); 642#ifdef DEBUG_PS5_CALIBRATION 643 SDL_Log("calibration[%d] bias = %d, sensitivity = %f", i, ctx->calibration[i].bias, ctx->calibration[i].sensitivity); 644#endif 645 // Some controllers have a bad calibration 646 if ((SDL_abs(ctx->calibration[i].bias) > 1024) || (SDL_fabsf(1.0f - ctx->calibration[i].sensitivity / divisor) > 0.5f)) { 647#ifdef DEBUG_PS5_CALIBRATION 648 SDL_Log("invalid calibration, ignoring"); 649#endif 650 ctx->hardware_calibration = false; 651 } 652 } 653 } 654} 655 656static float HIDAPI_DriverPS5_ApplyCalibrationData(SDL_DriverPS5_Context *ctx, int index, Sint16 value) 657{ 658 float result; 659 660 if (ctx->hardware_calibration) { 661 IMUCalibrationData *calibration = &ctx->calibration[index]; 662 663 result = (value - calibration->bias) * calibration->sensitivity; 664 } else if (index < 3) { 665 result = value * 64.f; 666 } else { 667 result = value; 668 } 669 670 // Convert the raw data to the units expected by SDL 671 if (index < 3) { 672 result = (result / GYRO_RES_PER_DEGREE) * SDL_PI_F / 180.0f; 673 } else { 674 result = (result / ACCEL_RES_PER_G) * SDL_STANDARD_GRAVITY; 675 } 676 return result; 677} 678 679static bool HIDAPI_DriverPS5_UpdateEffects(SDL_DriverPS5_Context *ctx, int effect_mask, bool application_usage) 680{ 681 DS5EffectsState_t effects; 682 683 // Make sure the Bluetooth connection sequence has completed before sending LED color change 684 if (ctx->device->is_bluetooth && ctx->enhanced_reports && 685 (effect_mask & (k_EDS5EffectLED | k_EDS5EffectPadLights)) != 0) { 686 if (ctx->led_reset_state != k_EDS5LEDResetStateComplete) { 687 ctx->led_reset_state = k_EDS5LEDResetStatePending; 688 return true; 689 } 690 } 691 692 SDL_zero(effects); 693 694 if (ctx->vibration_supported) { 695 if (ctx->rumble_left || ctx->rumble_right) { 696 if (ctx->enhanced_rumble) { 697 effects.ucEnableBits3 |= 0x04; // Enable improved rumble emulation on 2.24 firmware and newer 698 699 effects.ucRumbleLeft = ctx->rumble_left; 700 effects.ucRumbleRight = ctx->rumble_right; 701 } else { 702 effects.ucEnableBits1 |= 0x01; // Enable rumble emulation 703 704 // Shift to reduce effective rumble strength to match Xbox controllers 705 effects.ucRumbleLeft = ctx->rumble_left >> 1; 706 effects.ucRumbleRight = ctx->rumble_right >> 1; 707 } 708 effects.ucEnableBits1 |= 0x02; // Disable audio haptics 709 } else { 710 // Leaving emulated rumble bits off will restore audio haptics 711 } 712 713 if ((effect_mask & k_EDS5EffectRumbleStart) != 0) { 714 effects.ucEnableBits1 |= 0x02; // Disable audio haptics 715 } 716 if ((effect_mask & k_EDS5EffectRumble) != 0) { 717 // Already handled above 718 } 719 } 720 if (ctx->lightbar_supported) { 721 if ((effect_mask & k_EDS5EffectLEDReset) != 0) { 722 effects.ucEnableBits2 |= 0x08; // Reset LED state 723 } 724 if ((effect_mask & k_EDS5EffectLED) != 0) { 725 effects.ucEnableBits2 |= 0x04; // Enable LED color 726 727 // Populate the LED state with the appropriate color from our lookup table 728 if (ctx->color_set) { 729 effects.ucLedRed = ctx->led_red; 730 effects.ucLedGreen = ctx->led_green; 731 effects.ucLedBlue = ctx->led_blue; 732 } else { 733 SetLedsForPlayerIndex(&effects, ctx->player_index); 734 } 735 } 736 } 737 if (ctx->playerled_supported) { 738 if ((effect_mask & k_EDS5EffectPadLights) != 0) { 739 effects.ucEnableBits2 |= 0x10; // Enable touchpad lights 740 741 if (ctx->player_lights) { 742 SetLightsForPlayerIndex(&effects, ctx->player_index); 743 } else { 744 effects.ucPadLights = 0x00; 745 } 746 } 747 } 748 if ((effect_mask & k_EDS5EffectMicLight) != 0) { 749 effects.ucEnableBits2 |= 0x01; // Enable microphone light 750 751 effects.ucMicLightMode = 0; // Bitmask, 0x00 = off, 0x01 = solid, 0x02 = pulse 752 } 753 754 return HIDAPI_DriverPS5_InternalSendJoystickEffect(ctx, &effects, sizeof(effects), application_usage); 755} 756 757static void HIDAPI_DriverPS5_CheckPendingLEDReset(SDL_DriverPS5_Context *ctx) 758{ 759 bool led_reset_complete = false; 760 761 if (ctx->enhanced_reports && ctx->sensors_supported && !ctx->use_alternate_report) { 762 const PS5StatePacketCommon_t *packet = &ctx->last_state.state; 763 764 // Check the timer to make sure the Bluetooth connection LED animation is complete 765 const Uint32 connection_complete = 10200000; 766 Uint32 timestamp = LOAD32(packet->rgucSensorTimestamp[0], 767 packet->rgucSensorTimestamp[1], 768 packet->rgucSensorTimestamp[2], 769 packet->rgucSensorTimestamp[3]); 770 if (timestamp >= connection_complete) { 771 led_reset_complete = true; 772 } 773 } else { 774 // We don't know how to check the timer, just assume it's complete for now 775 led_reset_complete = true; 776 } 777 778 if (led_reset_complete) { 779 HIDAPI_DriverPS5_UpdateEffects(ctx, k_EDS5EffectLEDReset, false); 780 781 ctx->led_reset_state = k_EDS5LEDResetStateComplete; 782 783 HIDAPI_DriverPS5_UpdateEffects(ctx, (k_EDS5EffectLED | k_EDS5EffectPadLights), false); 784 } 785} 786 787static void HIDAPI_DriverPS5_TickleBluetooth(SDL_HIDAPI_Device *device) 788{ 789 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; 790 791 if (ctx->enhanced_reports) { 792 // This is just a dummy packet that should have no effect, since we don't set the CRC 793 Uint8 data[78]; 794 795 SDL_zeroa(data); 796 797 data[0] = k_EPS5ReportIdBluetoothEffects; 798 data[1] = 0x02; // Magic value 799 800 if (SDL_HIDAPI_LockRumble()) { 801 SDL_HIDAPI_SendRumbleAndUnlock(device, data, sizeof(data)); 802 } 803 } else { 804 // We can't even send an invalid effects packet, or it will put the controller in enhanced mode 805 if (device->num_joysticks > 0) { 806 HIDAPI_JoystickDisconnected(device, device->joysticks[0]); 807 } 808 } 809} 810 811static void HIDAPI_DriverPS5_SetEnhancedModeAvailable(SDL_DriverPS5_Context *ctx) 812{ 813 if (ctx->enhanced_mode_available) { 814 return; 815 } 816 ctx->enhanced_mode_available = true; 817 818 if (ctx->touchpad_supported) { 819 SDL_PrivateJoystickAddTouchpad(ctx->joystick, 2); 820 ctx->report_touchpad = true; 821 } 822 823 if (ctx->sensors_supported) { 824 // Standard DualSense sensor update rate is 250 Hz over USB 825 float update_rate = 250.0f; 826 827 if (ctx->device->is_bluetooth) { 828 // Bluetooth sensor update rate appears to be 1000 Hz 829 update_rate = 1000.0f; 830 } else if (SDL_IsJoystickDualSenseEdge(ctx->device->vendor_id, ctx->device->product_id)) { 831 // DualSense Edge sensor update rate is 1000 Hz over USB 832 update_rate = 1000.0f; 833 } 834 835 SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_GYRO, update_rate); 836 SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_ACCEL, update_rate); 837 } 838 839 ctx->report_battery = true; 840 841 HIDAPI_UpdateDeviceProperties(ctx->device); 842} 843 844static void HIDAPI_DriverPS5_SetEnhancedMode(SDL_DriverPS5_Context *ctx) 845{ 846 HIDAPI_DriverPS5_SetEnhancedModeAvailable(ctx); 847 848 if (!ctx->enhanced_mode) { 849 ctx->enhanced_mode = true; 850 851 // Switch into enhanced report mode 852 HIDAPI_DriverPS5_UpdateEffects(ctx, 0, false); 853 854 // Update the light effects 855 HIDAPI_DriverPS5_UpdateEffects(ctx, (k_EDS5EffectLED | k_EDS5EffectPadLights), false); 856 } 857} 858 859static void HIDAPI_DriverPS5_SetEnhancedReportHint(SDL_DriverPS5_Context *ctx, HIDAPI_PS5_EnhancedReportHint enhanced_report_hint) 860{ 861 switch (enhanced_report_hint) { 862 case PS5_ENHANCED_REPORT_HINT_OFF: 863 // Nothing to do, enhanced mode is a one-way ticket 864 break; 865 case PS5_ENHANCED_REPORT_HINT_ON: 866 HIDAPI_DriverPS5_SetEnhancedMode(ctx); 867 break; 868 case PS5_ENHANCED_REPORT_HINT_AUTO: 869 HIDAPI_DriverPS5_SetEnhancedModeAvailable(ctx); 870 break; 871 } 872 ctx->enhanced_report_hint = enhanced_report_hint; 873} 874 875static void HIDAPI_DriverPS5_UpdateEnhancedModeOnEnhancedReport(SDL_DriverPS5_Context *ctx) 876{ 877 ctx->enhanced_reports = true; 878 879 if (ctx->enhanced_report_hint == PS5_ENHANCED_REPORT_HINT_AUTO) { 880 HIDAPI_DriverPS5_SetEnhancedReportHint(ctx, PS5_ENHANCED_REPORT_HINT_ON); 881 } 882} 883 884static void HIDAPI_DriverPS5_UpdateEnhancedModeOnApplicationUsage(SDL_DriverPS5_Context *ctx) 885{ 886 if (ctx->enhanced_report_hint == PS5_ENHANCED_REPORT_HINT_AUTO) { 887 HIDAPI_DriverPS5_SetEnhancedReportHint(ctx, PS5_ENHANCED_REPORT_HINT_ON); 888 } 889} 890 891static void SDLCALL SDL_PS5EnhancedReportsChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 892{ 893 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)userdata; 894 895 if (ctx->device->is_bluetooth) { 896 if (hint && SDL_strcasecmp(hint, "auto") == 0) { 897 HIDAPI_DriverPS5_SetEnhancedReportHint(ctx, PS5_ENHANCED_REPORT_HINT_AUTO); 898 } else if (SDL_GetStringBoolean(hint, true)) { 899 HIDAPI_DriverPS5_SetEnhancedReportHint(ctx, PS5_ENHANCED_REPORT_HINT_ON); 900 } else { 901 HIDAPI_DriverPS5_SetEnhancedReportHint(ctx, PS5_ENHANCED_REPORT_HINT_OFF); 902 } 903 } else { 904 HIDAPI_DriverPS5_SetEnhancedReportHint(ctx, PS5_ENHANCED_REPORT_HINT_ON); 905 } 906} 907 908static void SDLCALL SDL_PS5PlayerLEDHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 909{ 910 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)userdata; 911 bool player_lights = SDL_GetStringBoolean(hint, true); 912 913 if (player_lights != ctx->player_lights) { 914 ctx->player_lights = player_lights; 915 916 HIDAPI_DriverPS5_UpdateEffects(ctx, k_EDS5EffectPadLights, false); 917 } 918} 919 920static void HIDAPI_DriverPS5_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) 921{ 922 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; 923 924 if (!ctx->joystick) { 925 return; 926 } 927 928 ctx->player_index = player_index; 929 930 // This will set the new LED state based on the new player index 931 // SDL automatically calls this, so it doesn't count as an application action to enable enhanced mode 932 HIDAPI_DriverPS5_UpdateEffects(ctx, (k_EDS5EffectLED | k_EDS5EffectPadLights), false); 933} 934 935static bool HIDAPI_DriverPS5_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 936{ 937 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; 938 939 SDL_AssertJoysticksLocked(); 940 941 ctx->joystick = joystick; 942 ctx->last_packet = SDL_GetTicks(); 943 ctx->report_sensors = false; 944 ctx->report_touchpad = false; 945 ctx->rumble_left = 0; 946 ctx->rumble_right = 0; 947 ctx->color_set = false; 948 ctx->led_reset_state = k_EDS5LEDResetStateNone; 949 SDL_zero(ctx->last_state); 950 951 // Initialize player index (needed for setting LEDs) 952 ctx->player_index = SDL_GetJoystickPlayerIndex(joystick); 953 ctx->player_lights = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED, true); 954 955 // Initialize the joystick capabilities 956 if (SDL_IsJoystickDualSenseEdge(device->vendor_id, device->product_id)) { 957 joystick->nbuttons = 17; // paddles and touchpad and microphone 958 } else if (ctx->touchpad_supported) { 959 joystick->nbuttons = 13; // touchpad and microphone 960 } else { 961 joystick->nbuttons = 11; 962 } 963 joystick->naxes = SDL_GAMEPAD_AXIS_COUNT; 964 joystick->nhats = 1; 965 joystick->firmware_version = ctx->firmware_version; 966 967 SDL_AddHintCallback(SDL_HINT_JOYSTICK_ENHANCED_REPORTS, 968 SDL_PS5EnhancedReportsChanged, ctx); 969 SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED, 970 SDL_PS5PlayerLEDHintChanged, ctx); 971 972 return true; 973} 974 975static bool HIDAPI_DriverPS5_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 976{ 977 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; 978 979 if (!ctx->vibration_supported) { 980 return SDL_Unsupported(); 981 } 982 983 if (!ctx->rumble_left && !ctx->rumble_right) { 984 HIDAPI_DriverPS5_UpdateEffects(ctx, k_EDS5EffectRumbleStart, true); 985 } 986 987 ctx->rumble_left = (low_frequency_rumble >> 8); 988 ctx->rumble_right = (high_frequency_rumble >> 8); 989 990 return HIDAPI_DriverPS5_UpdateEffects(ctx, k_EDS5EffectRumble, true); 991} 992 993static bool HIDAPI_DriverPS5_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) 994{ 995 return SDL_Unsupported(); 996} 997 998static Uint32 HIDAPI_DriverPS5_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 999{ 1000 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; 1001 Uint32 result = 0; 1002 1003 if (ctx->enhanced_mode_available) { 1004 if (ctx->lightbar_supported) { 1005 result |= SDL_JOYSTICK_CAP_RGB_LED; 1006 } 1007 if (ctx->playerled_supported) { 1008 result |= SDL_JOYSTICK_CAP_PLAYER_LED; 1009 } 1010 if (ctx->vibration_supported) { 1011 result |= SDL_JOYSTICK_CAP_RUMBLE; 1012 } 1013 } 1014 1015 return result; 1016} 1017 1018static bool HIDAPI_DriverPS5_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) 1019{ 1020 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; 1021 1022 if (!ctx->lightbar_supported) { 1023 return SDL_Unsupported(); 1024 } 1025 1026 ctx->color_set = true; 1027 ctx->led_red = red; 1028 ctx->led_green = green; 1029 ctx->led_blue = blue; 1030 1031 return HIDAPI_DriverPS5_UpdateEffects(ctx, k_EDS5EffectLED, true); 1032} 1033 1034static bool HIDAPI_DriverPS5_InternalSendJoystickEffect(SDL_DriverPS5_Context *ctx, const void *effect, int size, bool application_usage) 1035{ 1036 Uint8 data[78]; 1037 int report_size, offset; 1038 Uint8 *pending_data; 1039 int *pending_size; 1040 int maximum_size; 1041 1042 if (!ctx->effects_supported) { 1043 // We shouldn't be sending packets to this controller 1044 return SDL_Unsupported(); 1045 } 1046 1047 if (!ctx->enhanced_mode) { 1048 if (application_usage) { 1049 HIDAPI_DriverPS5_UpdateEnhancedModeOnApplicationUsage(ctx); 1050 1051 // Wait briefly before sending additional effects 1052 SDL_Delay(10); 1053 } 1054 1055 if (!ctx->enhanced_mode) { 1056 // We're not in enhanced mode, effects aren't allowed 1057 return SDL_Unsupported(); 1058 } 1059 } 1060 1061 SDL_zeroa(data); 1062 1063 if (ctx->device->is_bluetooth) { 1064 data[0] = k_EPS5ReportIdBluetoothEffects; 1065 data[1] = 0x02; // Magic value 1066 1067 report_size = 78; 1068 offset = 2; 1069 } else { 1070 data[0] = k_EPS5ReportIdUsbEffects; 1071 1072 report_size = 48; 1073 offset = 1; 1074 } 1075 1076 SDL_memcpy(&data[offset], effect, SDL_min((sizeof(data) - offset), (size_t)size)); 1077 1078 if (ctx->device->is_bluetooth) { 1079 // Bluetooth reports need a CRC at the end of the packet (at least on Linux) 1080 Uint8 ubHdr = 0xA2; // hidp header is part of the CRC calculation 1081 Uint32 unCRC; 1082 unCRC = SDL_crc32(0, &ubHdr, 1); 1083 unCRC = SDL_crc32(unCRC, data, (size_t)(report_size - sizeof(unCRC))); 1084 SDL_memcpy(&data[report_size - sizeof(unCRC)], &unCRC, sizeof(unCRC)); 1085 } 1086 1087 if (!SDL_HIDAPI_LockRumble()) { 1088 return false; 1089 } 1090 1091 // See if we can update an existing pending request 1092 if (SDL_HIDAPI_GetPendingRumbleLocked(ctx->device, &pending_data, &pending_size, &maximum_size)) { 1093 DS5EffectsState_t *effects = (DS5EffectsState_t *)&data[offset]; 1094 DS5EffectsState_t *pending_effects = (DS5EffectsState_t *)&pending_data[offset]; 1095 if (report_size == *pending_size && 1096 effects->ucEnableBits1 == pending_effects->ucEnableBits1 && 1097 effects->ucEnableBits2 == pending_effects->ucEnableBits2) { 1098 // We're simply updating the data for this request 1099 SDL_memcpy(pending_data, data, report_size); 1100 SDL_HIDAPI_UnlockRumble(); 1101 return true; 1102 } 1103 } 1104 1105 if (SDL_HIDAPI_SendRumbleAndUnlock(ctx->device, data, report_size) != report_size) { 1106 return false; 1107 } 1108 1109 return true; 1110} 1111 1112static bool HIDAPI_DriverPS5_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *effect, int size) 1113{ 1114 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; 1115 1116 return HIDAPI_DriverPS5_InternalSendJoystickEffect(ctx, effect, size, true); 1117} 1118 1119static bool HIDAPI_DriverPS5_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled) 1120{ 1121 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; 1122 1123 HIDAPI_DriverPS5_UpdateEnhancedModeOnApplicationUsage(ctx); 1124 1125 if (!ctx->sensors_supported || (enabled && !ctx->enhanced_mode)) { 1126 return SDL_Unsupported(); 1127 } 1128 1129 if (enabled) { 1130 HIDAPI_DriverPS5_LoadCalibrationData(device); 1131 } 1132 ctx->report_sensors = enabled; 1133 1134 return true; 1135} 1136 1137static void HIDAPI_DriverPS5_HandleSimpleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5SimpleStatePacket_t *packet, Uint64 timestamp) 1138{ 1139 Sint16 axis; 1140 1141 if (ctx->last_state.simple.rgucButtonsHatAndCounter[0] != packet->rgucButtonsHatAndCounter[0]) { 1142 { 1143 Uint8 data = (packet->rgucButtonsHatAndCounter[0] >> 4); 1144 1145 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data & 0x01) != 0)); 1146 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data & 0x02) != 0)); 1147 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data & 0x04) != 0)); 1148 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data & 0x08) != 0)); 1149 } 1150 { 1151 Uint8 data = (packet->rgucButtonsHatAndCounter[0] & 0x0F); 1152 Uint8 hat; 1153 1154 switch (data) { 1155 case 0: 1156 hat = SDL_HAT_UP; 1157 break; 1158 case 1: 1159 hat = SDL_HAT_RIGHTUP; 1160 break; 1161 case 2: 1162 hat = SDL_HAT_RIGHT; 1163 break; 1164 case 3: 1165 hat = SDL_HAT_RIGHTDOWN; 1166 break; 1167 case 4: 1168 hat = SDL_HAT_DOWN; 1169 break; 1170 case 5: 1171 hat = SDL_HAT_LEFTDOWN; 1172 break; 1173 case 6: 1174 hat = SDL_HAT_LEFT; 1175 break; 1176 case 7: 1177 hat = SDL_HAT_LEFTUP; 1178 break; 1179 default: 1180 hat = SDL_HAT_CENTERED; 1181 break; 1182 } 1183 SDL_SendJoystickHat(timestamp, joystick, 0, hat); 1184 } 1185 } 1186 1187 if (ctx->last_state.simple.rgucButtonsHatAndCounter[1] != packet->rgucButtonsHatAndCounter[1]) { 1188 Uint8 data = packet->rgucButtonsHatAndCounter[1]; 1189 1190 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data & 0x01) != 0)); 1191 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data & 0x02) != 0)); 1192 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data & 0x10) != 0)); 1193 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data & 0x20) != 0)); 1194 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data & 0x40) != 0)); 1195 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data & 0x80) != 0)); 1196 } 1197 1198 if (ctx->last_state.simple.rgucButtonsHatAndCounter[2] != packet->rgucButtonsHatAndCounter[2]) { 1199 Uint8 data = (packet->rgucButtonsHatAndCounter[2] & 0x03); 1200 1201 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data & 0x01) != 0)); 1202 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_PS5_TOUCHPAD, ((data & 0x02) != 0)); 1203 } 1204 1205 if (packet->ucTriggerLeft == 0 && (packet->rgucButtonsHatAndCounter[1] & 0x04)) { 1206 axis = SDL_JOYSTICK_AXIS_MAX; 1207 } else { 1208 axis = ((int)packet->ucTriggerLeft * 257) - 32768; 1209 } 1210 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis); 1211 if (packet->ucTriggerRight == 0 && (packet->rgucButtonsHatAndCounter[1] & 0x08)) { 1212 axis = SDL_JOYSTICK_AXIS_MAX; 1213 } else { 1214 axis = ((int)packet->ucTriggerRight * 257) - 32768; 1215 } 1216 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis); 1217 axis = ((int)packet->ucLeftJoystickX * 257) - 32768; 1218 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis); 1219 axis = ((int)packet->ucLeftJoystickY * 257) - 32768; 1220 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis); 1221 axis = ((int)packet->ucRightJoystickX * 257) - 32768; 1222 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis); 1223 axis = ((int)packet->ucRightJoystickY * 257) - 32768; 1224 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis); 1225 1226 SDL_memcpy(&ctx->last_state.simple, packet, sizeof(ctx->last_state.simple)); 1227} 1228 1229static void HIDAPI_DriverPS5_HandleStatePacketCommon(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacketCommon_t *packet, Uint64 timestamp) 1230{ 1231 Sint16 axis; 1232 1233 if (ctx->last_state.state.rgucButtonsAndHat[0] != packet->rgucButtonsAndHat[0]) { 1234 { 1235 Uint8 data = (packet->rgucButtonsAndHat[0] >> 4); 1236 1237 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data & 0x01) != 0)); 1238 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data & 0x02) != 0)); 1239 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data & 0x04) != 0)); 1240 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data & 0x08) != 0)); 1241 } 1242 { 1243 Uint8 data = (packet->rgucButtonsAndHat[0] & 0x0F); 1244 Uint8 hat; 1245 1246 switch (data) { 1247 case 0: 1248 hat = SDL_HAT_UP; 1249 break; 1250 case 1: 1251 hat = SDL_HAT_RIGHTUP; 1252 break; 1253 case 2: 1254 hat = SDL_HAT_RIGHT; 1255 break; 1256 case 3: 1257 hat = SDL_HAT_RIGHTDOWN; 1258 break; 1259 case 4: 1260 hat = SDL_HAT_DOWN; 1261 break; 1262 case 5: 1263 hat = SDL_HAT_LEFTDOWN; 1264 break; 1265 case 6: 1266 hat = SDL_HAT_LEFT; 1267 break; 1268 case 7: 1269 hat = SDL_HAT_LEFTUP; 1270 break; 1271 default: 1272 hat = SDL_HAT_CENTERED; 1273 break; 1274 } 1275 SDL_SendJoystickHat(timestamp, joystick, 0, hat); 1276 } 1277 } 1278 1279 if (ctx->last_state.state.rgucButtonsAndHat[1] != packet->rgucButtonsAndHat[1]) { 1280 Uint8 data = packet->rgucButtonsAndHat[1]; 1281 1282 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data & 0x01) != 0)); 1283 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data & 0x02) != 0)); 1284 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data & 0x10) != 0)); 1285 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data & 0x20) != 0)); 1286 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data & 0x40) != 0)); 1287 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data & 0x80) != 0)); 1288 } 1289 1290 if (ctx->last_state.state.rgucButtonsAndHat[2] != packet->rgucButtonsAndHat[2]) { 1291 Uint8 data = packet->rgucButtonsAndHat[2]; 1292 1293 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data & 0x01) != 0)); 1294 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_PS5_TOUCHPAD, ((data & 0x02) != 0)); 1295 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_PS5_MICROPHONE, ((data & 0x04) != 0)); 1296 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_PS5_LEFT_FUNCTION, ((data & 0x10) != 0)); 1297 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_PS5_RIGHT_FUNCTION, ((data & 0x20) != 0)); 1298 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_PS5_LEFT_PADDLE, ((data & 0x40) != 0)); 1299 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_PS5_RIGHT_PADDLE, ((data & 0x80) != 0)); 1300 } 1301 1302 if (packet->ucTriggerLeft == 0 && (packet->rgucButtonsAndHat[1] & 0x04)) { 1303 axis = SDL_JOYSTICK_AXIS_MAX; 1304 } else { 1305 axis = ((int)packet->ucTriggerLeft * 257) - 32768; 1306 } 1307 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis); 1308 if (packet->ucTriggerRight == 0 && (packet->rgucButtonsAndHat[1] & 0x08)) { 1309 axis = SDL_JOYSTICK_AXIS_MAX; 1310 } else { 1311 axis = ((int)packet->ucTriggerRight * 257) - 32768; 1312 } 1313 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis); 1314 axis = ((int)packet->ucLeftJoystickX * 257) - 32768; 1315 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis); 1316 axis = ((int)packet->ucLeftJoystickY * 257) - 32768; 1317 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis); 1318 axis = ((int)packet->ucRightJoystickX * 257) - 32768; 1319 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis); 1320 axis = ((int)packet->ucRightJoystickY * 257) - 32768; 1321 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis); 1322 1323 if (ctx->report_sensors) { 1324 Uint64 sensor_timestamp; 1325 float data[3]; 1326 1327 if (ctx->use_alternate_report) { 1328 // 16-bit timestamp 1329 Uint32 delta; 1330 Uint16 tick = LOAD16(packet->rgucSensorTimestamp[0], 1331 packet->rgucSensorTimestamp[1]); 1332 if (ctx->last_tick < tick) { 1333 delta = (tick - ctx->last_tick); 1334 } else { 1335 delta = (SDL_MAX_UINT16 - ctx->last_tick + tick + 1); 1336 } 1337 ctx->last_tick = tick; 1338 ctx->sensor_ticks += delta; 1339 1340 // Sensor timestamp is in 1us units 1341 sensor_timestamp = SDL_US_TO_NS(ctx->sensor_ticks); 1342 } else { 1343 // 32-bit timestamp 1344 Uint32 delta; 1345 Uint32 tick = LOAD32(packet->rgucSensorTimestamp[0], 1346 packet->rgucSensorTimestamp[1], 1347 packet->rgucSensorTimestamp[2], 1348 packet->rgucSensorTimestamp[3]); 1349 if (ctx->last_tick < tick) { 1350 delta = (tick - ctx->last_tick); 1351 } else { 1352 delta = (SDL_MAX_UINT32 - ctx->last_tick + tick + 1); 1353 } 1354 ctx->last_tick = tick; 1355 ctx->sensor_ticks += delta; 1356 1357 // Sensor timestamp is in 0.33us units 1358 sensor_timestamp = (ctx->sensor_ticks * SDL_NS_PER_US) / 3; 1359 } 1360 1361 data[0] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 0, LOAD16(packet->rgucGyroX[0], packet->rgucGyroX[1])); 1362 data[1] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 1, LOAD16(packet->rgucGyroY[0], packet->rgucGyroY[1])); 1363 data[2] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 2, LOAD16(packet->rgucGyroZ[0], packet->rgucGyroZ[1])); 1364 SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, sensor_timestamp, data, 3); 1365 1366 data[0] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 3, LOAD16(packet->rgucAccelX[0], packet->rgucAccelX[1])); 1367 data[1] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 4, LOAD16(packet->rgucAccelY[0], packet->rgucAccelY[1])); 1368 data[2] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 5, LOAD16(packet->rgucAccelZ[0], packet->rgucAccelZ[1])); 1369 SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, sensor_timestamp, data, 3); 1370 } 1371} 1372 1373static void HIDAPI_DriverPS5_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacket_t *packet, Uint64 timestamp) 1374{ 1375 static const float TOUCHPAD_SCALEX = 5.20833333e-4f; // 1.0f / 1920 1376 static const float TOUCHPAD_SCALEY = 9.34579439e-4f; // 1.0f / 1070 1377 bool touchpad_down; 1378 int touchpad_x, touchpad_y; 1379 1380 if (ctx->report_touchpad) { 1381 touchpad_down = ((packet->ucTouchpadCounter1 & 0x80) == 0); 1382 touchpad_x = packet->rgucTouchpadData1[0] | (((int)packet->rgucTouchpadData1[1] & 0x0F) << 8); 1383 touchpad_y = (packet->rgucTouchpadData1[1] >> 4) | ((int)packet->rgucTouchpadData1[2] << 4); 1384 SDL_SendJoystickTouchpad(timestamp, joystick, 0, 0, touchpad_down, touchpad_x * TOUCHPAD_SCALEX, touchpad_y * TOUCHPAD_SCALEY, touchpad_down ? 1.0f : 0.0f); 1385 1386 touchpad_down = ((packet->ucTouchpadCounter2 & 0x80) == 0); 1387 touchpad_x = packet->rgucTouchpadData2[0] | (((int)packet->rgucTouchpadData2[1] & 0x0F) << 8); 1388 touchpad_y = (packet->rgucTouchpadData2[1] >> 4) | ((int)packet->rgucTouchpadData2[2] << 4); 1389 SDL_SendJoystickTouchpad(timestamp, joystick, 0, 1, touchpad_down, touchpad_x * TOUCHPAD_SCALEX, touchpad_y * TOUCHPAD_SCALEY, touchpad_down ? 1.0f : 0.0f); 1390 } 1391 1392 if (ctx->report_battery) { 1393 SDL_PowerState state; 1394 int percent; 1395 Uint8 status = (packet->ucBatteryLevel >> 4) & 0x0F; 1396 Uint8 level = (packet->ucBatteryLevel & 0x0F); 1397 1398 switch (status) { 1399 case 0: 1400 state = SDL_POWERSTATE_ON_BATTERY; 1401 percent = SDL_min(level * 10 + 5, 100); 1402 break; 1403 case 1: 1404 state = SDL_POWERSTATE_CHARGING; 1405 percent = SDL_min(level * 10 + 5, 100); 1406 break; 1407 case 2: 1408 state = SDL_POWERSTATE_CHARGED; 1409 percent = 100; 1410 break; 1411 default: 1412 state = SDL_POWERSTATE_UNKNOWN; 1413 percent = 0; 1414 break; 1415 } 1416 SDL_SendJoystickPowerInfo(joystick, state, percent); 1417 } 1418 1419 HIDAPI_DriverPS5_HandleStatePacketCommon(joystick, dev, ctx, (PS5StatePacketCommon_t *)packet, timestamp); 1420 1421 SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state)); 1422} 1423 1424static void HIDAPI_DriverPS5_HandleStatePacketAlt(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacketAlt_t *packet, Uint64 timestamp) 1425{ 1426 static const float TOUCHPAD_SCALEX = 5.20833333e-4f; // 1.0f / 1920 1427 static const float TOUCHPAD_SCALEY = 9.34579439e-4f; // 1.0f / 1070 1428 bool touchpad_down; 1429 int touchpad_x, touchpad_y; 1430 1431 if (ctx->report_touchpad) { 1432 touchpad_down = ((packet->ucTouchpadCounter1 & 0x80) == 0); 1433 touchpad_x = packet->rgucTouchpadData1[0] | (((int)packet->rgucTouchpadData1[1] & 0x0F) << 8); 1434 touchpad_y = (packet->rgucTouchpadData1[1] >> 4) | ((int)packet->rgucTouchpadData1[2] << 4); 1435 SDL_SendJoystickTouchpad(timestamp, joystick, 0, 0, touchpad_down, touchpad_x * TOUCHPAD_SCALEX, touchpad_y * TOUCHPAD_SCALEY, touchpad_down ? 1.0f : 0.0f); 1436 1437 touchpad_down = ((packet->ucTouchpadCounter2 & 0x80) == 0); 1438 touchpad_x = packet->rgucTouchpadData2[0] | (((int)packet->rgucTouchpadData2[1] & 0x0F) << 8); 1439 touchpad_y = (packet->rgucTouchpadData2[1] >> 4) | ((int)packet->rgucTouchpadData2[2] << 4); 1440 SDL_SendJoystickTouchpad(timestamp, joystick, 0, 1, touchpad_down, touchpad_x * TOUCHPAD_SCALEX, touchpad_y * TOUCHPAD_SCALEY, touchpad_down ? 1.0f : 0.0f); 1441 } 1442 1443 HIDAPI_DriverPS5_HandleStatePacketCommon(joystick, dev, ctx, (PS5StatePacketCommon_t *)packet, timestamp); 1444 1445 SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state)); 1446} 1447 1448static bool VerifyCRC(Uint8 *data, int size) 1449{ 1450 Uint8 ubHdr = 0xA1; // hidp header is part of the CRC calculation 1451 Uint32 unCRC, unPacketCRC; 1452 Uint8 *packetCRC = data + size - sizeof(unPacketCRC); 1453 unCRC = SDL_crc32(0, &ubHdr, 1); 1454 unCRC = SDL_crc32(unCRC, data, (size_t)(size - sizeof(unCRC))); 1455 1456 unPacketCRC = LOAD32(packetCRC[0], 1457 packetCRC[1], 1458 packetCRC[2], 1459 packetCRC[3]); 1460 return (unCRC == unPacketCRC); 1461} 1462 1463static bool HIDAPI_DriverPS5_IsPacketValid(SDL_DriverPS5_Context *ctx, Uint8 *data, int size) 1464{ 1465 switch (data[0]) { 1466 case k_EPS5ReportIdState: 1467 if (ctx->is_nacon_dongle && size >= (1 + sizeof(PS5StatePacketAlt_t))) { 1468 // The report timestamp doesn't change when the controller isn't connected 1469 PS5StatePacketAlt_t *packet = (PS5StatePacketAlt_t *)&data[1]; 1470 if (SDL_memcmp(packet->rgucPacketSequence, ctx->last_state.state.rgucPacketSequence, sizeof(packet->rgucPacketSequence)) == 0) { 1471 return false; 1472 } 1473 if (ctx->last_state.alt_state.rgucAccelX[0] == 0 && ctx->last_state.alt_state.rgucAccelX[1] == 0 && 1474 ctx->last_state.alt_state.rgucAccelY[0] == 0 && ctx->last_state.alt_state.rgucAccelY[1] == 0 && 1475 ctx->last_state.alt_state.rgucAccelZ[0] == 0 && ctx->last_state.alt_state.rgucAccelZ[1] == 0) { 1476 // We don't have any state to compare yet, go ahead and copy it 1477 SDL_memcpy(&ctx->last_state, &data[1], sizeof(PS5StatePacketAlt_t)); 1478 return false; 1479 } 1480 } 1481 return true; 1482 1483 case k_EPS5ReportIdBluetoothState: 1484 if (VerifyCRC(data, size)) { 1485 return true; 1486 } 1487 break; 1488 default: 1489 break; 1490 } 1491 return false; 1492} 1493 1494static bool HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device) 1495{ 1496 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; 1497 SDL_Joystick *joystick = NULL; 1498 Uint8 data[USB_PACKET_LENGTH * 2]; 1499 int size; 1500 int packet_count = 0; 1501 Uint64 now = SDL_GetTicks(); 1502 1503 if (device->num_joysticks > 0) { 1504 joystick = SDL_GetJoystickFromID(device->joysticks[0]); 1505 } 1506 1507 while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) { 1508 Uint64 timestamp = SDL_GetTicksNS(); 1509 1510#ifdef DEBUG_PS5_PROTOCOL 1511 HIDAPI_DumpPacket("PS5 packet: size = %d", data, size); 1512#endif 1513 if (!HIDAPI_DriverPS5_IsPacketValid(ctx, data, size)) { 1514 continue; 1515 } 1516 1517 ++packet_count; 1518 ctx->last_packet = now; 1519 1520 if (!joystick) { 1521 continue; 1522 } 1523 1524 switch (data[0]) { 1525 case k_EPS5ReportIdState: 1526 if (size == 10 || size == 78) { 1527 HIDAPI_DriverPS5_HandleSimpleStatePacket(joystick, device->dev, ctx, (PS5SimpleStatePacket_t *)&data[1], timestamp); 1528 } else { 1529 if (ctx->use_alternate_report) { 1530 HIDAPI_DriverPS5_HandleStatePacketAlt(joystick, device->dev, ctx, (PS5StatePacketAlt_t *)&data[1], timestamp); 1531 } else { 1532 HIDAPI_DriverPS5_HandleStatePacket(joystick, device->dev, ctx, (PS5StatePacket_t *)&data[1], timestamp); 1533 } 1534 } 1535 break; 1536 case k_EPS5ReportIdBluetoothState: 1537 // This is the extended report, we can enable effects now in auto mode 1538 HIDAPI_DriverPS5_UpdateEnhancedModeOnEnhancedReport(ctx); 1539 1540 if (ctx->use_alternate_report) { 1541 HIDAPI_DriverPS5_HandleStatePacketAlt(joystick, device->dev, ctx, (PS5StatePacketAlt_t *)&data[2], timestamp); 1542 } else { 1543 HIDAPI_DriverPS5_HandleStatePacket(joystick, device->dev, ctx, (PS5StatePacket_t *)&data[2], timestamp); 1544 } 1545 if (ctx->led_reset_state == k_EDS5LEDResetStatePending) { 1546 HIDAPI_DriverPS5_CheckPendingLEDReset(ctx); 1547 } 1548 break; 1549 default: 1550#ifdef DEBUG_JOYSTICK 1551 SDL_Log("Unknown PS5 packet: 0x%.2x", data[0]); 1552#endif 1553 break; 1554 } 1555 } 1556 1557 if (device->is_bluetooth) { 1558 if (packet_count == 0) { 1559 // Check to see if it looks like the device disconnected 1560 if (now >= (ctx->last_packet + BLUETOOTH_DISCONNECT_TIMEOUT_MS)) { 1561 // Send an empty output report to tickle the Bluetooth stack 1562 HIDAPI_DriverPS5_TickleBluetooth(device); 1563 ctx->last_packet = now; 1564 } 1565 } else { 1566 // Reconnect the Bluetooth device once the USB device is gone 1567 if (device->num_joysticks == 0 && 1568 !HIDAPI_HasConnectedUSBDevice(device->serial)) { 1569 HIDAPI_JoystickConnected(device, NULL); 1570 } 1571 } 1572 } 1573 1574 if (ctx->is_nacon_dongle) { 1575 if (packet_count == 0) { 1576 if (device->num_joysticks > 0) { 1577 // Check to see if it looks like the device disconnected 1578 if (now >= (ctx->last_packet + BLUETOOTH_DISCONNECT_TIMEOUT_MS)) { 1579 HIDAPI_JoystickDisconnected(device, device->joysticks[0]); 1580 } 1581 } 1582 } else { 1583 if (device->num_joysticks == 0) { 1584 HIDAPI_JoystickConnected(device, NULL); 1585 } 1586 } 1587 } 1588 1589 if (packet_count == 0 && size < 0 && device->num_joysticks > 0) { 1590 // Read error, device is disconnected 1591 HIDAPI_JoystickDisconnected(device, device->joysticks[0]); 1592 } 1593 return (size >= 0); 1594} 1595 1596static void HIDAPI_DriverPS5_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 1597{ 1598 SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; 1599 1600 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_ENHANCED_REPORTS, 1601 SDL_PS5EnhancedReportsChanged, ctx); 1602 1603 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED, 1604 SDL_PS5PlayerLEDHintChanged, ctx); 1605 1606 ctx->joystick = NULL; 1607 1608 ctx->report_sensors = false; 1609 ctx->enhanced_mode = false; 1610 ctx->enhanced_mode_available = false; 1611} 1612 1613static void HIDAPI_DriverPS5_FreeDevice(SDL_HIDAPI_Device *device) 1614{ 1615} 1616 1617SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS5 = { 1618 SDL_HINT_JOYSTICK_HIDAPI_PS5, 1619 true, 1620 HIDAPI_DriverPS5_RegisterHints, 1621 HIDAPI_DriverPS5_UnregisterHints, 1622 HIDAPI_DriverPS5_IsEnabled, 1623 HIDAPI_DriverPS5_IsSupportedDevice, 1624 HIDAPI_DriverPS5_InitDevice, 1625 HIDAPI_DriverPS5_GetDevicePlayerIndex, 1626 HIDAPI_DriverPS5_SetDevicePlayerIndex, 1627 HIDAPI_DriverPS5_UpdateDevice, 1628 HIDAPI_DriverPS5_OpenJoystick, 1629 HIDAPI_DriverPS5_RumbleJoystick, 1630 HIDAPI_DriverPS5_RumbleJoystickTriggers, 1631 HIDAPI_DriverPS5_GetJoystickCapabilities, 1632 HIDAPI_DriverPS5_SetJoystickLED, 1633 HIDAPI_DriverPS5_SendJoystickEffect, 1634 HIDAPI_DriverPS5_SetJoystickSensorsEnabled, 1635 HIDAPI_DriverPS5_CloseJoystick, 1636 HIDAPI_DriverPS5_FreeDevice, 1637}; 1638 1639#endif // SDL_JOYSTICK_HIDAPI_PS5 1640 1641#endif // SDL_JOYSTICK_HIDAPI 1642
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.