SDL: Fixed detecting 8BitDo sensor timestamp on older firmware

From 8d5bf053f7d0eecdc58b638179163732f413a151 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 26 Jun 2025 10:46:50 -0700
Subject: [PATCH] Fixed detecting 8BitDo sensor timestamp on older firmware

Also updated the reported sensor rate over USB for new firmware
---
 src/joystick/hidapi/SDL_hidapi_8bitdo.c | 38 +++++++++++++++++++------
 1 file changed, 30 insertions(+), 8 deletions(-)

diff --git a/src/joystick/hidapi/SDL_hidapi_8bitdo.c b/src/joystick/hidapi/SDL_hidapi_8bitdo.c
index 09614f6cdf8b4..e9410157ffb98 100644
--- a/src/joystick/hidapi/SDL_hidapi_8bitdo.c
+++ b/src/joystick/hidapi/SDL_hidapi_8bitdo.c
@@ -187,13 +187,17 @@ static bool HIDAPI_Driver8BitDo_InitDevice(SDL_HIDAPI_Device *device)
         for (int attempt = 0; attempt < MAX_ATTEMPTS; ++attempt) {
             int size = ReadFeatureReport(device->dev, SDL_8BITDO_FEATURE_REPORTID_ENABLE_SDL_REPORTID, data, sizeof(data));
             if (size > 0) {
+#ifdef DEBUG_8BITDO_PROTOCOL
+                HIDAPI_DumpPacket("8BitDo features packet: size = %d", data, size);
+#endif
                 ctx->sensors_supported = true;
                 ctx->rumble_supported = true;
                 ctx->powerstate_supported = true;
 
-                if (data[13] == SDL_8BITDO_SENSOR_TIMESTAMP_ENABLE) {
+                if (size >= 14 && data[13] == SDL_8BITDO_SENSOR_TIMESTAMP_ENABLE) {
                     ctx->sensor_timestamp_supported = true;
                 }
+
                 // Set the serial number to the Bluetooth MAC address
                 if (size >= 12 && data[10] != 0) {
                     char serial[18];
@@ -231,18 +235,36 @@ static void HIDAPI_Driver8BitDo_SetDevicePlayerIndex(SDL_HIDAPI_Device *device,
 
 static Uint64 HIDAPI_Driver8BitDo_GetIMURateForProductID(SDL_HIDAPI_Device *device)
 {
+    SDL_Driver8BitDo_Context *ctx = (SDL_Driver8BitDo_Context *)device->context;
+
     // TODO: If sensor time stamp is sent, these fixed settings from observation can be replaced
     switch (device->product_id) {
-    // Note, This is estimated by observation of Bluetooth packets received in the testcontroller tool
-    case USB_PRODUCT_8BITDO_SN30_PRO_BT:
-    case USB_PRODUCT_8BITDO_SF30_PRO_BT:
-        return 90; // Observed to be anywhere between 60-90 hz. Possibly lossy in current state
     case USB_PRODUCT_8BITDO_SF30_PRO:
+    case USB_PRODUCT_8BITDO_SF30_PRO_BT:
     case USB_PRODUCT_8BITDO_SN30_PRO:
-        return 100;
+    case USB_PRODUCT_8BITDO_SN30_PRO_BT:
+        if (device->is_bluetooth) {
+            // Note, This is estimated by observation of Bluetooth packets received in the testcontroller tool
+            return 70; // Observed to be anywhere between 60-90 hz. Possibly lossy in current state
+        } else if (ctx->sensor_timestamp_supported) {
+            // This firmware appears to update at 200 Hz over USB
+            return 200;
+        } else {
+            // This firmware appears to update at 100 Hz over USB
+            return 100;
+        }
     case USB_PRODUCT_8BITDO_PRO_2:
-    case USB_PRODUCT_8BITDO_PRO_2_BT:// Note, labelled as "BT" but appears this way when wired. Observed bluetooth packet rate seems to be 80-90hz
-        return (device->is_bluetooth ? 85 : 100);
+    case USB_PRODUCT_8BITDO_PRO_2_BT: // Note, labeled as "BT" but appears this way when wired.
+        if (device->is_bluetooth) {
+            // Note, This is estimated by observation of Bluetooth packets received in the testcontroller tool
+            return 85; // Observed Bluetooth packet rate seems to be 80-90hz
+        } else if (ctx->sensor_timestamp_supported) {
+            // This firmware appears to update at 200 Hz over USB
+            return 200;
+        } else {
+            // This firmware appears to update at 100 Hz over USB
+            return 100;
+        }
     case USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS:
     default:
         return 120;