39
39
SDL_GAMEPAD_BUTTON_FLYDIGI_M2 ,
40
40
SDL_GAMEPAD_BUTTON_FLYDIGI_M3 ,
41
41
SDL_GAMEPAD_BUTTON_FLYDIGI_M4 ,
42
- SDL_GAMEPAD_BUTTON_FLYDIGI_FN ,
43
- SDL_GAMEPAD_BUTTON_FLYDIGI_C ,
44
- SDL_GAMEPAD_BUTTON_FLYDIGI_Z ,
45
- SDL_GAMEPAD_NUM_FLYDIGI_BUTTONS_WITH_CZ ,
42
+ SDL_GAMEPAD_NUM_BASE_FLYDIGI_BUTTONS
46
43
};
47
- #define SDL_GAMEPAD_NUM_FLYDIGI_BUTTONS_WITHOUT_CZ SDL_GAMEPAD_BUTTON_FLYDIGI_C
48
44
49
- #define FLYDIGI_ACCEL_SCALE 256.f
50
45
#define SENSOR_INTERVAL_NS 8000000ULL
51
46
#define FLYDIGI_CMD_REPORT_ID 0x05
52
47
#define FLYDIGI_HAPTIC_COMMAND 0x0F
53
48
#define FLYDIGI_GET_CONFIG_COMMAND 0xEB
49
+ #define FLYDIGI_GET_INFO_COMMAND 0xEC
54
50
55
51
#define LOAD16 (A , B ) (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8))
56
52
57
53
typedef struct
58
54
{
55
+ Uint8 deviceID ;
56
+ bool has_cz ;
57
+ bool wireless ;
59
58
bool sensors_supported ;
60
59
bool sensors_enabled ;
61
- bool touchpad_01_supported ;
62
- bool touchpad_02_supported ;
63
- bool rumble_supported ;
64
- bool rumble_type ;
65
- bool rgb_supported ;
66
- bool player_led_supported ;
67
- bool powerstate_supported ;
68
- bool has_cz ;
69
- Uint8 serial [6 ];
70
- Uint16 version ;
71
- Uint16 version_beta ;
60
+ Uint16 firmware_version ;
61
+ Uint64 sensor_timestamp ; // Microseconds. Simulate onboard clock. Advance by known rate: SENSOR_INTERVAL_NS == 8ms = 125 Hz
72
62
float accelScale ;
73
- float gyroScale ;
74
63
Uint8 last_state [USB_PACKET_LENGTH ];
75
- Uint64 sensor_timestamp ; // Microseconds. Simulate onboard clock. Advance by known rate: SENSOR_INTERVAL_NS == 8ms = 125 Hz
76
64
} SDL_DriverFlydigi_Context ;
77
65
78
- #pragma pack(push,1)
79
- typedef struct
80
- {
81
- bool sensors_supported ;
82
- bool touchpad_01_supported ;
83
- bool touchpad_02_supported ;
84
- bool rumble_supported ;
85
- bool rumble_type ;
86
- bool rgb_supported ;
87
- Uint8 device_type ;
88
- Uint8 serial [6 ];
89
- Uint16 version ;
90
- Uint16 version_beta ;
91
- Uint16 pid ;
92
- } FLYDIGI_DEVICE_INFO ;
93
-
94
- #pragma pack(pop)
95
-
96
66
97
67
static void HIDAPI_DriverFlydigi_RegisterHints (SDL_HintCallback callback , void * userdata )
98
68
{
@@ -114,6 +84,129 @@ static bool HIDAPI_DriverFlydigi_IsSupportedDevice(SDL_HIDAPI_Device *device, co
114
84
return SDL_IsJoystickFlydigiController (vendor_id , product_id ) && interface_number == 2 ;
115
85
}
116
86
87
+ static void UpdateDeviceIdentity (SDL_HIDAPI_Device * device )
88
+ {
89
+ SDL_DriverFlydigi_Context * ctx = (SDL_DriverFlydigi_Context * )device -> context ;
90
+
91
+ for (int attempt = 0 ; ctx -> deviceID == 0 && attempt < 3 ; ++ attempt ) {
92
+ const Uint8 request [] = { FLYDIGI_CMD_REPORT_ID , FLYDIGI_GET_INFO_COMMAND , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
93
+ int size = SDL_hid_write (device -> dev , request , sizeof (request ));
94
+ if (size < 0 ) {
95
+ break ;
96
+ }
97
+
98
+ // Read the reply
99
+ for (int i = 0 ; i < 100 ; ++ i ) {
100
+ SDL_Delay (1 );
101
+
102
+ Uint8 data [USB_PACKET_LENGTH ];
103
+ size = SDL_hid_read_timeout (device -> dev , data , sizeof (data ), 0 );
104
+ if (size < 0 ) {
105
+ break ;
106
+ }
107
+ if (size == 0 ) {
108
+ continue ;
109
+ }
110
+
111
+ #ifdef DEBUG_FLYDIGI_PROTOCOL
112
+ HIDAPI_DumpPacket ("Flydigi packet: size = %d" , data , size );
113
+ #endif
114
+ if (size == 32 && data [15 ] == 236 ) {
115
+ ctx -> deviceID = data [3 ];
116
+ ctx -> firmware_version = data [9 ] | (data [10 ] << 8 );
117
+
118
+ char serial [9 ];
119
+ (void )SDL_snprintf (serial , sizeof (serial ), "%.2x%.2x%.2x%.2x" , data [5 ], data [6 ], data [7 ], data [8 ]);
120
+ HIDAPI_SetDeviceSerial (device , serial );
121
+
122
+ // The Vader 2 with firmware 6.0.4.9 doesn't report the connection state
123
+ if (ctx -> firmware_version >= 0x6400 ) {
124
+ switch (data [13 ]) {
125
+ case 0 :
126
+ // Wireless connection
127
+ ctx -> wireless = true;
128
+ break ;
129
+ case 1 :
130
+ // Wired connection
131
+ ctx -> wireless = false;
132
+ break ;
133
+ default :
134
+ break ;
135
+ }
136
+ }
137
+
138
+ // Done!
139
+ break ;
140
+ }
141
+ }
142
+ }
143
+
144
+ if (ctx -> deviceID == 0 ) {
145
+ // Try to guess from the name of the controller
146
+ if (SDL_strstr (device -> name , "VADER" ) != NULL ) {
147
+ if (SDL_strstr (device -> name , "VADER2" ) != NULL ) {
148
+ ctx -> deviceID = 20 ;
149
+ } else if (SDL_strstr (device -> name , "VADER3" ) != NULL ) {
150
+ ctx -> deviceID = 28 ;
151
+ } else if (SDL_strstr (device -> name , "VADER4" ) != NULL ) {
152
+ ctx -> deviceID = 85 ;
153
+ }
154
+ } else if (SDL_strstr (device -> name , "APEX" ) != NULL ) {
155
+ if (SDL_strstr (device -> name , "APEX2" ) != NULL ) {
156
+ ctx -> deviceID = 19 ;
157
+ } else if (SDL_strstr (device -> name , "APEX3" ) != NULL ) {
158
+ ctx -> deviceID = 24 ;
159
+ } else if (SDL_strstr (device -> name , "APEX4" ) != NULL ) {
160
+ ctx -> deviceID = 84 ;
161
+ }
162
+ }
163
+ }
164
+ device -> guid .data [15 ] = ctx -> deviceID ;
165
+
166
+ switch (ctx -> deviceID ) {
167
+ case 19 :
168
+ HIDAPI_SetDeviceName (device , "Flydigi Apex 2" );
169
+ break ;
170
+ case 24 :
171
+ case 26 :
172
+ case 29 :
173
+ HIDAPI_SetDeviceName (device , "Flydigi Apex 3" );
174
+ break ;
175
+ case 84 :
176
+ // The Apex 4 controller has sensors, but they're only reported when gyro mouse is enabled
177
+ HIDAPI_SetDeviceName (device , "Flydigi Apex 4" );
178
+ break ;
179
+ case 20 :
180
+ case 21 :
181
+ case 23 :
182
+ // The Vader 2 controller has sensors, but they're only reported when gyro mouse is enabled
183
+ HIDAPI_SetDeviceName (device , "Flydigi Vader 2" );
184
+ ctx -> has_cz = true;
185
+ break ;
186
+ case 22 :
187
+ HIDAPI_SetDeviceName (device , "Flydigi Vader 2 Pro" );
188
+ ctx -> has_cz = true;
189
+ break ;
190
+ case 28 :
191
+ HIDAPI_SetDeviceName (device , "Flydigi Vader 3" );
192
+ ctx -> has_cz = true;
193
+ break ;
194
+ case 80 :
195
+ case 81 :
196
+ HIDAPI_SetDeviceName (device , "Flydigi Vader 3 Pro" );
197
+ ctx -> has_cz = true;
198
+ break ;
199
+ case 85 :
200
+ HIDAPI_SetDeviceName (device , "Flydigi Vader 4 Pro" );
201
+ ctx -> has_cz = true;
202
+ ctx -> sensors_supported = true;
203
+ ctx -> accelScale = SDL_STANDARD_GRAVITY / 256.0f ;
204
+ break ;
205
+ default :
206
+ break ;
207
+ }
208
+ }
209
+
117
210
static bool HIDAPI_DriverFlydigi_InitDevice (SDL_HIDAPI_Device * device )
118
211
{
119
212
SDL_DriverFlydigi_Context * ctx = (SDL_DriverFlydigi_Context * )SDL_calloc (1 , sizeof (* ctx ));
@@ -122,18 +215,7 @@ static bool HIDAPI_DriverFlydigi_InitDevice(SDL_HIDAPI_Device *device)
122
215
}
123
216
device -> context = ctx ;
124
217
125
- if (device -> product_id == USB_PRODUCT_FLYDIGI_VADER4_PRO ) {
126
- const int VADER4PRO_REPORT_SIZE = 32 ;
127
- Uint8 data [USB_PACKET_LENGTH ];
128
- int size = SDL_hid_read_timeout (device -> dev , data , sizeof (data ), 80 );
129
- if (size == VADER4PRO_REPORT_SIZE ) {
130
- ctx -> sensors_supported = true;
131
- ctx -> rumble_supported = true;
132
- }
133
- const char VADER3_NAME [] = "Flydigi VADER3" ;
134
- const char VADER4_NAME [] = "Flydigi VADER4" ;
135
- ctx -> has_cz = SDL_strncmp (device -> name , VADER3_NAME , sizeof (VADER3_NAME )) == 0 || SDL_strncmp (device -> name , VADER4_NAME , sizeof (VADER4_NAME )) == 0 ;
136
- }
218
+ UpdateDeviceIdentity (device );
137
219
138
220
return HIDAPI_JoystickConnected (device , NULL );
139
221
}
@@ -160,36 +242,35 @@ static bool HIDAPI_DriverFlydigi_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joy
160
242
SDL_zeroa (ctx -> last_state );
161
243
162
244
// Initialize the joystick capabilities
163
- joystick -> nbuttons = ctx -> has_cz ? SDL_GAMEPAD_NUM_FLYDIGI_BUTTONS_WITH_CZ : SDL_GAMEPAD_NUM_FLYDIGI_BUTTONS_WITHOUT_CZ ;
245
+ joystick -> nbuttons = SDL_GAMEPAD_NUM_BASE_FLYDIGI_BUTTONS ;
246
+ if (ctx -> has_cz ) {
247
+ joystick -> nbuttons += 2 ;
248
+ }
164
249
joystick -> naxes = SDL_GAMEPAD_AXIS_COUNT ;
165
250
joystick -> nhats = 1 ;
166
251
252
+ if (ctx -> wireless ) {
253
+ joystick -> connection_state = SDL_JOYSTICK_CONNECTION_WIRELESS ;
254
+ }
255
+
167
256
if (ctx -> sensors_supported ) {
168
257
SDL_PrivateJoystickAddSensor (joystick , SDL_SENSOR_GYRO , 125.0f );
169
258
SDL_PrivateJoystickAddSensor (joystick , SDL_SENSOR_ACCEL , 125.0f );
170
-
171
-
172
- ctx -> accelScale = SDL_STANDARD_GRAVITY / FLYDIGI_ACCEL_SCALE ;
173
259
}
174
260
175
261
return true;
176
262
}
177
263
178
264
static bool HIDAPI_DriverFlydigi_RumbleJoystick (SDL_HIDAPI_Device * device , SDL_Joystick * joystick , Uint16 low_frequency_rumble , Uint16 high_frequency_rumble )
179
265
{
180
- SDL_DriverFlydigi_Context * ctx = (SDL_DriverFlydigi_Context * )device -> context ;
181
- if (ctx -> rumble_supported ) {
182
- Uint8 rumble_packet [4 ] = { FLYDIGI_CMD_REPORT_ID , FLYDIGI_HAPTIC_COMMAND , 0x00 , 0x00 };
183
- rumble_packet [2 ] = low_frequency_rumble >> 8 ;
184
- rumble_packet [3 ] = high_frequency_rumble >> 8 ;
266
+ Uint8 rumble_packet [4 ] = { FLYDIGI_CMD_REPORT_ID , FLYDIGI_HAPTIC_COMMAND , 0x00 , 0x00 };
267
+ rumble_packet [2 ] = low_frequency_rumble >> 8 ;
268
+ rumble_packet [3 ] = high_frequency_rumble >> 8 ;
185
269
186
- if (SDL_HIDAPI_SendRumble (device , rumble_packet , sizeof (rumble_packet )) != sizeof (rumble_packet )) {
187
- return SDL_SetError ("Couldn't send rumble packet" );
188
- }
189
- return true;
190
- } else {
191
- return SDL_Unsupported ();
270
+ if (SDL_HIDAPI_SendRumble (device , rumble_packet , sizeof (rumble_packet )) != sizeof (rumble_packet )) {
271
+ return SDL_SetError ("Couldn't send rumble packet" );
192
272
}
273
+ return true;
193
274
}
194
275
195
276
static bool HIDAPI_DriverFlydigi_RumbleJoystickTriggers (SDL_HIDAPI_Device * device , SDL_Joystick * joystick , Uint16 left_rumble , Uint16 right_rumble )
@@ -199,12 +280,7 @@ static bool HIDAPI_DriverFlydigi_RumbleJoystickTriggers(SDL_HIDAPI_Device *devic
199
280
200
281
static Uint32 HIDAPI_DriverFlydigi_GetJoystickCapabilities (SDL_HIDAPI_Device * device , SDL_Joystick * joystick )
201
282
{
202
- SDL_DriverFlydigi_Context * ctx = (SDL_DriverFlydigi_Context * )device -> context ;
203
- Uint32 caps = 0 ;
204
- if (ctx -> rumble_supported ) {
205
- caps |= SDL_JOYSTICK_CAP_RUMBLE ;
206
- }
207
- return caps ;
283
+ return SDL_JOYSTICK_CAP_RUMBLE ;
208
284
}
209
285
210
286
static bool HIDAPI_DriverFlydigi_SetJoystickLED (SDL_HIDAPI_Device * device , SDL_Joystick * joystick , Uint8 red , Uint8 green , Uint8 blue )
@@ -235,10 +311,7 @@ static void HIDAPI_DriverFlydigi_HandleStatePacket(SDL_Joystick *joystick, SDL_D
235
311
return ;
236
312
}
237
313
238
- if (ctx -> last_state [8 ] != data [8 ]) {
239
- SDL_SendJoystickButton (timestamp , joystick , SDL_GAMEPAD_BUTTON_FLYDIGI_FN , ((data [8 ] & 0x01 ) != 0 ));
240
- SDL_SendJoystickButton (timestamp , joystick , SDL_GAMEPAD_BUTTON_GUIDE , ((data [8 ] & 0x08 ) != 0 ));
241
- }
314
+ Uint8 extra_button_index = SDL_GAMEPAD_NUM_BASE_FLYDIGI_BUTTONS ;
242
315
243
316
if (ctx -> last_state [9 ] != data [9 ]) {
244
317
Uint8 hat ;
@@ -290,12 +363,22 @@ static void HIDAPI_DriverFlydigi_HandleStatePacket(SDL_Joystick *joystick, SDL_D
290
363
}
291
364
292
365
if (ctx -> last_state [7 ] != data [7 ]) {
293
- SDL_SendJoystickButton (timestamp , joystick , SDL_GAMEPAD_BUTTON_FLYDIGI_C , ((data [7 ] & 0x01 ) != 0 ));
294
- SDL_SendJoystickButton (timestamp , joystick , SDL_GAMEPAD_BUTTON_FLYDIGI_Z , ((data [7 ] & 0x02 ) != 0 ));
295
366
SDL_SendJoystickButton (timestamp , joystick , SDL_GAMEPAD_BUTTON_FLYDIGI_M1 , ((data [7 ] & 0x04 ) != 0 ));
296
367
SDL_SendJoystickButton (timestamp , joystick , SDL_GAMEPAD_BUTTON_FLYDIGI_M2 , ((data [7 ] & 0x08 ) != 0 ));
297
368
SDL_SendJoystickButton (timestamp , joystick , SDL_GAMEPAD_BUTTON_FLYDIGI_M3 , ((data [7 ] & 0x10 ) != 0 ));
298
369
SDL_SendJoystickButton (timestamp , joystick , SDL_GAMEPAD_BUTTON_FLYDIGI_M4 , ((data [7 ] & 0x20 ) != 0 ));
370
+ if (ctx -> has_cz ) {
371
+ SDL_SendJoystickButton (timestamp , joystick , extra_button_index ++ , ((data [7 ] & 0x01 ) != 0 ));
372
+ SDL_SendJoystickButton (timestamp , joystick , extra_button_index ++ , ((data [7 ] & 0x02 ) != 0 ));
373
+ }
374
+ }
375
+
376
+ if (ctx -> last_state [8 ] != data [8 ]) {
377
+ SDL_SendJoystickButton (timestamp , joystick , SDL_GAMEPAD_BUTTON_GUIDE , ((data [8 ] & 0x08 ) != 0 ));
378
+ // The '+' button is used to toggle gyro mouse mode, so don't pass that to the application
379
+ //SDL_SendJoystickButton(timestamp, joystick, extra_button_index++, ((data[8] & 0x01) != 0));
380
+ // The '-' button is only available on the Vader 2, for simplicity let's ignore that
381
+ //SDL_SendJoystickButton(timestamp, joystick, extra_button_index++, ((data[8] & 0x10) != 0));
299
382
}
300
383
301
384
#define READ_STICK_AXIS (offset ) \
0 commit comments