Pārlūkot izejas kodu

Added enhanced support for the Flydigi Vader 5 Pro controller

Sam Lantinga 2 mēneši atpakaļ
vecāks
revīzija
0ac6f972f9

+ 1 - 0
src/SDL_utils.c

@@ -445,6 +445,7 @@ char *SDL_CreateDeviceName(Uint16 vendor, Uint16 product, const char *vendor_nam
         const char *prefix;
         const char *replacement;
     } replacements[] = {
+        { "(Standard system devices) ", "" },
         { "8BitDo Tech Ltd", "8BitDo" },
         { "ASTRO Gaming", "ASTRO" },
         { "Bensussen Deutsch & Associates,Inc.(BDA)", "BDA" },

+ 4 - 0
src/joystick/SDL_gamepad.c

@@ -1258,6 +1258,10 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
             if (guid.data[15] >= SDL_FLYDIGI_VADER2) {
                 // Vader series of controllers have C/Z buttons
                 SDL_strlcat(mapping_string, "misc2:b15,misc3:b16,", sizeof(mapping_string));
+                if (guid.data[15] == SDL_FLYDIGI_VADER5_PRO) {
+                    // Vader 5 has additional shoulder macro buttons and a circle button
+                    SDL_strlcat(mapping_string, "misc4:b17,misc5:b18,misc6:b19", sizeof(mapping_string));
+                }
             } else if (guid.data[15] == SDL_FLYDIGI_APEX5) {
                 // Apex 5 has additional shoulder macro buttons
                 SDL_strlcat(mapping_string, "misc2:b15,misc3:b16,", sizeof(mapping_string));

+ 83 - 15
src/joystick/hidapi/SDL_hidapi_flydigi.c

@@ -53,6 +53,9 @@ enum
 /* Rate of IMU Sensor Packets over wired connection observed in testcontroller at 500hz */
 #define SENSOR_INTERVAL_VADER4_PRO_WIRED_RATE_HZ  500
 #define SENSOR_INTERVAL_VADER4_PRO_WIRED_NS      (SDL_NS_PER_SECOND / SENSOR_INTERVAL_VADER4_PRO_WIRED_RATE_HZ)
+/* Rate of IMU Sensor Packets over wired connection observed in testcontroller at 500hz */
+#define SENSOR_INTERVAL_VADER5_PRO_RATE_HZ        500
+#define SENSOR_INTERVAL_VADER5_PRO_NS            (SDL_NS_PER_SECOND / SENSOR_INTERVAL_VADER5_PRO_RATE_HZ)
 
 /* Rate of IMU Sensor Packets over wireless dongle observed in testcontroller at 295hz */
 #define SENSOR_INTERVAL_APEX5_DONGLE_RATE_HZ     295
@@ -86,6 +89,7 @@ typedef struct
     bool available;
     bool has_cz;
     bool has_lmrm;
+    bool has_circle;
     bool wireless;
     bool sensors_supported;
     bool sensors_enabled;
@@ -117,7 +121,19 @@ static bool HIDAPI_DriverFlydigi_IsEnabled(void)
 
 static bool HIDAPI_DriverFlydigi_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)
 {
-    return SDL_IsJoystickFlydigiController(vendor_id, product_id) && interface_number == 2;
+    if (SDL_IsJoystickFlydigiController(vendor_id, product_id)) {
+        if (vendor_id == USB_VENDOR_FLYDIGI_V1) {
+            if (interface_number == 2) {
+                // Early controllers have their custom protocol on interface 2
+                return true;
+            }
+        } else {
+            // Newer controllers have their custom protocol on interface 1 or 2, but
+            // only expose one HID interface, so we'll accept any interface we see.
+            return true;
+        }
+    }
+    return false;
 }
 
 static bool HIDAPI_DriverFlydigi_InitControllerV1(SDL_HIDAPI_Device *device)
@@ -217,8 +233,15 @@ static bool GetReply(SDL_HIDAPI_Device* device, Uint8 command, Uint8* data, size
         HIDAPI_DumpPacket("Flydigi packet: size = %d", data, size);
 #endif
 
-        if (size == 32 && data[1] == FLYDIGI_V2_MAGIC1 && data[2] == FLYDIGI_V2_MAGIC2 && data[3] == command) {
-            return true;
+        if (size == 32) {
+            if (data[1] == FLYDIGI_V2_MAGIC1 && data[2] == FLYDIGI_V2_MAGIC2) {
+                // Skip the report ID
+                SDL_memmove(&data[0], &data[1], size - 1);
+                data[size - 1] = 0;
+            }
+            if (data[0] == FLYDIGI_V2_MAGIC1 && data[1] == FLYDIGI_V2_MAGIC2 && data[2] == command) {
+                return true;
+            }
         }
     }
     return false;
@@ -264,12 +287,27 @@ static bool HIDAPI_DriverFlydigi_InitControllerV2(SDL_HIDAPI_Device *device)
     }
 
     // Check the firmware version
-    ctx->firmware_version = LOAD16(data[17], data[16]);
-    if (ctx->firmware_version < 0x7031) {
+    Uint16 min_firmware_version;
+    ctx->firmware_version = LOAD16(data[16], data[15]);
+    switch (device->product_id) {
+    case USB_PRODUCT_FLYDIGI_V2_APEX:
+        // Minimum supported firmware version, Apex 5
+        min_firmware_version = 0x7031;
+        break;
+    case USB_PRODUCT_FLYDIGI_V2_VADER:
+        // Minimum supported firmware version, Vader 5 Pro
+        min_firmware_version = 0x7141;
+        break;
+    default:
+        // Unknown product, presumably this version is okay?
+        min_firmware_version = 0;
+        break;
+    }
+    if (ctx->firmware_version < min_firmware_version) {
         return SDL_SetError("Unsupported firmware version");
     }
 
-    switch (data[7]) {
+    switch (data[6]) {
     case 1:
         // Wired connection
         ctx->wireless = false;
@@ -281,7 +319,7 @@ static bool HIDAPI_DriverFlydigi_InitControllerV2(SDL_HIDAPI_Device *device)
     default:
         break;
     }
-    ctx->deviceID = data[6];
+    ctx->deviceID = data[5];
 
     // See whether we can acquire the controller
     const Uint8 query_status[] = { FLYDIGI_V2_CMD_REPORT_ID, FLYDIGI_V2_MAGIC1, FLYDIGI_V2_MAGIC2, FLYDIGI_V2_GET_STATUS_COMMAND };
@@ -291,7 +329,7 @@ static bool HIDAPI_DriverFlydigi_InitControllerV2(SDL_HIDAPI_Device *device)
     if (!GetReply(device, FLYDIGI_V2_GET_STATUS_COMMAND, data, sizeof(data))) {
         return SDL_SetError("Couldn't get controller status");
     }
-    if (data[10] == 1) {
+    if (data[9] == 1) {
         ctx->available = true;
     } else {
         // Click "Allow third-party apps to take over mappings" in the FlyDigi Space Station app
@@ -338,19 +376,26 @@ static void HIDAPI_DriverFlydigi_UpdateDeviceIdentity(SDL_HIDAPI_Device *device)
         break;
     case 128:
     case 129:
+        controller_type = SDL_FLYDIGI_APEX5;
+        break;
+    case 130:
+        controller_type = SDL_FLYDIGI_VADER5_PRO;
+        break;
     case 133:
     case 134:
         controller_type = SDL_FLYDIGI_APEX5;
         break;
     default:
         // Try to guess from the name of the controller
-        if (SDL_strstr(device->name, "VADER") != NULL) {
+        if (SDL_strcasestr(device->name, "VADER") != NULL) {
             if (SDL_strstr(device->name, "VADER2") != NULL) {
                 controller_type = SDL_FLYDIGI_VADER2;
             } else if (SDL_strstr(device->name, "VADER3") != NULL) {
                 controller_type = SDL_FLYDIGI_VADER3;
             } else if (SDL_strstr(device->name, "VADER4") != NULL) {
-                controller_type = SDL_FLYDIGI_VADER4;
+                controller_type = SDL_FLYDIGI_VADER4_PRO;
+            } else if (SDL_strstr(device->name, "Vader 5") != NULL) {
+                controller_type = SDL_FLYDIGI_VADER5_PRO;
             }
         } else if (SDL_strstr(device->name, "APEX") != NULL) {
             if (SDL_strstr(device->name, "APEX2") != NULL) {
@@ -410,7 +455,6 @@ static void HIDAPI_DriverFlydigi_UpdateDeviceIdentity(SDL_HIDAPI_Device *device)
         ctx->accelScale = SDL_STANDARD_GRAVITY / 256.0f;
         ctx->sensor_timestamp_step_ns = ctx->wireless ? SENSOR_INTERVAL_VADER4_PRO_DONGLE_NS : SENSOR_INTERVAL_VADER4_PRO_WIRED_NS;
         break;
-    case SDL_FLYDIGI_VADER4:
     case SDL_FLYDIGI_VADER4_PRO:
         HIDAPI_SetDeviceName(device, "Flydigi Vader 4 Pro");
         ctx->has_cz = true;
@@ -418,6 +462,16 @@ static void HIDAPI_DriverFlydigi_UpdateDeviceIdentity(SDL_HIDAPI_Device *device)
         ctx->accelScale = SDL_STANDARD_GRAVITY / 256.0f;
         ctx->sensor_timestamp_step_ns = ctx->wireless ? SENSOR_INTERVAL_VADER4_PRO_DONGLE_NS : SENSOR_INTERVAL_VADER4_PRO_WIRED_NS;
         break;
+    case SDL_FLYDIGI_VADER5_PRO:
+        HIDAPI_SetDeviceName(device, "Flydigi Vader 5 Pro");
+        ctx->has_cz = true;
+        ctx->has_lmrm = true;
+        ctx->has_circle = true;
+        ctx->sensors_supported = true;
+        ctx->accelScale = SDL_STANDARD_GRAVITY / 4096.0f;
+        ctx->gyroScale = DEG2RAD(2000.0f);
+        ctx->sensor_timestamp_step_ns = SENSOR_INTERVAL_VADER5_PRO_NS;
+        break;
     default:
         SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Unknown FlyDigi controller with ID %d, name '%s'", ctx->deviceID, device->name);
         break;
@@ -479,6 +533,9 @@ static bool HIDAPI_DriverFlydigi_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joy
     if (ctx->has_lmrm) {
         joystick->nbuttons += 2;
     }
+    if (ctx->has_circle) {
+        joystick->nbuttons += 1;
+    }
     joystick->naxes = SDL_GAMEPAD_AXIS_COUNT;
     joystick->nhats = 1;
 
@@ -748,17 +805,28 @@ static void HIDAPI_DriverFlydigi_HandleStatePacketV2(SDL_Joystick *joystick, SDL
         SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_FLYDIGI_M2, ((data[13] & 0x08) != 0));
         SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_FLYDIGI_M3, ((data[13] & 0x10) != 0));
         SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_FLYDIGI_M4, ((data[13] & 0x20) != 0));
+        if (ctx->has_cz) {
+            SDL_SendJoystickButton(timestamp, joystick, extra_button_index++, ((data[13] & 0x01) != 0));
+            SDL_SendJoystickButton(timestamp, joystick, extra_button_index++, ((data[13] & 0x02) != 0));
+        }
         if (ctx->has_lmrm) {
             SDL_SendJoystickButton(timestamp, joystick, extra_button_index++, ((data[13] & 0x40) != 0));
             SDL_SendJoystickButton(timestamp, joystick, extra_button_index++, ((data[13] & 0x80) != 0));
         }
+    } else {
+        if (ctx->has_cz) {
+            extra_button_index += 2;
+        }
+        if (ctx->has_lmrm) {
+            extra_button_index += 2;
+        }
     }
 
     if (ctx->last_state[14] != data[14]) {
         SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[14] & 0x08) != 0));
-        SDL_SendJoystickButton(timestamp, joystick, extra_button_index++, ((data[14] & 0x01) != 0));
-        // The '-' button is only available on the Vader 2, for simplicity let's ignore that
-        SDL_SendJoystickButton(timestamp, joystick, extra_button_index++, ((data[8] & 0x10) != 0));
+        if (ctx->has_circle) {
+            SDL_SendJoystickButton(timestamp, joystick, extra_button_index++, ((data[14] & 0x01) != 0));
+        }
     }
 
     axis = LOAD16(data[3], data[4]);
@@ -813,7 +881,7 @@ static void HIDAPI_DriverFlydigi_HandleStatePacketV2(SDL_Joystick *joystick, SDL
 
 static void HIDAPI_DriverFlydigi_HandleStatusUpdate(SDL_HIDAPI_Device *device, Uint8 *data, int size)
 {
-    if (data[9] == 1) {
+    if (data[9] & 0x01) {
         // We can now acquire the controller
         HIDAPI_DriverFlydigi_SetAvailable(device, true);
     } else {

+ 1 - 1
src/joystick/hidapi/SDL_hidapi_flydigi.h

@@ -32,7 +32,7 @@ typedef enum
     SDL_FLYDIGI_VADER2_PRO,
     SDL_FLYDIGI_VADER3,
     SDL_FLYDIGI_VADER3_PRO,
-    SDL_FLYDIGI_VADER4,
     SDL_FLYDIGI_VADER4_PRO,
+    SDL_FLYDIGI_VADER5_PRO,
 } SDL_FlyDigiControllerType;