Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/sdl/joystick/hidapi/SDL_hidapi_shield.c
9906 views
1
/*
2
Simple DirectMedia Layer
3
Copyright (C) 1997-2025 Sam Lantinga <[email protected]>
4
5
This software is provided 'as-is', without any express or implied
6
warranty. In no event will the authors be held liable for any damages
7
arising from the use of this software.
8
9
Permission is granted to anyone to use this software for any purpose,
10
including commercial applications, and to alter it and redistribute it
11
freely, subject to the following restrictions:
12
13
1. The origin of this software must not be misrepresented; you must not
14
claim that you wrote the original software. If you use this software
15
in a product, an acknowledgment in the product documentation would be
16
appreciated but is not required.
17
2. Altered source versions must be plainly marked as such, and must not be
18
misrepresented as being the original software.
19
3. This notice may not be removed or altered from any source distribution.
20
*/
21
#include "SDL_internal.h"
22
23
#ifdef SDL_JOYSTICK_HIDAPI
24
25
#include "../SDL_sysjoystick.h"
26
#include "SDL_hidapijoystick_c.h"
27
#include "SDL_hidapi_rumble.h"
28
29
#ifdef SDL_JOYSTICK_HIDAPI_SHIELD
30
31
// Define this if you want to log all packets from the controller
32
// #define DEBUG_SHIELD_PROTOCOL
33
34
#define CMD_BATTERY_STATE 0x07
35
#define CMD_RUMBLE 0x39
36
#define CMD_CHARGE_STATE 0x3A
37
38
// Milliseconds between polls of battery state
39
#define BATTERY_POLL_INTERVAL_MS 60000
40
41
// Milliseconds between retransmission of rumble to keep motors running
42
#define RUMBLE_REFRESH_INTERVAL_MS 500
43
44
// Reports that are too small are dropped over Bluetooth
45
#define HID_REPORT_SIZE 33
46
47
enum
48
{
49
SDL_GAMEPAD_BUTTON_SHIELD_SHARE = 11,
50
SDL_GAMEPAD_BUTTON_SHIELD_V103_TOUCHPAD,
51
SDL_GAMEPAD_BUTTON_SHIELD_V103_MINUS,
52
SDL_GAMEPAD_BUTTON_SHIELD_V103_PLUS,
53
SDL_GAMEPAD_NUM_SHIELD_V103_BUTTONS,
54
55
SDL_GAMEPAD_NUM_SHIELD_V104_BUTTONS = SDL_GAMEPAD_BUTTON_SHIELD_SHARE + 1,
56
};
57
58
typedef enum
59
{
60
k_ShieldReportIdControllerState = 0x01,
61
k_ShieldReportIdControllerTouch = 0x02,
62
k_ShieldReportIdCommandResponse = 0x03,
63
k_ShieldReportIdCommandRequest = 0x04,
64
} EShieldReportId;
65
66
// This same report structure is used for both requests and responses
67
typedef struct
68
{
69
Uint8 report_id;
70
Uint8 cmd;
71
Uint8 seq_num;
72
Uint8 payload[HID_REPORT_SIZE - 3];
73
} ShieldCommandReport_t;
74
SDL_COMPILE_TIME_ASSERT(ShieldCommandReport_t, sizeof(ShieldCommandReport_t) == HID_REPORT_SIZE);
75
76
typedef struct
77
{
78
Uint8 seq_num;
79
80
bool has_charging;
81
Uint8 charging;
82
bool has_battery_level;
83
Uint8 battery_level;
84
Uint64 last_battery_query_time;
85
86
bool rumble_report_pending;
87
bool rumble_update_pending;
88
Uint8 left_motor_amplitude;
89
Uint8 right_motor_amplitude;
90
Uint64 last_rumble_time;
91
92
Uint8 last_state[USB_PACKET_LENGTH];
93
} SDL_DriverShield_Context;
94
95
static void HIDAPI_DriverShield_RegisterHints(SDL_HintCallback callback, void *userdata)
96
{
97
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_SHIELD, callback, userdata);
98
}
99
100
static void HIDAPI_DriverShield_UnregisterHints(SDL_HintCallback callback, void *userdata)
101
{
102
SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_SHIELD, callback, userdata);
103
}
104
105
static bool HIDAPI_DriverShield_IsEnabled(void)
106
{
107
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_SHIELD, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT));
108
}
109
110
static bool HIDAPI_DriverShield_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)
111
{
112
return SDL_IsJoystickNVIDIASHIELDController(vendor_id, product_id);
113
}
114
115
static bool HIDAPI_DriverShield_InitDevice(SDL_HIDAPI_Device *device)
116
{
117
SDL_DriverShield_Context *ctx;
118
119
ctx = (SDL_DriverShield_Context *)SDL_calloc(1, sizeof(*ctx));
120
if (!ctx) {
121
return false;
122
}
123
device->context = ctx;
124
125
HIDAPI_SetDeviceName(device, "NVIDIA SHIELD Controller");
126
127
return HIDAPI_JoystickConnected(device, NULL);
128
}
129
130
static int HIDAPI_DriverShield_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
131
{
132
return -1;
133
}
134
135
static void HIDAPI_DriverShield_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
136
{
137
}
138
139
static bool HIDAPI_DriverShield_SendCommand(SDL_HIDAPI_Device *device, Uint8 cmd, const void *data, int size)
140
{
141
SDL_DriverShield_Context *ctx = (SDL_DriverShield_Context *)device->context;
142
ShieldCommandReport_t cmd_pkt;
143
144
if (size > sizeof(cmd_pkt.payload)) {
145
return SDL_SetError("Command data exceeds HID report size");
146
}
147
148
if (!SDL_HIDAPI_LockRumble()) {
149
return false;
150
}
151
152
cmd_pkt.report_id = k_ShieldReportIdCommandRequest;
153
cmd_pkt.cmd = cmd;
154
cmd_pkt.seq_num = ctx->seq_num++;
155
if (data) {
156
SDL_memcpy(cmd_pkt.payload, data, size);
157
}
158
159
// Zero unused data in the payload
160
if (size != sizeof(cmd_pkt.payload)) {
161
SDL_memset(&cmd_pkt.payload[size], 0, sizeof(cmd_pkt.payload) - size);
162
}
163
164
if (SDL_HIDAPI_SendRumbleAndUnlock(device, (Uint8 *)&cmd_pkt, sizeof(cmd_pkt)) != sizeof(cmd_pkt)) {
165
return SDL_SetError("Couldn't send command packet");
166
}
167
168
return true;
169
}
170
171
static bool HIDAPI_DriverShield_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
172
{
173
SDL_DriverShield_Context *ctx = (SDL_DriverShield_Context *)device->context;
174
175
SDL_AssertJoysticksLocked();
176
177
ctx->rumble_report_pending = false;
178
ctx->rumble_update_pending = false;
179
ctx->left_motor_amplitude = 0;
180
ctx->right_motor_amplitude = 0;
181
ctx->last_rumble_time = 0;
182
SDL_zeroa(ctx->last_state);
183
184
// Initialize the joystick capabilities
185
if (device->product_id == USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V103) {
186
joystick->nbuttons = SDL_GAMEPAD_NUM_SHIELD_V103_BUTTONS;
187
joystick->naxes = SDL_GAMEPAD_AXIS_COUNT;
188
joystick->nhats = 1;
189
190
SDL_PrivateJoystickAddTouchpad(joystick, 1);
191
} else {
192
joystick->nbuttons = SDL_GAMEPAD_NUM_SHIELD_V104_BUTTONS;
193
joystick->naxes = SDL_GAMEPAD_AXIS_COUNT;
194
joystick->nhats = 1;
195
}
196
197
// Request battery and charging info
198
ctx->last_battery_query_time = SDL_GetTicks();
199
HIDAPI_DriverShield_SendCommand(device, CMD_CHARGE_STATE, NULL, 0);
200
HIDAPI_DriverShield_SendCommand(device, CMD_BATTERY_STATE, NULL, 0);
201
202
return true;
203
}
204
205
static bool HIDAPI_DriverShield_SendNextRumble(SDL_HIDAPI_Device *device)
206
{
207
SDL_DriverShield_Context *ctx = (SDL_DriverShield_Context *)device->context;
208
Uint8 rumble_data[3];
209
210
if (!ctx->rumble_update_pending) {
211
return true;
212
}
213
214
rumble_data[0] = 0x01; // enable
215
rumble_data[1] = ctx->left_motor_amplitude;
216
rumble_data[2] = ctx->right_motor_amplitude;
217
218
ctx->rumble_update_pending = false;
219
ctx->last_rumble_time = SDL_GetTicks();
220
221
return HIDAPI_DriverShield_SendCommand(device, CMD_RUMBLE, rumble_data, sizeof(rumble_data));
222
}
223
224
static bool HIDAPI_DriverShield_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
225
{
226
if (device->product_id == USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V103) {
227
Uint8 rumble_packet[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
228
229
rumble_packet[2] = (low_frequency_rumble >> 8);
230
rumble_packet[4] = (high_frequency_rumble >> 8);
231
232
if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
233
return SDL_SetError("Couldn't send rumble packet");
234
}
235
return true;
236
237
} else {
238
SDL_DriverShield_Context *ctx = (SDL_DriverShield_Context *)device->context;
239
240
// The rumble motors are quite intense, so tone down the intensity like the official driver does
241
ctx->left_motor_amplitude = low_frequency_rumble >> 11;
242
ctx->right_motor_amplitude = high_frequency_rumble >> 11;
243
ctx->rumble_update_pending = true;
244
245
if (ctx->rumble_report_pending) {
246
// We will service this after the hardware acknowledges the previous request
247
return true;
248
}
249
250
return HIDAPI_DriverShield_SendNextRumble(device);
251
}
252
}
253
254
static bool HIDAPI_DriverShield_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
255
{
256
return SDL_Unsupported();
257
}
258
259
static Uint32 HIDAPI_DriverShield_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
260
{
261
return SDL_JOYSTICK_CAP_RUMBLE;
262
}
263
264
static bool HIDAPI_DriverShield_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
265
{
266
return SDL_Unsupported();
267
}
268
269
static bool HIDAPI_DriverShield_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
270
{
271
const Uint8 *data_bytes = (const Uint8 *)data;
272
273
if (size > 1) {
274
// Single command byte followed by a variable length payload
275
return HIDAPI_DriverShield_SendCommand(device, data_bytes[0], &data_bytes[1], size - 1);
276
} else if (size == 1) {
277
// Single command byte with no payload
278
return HIDAPI_DriverShield_SendCommand(device, data_bytes[0], NULL, 0);
279
} else {
280
return SDL_SetError("Effect data must at least contain a command byte");
281
}
282
}
283
284
static bool HIDAPI_DriverShield_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled)
285
{
286
return SDL_Unsupported();
287
}
288
289
static void HIDAPI_DriverShield_HandleStatePacketV103(SDL_Joystick *joystick, SDL_DriverShield_Context *ctx, Uint8 *data, int size)
290
{
291
Uint64 timestamp = SDL_GetTicksNS();
292
293
if (ctx->last_state[3] != data[3]) {
294
Uint8 hat;
295
296
switch (data[3]) {
297
case 0:
298
hat = SDL_HAT_UP;
299
break;
300
case 1:
301
hat = SDL_HAT_RIGHTUP;
302
break;
303
case 2:
304
hat = SDL_HAT_RIGHT;
305
break;
306
case 3:
307
hat = SDL_HAT_RIGHTDOWN;
308
break;
309
case 4:
310
hat = SDL_HAT_DOWN;
311
break;
312
case 5:
313
hat = SDL_HAT_LEFTDOWN;
314
break;
315
case 6:
316
hat = SDL_HAT_LEFT;
317
break;
318
case 7:
319
hat = SDL_HAT_LEFTUP;
320
break;
321
default:
322
hat = SDL_HAT_CENTERED;
323
break;
324
}
325
SDL_SendJoystickHat(timestamp, joystick, 0, hat);
326
}
327
328
if (ctx->last_state[1] != data[1]) {
329
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[1] & 0x01) != 0));
330
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[1] & 0x02) != 0));
331
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[1] & 0x04) != 0));
332
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[1] & 0x08) != 0));
333
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[1] & 0x10) != 0));
334
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[1] & 0x20) != 0));
335
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[1] & 0x40) != 0));
336
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[1] & 0x80) != 0));
337
}
338
339
if (ctx->last_state[2] != data[2]) {
340
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[2] & 0x02) != 0));
341
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SHIELD_V103_PLUS, ((data[2] & 0x08) != 0));
342
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SHIELD_V103_MINUS, ((data[2] & 0x10) != 0));
343
//SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[2] & 0x20) != 0));
344
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[2] & 0x40) != 0));
345
//SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SHIELD_SHARE, ((data[2] & 0x80) != 0));
346
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[2] & 0x80) != 0));
347
}
348
349
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, SDL_Swap16LE(*(Sint16 *)&data[4]) - 0x8000);
350
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, SDL_Swap16LE(*(Sint16 *)&data[6]) - 0x8000);
351
352
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, SDL_Swap16LE(*(Sint16 *)&data[8]) - 0x8000);
353
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, SDL_Swap16LE(*(Sint16 *)&data[10]) - 0x8000);
354
355
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, SDL_Swap16LE(*(Sint16 *)&data[12]) - 0x8000);
356
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, SDL_Swap16LE(*(Sint16 *)&data[14]) - 0x8000);
357
358
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
359
}
360
361
#undef clamp
362
#define clamp(val, min, max) (((val) > (max)) ? (max) : (((val) < (min)) ? (min) : (val)))
363
364
static void HIDAPI_DriverShield_HandleTouchPacketV103(SDL_Joystick *joystick, SDL_DriverShield_Context *ctx, const Uint8 *data, int size)
365
{
366
bool touchpad_down;
367
float touchpad_x, touchpad_y;
368
Uint64 timestamp = SDL_GetTicksNS();
369
370
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SHIELD_V103_TOUCHPAD, ((data[1] & 0x01) != 0));
371
372
// It's a triangular pad, but just use the center as the usable touch area
373
touchpad_down = ((data[1] & 0x80) == 0);
374
touchpad_x = clamp((float)(data[2] - 0x70) / 0x50, 0.0f, 1.0f);
375
touchpad_y = clamp((float)(data[4] - 0x40) / 0x15, 0.0f, 1.0f);
376
SDL_SendJoystickTouchpad(timestamp, joystick, 0, 0, touchpad_down, touchpad_x, touchpad_y, touchpad_down ? 1.0f : 0.0f);
377
}
378
379
static void HIDAPI_DriverShield_HandleStatePacketV104(SDL_Joystick *joystick, SDL_DriverShield_Context *ctx, Uint8 *data, int size)
380
{
381
Uint64 timestamp = SDL_GetTicksNS();
382
383
if (size < 23) {
384
return;
385
}
386
387
if (ctx->last_state[2] != data[2]) {
388
Uint8 hat;
389
390
switch (data[2]) {
391
case 0:
392
hat = SDL_HAT_UP;
393
break;
394
case 1:
395
hat = SDL_HAT_RIGHTUP;
396
break;
397
case 2:
398
hat = SDL_HAT_RIGHT;
399
break;
400
case 3:
401
hat = SDL_HAT_RIGHTDOWN;
402
break;
403
case 4:
404
hat = SDL_HAT_DOWN;
405
break;
406
case 5:
407
hat = SDL_HAT_LEFTDOWN;
408
break;
409
case 6:
410
hat = SDL_HAT_LEFT;
411
break;
412
case 7:
413
hat = SDL_HAT_LEFTUP;
414
break;
415
default:
416
hat = SDL_HAT_CENTERED;
417
break;
418
}
419
SDL_SendJoystickHat(timestamp, joystick, 0, hat);
420
}
421
422
if (ctx->last_state[3] != data[3]) {
423
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[3] & 0x01) != 0));
424
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[3] & 0x02) != 0));
425
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[3] & 0x04) != 0));
426
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[3] & 0x08) != 0));
427
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[3] & 0x10) != 0));
428
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[3] & 0x20) != 0));
429
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[3] & 0x40) != 0));
430
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[3] & 0x80) != 0));
431
}
432
433
if (ctx->last_state[4] != data[4]) {
434
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[4] & 0x01) != 0));
435
}
436
437
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, SDL_Swap16LE(*(Sint16 *)&data[9]) - 0x8000);
438
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, SDL_Swap16LE(*(Sint16 *)&data[11]) - 0x8000);
439
440
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, SDL_Swap16LE(*(Sint16 *)&data[13]) - 0x8000);
441
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, SDL_Swap16LE(*(Sint16 *)&data[15]) - 0x8000);
442
443
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, SDL_Swap16LE(*(Sint16 *)&data[19]) - 0x8000);
444
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, SDL_Swap16LE(*(Sint16 *)&data[21]) - 0x8000);
445
446
if (ctx->last_state[17] != data[17]) {
447
//SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SHIELD_SHARE, ((data[17] & 0x01) != 0));
448
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[17] & 0x02) != 0));
449
//SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[17] & 0x04) != 0));
450
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[17] & 0x01) != 0));
451
}
452
453
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
454
}
455
456
static void HIDAPI_DriverShield_UpdatePowerInfo(SDL_Joystick *joystick, SDL_DriverShield_Context *ctx)
457
{
458
if (!ctx->has_charging || !ctx->has_battery_level) {
459
return;
460
}
461
462
SDL_PowerState state = ctx->charging ? SDL_POWERSTATE_CHARGING : SDL_POWERSTATE_ON_BATTERY;
463
int percent = ctx->battery_level * 20;
464
SDL_SendJoystickPowerInfo(joystick, state, percent);
465
}
466
467
static bool HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device)
468
{
469
SDL_DriverShield_Context *ctx = (SDL_DriverShield_Context *)device->context;
470
SDL_Joystick *joystick = NULL;
471
Uint8 data[USB_PACKET_LENGTH];
472
int size = 0;
473
ShieldCommandReport_t *cmd_resp_report;
474
475
if (device->num_joysticks > 0) {
476
joystick = SDL_GetJoystickFromID(device->joysticks[0]);
477
} else {
478
return false;
479
}
480
481
while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
482
#ifdef DEBUG_SHIELD_PROTOCOL
483
HIDAPI_DumpPacket("NVIDIA SHIELD packet: size = %d", data, size);
484
#endif
485
486
// Byte 0 is HID report ID
487
switch (data[0]) {
488
case k_ShieldReportIdControllerState:
489
if (!joystick) {
490
break;
491
}
492
if (size == 16) {
493
HIDAPI_DriverShield_HandleStatePacketV103(joystick, ctx, data, size);
494
} else {
495
HIDAPI_DriverShield_HandleStatePacketV104(joystick, ctx, data, size);
496
}
497
break;
498
case k_ShieldReportIdControllerTouch:
499
if (!joystick) {
500
break;
501
}
502
HIDAPI_DriverShield_HandleTouchPacketV103(joystick, ctx, data, size);
503
break;
504
case k_ShieldReportIdCommandResponse:
505
cmd_resp_report = (ShieldCommandReport_t *)data;
506
switch (cmd_resp_report->cmd) {
507
case CMD_RUMBLE:
508
ctx->rumble_report_pending = false;
509
HIDAPI_DriverShield_SendNextRumble(device);
510
break;
511
case CMD_CHARGE_STATE:
512
ctx->has_charging = true;
513
ctx->charging = cmd_resp_report->payload[0];
514
HIDAPI_DriverShield_UpdatePowerInfo(joystick, ctx);
515
break;
516
case CMD_BATTERY_STATE:
517
ctx->has_battery_level = true;
518
ctx->battery_level = cmd_resp_report->payload[2];
519
HIDAPI_DriverShield_UpdatePowerInfo(joystick, ctx);
520
break;
521
}
522
break;
523
}
524
}
525
526
// Ask for battery state again if we're due for an update
527
if (joystick && SDL_GetTicks() >= (ctx->last_battery_query_time + BATTERY_POLL_INTERVAL_MS)) {
528
ctx->last_battery_query_time = SDL_GetTicks();
529
HIDAPI_DriverShield_SendCommand(device, CMD_BATTERY_STATE, NULL, 0);
530
}
531
532
// Retransmit rumble packets if they've lasted longer than the hardware supports
533
if ((ctx->left_motor_amplitude != 0 || ctx->right_motor_amplitude != 0) &&
534
SDL_GetTicks() >= (ctx->last_rumble_time + RUMBLE_REFRESH_INTERVAL_MS)) {
535
ctx->rumble_update_pending = true;
536
HIDAPI_DriverShield_SendNextRumble(device);
537
}
538
539
if (size < 0) {
540
// Read error, device is disconnected
541
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
542
}
543
return (size >= 0);
544
}
545
546
static void HIDAPI_DriverShield_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
547
{
548
}
549
550
static void HIDAPI_DriverShield_FreeDevice(SDL_HIDAPI_Device *device)
551
{
552
}
553
554
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverShield = {
555
SDL_HINT_JOYSTICK_HIDAPI_SHIELD,
556
true,
557
HIDAPI_DriverShield_RegisterHints,
558
HIDAPI_DriverShield_UnregisterHints,
559
HIDAPI_DriverShield_IsEnabled,
560
HIDAPI_DriverShield_IsSupportedDevice,
561
HIDAPI_DriverShield_InitDevice,
562
HIDAPI_DriverShield_GetDevicePlayerIndex,
563
HIDAPI_DriverShield_SetDevicePlayerIndex,
564
HIDAPI_DriverShield_UpdateDevice,
565
HIDAPI_DriverShield_OpenJoystick,
566
HIDAPI_DriverShield_RumbleJoystick,
567
HIDAPI_DriverShield_RumbleJoystickTriggers,
568
HIDAPI_DriverShield_GetJoystickCapabilities,
569
HIDAPI_DriverShield_SetJoystickLED,
570
HIDAPI_DriverShield_SendJoystickEffect,
571
HIDAPI_DriverShield_SetJoystickSensorsEnabled,
572
HIDAPI_DriverShield_CloseJoystick,
573
HIDAPI_DriverShield_FreeDevice,
574
};
575
576
#endif // SDL_JOYSTICK_HIDAPI_SHIELD
577
578
#endif // SDL_JOYSTICK_HIDAPI
579
580