sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_hidapi_ps4.c (29017B)


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