SDL_hidapi_switch.c (50344B)
1 /* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> 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 /* This driver supports the Nintendo Switch Pro controller. 22 Code and logic contributed by Valve Corporation under the SDL zlib license. 23 */ 24 #include "../../SDL_internal.h" 25 26 #ifdef SDL_JOYSTICK_HIDAPI 27 28 #include "SDL_hints.h" 29 #include "SDL_events.h" 30 #include "SDL_timer.h" 31 #include "SDL_joystick.h" 32 #include "SDL_gamecontroller.h" 33 #include "../../SDL_hints_c.h" 34 #include "../SDL_sysjoystick.h" 35 #include "SDL_hidapijoystick_c.h" 36 #include "SDL_hidapi_rumble.h" 37 38 39 #ifdef SDL_JOYSTICK_HIDAPI_SWITCH 40 41 /* Define this if you want to log all packets from the controller */ 42 /*#define DEBUG_SWITCH_PROTOCOL*/ 43 44 /* Define this to get log output for rumble logic */ 45 /*#define DEBUG_RUMBLE*/ 46 47 /* How often you can write rumble commands to the controller in Bluetooth mode 48 If you send commands more frequently than this, you can turn off the controller. 49 */ 50 #define RUMBLE_WRITE_FREQUENCY_MS 25 51 52 /* How often you have to refresh a long duration rumble to keep the motors running */ 53 #define RUMBLE_REFRESH_FREQUENCY_MS 40 54 55 typedef enum { 56 k_eSwitchInputReportIDs_SubcommandReply = 0x21, 57 k_eSwitchInputReportIDs_FullControllerState = 0x30, 58 k_eSwitchInputReportIDs_SimpleControllerState = 0x3F, 59 k_eSwitchInputReportIDs_CommandAck = 0x81, 60 } ESwitchInputReportIDs; 61 62 typedef enum { 63 k_eSwitchOutputReportIDs_RumbleAndSubcommand = 0x01, 64 k_eSwitchOutputReportIDs_Rumble = 0x10, 65 k_eSwitchOutputReportIDs_Proprietary = 0x80, 66 } ESwitchOutputReportIDs; 67 68 typedef enum { 69 k_eSwitchSubcommandIDs_BluetoothManualPair = 0x01, 70 k_eSwitchSubcommandIDs_RequestDeviceInfo = 0x02, 71 k_eSwitchSubcommandIDs_SetInputReportMode = 0x03, 72 k_eSwitchSubcommandIDs_SetHCIState = 0x06, 73 k_eSwitchSubcommandIDs_SPIFlashRead = 0x10, 74 k_eSwitchSubcommandIDs_SetPlayerLights = 0x30, 75 k_eSwitchSubcommandIDs_SetHomeLight = 0x38, 76 k_eSwitchSubcommandIDs_EnableIMU = 0x40, 77 k_eSwitchSubcommandIDs_SetIMUSensitivity = 0x41, 78 k_eSwitchSubcommandIDs_EnableVibration = 0x48, 79 } ESwitchSubcommandIDs; 80 81 typedef enum { 82 k_eSwitchProprietaryCommandIDs_Handshake = 0x02, 83 k_eSwitchProprietaryCommandIDs_HighSpeed = 0x03, 84 k_eSwitchProprietaryCommandIDs_ForceUSB = 0x04, 85 k_eSwitchProprietaryCommandIDs_ClearUSB = 0x05, 86 k_eSwitchProprietaryCommandIDs_ResetMCU = 0x06, 87 } ESwitchProprietaryCommandIDs; 88 89 typedef enum { 90 k_eSwitchDeviceInfoControllerType_JoyConLeft = 0x1, 91 k_eSwitchDeviceInfoControllerType_JoyConRight = 0x2, 92 k_eSwitchDeviceInfoControllerType_ProController = 0x3, 93 } ESwitchDeviceInfoControllerType; 94 95 #define k_unSwitchOutputPacketDataLength 49 96 #define k_unSwitchMaxOutputPacketLength 64 97 #define k_unSwitchBluetoothPacketLength k_unSwitchOutputPacketDataLength 98 #define k_unSwitchUSBPacketLength k_unSwitchMaxOutputPacketLength 99 100 #define k_unSPIStickCalibrationStartOffset 0x603D 101 #define k_unSPIStickCalibrationEndOffset 0x604E 102 #define k_unSPIStickCalibrationLength (k_unSPIStickCalibrationEndOffset - k_unSPIStickCalibrationStartOffset + 1) 103 104 #pragma pack(1) 105 typedef struct 106 { 107 Uint8 rgucButtons[2]; 108 Uint8 ucStickHat; 109 Uint8 rgucJoystickLeft[2]; 110 Uint8 rgucJoystickRight[2]; 111 } SwitchInputOnlyControllerStatePacket_t; 112 113 typedef struct 114 { 115 Uint8 rgucButtons[2]; 116 Uint8 ucStickHat; 117 Sint16 sJoystickLeft[2]; 118 Sint16 sJoystickRight[2]; 119 } SwitchSimpleStatePacket_t; 120 121 typedef struct 122 { 123 Uint8 ucCounter; 124 Uint8 ucBatteryAndConnection; 125 Uint8 rgucButtons[3]; 126 Uint8 rgucJoystickLeft[3]; 127 Uint8 rgucJoystickRight[3]; 128 Uint8 ucVibrationCode; 129 } SwitchControllerStatePacket_t; 130 131 typedef struct 132 { 133 SwitchControllerStatePacket_t controllerState; 134 135 struct { 136 Sint16 sAccelX; 137 Sint16 sAccelY; 138 Sint16 sAccelZ; 139 140 Sint16 sGyroX; 141 Sint16 sGyroY; 142 Sint16 sGyroZ; 143 } imuState[3]; 144 } SwitchStatePacket_t; 145 146 typedef struct 147 { 148 Uint32 unAddress; 149 Uint8 ucLength; 150 } SwitchSPIOpData_t; 151 152 typedef struct 153 { 154 SwitchControllerStatePacket_t m_controllerState; 155 156 Uint8 ucSubcommandAck; 157 Uint8 ucSubcommandID; 158 159 #define k_unSubcommandDataBytes 35 160 union { 161 Uint8 rgucSubcommandData[k_unSubcommandDataBytes]; 162 163 struct { 164 SwitchSPIOpData_t opData; 165 Uint8 rgucReadData[k_unSubcommandDataBytes - sizeof(SwitchSPIOpData_t)]; 166 } spiReadData; 167 168 struct { 169 Uint8 rgucFirmwareVersion[2]; 170 Uint8 ucDeviceType; 171 Uint8 ucFiller1; 172 Uint8 rgucMACAddress[6]; 173 Uint8 ucFiller2; 174 Uint8 ucColorLocation; 175 } deviceInfo; 176 }; 177 } SwitchSubcommandInputPacket_t; 178 179 typedef struct 180 { 181 Uint8 rgucData[4]; 182 } SwitchRumbleData_t; 183 184 typedef struct 185 { 186 Uint8 ucPacketType; 187 Uint8 ucPacketNumber; 188 SwitchRumbleData_t rumbleData[2]; 189 } SwitchCommonOutputPacket_t; 190 191 typedef struct 192 { 193 SwitchCommonOutputPacket_t commonData; 194 195 Uint8 ucSubcommandID; 196 Uint8 rgucSubcommandData[k_unSwitchOutputPacketDataLength - sizeof(SwitchCommonOutputPacket_t) - 1]; 197 } SwitchSubcommandOutputPacket_t; 198 199 typedef struct 200 { 201 Uint8 ucPacketType; 202 Uint8 ucProprietaryID; 203 204 Uint8 rgucProprietaryData[k_unSwitchOutputPacketDataLength - 1 - 1]; 205 } SwitchProprietaryOutputPacket_t; 206 #pragma pack() 207 208 typedef struct { 209 SDL_HIDAPI_Device *device; 210 SDL_bool m_bInputOnly; 211 SDL_bool m_bHasHomeLED; 212 SDL_bool m_bUsingBluetooth; 213 SDL_bool m_bIsGameCube; 214 SDL_bool m_bUseButtonLabels; 215 Uint8 m_nCommandNumber; 216 SwitchCommonOutputPacket_t m_RumblePacket; 217 Uint8 m_rgucReadBuffer[k_unSwitchMaxOutputPacketLength]; 218 SDL_bool m_bRumbleActive; 219 Uint32 m_unRumbleSent; 220 SDL_bool m_bRumblePending; 221 SDL_bool m_bRumbleZeroPending; 222 Uint32 m_unRumblePending; 223 224 SwitchInputOnlyControllerStatePacket_t m_lastInputOnlyState; 225 SwitchSimpleStatePacket_t m_lastSimpleState; 226 SwitchStatePacket_t m_lastFullState; 227 228 struct StickCalibrationData { 229 struct { 230 Sint16 sCenter; 231 Sint16 sMin; 232 Sint16 sMax; 233 } axis[2]; 234 } m_StickCalData[2]; 235 236 struct StickExtents { 237 struct { 238 Sint16 sMin; 239 Sint16 sMax; 240 } axis[2]; 241 } m_StickExtents[2]; 242 } SDL_DriverSwitch_Context; 243 244 245 static SDL_bool 246 HasHomeLED(int vendor_id, int product_id) 247 { 248 /* The Power A Nintendo Switch Pro controllers don't have a Home LED */ 249 if (vendor_id == 0 && product_id == 0) { 250 return SDL_FALSE; 251 } 252 253 /* HORI Wireless Switch Pad */ 254 if (vendor_id == 0x0f0d && product_id == 0x00f6) { 255 return SDL_FALSE; 256 } 257 258 return SDL_TRUE; 259 } 260 261 static SDL_bool 262 IsGameCubeFormFactor(int vendor_id, int product_id) 263 { 264 static Uint32 gamecube_formfactor[] = { 265 MAKE_VIDPID(0x0e6f, 0x0185), /* PDP Wired Fight Pad Pro for Nintendo Switch */ 266 MAKE_VIDPID(0x20d6, 0xa711), /* Core (Plus) Wired Controller */ 267 }; 268 Uint32 id = MAKE_VIDPID(vendor_id, product_id); 269 int i; 270 271 for (i = 0; i < SDL_arraysize(gamecube_formfactor); ++i) { 272 if (id == gamecube_formfactor[i]) { 273 return SDL_TRUE; 274 } 275 } 276 return SDL_FALSE; 277 } 278 279 static SDL_bool 280 HIDAPI_DriverSwitch_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol) 281 { 282 /* The HORI Wireless Switch Pad enumerates as a HID device when connected via USB 283 with the same VID/PID as when connected over Bluetooth but doesn't actually 284 support communication over USB. The most reliable way to block this without allowing the 285 controller to continually attempt to reconnect is to filter it out by manufactuer/product string. 286 Note that the controller does have a different product string when connected over Bluetooth. 287 */ 288 if (SDL_strcmp( name, "HORI Wireless Switch Pad" ) == 0) { 289 return SDL_FALSE; 290 } 291 return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) ? SDL_TRUE : SDL_FALSE; 292 } 293 294 static const char * 295 HIDAPI_DriverSwitch_GetDeviceName(Uint16 vendor_id, Uint16 product_id) 296 { 297 /* Give a user friendly name for this controller */ 298 return "Nintendo Switch Pro Controller"; 299 } 300 301 static int ReadInput(SDL_DriverSwitch_Context *ctx) 302 { 303 /* Make sure we don't try to read at the same time a write is happening */ 304 if (SDL_AtomicGet(&ctx->device->rumble_pending) > 0) { 305 return 0; 306 } 307 308 return hid_read_timeout(ctx->device->dev, ctx->m_rgucReadBuffer, sizeof(ctx->m_rgucReadBuffer), 0); 309 } 310 311 static int WriteOutput(SDL_DriverSwitch_Context *ctx, const Uint8 *data, int size) 312 { 313 /* Use the rumble thread for general asynchronous writes */ 314 if (SDL_HIDAPI_LockRumble() < 0) { 315 return -1; 316 } 317 return SDL_HIDAPI_SendRumbleAndUnlock(ctx->device, data, size); 318 } 319 320 static SwitchSubcommandInputPacket_t *ReadSubcommandReply(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs expectedID) 321 { 322 /* Average response time for messages is ~30ms */ 323 Uint32 TimeoutMs = 100; 324 Uint32 startTicks = SDL_GetTicks(); 325 326 int nRead = 0; 327 while ((nRead = ReadInput(ctx)) != -1) { 328 if (nRead > 0) { 329 if (ctx->m_rgucReadBuffer[0] == k_eSwitchInputReportIDs_SubcommandReply) { 330 SwitchSubcommandInputPacket_t *reply = (SwitchSubcommandInputPacket_t *)&ctx->m_rgucReadBuffer[1]; 331 if (reply->ucSubcommandID == expectedID && (reply->ucSubcommandAck & 0x80)) { 332 return reply; 333 } 334 } 335 } else { 336 SDL_Delay(1); 337 } 338 339 if (SDL_TICKS_PASSED(SDL_GetTicks(), startTicks + TimeoutMs)) { 340 break; 341 } 342 } 343 return NULL; 344 } 345 346 static SDL_bool ReadProprietaryReply(SDL_DriverSwitch_Context *ctx, ESwitchProprietaryCommandIDs expectedID) 347 { 348 /* Average response time for messages is ~30ms */ 349 Uint32 TimeoutMs = 100; 350 Uint32 startTicks = SDL_GetTicks(); 351 352 int nRead = 0; 353 while ((nRead = ReadInput(ctx)) != -1) { 354 if (nRead > 0) { 355 if (ctx->m_rgucReadBuffer[0] == k_eSwitchInputReportIDs_CommandAck && ctx->m_rgucReadBuffer[1] == expectedID) { 356 return SDL_TRUE; 357 } 358 } else { 359 SDL_Delay(1); 360 } 361 362 if (SDL_TICKS_PASSED(SDL_GetTicks(), startTicks + TimeoutMs)) { 363 break; 364 } 365 } 366 return SDL_FALSE; 367 } 368 369 static void ConstructSubcommand(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs ucCommandID, Uint8 *pBuf, Uint8 ucLen, SwitchSubcommandOutputPacket_t *outPacket) 370 { 371 SDL_memset(outPacket, 0, sizeof(*outPacket)); 372 373 outPacket->commonData.ucPacketType = k_eSwitchOutputReportIDs_RumbleAndSubcommand; 374 outPacket->commonData.ucPacketNumber = ctx->m_nCommandNumber; 375 376 SDL_memcpy(&outPacket->commonData.rumbleData, &ctx->m_RumblePacket.rumbleData, sizeof(ctx->m_RumblePacket.rumbleData)); 377 378 outPacket->ucSubcommandID = ucCommandID; 379 SDL_memcpy(outPacket->rgucSubcommandData, pBuf, ucLen); 380 381 ctx->m_nCommandNumber = (ctx->m_nCommandNumber + 1) & 0xF; 382 } 383 384 static SDL_bool WritePacket(SDL_DriverSwitch_Context *ctx, void *pBuf, Uint8 ucLen) 385 { 386 Uint8 rgucBuf[k_unSwitchMaxOutputPacketLength]; 387 const size_t unWriteSize = ctx->m_bUsingBluetooth ? k_unSwitchBluetoothPacketLength : k_unSwitchUSBPacketLength; 388 389 if (ucLen > k_unSwitchOutputPacketDataLength) { 390 return SDL_FALSE; 391 } 392 393 if (ucLen < unWriteSize) { 394 SDL_memcpy(rgucBuf, pBuf, ucLen); 395 SDL_memset(rgucBuf+ucLen, 0, unWriteSize-ucLen); 396 pBuf = rgucBuf; 397 ucLen = (Uint8)unWriteSize; 398 } 399 return (WriteOutput(ctx, (Uint8 *)pBuf, ucLen) >= 0); 400 } 401 402 static SDL_bool WriteSubcommand(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs ucCommandID, Uint8 *pBuf, Uint8 ucLen, SwitchSubcommandInputPacket_t **ppReply) 403 { 404 int nRetries = 5; 405 SwitchSubcommandInputPacket_t *reply = NULL; 406 407 while (!reply && nRetries--) { 408 SwitchSubcommandOutputPacket_t commandPacket; 409 ConstructSubcommand(ctx, ucCommandID, pBuf, ucLen, &commandPacket); 410 411 if (!WritePacket(ctx, &commandPacket, sizeof(commandPacket))) { 412 continue; 413 } 414 415 reply = ReadSubcommandReply(ctx, ucCommandID); 416 } 417 418 if (ppReply) { 419 *ppReply = reply; 420 } 421 return reply != NULL; 422 } 423 424 static SDL_bool WriteProprietary(SDL_DriverSwitch_Context *ctx, ESwitchProprietaryCommandIDs ucCommand, Uint8 *pBuf, Uint8 ucLen, SDL_bool waitForReply) 425 { 426 int nRetries = 5; 427 428 while (nRetries--) { 429 SwitchProprietaryOutputPacket_t packet; 430 431 if ((!pBuf && ucLen > 0) || ucLen > sizeof(packet.rgucProprietaryData)) { 432 return SDL_FALSE; 433 } 434 435 packet.ucPacketType = k_eSwitchOutputReportIDs_Proprietary; 436 packet.ucProprietaryID = ucCommand; 437 if (pBuf) { 438 SDL_memcpy(packet.rgucProprietaryData, pBuf, ucLen); 439 } 440 441 if (!WritePacket(ctx, &packet, sizeof(packet))) { 442 continue; 443 } 444 445 if (!waitForReply || ReadProprietaryReply(ctx, ucCommand)) { 446 return SDL_TRUE; 447 } 448 } 449 return SDL_FALSE; 450 } 451 452 static void SetNeutralRumble(SwitchRumbleData_t *pRumble) 453 { 454 pRumble->rgucData[0] = 0x00; 455 pRumble->rgucData[1] = 0x01; 456 pRumble->rgucData[2] = 0x40; 457 pRumble->rgucData[3] = 0x40; 458 } 459 460 static void EncodeRumble(SwitchRumbleData_t *pRumble, Uint16 usHighFreq, Uint8 ucHighFreqAmp, Uint8 ucLowFreq, Uint16 usLowFreqAmp) 461 { 462 if (ucHighFreqAmp > 0 || usLowFreqAmp > 0) { 463 // High-band frequency and low-band amplitude are actually nine-bits each so they 464 // take a bit from the high-band amplitude and low-band frequency bytes respectively 465 pRumble->rgucData[0] = usHighFreq & 0xFF; 466 pRumble->rgucData[1] = ucHighFreqAmp | ((usHighFreq >> 8) & 0x01); 467 468 pRumble->rgucData[2] = ucLowFreq | ((usLowFreqAmp >> 8) & 0x80); 469 pRumble->rgucData[3] = usLowFreqAmp & 0xFF; 470 471 #ifdef DEBUG_RUMBLE 472 SDL_Log("Freq: %.2X %.2X %.2X, Amp: %.2X %.2X %.2X\n", 473 usHighFreq & 0xFF, ((usHighFreq >> 8) & 0x01), ucLowFreq, 474 ucHighFreqAmp, ((usLowFreqAmp >> 8) & 0x80), usLowFreqAmp & 0xFF); 475 #endif 476 } else { 477 SetNeutralRumble(pRumble); 478 } 479 } 480 481 static SDL_bool WriteRumble(SDL_DriverSwitch_Context *ctx) 482 { 483 /* Write into m_RumblePacket rather than a temporary buffer to allow the current rumble state 484 * to be retained for subsequent rumble or subcommand packets sent to the controller 485 */ 486 ctx->m_RumblePacket.ucPacketType = k_eSwitchOutputReportIDs_Rumble; 487 ctx->m_RumblePacket.ucPacketNumber = ctx->m_nCommandNumber; 488 ctx->m_nCommandNumber = (ctx->m_nCommandNumber + 1) & 0xF; 489 490 /* Refresh the rumble state periodically */ 491 ctx->m_unRumbleSent = SDL_GetTicks(); 492 493 return WritePacket(ctx, (Uint8 *)&ctx->m_RumblePacket, sizeof(ctx->m_RumblePacket)); 494 } 495 496 static SDL_bool BTrySetupUSB(SDL_DriverSwitch_Context *ctx) 497 { 498 /* We have to send a connection handshake to the controller when communicating over USB 499 * before we're able to send it other commands. Luckily this command is not supported 500 * over Bluetooth, so we can use the controller's lack of response as a way to 501 * determine if the connection is over USB or Bluetooth 502 */ 503 if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Handshake, NULL, 0, SDL_TRUE)) { 504 return SDL_FALSE; 505 } 506 if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_HighSpeed, NULL, 0, SDL_TRUE)) { 507 /* The 8BitDo M30 and SF30 Pro don't respond to this command, but otherwise work correctly */ 508 /*return SDL_FALSE;*/ 509 } 510 if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Handshake, NULL, 0, SDL_TRUE)) { 511 return SDL_FALSE; 512 } 513 return SDL_TRUE; 514 } 515 516 static SDL_bool SetVibrationEnabled(SDL_DriverSwitch_Context *ctx, Uint8 enabled) 517 { 518 return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_EnableVibration, &enabled, sizeof(enabled), NULL); 519 520 } 521 static SDL_bool SetInputMode(SDL_DriverSwitch_Context *ctx, Uint8 input_mode) 522 { 523 return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetInputReportMode, &input_mode, 1, NULL); 524 } 525 526 static SDL_bool SetHomeLED(SDL_DriverSwitch_Context *ctx, Uint8 brightness) 527 { 528 Uint8 ucLedIntensity = 0; 529 Uint8 rgucBuffer[4]; 530 531 if (brightness > 0) { 532 if (brightness < 65) { 533 ucLedIntensity = (brightness + 5) / 10; 534 } else { 535 ucLedIntensity = (Uint8)SDL_ceilf(0xF * SDL_powf((float)brightness / 100.f, 2.13f)); 536 } 537 } 538 539 rgucBuffer[0] = (0x0 << 4) | 0x1; /* 0 mini cycles (besides first), cycle duration 8ms */ 540 rgucBuffer[1] = ((ucLedIntensity & 0xF) << 4) | 0x0; /* LED start intensity (0x0-0xF), 0 cycles (LED stays on at start intensity after first cycle) */ 541 rgucBuffer[2] = ((ucLedIntensity & 0xF) << 4) | 0x0; /* First cycle LED intensity, 0x0 intensity for second cycle */ 542 rgucBuffer[3] = (0x0 << 4) | 0x0; /* 8ms fade transition to first cycle, 8ms first cycle LED duration */ 543 544 return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetHomeLight, rgucBuffer, sizeof(rgucBuffer), NULL); 545 } 546 547 static SDL_bool SetSlotLED(SDL_DriverSwitch_Context *ctx, Uint8 slot) 548 { 549 Uint8 led_data = (1 << slot); 550 return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetPlayerLights, &led_data, sizeof(led_data), NULL); 551 } 552 553 static SDL_bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx, Uint8 input_mode) 554 { 555 Uint8 *pStickCal; 556 size_t stick, axis; 557 SwitchSubcommandInputPacket_t *reply = NULL; 558 559 /* Read Calibration Info */ 560 SwitchSPIOpData_t readParams; 561 readParams.unAddress = k_unSPIStickCalibrationStartOffset; 562 readParams.ucLength = k_unSPIStickCalibrationLength; 563 564 if (!WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SPIFlashRead, (uint8_t *)&readParams, sizeof(readParams), &reply)) { 565 return SDL_FALSE; 566 } 567 568 /* Stick calibration values are 12-bits each and are packed by bit 569 * For whatever reason the fields are in a different order for each stick 570 * Left: X-Max, Y-Max, X-Center, Y-Center, X-Min, Y-Min 571 * Right: X-Center, Y-Center, X-Min, Y-Min, X-Max, Y-Max 572 */ 573 pStickCal = reply->spiReadData.rgucReadData; 574 575 /* Left stick */ 576 ctx->m_StickCalData[0].axis[0].sMax = ((pStickCal[1] << 8) & 0xF00) | pStickCal[0]; /* X Axis max above center */ 577 ctx->m_StickCalData[0].axis[1].sMax = (pStickCal[2] << 4) | (pStickCal[1] >> 4); /* Y Axis max above center */ 578 ctx->m_StickCalData[0].axis[0].sCenter = ((pStickCal[4] << 8) & 0xF00) | pStickCal[3]; /* X Axis center */ 579 ctx->m_StickCalData[0].axis[1].sCenter = (pStickCal[5] << 4) | (pStickCal[4] >> 4); /* Y Axis center */ 580 ctx->m_StickCalData[0].axis[0].sMin = ((pStickCal[7] << 8) & 0xF00) | pStickCal[6]; /* X Axis min below center */ 581 ctx->m_StickCalData[0].axis[1].sMin = (pStickCal[8] << 4) | (pStickCal[7] >> 4); /* Y Axis min below center */ 582 583 /* Right stick */ 584 ctx->m_StickCalData[1].axis[0].sCenter = ((pStickCal[10] << 8) & 0xF00) | pStickCal[9]; /* X Axis center */ 585 ctx->m_StickCalData[1].axis[1].sCenter = (pStickCal[11] << 4) | (pStickCal[10] >> 4); /* Y Axis center */ 586 ctx->m_StickCalData[1].axis[0].sMin = ((pStickCal[13] << 8) & 0xF00) | pStickCal[12]; /* X Axis min below center */ 587 ctx->m_StickCalData[1].axis[1].sMin = (pStickCal[14] << 4) | (pStickCal[13] >> 4); /* Y Axis min below center */ 588 ctx->m_StickCalData[1].axis[0].sMax = ((pStickCal[16] << 8) & 0xF00) | pStickCal[15]; /* X Axis max above center */ 589 ctx->m_StickCalData[1].axis[1].sMax = (pStickCal[17] << 4) | (pStickCal[16] >> 4); /* Y Axis max above center */ 590 591 /* Filter out any values that were uninitialized (0xFFF) in the SPI read */ 592 for (stick = 0; stick < 2; ++stick) { 593 for (axis = 0; axis < 2; ++axis) { 594 if (ctx->m_StickCalData[stick].axis[axis].sCenter == 0xFFF) { 595 ctx->m_StickCalData[stick].axis[axis].sCenter = 0; 596 } 597 if (ctx->m_StickCalData[stick].axis[axis].sMax == 0xFFF) { 598 ctx->m_StickCalData[stick].axis[axis].sMax = 0; 599 } 600 if (ctx->m_StickCalData[stick].axis[axis].sMin == 0xFFF) { 601 ctx->m_StickCalData[stick].axis[axis].sMin = 0; 602 } 603 } 604 } 605 606 if (input_mode == k_eSwitchInputReportIDs_SimpleControllerState) { 607 for (stick = 0; stick < 2; ++stick) { 608 for(axis = 0; axis < 2; ++axis) { 609 ctx->m_StickExtents[stick].axis[axis].sMin = (Sint16)(SDL_MIN_SINT16 * 0.5f); 610 ctx->m_StickExtents[stick].axis[axis].sMax = (Sint16)(SDL_MAX_SINT16 * 0.5f); 611 } 612 } 613 } else { 614 for (stick = 0; stick < 2; ++stick) { 615 for(axis = 0; axis < 2; ++axis) { 616 ctx->m_StickExtents[stick].axis[axis].sMin = -(Sint16)(ctx->m_StickCalData[stick].axis[axis].sMin * 0.7f); 617 ctx->m_StickExtents[stick].axis[axis].sMax = (Sint16)(ctx->m_StickCalData[stick].axis[axis].sMax * 0.7f); 618 } 619 } 620 } 621 return SDL_TRUE; 622 } 623 624 static float fsel(float fComparand, float fValGE, float fLT) 625 { 626 return fComparand >= 0 ? fValGE : fLT; 627 } 628 629 static float RemapVal(float val, float A, float B, float C, float D) 630 { 631 if (A == B) { 632 return fsel(val - B , D , C); 633 } 634 return C + (D - C) * (val - A) / (B - A); 635 } 636 637 static Sint16 ApplyStickCalibrationCentered(SDL_DriverSwitch_Context *ctx, int nStick, int nAxis, Sint16 sRawValue, Sint16 sCenter) 638 { 639 sRawValue -= sCenter; 640 641 if (sRawValue > ctx->m_StickExtents[nStick].axis[nAxis].sMax) { 642 ctx->m_StickExtents[nStick].axis[nAxis].sMax = sRawValue; 643 } 644 if (sRawValue < ctx->m_StickExtents[nStick].axis[nAxis].sMin) { 645 ctx->m_StickExtents[nStick].axis[nAxis].sMin = sRawValue; 646 } 647 648 if (sRawValue > 0) { 649 return (Sint16)(RemapVal(sRawValue, 0, ctx->m_StickExtents[nStick].axis[nAxis].sMax, 0, SDL_MAX_SINT16)); 650 } else { 651 return (Sint16)(RemapVal(sRawValue, ctx->m_StickExtents[nStick].axis[nAxis].sMin, 0, SDL_MIN_SINT16, 0)); 652 } 653 } 654 655 static Sint16 ApplyStickCalibration(SDL_DriverSwitch_Context *ctx, int nStick, int nAxis, Sint16 sRawValue) 656 { 657 return ApplyStickCalibrationCentered(ctx, nStick, nAxis, sRawValue, ctx->m_StickCalData[nStick].axis[nAxis].sCenter); 658 } 659 660 static void SDLCALL SDL_GameControllerButtonReportingHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 661 { 662 SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)userdata; 663 ctx->m_bUseButtonLabels = SDL_GetStringBoolean(hint, SDL_TRUE); 664 } 665 666 static Uint8 RemapButton(SDL_DriverSwitch_Context *ctx, Uint8 button) 667 { 668 if (!ctx->m_bUseButtonLabels) { 669 /* Use button positions */ 670 if (ctx->m_bIsGameCube) { 671 switch (button) { 672 case SDL_CONTROLLER_BUTTON_B: 673 return SDL_CONTROLLER_BUTTON_X; 674 case SDL_CONTROLLER_BUTTON_X: 675 return SDL_CONTROLLER_BUTTON_B; 676 default: 677 break; 678 } 679 } else { 680 switch (button) { 681 case SDL_CONTROLLER_BUTTON_A: 682 return SDL_CONTROLLER_BUTTON_B; 683 case SDL_CONTROLLER_BUTTON_B: 684 return SDL_CONTROLLER_BUTTON_A; 685 case SDL_CONTROLLER_BUTTON_X: 686 return SDL_CONTROLLER_BUTTON_Y; 687 case SDL_CONTROLLER_BUTTON_Y: 688 return SDL_CONTROLLER_BUTTON_X; 689 default: 690 break; 691 } 692 } 693 } 694 return button; 695 } 696 697 static SDL_bool 698 HIDAPI_DriverSwitch_InitDevice(SDL_HIDAPI_Device *device) 699 { 700 return HIDAPI_JoystickConnected(device, NULL); 701 } 702 703 static int 704 HIDAPI_DriverSwitch_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id) 705 { 706 return -1; 707 } 708 709 static void 710 HIDAPI_DriverSwitch_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) 711 { 712 } 713 714 static SDL_bool 715 HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 716 { 717 SDL_DriverSwitch_Context *ctx; 718 Uint8 input_mode; 719 720 ctx = (SDL_DriverSwitch_Context *)SDL_calloc(1, sizeof(*ctx)); 721 if (!ctx) { 722 SDL_OutOfMemory(); 723 goto error; 724 } 725 ctx->device = device; 726 device->context = ctx; 727 728 device->dev = hid_open_path(device->path, 0); 729 if (!device->dev) { 730 SDL_SetError("Couldn't open %s", device->path); 731 goto error; 732 } 733 734 /* Find out whether or not we can send output reports */ 735 ctx->m_bInputOnly = SDL_IsJoystickNintendoSwitchProInputOnly(device->vendor_id, device->product_id); 736 if (!ctx->m_bInputOnly) { 737 ctx->m_bHasHomeLED = HasHomeLED(device->vendor_id, device->product_id); 738 739 /* Initialize rumble data */ 740 SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]); 741 SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]); 742 743 /* Try setting up USB mode, and if that fails we're using Bluetooth */ 744 if (!BTrySetupUSB(ctx)) { 745 ctx->m_bUsingBluetooth = SDL_TRUE; 746 } 747 748 /* Determine the desired input mode (needed before loading stick calibration) */ 749 if (ctx->m_bUsingBluetooth) { 750 input_mode = k_eSwitchInputReportIDs_SimpleControllerState; 751 } else { 752 input_mode = k_eSwitchInputReportIDs_FullControllerState; 753 } 754 755 /* The official Nintendo Switch Pro Controller supports FullControllerState over bluetooth 756 * just fine. We really should use that, or else the epowerlevel code in 757 * HandleFullControllerState is completely pointless. We need full state if we want battery 758 * level and we only care about battery level over bluetooth anyway. 759 */ 760 if (device->vendor_id == USB_VENDOR_NINTENDO && 761 device->product_id == USB_PRODUCT_NINTENDO_SWITCH_PRO) { 762 input_mode = k_eSwitchInputReportIDs_FullControllerState; 763 } 764 765 if (!LoadStickCalibration(ctx, input_mode)) { 766 SDL_SetError("Couldn't load stick calibration"); 767 goto error; 768 } 769 770 if (!SetVibrationEnabled(ctx, 1)) { 771 SDL_SetError("Couldn't enable vibration"); 772 goto error; 773 } 774 775 /* Set desired input mode */ 776 if (!SetInputMode(ctx, input_mode)) { 777 SDL_SetError("Couldn't set input mode"); 778 goto error; 779 } 780 781 /* Start sending USB reports */ 782 if (!ctx->m_bUsingBluetooth) { 783 /* ForceUSB doesn't generate an ACK, so don't wait for a reply */ 784 if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_ForceUSB, NULL, 0, SDL_FALSE)) { 785 SDL_SetError("Couldn't start USB reports"); 786 goto error; 787 } 788 } 789 790 /* Set the LED state */ 791 if (ctx->m_bHasHomeLED) { 792 SetHomeLED(ctx, 100); 793 } 794 SetSlotLED(ctx, (joystick->instance_id % 4)); 795 } 796 797 if (IsGameCubeFormFactor(device->vendor_id, device->product_id)) { 798 /* This is a controller shaped like a GameCube controller, with a large central A button */ 799 ctx->m_bIsGameCube = SDL_TRUE; 800 } 801 802 SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, 803 SDL_GameControllerButtonReportingHintChanged, ctx); 804 805 /* Initialize the joystick capabilities */ 806 joystick->nbuttons = 16; 807 joystick->naxes = SDL_CONTROLLER_AXIS_MAX; 808 joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED; 809 810 return SDL_TRUE; 811 812 error: 813 if (device->dev) { 814 hid_close(device->dev); 815 device->dev = NULL; 816 } 817 if (device->context) { 818 SDL_free(device->context); 819 device->context = NULL; 820 } 821 return SDL_FALSE; 822 } 823 824 static int 825 HIDAPI_DriverSwitch_ActuallyRumbleJoystick(SDL_DriverSwitch_Context *ctx, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 826 { 827 /* Experimentally determined rumble values. These will only matter on some controllers as tested ones 828 * seem to disregard these and just use any non-zero rumble values as a binary flag for constant rumble 829 * 830 * More information about these values can be found here: 831 * https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md 832 */ 833 const Uint16 k_usHighFreq = 0x0074; 834 const Uint8 k_ucHighFreqAmp = 0xBE; 835 const Uint8 k_ucLowFreq = 0x3D; 836 const Uint16 k_usLowFreqAmp = 0x806F; 837 838 if (low_frequency_rumble) { 839 EncodeRumble(&ctx->m_RumblePacket.rumbleData[0], k_usHighFreq, k_ucHighFreqAmp, k_ucLowFreq, k_usLowFreqAmp); 840 } else { 841 SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]); 842 } 843 844 if (high_frequency_rumble) { 845 EncodeRumble(&ctx->m_RumblePacket.rumbleData[1], k_usHighFreq, k_ucHighFreqAmp, k_ucLowFreq, k_usLowFreqAmp); 846 } else { 847 SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]); 848 } 849 850 ctx->m_bRumbleActive = (low_frequency_rumble || high_frequency_rumble) ? SDL_TRUE : SDL_FALSE; 851 852 if (!WriteRumble(ctx)) { 853 SDL_SetError("Couldn't send rumble packet"); 854 return -1; 855 } 856 return 0; 857 } 858 859 static int 860 HIDAPI_DriverSwitch_SendPendingRumble(SDL_DriverSwitch_Context *ctx) 861 { 862 if ((SDL_GetTicks() - ctx->m_unRumbleSent) < RUMBLE_WRITE_FREQUENCY_MS) { 863 return 0; 864 } 865 866 if (ctx->m_bRumblePending) { 867 Uint16 low_frequency_rumble = (Uint16)(ctx->m_unRumblePending >> 16); 868 Uint16 high_frequency_rumble = (Uint16)ctx->m_unRumblePending; 869 870 #ifdef DEBUG_RUMBLE 871 SDL_Log("Sent pending rumble %d/%d\n", low_frequency_rumble, high_frequency_rumble); 872 #endif 873 ctx->m_bRumblePending = SDL_FALSE; 874 ctx->m_unRumblePending = 0; 875 876 return HIDAPI_DriverSwitch_ActuallyRumbleJoystick(ctx, low_frequency_rumble, high_frequency_rumble); 877 } 878 879 if (ctx->m_bRumbleZeroPending) { 880 ctx->m_bRumbleZeroPending = SDL_FALSE; 881 882 #ifdef DEBUG_RUMBLE 883 SDL_Log("Sent pending zero rumble\n"); 884 #endif 885 return HIDAPI_DriverSwitch_ActuallyRumbleJoystick(ctx, 0, 0); 886 } 887 888 return 0; 889 } 890 891 static int 892 HIDAPI_DriverSwitch_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 893 { 894 SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context; 895 896 if (ctx->m_bRumblePending) { 897 if (HIDAPI_DriverSwitch_SendPendingRumble(ctx) < 0) { 898 return -1; 899 } 900 } 901 902 if (ctx->m_bUsingBluetooth && (SDL_GetTicks() - ctx->m_unRumbleSent) < RUMBLE_WRITE_FREQUENCY_MS) { 903 if (low_frequency_rumble || high_frequency_rumble) { 904 Uint32 unRumblePending = ((Uint32)low_frequency_rumble << 16) | high_frequency_rumble; 905 906 /* Keep the highest rumble intensity in the given interval */ 907 if (unRumblePending > ctx->m_unRumblePending) { 908 ctx->m_unRumblePending = unRumblePending; 909 } 910 ctx->m_bRumblePending = SDL_TRUE; 911 ctx->m_bRumbleZeroPending = SDL_FALSE; 912 } else { 913 /* When rumble is complete, turn it off */ 914 ctx->m_bRumbleZeroPending = SDL_TRUE; 915 } 916 return 0; 917 } 918 919 #ifdef DEBUG_RUMBLE 920 SDL_Log("Sent rumble %d/%d\n", low_frequency_rumble, high_frequency_rumble); 921 #endif 922 923 return HIDAPI_DriverSwitch_ActuallyRumbleJoystick(ctx, low_frequency_rumble, high_frequency_rumble); 924 } 925 926 static int 927 HIDAPI_DriverSwitch_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) 928 { 929 return SDL_Unsupported(); 930 } 931 932 static SDL_bool 933 HIDAPI_DriverSwitch_HasJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 934 { 935 /* Doesn't have an RGB LED, so don't return true here */ 936 return SDL_FALSE; 937 } 938 939 static int 940 HIDAPI_DriverSwitch_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) 941 { 942 return SDL_Unsupported(); 943 } 944 945 static int 946 HIDAPI_DriverSwitch_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled) 947 { 948 return SDL_Unsupported(); 949 } 950 951 static void HandleInputOnlyControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchInputOnlyControllerStatePacket_t *packet) 952 { 953 Sint16 axis; 954 955 if (packet->rgucButtons[0] != ctx->m_lastInputOnlyState.rgucButtons[0]) { 956 Uint8 data = packet->rgucButtons[0]; 957 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_A), (data & 0x04) ? SDL_PRESSED : SDL_RELEASED); 958 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_B), (data & 0x02) ? SDL_PRESSED : SDL_RELEASED); 959 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_X), (data & 0x08) ? SDL_PRESSED : SDL_RELEASED); 960 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_Y), (data & 0x01) ? SDL_PRESSED : SDL_RELEASED); 961 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED); 962 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED); 963 964 axis = (data & 0x40) ? 32767 : -32768; 965 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis); 966 967 axis = (data & 0x80) ? 32767 : -32768; 968 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis); 969 } 970 971 if (packet->rgucButtons[1] != ctx->m_lastInputOnlyState.rgucButtons[1]) { 972 Uint8 data = packet->rgucButtons[1]; 973 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED); 974 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED); 975 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED); 976 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED); 977 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED); 978 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED); 979 } 980 981 if (packet->ucStickHat != ctx->m_lastInputOnlyState.ucStickHat) { 982 SDL_bool dpad_up = SDL_FALSE; 983 SDL_bool dpad_down = SDL_FALSE; 984 SDL_bool dpad_left = SDL_FALSE; 985 SDL_bool dpad_right = SDL_FALSE; 986 987 switch (packet->ucStickHat) { 988 case 0: 989 dpad_up = SDL_TRUE; 990 break; 991 case 1: 992 dpad_up = SDL_TRUE; 993 dpad_right = SDL_TRUE; 994 break; 995 case 2: 996 dpad_right = SDL_TRUE; 997 break; 998 case 3: 999 dpad_right = SDL_TRUE; 1000 dpad_down = SDL_TRUE; 1001 break; 1002 case 4: 1003 dpad_down = SDL_TRUE; 1004 break; 1005 case 5: 1006 dpad_left = SDL_TRUE; 1007 dpad_down = SDL_TRUE; 1008 break; 1009 case 6: 1010 dpad_left = SDL_TRUE; 1011 break; 1012 case 7: 1013 dpad_up = SDL_TRUE; 1014 dpad_left = SDL_TRUE; 1015 break; 1016 default: 1017 break; 1018 } 1019 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down); 1020 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up); 1021 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right); 1022 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left); 1023 } 1024 1025 if (packet->rgucJoystickLeft[0] != ctx->m_lastInputOnlyState.rgucJoystickLeft[0]) { 1026 axis = (Sint16)(RemapVal(packet->rgucJoystickLeft[0], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16)); 1027 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis); 1028 } 1029 1030 if (packet->rgucJoystickLeft[1] != ctx->m_lastInputOnlyState.rgucJoystickLeft[1]) { 1031 axis = (Sint16)(RemapVal(packet->rgucJoystickLeft[1], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16)); 1032 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis); 1033 } 1034 1035 if (packet->rgucJoystickRight[0] != ctx->m_lastInputOnlyState.rgucJoystickRight[0]) { 1036 axis = (Sint16)(RemapVal(packet->rgucJoystickRight[0], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16)); 1037 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis); 1038 } 1039 1040 if (packet->rgucJoystickRight[1] != ctx->m_lastInputOnlyState.rgucJoystickRight[1]) { 1041 axis = (Sint16)(RemapVal(packet->rgucJoystickRight[1], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16)); 1042 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis); 1043 } 1044 1045 ctx->m_lastInputOnlyState = *packet; 1046 } 1047 1048 static void HandleSimpleControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchSimpleStatePacket_t *packet) 1049 { 1050 /* 0x8000 is the neutral value for all joystick axes */ 1051 const Uint16 usJoystickCenter = 0x8000; 1052 Sint16 axis; 1053 1054 if (packet->rgucButtons[0] != ctx->m_lastSimpleState.rgucButtons[0]) { 1055 Uint8 data = packet->rgucButtons[0]; 1056 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_A), (data & 0x02) ? SDL_PRESSED : SDL_RELEASED); 1057 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_B), (data & 0x01) ? SDL_PRESSED : SDL_RELEASED); 1058 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_X), (data & 0x08) ? SDL_PRESSED : SDL_RELEASED); 1059 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_Y), (data & 0x04) ? SDL_PRESSED : SDL_RELEASED); 1060 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED); 1061 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED); 1062 1063 axis = (data & 0x40) ? 32767 : -32768; 1064 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis); 1065 1066 axis = (data & 0x80) ? 32767 : -32768; 1067 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis); 1068 } 1069 1070 if (packet->rgucButtons[1] != ctx->m_lastSimpleState.rgucButtons[1]) { 1071 Uint8 data = packet->rgucButtons[1]; 1072 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED); 1073 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED); 1074 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED); 1075 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED); 1076 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED); 1077 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED); 1078 } 1079 1080 if (packet->ucStickHat != ctx->m_lastSimpleState.ucStickHat) { 1081 SDL_bool dpad_up = SDL_FALSE; 1082 SDL_bool dpad_down = SDL_FALSE; 1083 SDL_bool dpad_left = SDL_FALSE; 1084 SDL_bool dpad_right = SDL_FALSE; 1085 1086 switch (packet->ucStickHat) { 1087 case 0: 1088 dpad_up = SDL_TRUE; 1089 break; 1090 case 1: 1091 dpad_up = SDL_TRUE; 1092 dpad_right = SDL_TRUE; 1093 break; 1094 case 2: 1095 dpad_right = SDL_TRUE; 1096 break; 1097 case 3: 1098 dpad_right = SDL_TRUE; 1099 dpad_down = SDL_TRUE; 1100 break; 1101 case 4: 1102 dpad_down = SDL_TRUE; 1103 break; 1104 case 5: 1105 dpad_left = SDL_TRUE; 1106 dpad_down = SDL_TRUE; 1107 break; 1108 case 6: 1109 dpad_left = SDL_TRUE; 1110 break; 1111 case 7: 1112 dpad_up = SDL_TRUE; 1113 dpad_left = SDL_TRUE; 1114 break; 1115 default: 1116 break; 1117 } 1118 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down); 1119 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up); 1120 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right); 1121 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left); 1122 } 1123 1124 axis = ApplyStickCalibrationCentered(ctx, 0, 0, packet->sJoystickLeft[0], (Sint16)usJoystickCenter); 1125 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis); 1126 1127 axis = ApplyStickCalibrationCentered(ctx, 0, 1, packet->sJoystickLeft[1], (Sint16)usJoystickCenter); 1128 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis); 1129 1130 axis = ApplyStickCalibrationCentered(ctx, 1, 0, packet->sJoystickRight[0], (Sint16)usJoystickCenter); 1131 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis); 1132 1133 axis = ApplyStickCalibrationCentered(ctx, 1, 1, packet->sJoystickRight[1], (Sint16)usJoystickCenter); 1134 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis); 1135 1136 ctx->m_lastSimpleState = *packet; 1137 } 1138 1139 static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchStatePacket_t *packet) 1140 { 1141 Sint16 axis; 1142 1143 if (packet->controllerState.rgucButtons[0] != ctx->m_lastFullState.controllerState.rgucButtons[0]) { 1144 Uint8 data = packet->controllerState.rgucButtons[0]; 1145 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_A), (data & 0x08) ? SDL_PRESSED : SDL_RELEASED); 1146 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_B), (data & 0x04) ? SDL_PRESSED : SDL_RELEASED); 1147 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_X), (data & 0x02) ? SDL_PRESSED : SDL_RELEASED); 1148 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_Y), (data & 0x01) ? SDL_PRESSED : SDL_RELEASED); 1149 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED); 1150 axis = (data & 0x80) ? 32767 : -32768; 1151 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis); 1152 } 1153 1154 if (packet->controllerState.rgucButtons[1] != ctx->m_lastFullState.controllerState.rgucButtons[1]) { 1155 Uint8 data = packet->controllerState.rgucButtons[1]; 1156 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED); 1157 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED); 1158 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED); 1159 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED); 1160 1161 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED); 1162 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED); 1163 } 1164 1165 if (packet->controllerState.rgucButtons[2] != ctx->m_lastFullState.controllerState.rgucButtons[2]) { 1166 Uint8 data = packet->controllerState.rgucButtons[2]; 1167 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED); 1168 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED); 1169 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED); 1170 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED); 1171 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED); 1172 axis = (data & 0x80) ? 32767 : -32768; 1173 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis); 1174 } 1175 1176 axis = packet->controllerState.rgucJoystickLeft[0] | ((packet->controllerState.rgucJoystickLeft[1] & 0xF) << 8); 1177 axis = ApplyStickCalibration(ctx, 0, 0, axis); 1178 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis); 1179 1180 axis = ((packet->controllerState.rgucJoystickLeft[1] & 0xF0) >> 4) | (packet->controllerState.rgucJoystickLeft[2] << 4); 1181 axis = ApplyStickCalibration(ctx, 0, 1, axis); 1182 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, ~axis); 1183 1184 axis = packet->controllerState.rgucJoystickRight[0] | ((packet->controllerState.rgucJoystickRight[1] & 0xF) << 8); 1185 axis = ApplyStickCalibration(ctx, 1, 0, axis); 1186 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis); 1187 1188 axis = ((packet->controllerState.rgucJoystickRight[1] & 0xF0) >> 4) | (packet->controllerState.rgucJoystickRight[2] << 4); 1189 axis = ApplyStickCalibration(ctx, 1, 1, axis); 1190 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, ~axis); 1191 1192 /* High nibble of battery/connection byte is battery level, low nibble is connection status 1193 * LSB of connection nibble is USB/Switch connection status 1194 */ 1195 if (packet->controllerState.ucBatteryAndConnection & 0x1) { 1196 joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED; 1197 } else { 1198 /* LSB of the battery nibble is used to report charging. 1199 * The battery level is reported from 0(empty)-8(full) 1200 */ 1201 int level = (packet->controllerState.ucBatteryAndConnection & 0xE0) >> 4; 1202 if (level == 0) { 1203 joystick->epowerlevel = SDL_JOYSTICK_POWER_EMPTY; 1204 } else if (level <= 2) { 1205 joystick->epowerlevel = SDL_JOYSTICK_POWER_LOW; 1206 } else if (level <= 6) { 1207 joystick->epowerlevel = SDL_JOYSTICK_POWER_MEDIUM; 1208 } else { 1209 joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL; 1210 } 1211 } 1212 1213 ctx->m_lastFullState = *packet; 1214 } 1215 1216 static SDL_bool 1217 HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device) 1218 { 1219 SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context; 1220 SDL_Joystick *joystick = NULL; 1221 int size; 1222 1223 if (device->num_joysticks > 0) { 1224 joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); 1225 } 1226 if (!joystick) { 1227 return SDL_FALSE; 1228 } 1229 1230 while ((size = ReadInput(ctx)) > 0) { 1231 #ifdef DEBUG_SWITCH_PROTOCOL 1232 HIDAPI_DumpPacket("Nintendo Switch packet: size = %d", ctx->m_rgucReadBuffer, size); 1233 #endif 1234 if (ctx->m_bInputOnly) { 1235 HandleInputOnlyControllerState(joystick, ctx, (SwitchInputOnlyControllerStatePacket_t *)&ctx->m_rgucReadBuffer[0]); 1236 } else { 1237 switch (ctx->m_rgucReadBuffer[0]) { 1238 case k_eSwitchInputReportIDs_SimpleControllerState: 1239 HandleSimpleControllerState(joystick, ctx, (SwitchSimpleStatePacket_t *)&ctx->m_rgucReadBuffer[1]); 1240 break; 1241 case k_eSwitchInputReportIDs_FullControllerState: 1242 HandleFullControllerState(joystick, ctx, (SwitchStatePacket_t *)&ctx->m_rgucReadBuffer[1]); 1243 break; 1244 default: 1245 break; 1246 } 1247 } 1248 } 1249 1250 if (ctx->m_bRumblePending || ctx->m_bRumbleZeroPending) { 1251 HIDAPI_DriverSwitch_SendPendingRumble(ctx); 1252 } else if (ctx->m_bRumbleActive && 1253 SDL_TICKS_PASSED(SDL_GetTicks(), ctx->m_unRumbleSent + RUMBLE_REFRESH_FREQUENCY_MS)) { 1254 #ifdef DEBUG_RUMBLE 1255 SDL_Log("Sent continuing rumble\n"); 1256 #endif 1257 WriteRumble(ctx); 1258 } 1259 1260 if (size < 0) { 1261 /* Read error, device is disconnected */ 1262 HIDAPI_JoystickDisconnected(device, joystick->instance_id); 1263 } 1264 return (size >= 0); 1265 } 1266 1267 static void 1268 HIDAPI_DriverSwitch_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 1269 { 1270 SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context; 1271 1272 if (!ctx->m_bInputOnly) { 1273 /* Restore simple input mode for other applications */ 1274 SetInputMode(ctx, k_eSwitchInputReportIDs_SimpleControllerState); 1275 } 1276 1277 SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, 1278 SDL_GameControllerButtonReportingHintChanged, ctx); 1279 1280 hid_close(device->dev); 1281 device->dev = NULL; 1282 1283 SDL_free(device->context); 1284 device->context = NULL; 1285 } 1286 1287 static void 1288 HIDAPI_DriverSwitch_FreeDevice(SDL_HIDAPI_Device *device) 1289 { 1290 } 1291 1292 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch = 1293 { 1294 SDL_HINT_JOYSTICK_HIDAPI_SWITCH, 1295 SDL_TRUE, 1296 HIDAPI_DriverSwitch_IsSupportedDevice, 1297 HIDAPI_DriverSwitch_GetDeviceName, 1298 HIDAPI_DriverSwitch_InitDevice, 1299 HIDAPI_DriverSwitch_GetDevicePlayerIndex, 1300 HIDAPI_DriverSwitch_SetDevicePlayerIndex, 1301 HIDAPI_DriverSwitch_UpdateDevice, 1302 HIDAPI_DriverSwitch_OpenJoystick, 1303 HIDAPI_DriverSwitch_RumbleJoystick, 1304 HIDAPI_DriverSwitch_RumbleJoystickTriggers, 1305 HIDAPI_DriverSwitch_HasJoystickLED, 1306 HIDAPI_DriverSwitch_SetJoystickLED, 1307 HIDAPI_DriverSwitch_SetJoystickSensorsEnabled, 1308 HIDAPI_DriverSwitch_CloseJoystick, 1309 HIDAPI_DriverSwitch_FreeDevice, 1310 }; 1311 1312 #endif /* SDL_JOYSTICK_HIDAPI_SWITCH */ 1313 1314 #endif /* SDL_JOYSTICK_HIDAPI */ 1315 1316 /* vi: set ts=4 sw=4 expandtab: */