Drop PS5 Bluetooth reports that fail CRC check

This commit is contained in:
Sam Lantinga 2022-09-26 22:47:21 -07:00
parent db075ff3ba
commit 8c40a6b0c7
1 changed files with 56 additions and 17 deletions

View File

@ -45,6 +45,10 @@
#define BLUETOOTH_DISCONNECT_TIMEOUT_MS 500 #define BLUETOOTH_DISCONNECT_TIMEOUT_MS 500
#define LOAD16(A, B) (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8)) #define LOAD16(A, B) (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8))
#define LOAD32(A, B, C, D) ((((Uint32)(A)) << 0) | \
(((Uint32)(B)) << 8) | \
(((Uint32)(C)) << 16) | \
(((Uint32)(D)) << 24))
typedef enum typedef enum
{ {
@ -1256,6 +1260,40 @@ HIDAPI_DriverPS5_HandleStatePacketAlt(SDL_Joystick *joystick, SDL_hid_device *de
SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state)); SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state));
} }
static SDL_bool
VerifyCRC(Uint8 *data, int size)
{
Uint8 ubHdr = 0xA1; /* hidp header is part of the CRC calculation */
Uint32 unCRC, unPacketCRC;
Uint8 *packetCRC = data + size - sizeof(unPacketCRC);
unCRC = SDL_crc32(0, &ubHdr, 1);
unCRC = SDL_crc32(unCRC, data, (size_t)(size - sizeof(unCRC)));
unPacketCRC = LOAD32(packetCRC[0],
packetCRC[1],
packetCRC[2],
packetCRC[3]);
return (unCRC == unPacketCRC) ? SDL_TRUE : SDL_FALSE;
}
static SDL_bool
HIDAPI_DriverPS5_IsPacketValid(SDL_DriverPS5_Context *ctx, Uint8 *data, int size)
{
switch (data[0]) {
case k_EPS5ReportIdState:
return SDL_TRUE;
case k_EPS5ReportIdBluetoothState:
if (VerifyCRC(data, size)) {
return SDL_TRUE;
}
break;
default:
break;
}
return SDL_FALSE;
}
static SDL_bool static SDL_bool
HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device) HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
{ {
@ -1265,25 +1303,18 @@ HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
int size; int size;
int packet_count = 0; int packet_count = 0;
/* Reconnect the Bluetooth device once the USB device is gone */
if (device->num_joysticks == 0 &&
device->is_bluetooth &&
!HIDAPI_HasConnectedUSBDevice(device->serial)) {
if (SDL_hid_read_timeout(device->dev, data, sizeof(data), 0) > 0) {
HIDAPI_JoystickConnected(device, NULL);
}
}
if (device->num_joysticks > 0) { if (device->num_joysticks > 0) {
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
} else {
return SDL_FALSE;
} }
while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) { while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
#ifdef DEBUG_PS5_PROTOCOL #ifdef DEBUG_PS5_PROTOCOL
HIDAPI_DumpPacket("PS5 packet: size = %d", data, size); HIDAPI_DumpPacket("PS5 packet: size = %d", data, size);
#endif #endif
if (!HIDAPI_DriverPS5_IsPacketValid(ctx, data, size)) {
continue;
}
++packet_count; ++packet_count;
ctx->last_packet = SDL_GetTicks(); ctx->last_packet = SDL_GetTicks();
@ -1327,15 +1358,23 @@ HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
} }
} }
if (device->is_bluetooth && packet_count == 0) { if (device->is_bluetooth) {
if (packet_count == 0) {
/* Check to see if it looks like the device disconnected */ /* Check to see if it looks like the device disconnected */
if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->last_packet + BLUETOOTH_DISCONNECT_TIMEOUT_MS)) { if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->last_packet + BLUETOOTH_DISCONNECT_TIMEOUT_MS)) {
/* Send an empty output report to tickle the Bluetooth stack */ /* Send an empty output report to tickle the Bluetooth stack */
HIDAPI_DriverPS5_TickleBluetooth(device); HIDAPI_DriverPS5_TickleBluetooth(device);
} }
} else {
/* Reconnect the Bluetooth device once the USB device is gone */
if (device->num_joysticks == 0 &&
!HIDAPI_HasConnectedUSBDevice(device->serial)) {
HIDAPI_JoystickConnected(device, NULL);
}
}
} }
if (size < 0) { if (size < 0 && device->num_joysticks > 0) {
/* Read error, device is disconnected */ /* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, device->joysticks[0]); HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
} }