SDL_hidapi_ps5.c 63 KB

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