Atlas - SDL_hidapi_shield.c
Home / ext / SDL / src / joystick / hidapi Lines: 1 | Size: 21490 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]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 47enum 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 58typedef 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 67typedef struct 68{ 69 Uint8 report_id; 70 Uint8 cmd; 71 Uint8 seq_num; 72 Uint8 payload[HID_REPORT_SIZE - 3]; 73} ShieldCommandReport_t; 74SDL_COMPILE_TIME_ASSERT(ShieldCommandReport_t, sizeof(ShieldCommandReport_t) == HID_REPORT_SIZE); 75 76typedef 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 95static void HIDAPI_DriverShield_RegisterHints(SDL_HintCallback callback, void *userdata) 96{ 97 SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_SHIELD, callback, userdata); 98} 99 100static void HIDAPI_DriverShield_UnregisterHints(SDL_HintCallback callback, void *userdata) 101{ 102 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_SHIELD, callback, userdata); 103} 104 105static 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 110static 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 115static 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 130static int HIDAPI_DriverShield_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id) 131{ 132 return -1; 133} 134 135static void HIDAPI_DriverShield_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) 136{ 137} 138 139static 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 171static 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 205static 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 224static 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 254static bool HIDAPI_DriverShield_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) 255{ 256 return SDL_Unsupported(); 257} 258 259static Uint32 HIDAPI_DriverShield_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 260{ 261 return SDL_JOYSTICK_CAP_RUMBLE; 262} 263 264static bool HIDAPI_DriverShield_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) 265{ 266 return SDL_Unsupported(); 267} 268 269static 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 284static bool HIDAPI_DriverShield_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled) 285{ 286 return SDL_Unsupported(); 287} 288 289static 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 364static 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 379static 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 456static 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 467static 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 if (!joystick) { 486 continue; 487 } 488 489 // Byte 0 is HID report ID 490 switch (data[0]) { 491 case k_ShieldReportIdControllerState: 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 HIDAPI_DriverShield_HandleTouchPacketV103(joystick, ctx, data, size); 500 break; 501 case k_ShieldReportIdCommandResponse: 502 cmd_resp_report = (ShieldCommandReport_t *)data; 503 switch (cmd_resp_report->cmd) { 504 case CMD_RUMBLE: 505 ctx->rumble_report_pending = false; 506 HIDAPI_DriverShield_SendNextRumble(device); 507 break; 508 case CMD_CHARGE_STATE: 509 ctx->has_charging = true; 510 ctx->charging = cmd_resp_report->payload[0]; 511 HIDAPI_DriverShield_UpdatePowerInfo(joystick, ctx); 512 break; 513 case CMD_BATTERY_STATE: 514 ctx->has_battery_level = true; 515 ctx->battery_level = cmd_resp_report->payload[2]; 516 HIDAPI_DriverShield_UpdatePowerInfo(joystick, ctx); 517 break; 518 } 519 break; 520 } 521 } 522 523 // Ask for battery state again if we're due for an update 524 if (joystick && SDL_GetTicks() >= (ctx->last_battery_query_time + BATTERY_POLL_INTERVAL_MS)) { 525 ctx->last_battery_query_time = SDL_GetTicks(); 526 HIDAPI_DriverShield_SendCommand(device, CMD_BATTERY_STATE, NULL, 0); 527 } 528 529 // Retransmit rumble packets if they've lasted longer than the hardware supports 530 if ((ctx->left_motor_amplitude != 0 || ctx->right_motor_amplitude != 0) && 531 SDL_GetTicks() >= (ctx->last_rumble_time + RUMBLE_REFRESH_INTERVAL_MS)) { 532 ctx->rumble_update_pending = true; 533 HIDAPI_DriverShield_SendNextRumble(device); 534 } 535 536 if (size < 0) { 537 // Read error, device is disconnected 538 HIDAPI_JoystickDisconnected(device, device->joysticks[0]); 539 } 540 return (size >= 0); 541} 542 543static void HIDAPI_DriverShield_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 544{ 545} 546 547static void HIDAPI_DriverShield_FreeDevice(SDL_HIDAPI_Device *device) 548{ 549} 550 551SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverShield = { 552 SDL_HINT_JOYSTICK_HIDAPI_SHIELD, 553 true, 554 HIDAPI_DriverShield_RegisterHints, 555 HIDAPI_DriverShield_UnregisterHints, 556 HIDAPI_DriverShield_IsEnabled, 557 HIDAPI_DriverShield_IsSupportedDevice, 558 HIDAPI_DriverShield_InitDevice, 559 HIDAPI_DriverShield_GetDevicePlayerIndex, 560 HIDAPI_DriverShield_SetDevicePlayerIndex, 561 HIDAPI_DriverShield_UpdateDevice, 562 HIDAPI_DriverShield_OpenJoystick, 563 HIDAPI_DriverShield_RumbleJoystick, 564 HIDAPI_DriverShield_RumbleJoystickTriggers, 565 HIDAPI_DriverShield_GetJoystickCapabilities, 566 HIDAPI_DriverShield_SetJoystickLED, 567 HIDAPI_DriverShield_SendJoystickEffect, 568 HIDAPI_DriverShield_SetJoystickSensorsEnabled, 569 HIDAPI_DriverShield_CloseJoystick, 570 HIDAPI_DriverShield_FreeDevice, 571}; 572 573#endif // SDL_JOYSTICK_HIDAPI_SHIELD 574 575#endif // SDL_JOYSTICK_HIDAPI 576[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.