|
|
@@ -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 {
|