1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2021 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 /* The initialization sequence doesn't appear to work correctly on Windows unless
48 the reads and writes are on the same thread.
49
50 ... and now I can't reproduce this, so I'm leaving it in, but disabled for now.
51 */
52 /*#define SWITCH_SYNCHRONOUS_WRITES*/
53
54 /* How often you can write rumble commands to the controller.
55 If you send commands more frequently than this, you can turn off the controller
56 in Bluetooth mode, or the motors can miss the command in USB mode.
57 */
58 #define RUMBLE_WRITE_FREQUENCY_MS 30
59
60 /* How often you have to refresh a long duration rumble to keep the motors running */
61 #define RUMBLE_REFRESH_FREQUENCY_MS 50
62
63 #define SWITCH_GYRO_SCALE 14.2842f
64 #define SWITCH_ACCEL_SCALE 4096.f
65
66 typedef enum {
67 k_eSwitchInputReportIDs_SubcommandReply = 0x21,
68 k_eSwitchInputReportIDs_FullControllerState = 0x30,
69 k_eSwitchInputReportIDs_SimpleControllerState = 0x3F,
70 k_eSwitchInputReportIDs_CommandAck = 0x81,
71 } ESwitchInputReportIDs;
72
73 typedef enum {
74 k_eSwitchOutputReportIDs_RumbleAndSubcommand = 0x01,
75 k_eSwitchOutputReportIDs_Rumble = 0x10,
76 k_eSwitchOutputReportIDs_Proprietary = 0x80,
77 } ESwitchOutputReportIDs;
78
79 typedef enum {
80 k_eSwitchSubcommandIDs_BluetoothManualPair = 0x01,
81 k_eSwitchSubcommandIDs_RequestDeviceInfo = 0x02,
82 k_eSwitchSubcommandIDs_SetInputReportMode = 0x03,
83 k_eSwitchSubcommandIDs_SetHCIState = 0x06,
84 k_eSwitchSubcommandIDs_SPIFlashRead = 0x10,
85 k_eSwitchSubcommandIDs_SetPlayerLights = 0x30,
86 k_eSwitchSubcommandIDs_SetHomeLight = 0x38,
87 k_eSwitchSubcommandIDs_EnableIMU = 0x40,
88 k_eSwitchSubcommandIDs_SetIMUSensitivity = 0x41,
89 k_eSwitchSubcommandIDs_EnableVibration = 0x48,
90 } ESwitchSubcommandIDs;
91
92 typedef enum {
93 k_eSwitchProprietaryCommandIDs_Status = 0x01,
94 k_eSwitchProprietaryCommandIDs_Handshake = 0x02,
95 k_eSwitchProprietaryCommandIDs_HighSpeed = 0x03,
96 k_eSwitchProprietaryCommandIDs_ForceUSB = 0x04,
97 k_eSwitchProprietaryCommandIDs_ClearUSB = 0x05,
98 k_eSwitchProprietaryCommandIDs_ResetMCU = 0x06,
99 } ESwitchProprietaryCommandIDs;
100
101 typedef enum {
102 k_eSwitchDeviceInfoControllerType_Unknown = 0x0,
103 k_eSwitchDeviceInfoControllerType_JoyConLeft = 0x1,
104 k_eSwitchDeviceInfoControllerType_JoyConRight = 0x2,
105 k_eSwitchDeviceInfoControllerType_ProController = 0x3,
106 } ESwitchDeviceInfoControllerType;
107
108 #define k_unSwitchOutputPacketDataLength 49
109 #define k_unSwitchMaxOutputPacketLength 64
110 #define k_unSwitchBluetoothPacketLength k_unSwitchOutputPacketDataLength
111 #define k_unSwitchUSBPacketLength k_unSwitchMaxOutputPacketLength
112
113 #define k_unSPIStickCalibrationStartOffset 0x603D
114 #define k_unSPIStickCalibrationEndOffset 0x604E
115 #define k_unSPIStickCalibrationLength (k_unSPIStickCalibrationEndOffset - k_unSPIStickCalibrationStartOffset + 1)
116
117 #pragma pack(1)
118 typedef struct
119 {
120 Uint8 rgucButtons[2];
121 Uint8 ucStickHat;
122 Uint8 rgucJoystickLeft[2];
123 Uint8 rgucJoystickRight[2];
124 } SwitchInputOnlyControllerStatePacket_t;
125
126 typedef struct
127 {
128 Uint8 rgucButtons[2];
129 Uint8 ucStickHat;
130 Sint16 sJoystickLeft[2];
131 Sint16 sJoystickRight[2];
132 } SwitchSimpleStatePacket_t;
133
134 typedef struct
135 {
136 Uint8 ucCounter;
137 Uint8 ucBatteryAndConnection;
138 Uint8 rgucButtons[3];
139 Uint8 rgucJoystickLeft[3];
140 Uint8 rgucJoystickRight[3];
141 Uint8 ucVibrationCode;
142 } SwitchControllerStatePacket_t;
143
144 typedef struct
145 {
146 SwitchControllerStatePacket_t controllerState;
147
148 struct {
149 Sint16 sAccelX;
150 Sint16 sAccelY;
151 Sint16 sAccelZ;
152
153 Sint16 sGyroX;
154 Sint16 sGyroY;
155 Sint16 sGyroZ;
156 } imuState[3];
157 } SwitchStatePacket_t;
158
159 typedef struct
160 {
161 Uint32 unAddress;
162 Uint8 ucLength;
163 } SwitchSPIOpData_t;
164
165 typedef struct
166 {
167 SwitchControllerStatePacket_t m_controllerState;
168
169 Uint8 ucSubcommandAck;
170 Uint8 ucSubcommandID;
171
172 #define k_unSubcommandDataBytes 35
173 union {
174 Uint8 rgucSubcommandData[k_unSubcommandDataBytes];
175
176 struct {
177 SwitchSPIOpData_t opData;
178 Uint8 rgucReadData[k_unSubcommandDataBytes - sizeof(SwitchSPIOpData_t)];
179 } spiReadData;
180
181 struct {
182 Uint8 rgucFirmwareVersion[2];
183 Uint8 ucDeviceType;
184 Uint8 ucFiller1;
185 Uint8 rgucMACAddress[6];
186 Uint8 ucFiller2;
187 Uint8 ucColorLocation;
188 } deviceInfo;
189 };
190 } SwitchSubcommandInputPacket_t;
191
192 typedef struct
193 {
194 Uint8 ucPacketType;
195 Uint8 ucCommandID;
196 Uint8 ucFiller;
197
198 Uint8 ucDeviceType;
199 Uint8 rgucMACAddress[6];
200 } SwitchProprietaryStatusPacket_t;
201
202 typedef struct
203 {
204 Uint8 rgucData[4];
205 } SwitchRumbleData_t;
206
207 typedef struct
208 {
209 Uint8 ucPacketType;
210 Uint8 ucPacketNumber;
211 SwitchRumbleData_t rumbleData[2];
212 } SwitchCommonOutputPacket_t;
213
214 typedef struct
215 {
216 SwitchCommonOutputPacket_t commonData;
217
218 Uint8 ucSubcommandID;
219 Uint8 rgucSubcommandData[k_unSwitchOutputPacketDataLength - sizeof(SwitchCommonOutputPacket_t) - 1];
220 } SwitchSubcommandOutputPacket_t;
221
222 typedef struct
223 {
224 Uint8 ucPacketType;
225 Uint8 ucProprietaryID;
226
227 Uint8 rgucProprietaryData[k_unSwitchOutputPacketDataLength - 1 - 1];
228 } SwitchProprietaryOutputPacket_t;
229 #pragma pack()
230
231 typedef struct {
232 SDL_HIDAPI_Device *device;
233 SDL_bool m_bInputOnly;
234 SDL_bool m_bHasHomeLED;
235 SDL_bool m_bUsingBluetooth;
236 SDL_bool m_bIsGameCube;
237 SDL_bool m_bUseButtonLabels;
238 ESwitchDeviceInfoControllerType m_eControllerType;
239 Uint8 m_rgucMACAddress[6];
240 Uint8 m_nCommandNumber;
241 SwitchCommonOutputPacket_t m_RumblePacket;
242 Uint8 m_rgucReadBuffer[k_unSwitchMaxOutputPacketLength];
243 SDL_bool m_bRumbleActive;
244 Uint32 m_unRumbleSent;
245 SDL_bool m_bRumblePending;
246 SDL_bool m_bRumbleZeroPending;
247 Uint32 m_unRumblePending;
248 SDL_bool m_bHasSensors;
249 SDL_bool m_bReportSensors;
250
251 SwitchInputOnlyControllerStatePacket_t m_lastInputOnlyState;
252 SwitchSimpleStatePacket_t m_lastSimpleState;
253 SwitchStatePacket_t m_lastFullState;
254
255 struct StickCalibrationData {
256 struct {
257 Sint16 sCenter;
258 Sint16 sMin;
259 Sint16 sMax;
260 } axis[2];
261 } m_StickCalData[2];
262
263 struct StickExtents {
264 struct {
265 Sint16 sMin;
266 Sint16 sMax;
267 } axis[2];
268 } m_StickExtents[2];
269 } SDL_DriverSwitch_Context;
270
271
272 static SDL_bool
HasHomeLED(int vendor_id,int product_id)273 HasHomeLED(int vendor_id, int product_id)
274 {
275 /* The Power A Nintendo Switch Pro controllers don't have a Home LED */
276 if (vendor_id == 0 && product_id == 0) {
277 return SDL_FALSE;
278 }
279
280 /* HORI Wireless Switch Pad */
281 if (vendor_id == 0x0f0d && product_id == 0x00f6) {
282 return SDL_FALSE;
283 }
284
285 return SDL_TRUE;
286 }
287
288 static SDL_bool
IsGameCubeFormFactor(int vendor_id,int product_id)289 IsGameCubeFormFactor(int vendor_id, int product_id)
290 {
291 static Uint32 gamecube_formfactor[] = {
292 MAKE_VIDPID(0x0e6f, 0x0185), /* PDP Wired Fight Pad Pro for Nintendo Switch */
293 MAKE_VIDPID(0x20d6, 0xa711), /* Core (Plus) Wired Controller */
294 };
295 Uint32 id = MAKE_VIDPID(vendor_id, product_id);
296 int i;
297
298 for (i = 0; i < SDL_arraysize(gamecube_formfactor); ++i) {
299 if (id == gamecube_formfactor[i]) {
300 return SDL_TRUE;
301 }
302 }
303 return SDL_FALSE;
304 }
305
306 static SDL_bool
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)307 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)
308 {
309 /* The HORI Wireless Switch Pad enumerates as a HID device when connected via USB
310 with the same VID/PID as when connected over Bluetooth but doesn't actually
311 support communication over USB. The most reliable way to block this without allowing the
312 controller to continually attempt to reconnect is to filter it out by manufactuer/product string.
313 Note that the controller does have a different product string when connected over Bluetooth.
314 */
315 if (SDL_strcmp(name, "HORI Wireless Switch Pad") == 0) {
316 return SDL_FALSE;
317 }
318 return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) ? SDL_TRUE : SDL_FALSE;
319 }
320
321 static const char *
HIDAPI_DriverSwitch_GetDeviceName(Uint16 vendor_id,Uint16 product_id)322 HIDAPI_DriverSwitch_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
323 {
324 /* Give a user friendly name for this controller */
325 if (vendor_id == USB_VENDOR_NINTENDO) {
326 if (product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP) {
327 return "Nintendo Switch Joy-Con Grip";
328 }
329
330 if (product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_LEFT) {
331 return "Nintendo Switch Joy-Con Left";
332 }
333
334 if (product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_RIGHT) {
335 return "Nintendo Switch Joy-Con Right";
336 }
337 }
338
339 return "Nintendo Switch Pro Controller";
340 }
341
ReadInput(SDL_DriverSwitch_Context * ctx)342 static int ReadInput(SDL_DriverSwitch_Context *ctx)
343 {
344 /* Make sure we don't try to read at the same time a write is happening */
345 if (SDL_AtomicGet(&ctx->device->rumble_pending) > 0) {
346 return 0;
347 }
348
349 return SDL_hid_read_timeout(ctx->device->dev, ctx->m_rgucReadBuffer, sizeof(ctx->m_rgucReadBuffer), 0);
350 }
351
WriteOutput(SDL_DriverSwitch_Context * ctx,const Uint8 * data,int size)352 static int WriteOutput(SDL_DriverSwitch_Context *ctx, const Uint8 *data, int size)
353 {
354 #ifdef SWITCH_SYNCHRONOUS_WRITES
355 return SDL_hid_write(ctx->device->dev, data, size);
356 #else
357 /* Use the rumble thread for general asynchronous writes */
358 if (SDL_HIDAPI_LockRumble() < 0) {
359 return -1;
360 }
361 return SDL_HIDAPI_SendRumbleAndUnlock(ctx->device, data, size);
362 #endif /* SWITCH_SYNCHRONOUS_WRITES */
363 }
364
ReadSubcommandReply(SDL_DriverSwitch_Context * ctx,ESwitchSubcommandIDs expectedID)365 static SwitchSubcommandInputPacket_t *ReadSubcommandReply(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs expectedID)
366 {
367 /* Average response time for messages is ~30ms */
368 Uint32 TimeoutMs = 100;
369 Uint32 startTicks = SDL_GetTicks();
370
371 int nRead = 0;
372 while ((nRead = ReadInput(ctx)) != -1) {
373 if (nRead > 0) {
374 if (ctx->m_rgucReadBuffer[0] == k_eSwitchInputReportIDs_SubcommandReply) {
375 SwitchSubcommandInputPacket_t *reply = (SwitchSubcommandInputPacket_t *)&ctx->m_rgucReadBuffer[1];
376 if (reply->ucSubcommandID == expectedID && (reply->ucSubcommandAck & 0x80)) {
377 return reply;
378 }
379 }
380 } else {
381 SDL_Delay(1);
382 }
383
384 if (SDL_TICKS_PASSED(SDL_GetTicks(), startTicks + TimeoutMs)) {
385 break;
386 }
387 }
388 return NULL;
389 }
390
ReadProprietaryReply(SDL_DriverSwitch_Context * ctx,ESwitchProprietaryCommandIDs expectedID)391 static SDL_bool ReadProprietaryReply(SDL_DriverSwitch_Context *ctx, ESwitchProprietaryCommandIDs expectedID)
392 {
393 /* Average response time for messages is ~30ms */
394 Uint32 TimeoutMs = 100;
395 Uint32 startTicks = SDL_GetTicks();
396
397 int nRead = 0;
398 while ((nRead = ReadInput(ctx)) != -1) {
399 if (nRead > 0) {
400 if (ctx->m_rgucReadBuffer[0] == k_eSwitchInputReportIDs_CommandAck && ctx->m_rgucReadBuffer[1] == expectedID) {
401 return SDL_TRUE;
402 }
403 } else {
404 SDL_Delay(1);
405 }
406
407 if (SDL_TICKS_PASSED(SDL_GetTicks(), startTicks + TimeoutMs)) {
408 break;
409 }
410 }
411 return SDL_FALSE;
412 }
413
ConstructSubcommand(SDL_DriverSwitch_Context * ctx,ESwitchSubcommandIDs ucCommandID,Uint8 * pBuf,Uint8 ucLen,SwitchSubcommandOutputPacket_t * outPacket)414 static void ConstructSubcommand(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs ucCommandID, Uint8 *pBuf, Uint8 ucLen, SwitchSubcommandOutputPacket_t *outPacket)
415 {
416 SDL_memset(outPacket, 0, sizeof(*outPacket));
417
418 outPacket->commonData.ucPacketType = k_eSwitchOutputReportIDs_RumbleAndSubcommand;
419 outPacket->commonData.ucPacketNumber = ctx->m_nCommandNumber;
420
421 SDL_memcpy(outPacket->commonData.rumbleData, ctx->m_RumblePacket.rumbleData, sizeof(ctx->m_RumblePacket.rumbleData));
422
423 outPacket->ucSubcommandID = ucCommandID;
424 SDL_memcpy(outPacket->rgucSubcommandData, pBuf, ucLen);
425
426 ctx->m_nCommandNumber = (ctx->m_nCommandNumber + 1) & 0xF;
427 }
428
WritePacket(SDL_DriverSwitch_Context * ctx,void * pBuf,Uint8 ucLen)429 static SDL_bool WritePacket(SDL_DriverSwitch_Context *ctx, void *pBuf, Uint8 ucLen)
430 {
431 Uint8 rgucBuf[k_unSwitchMaxOutputPacketLength];
432 const size_t unWriteSize = ctx->m_bUsingBluetooth ? k_unSwitchBluetoothPacketLength : k_unSwitchUSBPacketLength;
433
434 if (ucLen > k_unSwitchOutputPacketDataLength) {
435 return SDL_FALSE;
436 }
437
438 if (ucLen < unWriteSize) {
439 SDL_memcpy(rgucBuf, pBuf, ucLen);
440 SDL_memset(rgucBuf+ucLen, 0, unWriteSize-ucLen);
441 pBuf = rgucBuf;
442 ucLen = (Uint8)unWriteSize;
443 }
444 return (WriteOutput(ctx, (Uint8 *)pBuf, ucLen) >= 0);
445 }
446
WriteSubcommand(SDL_DriverSwitch_Context * ctx,ESwitchSubcommandIDs ucCommandID,Uint8 * pBuf,Uint8 ucLen,SwitchSubcommandInputPacket_t ** ppReply)447 static SDL_bool WriteSubcommand(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs ucCommandID, Uint8 *pBuf, Uint8 ucLen, SwitchSubcommandInputPacket_t **ppReply)
448 {
449 int nRetries = 5;
450 SwitchSubcommandInputPacket_t *reply = NULL;
451
452 while (!reply && nRetries--) {
453 SwitchSubcommandOutputPacket_t commandPacket;
454 ConstructSubcommand(ctx, ucCommandID, pBuf, ucLen, &commandPacket);
455
456 if (!WritePacket(ctx, &commandPacket, sizeof(commandPacket))) {
457 continue;
458 }
459
460 reply = ReadSubcommandReply(ctx, ucCommandID);
461 }
462
463 if (ppReply) {
464 *ppReply = reply;
465 }
466 return reply != NULL;
467 }
468
WriteProprietary(SDL_DriverSwitch_Context * ctx,ESwitchProprietaryCommandIDs ucCommand,Uint8 * pBuf,Uint8 ucLen,SDL_bool waitForReply)469 static SDL_bool WriteProprietary(SDL_DriverSwitch_Context *ctx, ESwitchProprietaryCommandIDs ucCommand, Uint8 *pBuf, Uint8 ucLen, SDL_bool waitForReply)
470 {
471 int nRetries = 5;
472
473 while (nRetries--) {
474 SwitchProprietaryOutputPacket_t packet;
475
476 if ((!pBuf && ucLen > 0) || ucLen > sizeof(packet.rgucProprietaryData)) {
477 return SDL_FALSE;
478 }
479
480 SDL_zero(packet);
481 packet.ucPacketType = k_eSwitchOutputReportIDs_Proprietary;
482 packet.ucProprietaryID = ucCommand;
483 if (pBuf) {
484 SDL_memcpy(packet.rgucProprietaryData, pBuf, ucLen);
485 }
486
487 if (!WritePacket(ctx, &packet, sizeof(packet))) {
488 continue;
489 }
490
491 if (!waitForReply || ReadProprietaryReply(ctx, ucCommand)) {
492 return SDL_TRUE;
493 }
494 }
495 return SDL_FALSE;
496 }
497
EncodeRumbleHighAmplitude(Uint16 amplitude)498 static Uint8 EncodeRumbleHighAmplitude(Uint16 amplitude) {
499 /* More information about these values can be found here:
500 * https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md
501 */
502 Uint16 hfa[101][2] = { {0, 0x0},{514, 0x2},{775, 0x4},{921, 0x6},{1096, 0x8},{1303, 0x0a},{1550, 0x0c},
503 {1843, 0x0e},{2192, 0x10},{2606, 0x12},{3100, 0x14},{3686, 0x16},{4383, 0x18},{5213, 0x1a},
504 {6199, 0x1c},{7372, 0x1e},{7698, 0x20},{8039, 0x22},{8395, 0x24},{8767, 0x26},{9155, 0x28},
505 {9560, 0x2a},{9984, 0x2c},{10426, 0x2e},{10887, 0x30},{11369, 0x32},{11873, 0x34},{12398, 0x36},
506 {12947, 0x38},{13520, 0x3a},{14119, 0x3c},{14744, 0x3e},{15067, 0x40},{15397, 0x42},{15734, 0x44},
507 {16079, 0x46},{16431, 0x48},{16790, 0x4a},{17158, 0x4c},{17534, 0x4e},{17918, 0x50},{18310, 0x52},
508 {18711, 0x54},{19121, 0x56},{19540, 0x58},{19967, 0x5a},{20405, 0x5c},{20851, 0x5e},{21308, 0x60},
509 {21775, 0x62},{22251, 0x64},{22739, 0x66},{23236, 0x68},{23745, 0x6a},{24265, 0x6c},{24797, 0x6e},
510 {25340, 0x70},{25894, 0x72},{26462, 0x74},{27041, 0x76},{27633, 0x78},{28238, 0x7a},{28856, 0x7c},
511 {29488, 0x7e},{30134, 0x80},{30794, 0x82},{31468, 0x84},{32157, 0x86},{32861, 0x88},{33581, 0x8a},
512 {34316, 0x8c},{35068, 0x8e},{35836, 0x90},{36620, 0x92},{37422, 0x94},{38242, 0x96},{39079, 0x98},
513 {39935, 0x9a},{40809, 0x9c},{41703, 0x9e},{42616, 0xa0},{43549, 0xa2},{44503, 0xa4},{45477, 0xa6},
514 {46473, 0xa8},{47491, 0xaa},{48531, 0xac},{49593, 0xae},{50679, 0xb0},{51789, 0xb2},{52923, 0xb4},
515 {54082, 0xb6},{55266, 0xb8},{56476, 0xba},{57713, 0xbc},{58977, 0xbe},{60268, 0xc0},{61588, 0xc2},
516 {62936, 0xc4},{64315, 0xc6},{65535, 0xc8} };
517 int index = 0;
518 for ( ; index < 101; index++) {
519 if (amplitude <= hfa[index][0]) {
520 return (Uint8)hfa[index][1];
521 }
522 }
523 return (Uint8)hfa[100][1];
524 }
525
EncodeRumbleLowAmplitude(Uint16 amplitude)526 static Uint16 EncodeRumbleLowAmplitude(Uint16 amplitude) {
527 /* More information about these values can be found here:
528 * https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md
529 */
530 Uint16 lfa[101][2] = { {0, 0x0040},{514, 0x8040},{775, 0x0041},{921, 0x8041},{1096, 0x0042},
531 {1303, 0x8042},{1550, 0x0043},{1843, 0x8043},{2192, 0x0044},{2606, 0x8044},{3100, 0x0045},
532 {3686, 0x8045},{4383, 0x0046},{5213, 0x8046},{6199, 0x0047},{7372, 0x8047},{7698, 0x0048},
533 {8039, 0x8048},{8395, 0x0049},{8767, 0x8049},{9155, 0x004a},{9560, 0x804a},{9984, 0x004b},
534 {10426, 0x804b},{10887, 0x004c},{11369, 0x804c},{11873, 0x004d},{12398, 0x804d},{12947, 0x004e},
535 {13520, 0x804e},{14119, 0x004f},{14744, 0x804f},{15067, 0x0050},{15397, 0x8050},{15734, 0x0051},
536 {16079, 0x8051},{16431, 0x0052},{16790, 0x8052},{17158, 0x0053},{17534, 0x8053},{17918, 0x0054},
537 {18310, 0x8054},{18711, 0x0055},{19121, 0x8055},{19540, 0x0056},{19967, 0x8056},{20405, 0x0057},
538 {20851, 0x8057},{21308, 0x0058},{21775, 0x8058},{22251, 0x0059},{22739, 0x8059},{23236, 0x005a},
539 {23745, 0x805a},{24265, 0x005b},{24797, 0x805b},{25340, 0x005c},{25894, 0x805c},{26462, 0x005d},
540 {27041, 0x805d},{27633, 0x005e},{28238, 0x805e},{28856, 0x005f},{29488, 0x805f},{30134, 0x0060},
541 {30794, 0x8060},{31468, 0x0061},{32157, 0x8061},{32861, 0x0062},{33581, 0x8062},{34316, 0x0063},
542 {35068, 0x8063},{35836, 0x0064},{36620, 0x8064},{37422, 0x0065},{38242, 0x8065},{39079, 0x0066},
543 {39935, 0x8066},{40809, 0x0067},{41703, 0x8067},{42616, 0x0068},{43549, 0x8068},{44503, 0x0069},
544 {45477, 0x8069},{46473, 0x006a},{47491, 0x806a},{48531, 0x006b},{49593, 0x806b},{50679, 0x006c},
545 {51789, 0x806c},{52923, 0x006d},{54082, 0x806d},{55266, 0x006e},{56476, 0x806e},{57713, 0x006f},
546 {58977, 0x806f},{60268, 0x0070},{61588, 0x8070},{62936, 0x0071},{64315, 0x8071},{65535, 0x0072} };
547 int index = 0;
548 for (; index < 101; index++) {
549 if (amplitude <= lfa[index][0]) {
550 return lfa[index][1];
551 }
552 }
553 return lfa[100][1];
554 }
555
SetNeutralRumble(SwitchRumbleData_t * pRumble)556 static void SetNeutralRumble(SwitchRumbleData_t *pRumble)
557 {
558 pRumble->rgucData[0] = 0x00;
559 pRumble->rgucData[1] = 0x01;
560 pRumble->rgucData[2] = 0x40;
561 pRumble->rgucData[3] = 0x40;
562 }
563
EncodeRumble(SwitchRumbleData_t * pRumble,Uint16 usHighFreq,Uint8 ucHighFreqAmp,Uint8 ucLowFreq,Uint16 usLowFreqAmp)564 static void EncodeRumble(SwitchRumbleData_t *pRumble, Uint16 usHighFreq, Uint8 ucHighFreqAmp, Uint8 ucLowFreq, Uint16 usLowFreqAmp)
565 {
566 if (ucHighFreqAmp > 0 || usLowFreqAmp > 0) {
567 // High-band frequency and low-band amplitude are actually nine-bits each so they
568 // take a bit from the high-band amplitude and low-band frequency bytes respectively
569 pRumble->rgucData[0] = usHighFreq & 0xFF;
570 pRumble->rgucData[1] = ucHighFreqAmp | ((usHighFreq >> 8) & 0x01);
571
572 pRumble->rgucData[2] = ucLowFreq | ((usLowFreqAmp >> 8) & 0x80);
573 pRumble->rgucData[3] = usLowFreqAmp & 0xFF;
574
575 #ifdef DEBUG_RUMBLE
576 SDL_Log("Freq: %.2X %.2X %.2X, Amp: %.2X %.2X %.2X\n",
577 usHighFreq & 0xFF, ((usHighFreq >> 8) & 0x01), ucLowFreq,
578 ucHighFreqAmp, ((usLowFreqAmp >> 8) & 0x80), usLowFreqAmp & 0xFF);
579 #endif
580 } else {
581 SetNeutralRumble(pRumble);
582 }
583 }
584
WriteRumble(SDL_DriverSwitch_Context * ctx)585 static SDL_bool WriteRumble(SDL_DriverSwitch_Context *ctx)
586 {
587 /* Write into m_RumblePacket rather than a temporary buffer to allow the current rumble state
588 * to be retained for subsequent rumble or subcommand packets sent to the controller
589 */
590 ctx->m_RumblePacket.ucPacketType = k_eSwitchOutputReportIDs_Rumble;
591 ctx->m_RumblePacket.ucPacketNumber = ctx->m_nCommandNumber;
592 ctx->m_nCommandNumber = (ctx->m_nCommandNumber + 1) & 0xF;
593
594 /* Refresh the rumble state periodically */
595 ctx->m_unRumbleSent = SDL_GetTicks();
596
597 return WritePacket(ctx, (Uint8 *)&ctx->m_RumblePacket, sizeof(ctx->m_RumblePacket));
598 }
599
BReadDeviceInfo(SDL_DriverSwitch_Context * ctx)600 static SDL_bool BReadDeviceInfo(SDL_DriverSwitch_Context *ctx)
601 {
602 SwitchSubcommandInputPacket_t *reply = NULL;
603
604 ctx->m_bUsingBluetooth = SDL_FALSE;
605
606 if (WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Status, NULL, 0, SDL_TRUE)) {
607 SwitchProprietaryStatusPacket_t *status = (SwitchProprietaryStatusPacket_t *)&ctx->m_rgucReadBuffer[0];
608 size_t i;
609
610 ctx->m_eControllerType = (ESwitchDeviceInfoControllerType)status->ucDeviceType;
611 for (i = 0; i < sizeof (ctx->m_rgucMACAddress); ++i)
612 ctx->m_rgucMACAddress[i] = status->rgucMACAddress[ sizeof(ctx->m_rgucMACAddress) - i - 1 ];
613
614 return SDL_TRUE;
615 }
616
617 ctx->m_bUsingBluetooth = SDL_TRUE;
618
619 if (WriteSubcommand(ctx, k_eSwitchSubcommandIDs_RequestDeviceInfo, NULL, 0, &reply)) {
620 // Byte 2: Controller ID (1=LJC, 2=RJC, 3=Pro)
621 ctx->m_eControllerType = (ESwitchDeviceInfoControllerType)reply->deviceInfo.ucDeviceType;
622
623 // Bytes 4-9: MAC address (big-endian)
624 SDL_memcpy(ctx->m_rgucMACAddress, reply->deviceInfo.rgucMACAddress, sizeof(ctx->m_rgucMACAddress));
625
626 return SDL_TRUE;
627 }
628
629 ctx->m_bUsingBluetooth = SDL_FALSE;
630
631 return SDL_FALSE;
632 }
633
BTrySetupUSB(SDL_DriverSwitch_Context * ctx)634 static SDL_bool BTrySetupUSB(SDL_DriverSwitch_Context *ctx)
635 {
636 /* We have to send a connection handshake to the controller when communicating over USB
637 * before we're able to send it other commands. Luckily this command is not supported
638 * over Bluetooth, so we can use the controller's lack of response as a way to
639 * determine if the connection is over USB or Bluetooth
640 */
641 if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Handshake, NULL, 0, SDL_TRUE)) {
642 return SDL_FALSE;
643 }
644 if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_HighSpeed, NULL, 0, SDL_TRUE)) {
645 /* The 8BitDo M30 and SF30 Pro don't respond to this command, but otherwise work correctly */
646 /*return SDL_FALSE;*/
647 }
648 if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Handshake, NULL, 0, SDL_TRUE)) {
649 /* This fails on the right Joy-Con when plugged into the charging grip */
650 /*return SDL_FALSE;*/
651 }
652 if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_ForceUSB, NULL, 0, SDL_FALSE)) {
653 return SDL_FALSE;
654 }
655 return SDL_TRUE;
656 }
657
SetVibrationEnabled(SDL_DriverSwitch_Context * ctx,Uint8 enabled)658 static SDL_bool SetVibrationEnabled(SDL_DriverSwitch_Context *ctx, Uint8 enabled)
659 {
660 return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_EnableVibration, &enabled, sizeof(enabled), NULL);
661
662 }
SetInputMode(SDL_DriverSwitch_Context * ctx,Uint8 input_mode)663 static SDL_bool SetInputMode(SDL_DriverSwitch_Context *ctx, Uint8 input_mode)
664 {
665 return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetInputReportMode, &input_mode, 1, NULL);
666 }
667
SetHomeLED(SDL_DriverSwitch_Context * ctx,Uint8 brightness)668 static SDL_bool SetHomeLED(SDL_DriverSwitch_Context *ctx, Uint8 brightness)
669 {
670 Uint8 ucLedIntensity = 0;
671 Uint8 rgucBuffer[4];
672
673 if (brightness > 0) {
674 if (brightness < 65) {
675 ucLedIntensity = (brightness + 5) / 10;
676 } else {
677 ucLedIntensity = (Uint8)SDL_ceilf(0xF * SDL_powf((float)brightness / 100.f, 2.13f));
678 }
679 }
680
681 rgucBuffer[0] = (0x0 << 4) | 0x1; /* 0 mini cycles (besides first), cycle duration 8ms */
682 rgucBuffer[1] = ((ucLedIntensity & 0xF) << 4) | 0x0; /* LED start intensity (0x0-0xF), 0 cycles (LED stays on at start intensity after first cycle) */
683 rgucBuffer[2] = ((ucLedIntensity & 0xF) << 4) | 0x0; /* First cycle LED intensity, 0x0 intensity for second cycle */
684 rgucBuffer[3] = (0x0 << 4) | 0x0; /* 8ms fade transition to first cycle, 8ms first cycle LED duration */
685
686 return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetHomeLight, rgucBuffer, sizeof(rgucBuffer), NULL);
687 }
688
SetSlotLED(SDL_DriverSwitch_Context * ctx,Uint8 slot)689 static SDL_bool SetSlotLED(SDL_DriverSwitch_Context *ctx, Uint8 slot)
690 {
691 Uint8 led_data = (1 << slot);
692 return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetPlayerLights, &led_data, sizeof(led_data), NULL);
693 }
694
SetIMUEnabled(SDL_DriverSwitch_Context * ctx,SDL_bool enabled)695 static SDL_bool SetIMUEnabled(SDL_DriverSwitch_Context* ctx, SDL_bool enabled)
696 {
697 Uint8 imu_data = enabled ? 1 : 0;
698 return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_EnableIMU, &imu_data, sizeof(imu_data), NULL);
699 }
700
LoadStickCalibration(SDL_DriverSwitch_Context * ctx,Uint8 input_mode)701 static SDL_bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx, Uint8 input_mode)
702 {
703 Uint8 *pStickCal;
704 size_t stick, axis;
705 SwitchSubcommandInputPacket_t *reply = NULL;
706
707 /* Read Calibration Info */
708 SwitchSPIOpData_t readParams;
709 readParams.unAddress = k_unSPIStickCalibrationStartOffset;
710 readParams.ucLength = k_unSPIStickCalibrationLength;
711
712 if (!WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SPIFlashRead, (uint8_t *)&readParams, sizeof(readParams), &reply)) {
713 return SDL_FALSE;
714 }
715
716 /* Stick calibration values are 12-bits each and are packed by bit
717 * For whatever reason the fields are in a different order for each stick
718 * Left: X-Max, Y-Max, X-Center, Y-Center, X-Min, Y-Min
719 * Right: X-Center, Y-Center, X-Min, Y-Min, X-Max, Y-Max
720 */
721 pStickCal = reply->spiReadData.rgucReadData;
722
723 /* Left stick */
724 ctx->m_StickCalData[0].axis[0].sMax = ((pStickCal[1] << 8) & 0xF00) | pStickCal[0]; /* X Axis max above center */
725 ctx->m_StickCalData[0].axis[1].sMax = (pStickCal[2] << 4) | (pStickCal[1] >> 4); /* Y Axis max above center */
726 ctx->m_StickCalData[0].axis[0].sCenter = ((pStickCal[4] << 8) & 0xF00) | pStickCal[3]; /* X Axis center */
727 ctx->m_StickCalData[0].axis[1].sCenter = (pStickCal[5] << 4) | (pStickCal[4] >> 4); /* Y Axis center */
728 ctx->m_StickCalData[0].axis[0].sMin = ((pStickCal[7] << 8) & 0xF00) | pStickCal[6]; /* X Axis min below center */
729 ctx->m_StickCalData[0].axis[1].sMin = (pStickCal[8] << 4) | (pStickCal[7] >> 4); /* Y Axis min below center */
730
731 /* Right stick */
732 ctx->m_StickCalData[1].axis[0].sCenter = ((pStickCal[10] << 8) & 0xF00) | pStickCal[9]; /* X Axis center */
733 ctx->m_StickCalData[1].axis[1].sCenter = (pStickCal[11] << 4) | (pStickCal[10] >> 4); /* Y Axis center */
734 ctx->m_StickCalData[1].axis[0].sMin = ((pStickCal[13] << 8) & 0xF00) | pStickCal[12]; /* X Axis min below center */
735 ctx->m_StickCalData[1].axis[1].sMin = (pStickCal[14] << 4) | (pStickCal[13] >> 4); /* Y Axis min below center */
736 ctx->m_StickCalData[1].axis[0].sMax = ((pStickCal[16] << 8) & 0xF00) | pStickCal[15]; /* X Axis max above center */
737 ctx->m_StickCalData[1].axis[1].sMax = (pStickCal[17] << 4) | (pStickCal[16] >> 4); /* Y Axis max above center */
738
739 /* Filter out any values that were uninitialized (0xFFF) in the SPI read */
740 for (stick = 0; stick < 2; ++stick) {
741 for (axis = 0; axis < 2; ++axis) {
742 if (ctx->m_StickCalData[stick].axis[axis].sCenter == 0xFFF) {
743 ctx->m_StickCalData[stick].axis[axis].sCenter = 0;
744 }
745 if (ctx->m_StickCalData[stick].axis[axis].sMax == 0xFFF) {
746 ctx->m_StickCalData[stick].axis[axis].sMax = 0;
747 }
748 if (ctx->m_StickCalData[stick].axis[axis].sMin == 0xFFF) {
749 ctx->m_StickCalData[stick].axis[axis].sMin = 0;
750 }
751 }
752 }
753
754 if (input_mode == k_eSwitchInputReportIDs_SimpleControllerState) {
755 for (stick = 0; stick < 2; ++stick) {
756 for(axis = 0; axis < 2; ++axis) {
757 ctx->m_StickExtents[stick].axis[axis].sMin = (Sint16)(SDL_MIN_SINT16 * 0.5f);
758 ctx->m_StickExtents[stick].axis[axis].sMax = (Sint16)(SDL_MAX_SINT16 * 0.5f);
759 }
760 }
761 } else {
762 for (stick = 0; stick < 2; ++stick) {
763 for(axis = 0; axis < 2; ++axis) {
764 ctx->m_StickExtents[stick].axis[axis].sMin = -(Sint16)(ctx->m_StickCalData[stick].axis[axis].sMin * 0.7f);
765 ctx->m_StickExtents[stick].axis[axis].sMax = (Sint16)(ctx->m_StickCalData[stick].axis[axis].sMax * 0.7f);
766 }
767 }
768 }
769 return SDL_TRUE;
770 }
771
ApplyStickCalibrationCentered(SDL_DriverSwitch_Context * ctx,int nStick,int nAxis,Sint16 sRawValue,Sint16 sCenter)772 static Sint16 ApplyStickCalibrationCentered(SDL_DriverSwitch_Context *ctx, int nStick, int nAxis, Sint16 sRawValue, Sint16 sCenter)
773 {
774 sRawValue -= sCenter;
775
776 if (sRawValue > ctx->m_StickExtents[nStick].axis[nAxis].sMax) {
777 ctx->m_StickExtents[nStick].axis[nAxis].sMax = sRawValue;
778 }
779 if (sRawValue < ctx->m_StickExtents[nStick].axis[nAxis].sMin) {
780 ctx->m_StickExtents[nStick].axis[nAxis].sMin = sRawValue;
781 }
782
783 return (Sint16)HIDAPI_RemapVal(sRawValue, ctx->m_StickExtents[nStick].axis[nAxis].sMin, ctx->m_StickExtents[nStick].axis[nAxis].sMax, SDL_MIN_SINT16, SDL_MAX_SINT16);
784 }
785
ApplyStickCalibration(SDL_DriverSwitch_Context * ctx,int nStick,int nAxis,Sint16 sRawValue)786 static Sint16 ApplyStickCalibration(SDL_DriverSwitch_Context *ctx, int nStick, int nAxis, Sint16 sRawValue)
787 {
788 return ApplyStickCalibrationCentered(ctx, nStick, nAxis, sRawValue, ctx->m_StickCalData[nStick].axis[nAxis].sCenter);
789 }
790
SDL_GameControllerButtonReportingHintChanged(void * userdata,const char * name,const char * oldValue,const char * hint)791 static void SDLCALL SDL_GameControllerButtonReportingHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
792 {
793 SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)userdata;
794 ctx->m_bUseButtonLabels = SDL_GetStringBoolean(hint, SDL_TRUE);
795 }
796
RemapButton(SDL_DriverSwitch_Context * ctx,Uint8 button)797 static Uint8 RemapButton(SDL_DriverSwitch_Context *ctx, Uint8 button)
798 {
799 if (!ctx->m_bUseButtonLabels) {
800 /* Use button positions */
801 if (ctx->m_bIsGameCube) {
802 switch (button) {
803 case SDL_CONTROLLER_BUTTON_B:
804 return SDL_CONTROLLER_BUTTON_X;
805 case SDL_CONTROLLER_BUTTON_X:
806 return SDL_CONTROLLER_BUTTON_B;
807 default:
808 break;
809 }
810 } else {
811 switch (button) {
812 case SDL_CONTROLLER_BUTTON_A:
813 return SDL_CONTROLLER_BUTTON_B;
814 case SDL_CONTROLLER_BUTTON_B:
815 return SDL_CONTROLLER_BUTTON_A;
816 case SDL_CONTROLLER_BUTTON_X:
817 return SDL_CONTROLLER_BUTTON_Y;
818 case SDL_CONTROLLER_BUTTON_Y:
819 return SDL_CONTROLLER_BUTTON_X;
820 default:
821 break;
822 }
823 }
824 }
825 return button;
826 }
827
828 static SDL_bool
HIDAPI_DriverSwitch_InitDevice(SDL_HIDAPI_Device * device)829 HIDAPI_DriverSwitch_InitDevice(SDL_HIDAPI_Device *device)
830 {
831 return HIDAPI_JoystickConnected(device, NULL);
832 }
833
834 static int
HIDAPI_DriverSwitch_GetDevicePlayerIndex(SDL_HIDAPI_Device * device,SDL_JoystickID instance_id)835 HIDAPI_DriverSwitch_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
836 {
837 return -1;
838 }
839
840 static void
HIDAPI_DriverSwitch_SetDevicePlayerIndex(SDL_HIDAPI_Device * device,SDL_JoystickID instance_id,int player_index)841 HIDAPI_DriverSwitch_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
842 {
843 }
844
845 static SDL_bool
HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)846 HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
847 {
848 SDL_DriverSwitch_Context *ctx;
849 Uint8 input_mode;
850
851 ctx = (SDL_DriverSwitch_Context *)SDL_calloc(1, sizeof(*ctx));
852 if (!ctx) {
853 SDL_OutOfMemory();
854 goto error;
855 }
856 ctx->device = device;
857 device->context = ctx;
858
859 device->dev = SDL_hid_open_path(device->path, 0);
860 if (!device->dev) {
861 SDL_SetError("Couldn't open %s", device->path);
862 goto error;
863 }
864
865 /* Find out whether or not we can send output reports */
866 ctx->m_bInputOnly = SDL_IsJoystickNintendoSwitchProInputOnly(device->vendor_id, device->product_id);
867 if (!ctx->m_bInputOnly) {
868 ctx->m_bHasHomeLED = HasHomeLED(device->vendor_id, device->product_id);
869
870 /* Initialize rumble data */
871 SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]);
872 SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]);
873
874 if (!BReadDeviceInfo(ctx)) {
875 SDL_SetError("Couldn't read device info");
876 goto error;
877 }
878
879 if (!ctx->m_bUsingBluetooth) {
880 if (!BTrySetupUSB(ctx)) {
881 SDL_SetError("Couldn't setup USB mode");
882 goto error;
883 }
884 }
885
886 /* Determine the desired input mode (needed before loading stick calibration) */
887 if (ctx->m_bUsingBluetooth) {
888 input_mode = k_eSwitchInputReportIDs_SimpleControllerState;
889 } else {
890 input_mode = k_eSwitchInputReportIDs_FullControllerState;
891 }
892
893 /* The official Nintendo Switch Pro Controller supports FullControllerState over bluetooth
894 * just fine. We really should use that, or else the epowerlevel code in
895 * HandleFullControllerState is completely pointless. We need full state if we want battery
896 * level and we only care about battery level over bluetooth anyway.
897 */
898 if (device->vendor_id == USB_VENDOR_NINTENDO &&
899 (device->product_id == USB_PRODUCT_NINTENDO_SWITCH_PRO ||
900 device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP ||
901 device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_LEFT ||
902 device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_RIGHT)) {
903 input_mode = k_eSwitchInputReportIDs_FullControllerState;
904 }
905
906 if (input_mode == k_eSwitchInputReportIDs_FullControllerState) {
907 SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 200.0f);
908 SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 200.0f);
909 ctx->m_bHasSensors = SDL_TRUE;
910 }
911
912 if (!LoadStickCalibration(ctx, input_mode)) {
913 SDL_SetError("Couldn't load stick calibration");
914 goto error;
915 }
916
917 if (!SetVibrationEnabled(ctx, 1)) {
918 SDL_SetError("Couldn't enable vibration");
919 goto error;
920 }
921
922 /* Set desired input mode */
923 if (!SetInputMode(ctx, input_mode)) {
924 SDL_SetError("Couldn't set input mode");
925 goto error;
926 }
927
928 /* Start sending USB reports */
929 if (!ctx->m_bUsingBluetooth) {
930 /* ForceUSB doesn't generate an ACK, so don't wait for a reply */
931 if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_ForceUSB, NULL, 0, SDL_FALSE)) {
932 SDL_SetError("Couldn't start USB reports");
933 goto error;
934 }
935 }
936
937 /* Set the LED state */
938 if (ctx->m_bHasHomeLED) {
939 const char *hint = SDL_GetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED);
940 if (hint && *hint) {
941 if (SDL_GetStringBoolean(hint, SDL_TRUE)) {
942 SetHomeLED(ctx, 100);
943 } else {
944 SetHomeLED(ctx, 0);
945 }
946 }
947 }
948 SetSlotLED(ctx, (joystick->instance_id % 4));
949
950 /* Set the serial number */
951 {
952 char serial[18];
953
954 SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
955 ctx->m_rgucMACAddress[0],
956 ctx->m_rgucMACAddress[1],
957 ctx->m_rgucMACAddress[2],
958 ctx->m_rgucMACAddress[3],
959 ctx->m_rgucMACAddress[4],
960 ctx->m_rgucMACAddress[5]);
961 joystick->serial = SDL_strdup(serial);
962 }
963 }
964
965 if (IsGameCubeFormFactor(device->vendor_id, device->product_id)) {
966 /* This is a controller shaped like a GameCube controller, with a large central A button */
967 ctx->m_bIsGameCube = SDL_TRUE;
968 }
969
970 SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS,
971 SDL_GameControllerButtonReportingHintChanged, ctx);
972
973 /* Initialize the joystick capabilities */
974 if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConLeft ||
975 ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) {
976 joystick->nbuttons = 20;
977 } else {
978 joystick->nbuttons = 16;
979 }
980 joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
981 joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
982
983 return SDL_TRUE;
984
985 error:
986 SDL_LockMutex(device->dev_lock);
987 {
988 if (device->dev) {
989 SDL_hid_close(device->dev);
990 device->dev = NULL;
991 }
992 if (device->context) {
993 SDL_free(device->context);
994 device->context = NULL;
995 }
996 }
997 SDL_UnlockMutex(device->dev_lock);
998 return SDL_FALSE;
999 }
1000
1001 static int
HIDAPI_DriverSwitch_ActuallyRumbleJoystick(SDL_DriverSwitch_Context * ctx,Uint16 low_frequency_rumble,Uint16 high_frequency_rumble)1002 HIDAPI_DriverSwitch_ActuallyRumbleJoystick(SDL_DriverSwitch_Context *ctx, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
1003 {
1004 /* Experimentally determined rumble values. These will only matter on some controllers as tested ones
1005 * seem to disregard these and just use any non-zero rumble values as a binary flag for constant rumble
1006 *
1007 * More information about these values can be found here:
1008 * https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md
1009 */
1010 const Uint16 k_usHighFreq = 0x0074;
1011 const Uint8 k_ucHighFreqAmp = EncodeRumbleHighAmplitude(high_frequency_rumble);
1012 const Uint8 k_ucLowFreq = 0x3D;
1013 const Uint16 k_usLowFreqAmp = EncodeRumbleLowAmplitude(low_frequency_rumble);
1014
1015 if (low_frequency_rumble || high_frequency_rumble) {
1016 EncodeRumble(&ctx->m_RumblePacket.rumbleData[0], k_usHighFreq, k_ucHighFreqAmp, k_ucLowFreq, k_usLowFreqAmp);
1017 EncodeRumble(&ctx->m_RumblePacket.rumbleData[1], k_usHighFreq, k_ucHighFreqAmp, k_ucLowFreq, k_usLowFreqAmp);
1018 } else {
1019 SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]);
1020 SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]);
1021 }
1022
1023 ctx->m_bRumbleActive = (low_frequency_rumble || high_frequency_rumble) ? SDL_TRUE : SDL_FALSE;
1024
1025 if (!WriteRumble(ctx)) {
1026 SDL_SetError("Couldn't send rumble packet");
1027 return -1;
1028 }
1029 return 0;
1030 }
1031
1032 static int
HIDAPI_DriverSwitch_SendPendingRumble(SDL_DriverSwitch_Context * ctx)1033 HIDAPI_DriverSwitch_SendPendingRumble(SDL_DriverSwitch_Context *ctx)
1034 {
1035 if (!SDL_TICKS_PASSED(SDL_GetTicks(), ctx->m_unRumbleSent + RUMBLE_WRITE_FREQUENCY_MS)) {
1036 return 0;
1037 }
1038
1039 if (ctx->m_bRumblePending) {
1040 Uint16 low_frequency_rumble = (Uint16)(ctx->m_unRumblePending >> 16);
1041 Uint16 high_frequency_rumble = (Uint16)ctx->m_unRumblePending;
1042
1043 #ifdef DEBUG_RUMBLE
1044 SDL_Log("Sent pending rumble %d/%d, %d ms after previous rumble\n", low_frequency_rumble, high_frequency_rumble, SDL_GetTicks() - ctx->m_unRumbleSent);
1045 #endif
1046 ctx->m_bRumblePending = SDL_FALSE;
1047 ctx->m_unRumblePending = 0;
1048
1049 return HIDAPI_DriverSwitch_ActuallyRumbleJoystick(ctx, low_frequency_rumble, high_frequency_rumble);
1050 }
1051
1052 if (ctx->m_bRumbleZeroPending) {
1053 ctx->m_bRumbleZeroPending = SDL_FALSE;
1054
1055 #ifdef DEBUG_RUMBLE
1056 SDL_Log("Sent pending zero rumble, %d ms after previous rumble\n", SDL_GetTicks() - ctx->m_unRumbleSent);
1057 #endif
1058 return HIDAPI_DriverSwitch_ActuallyRumbleJoystick(ctx, 0, 0);
1059 }
1060
1061 return 0;
1062 }
1063
1064 static int
HIDAPI_DriverSwitch_RumbleJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,Uint16 low_frequency_rumble,Uint16 high_frequency_rumble)1065 HIDAPI_DriverSwitch_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
1066 {
1067 SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context;
1068
1069 if (ctx->m_bInputOnly) {
1070 return SDL_Unsupported();
1071 }
1072
1073 if (ctx->m_bRumblePending) {
1074 if (HIDAPI_DriverSwitch_SendPendingRumble(ctx) < 0) {
1075 return -1;
1076 }
1077 }
1078
1079 if (!SDL_TICKS_PASSED(SDL_GetTicks(), ctx->m_unRumbleSent + RUMBLE_WRITE_FREQUENCY_MS)) {
1080 if (low_frequency_rumble || high_frequency_rumble) {
1081 Uint32 unRumblePending = ((Uint32)low_frequency_rumble << 16) | high_frequency_rumble;
1082
1083 /* Keep the highest rumble intensity in the given interval */
1084 if (unRumblePending > ctx->m_unRumblePending) {
1085 ctx->m_unRumblePending = unRumblePending;
1086 }
1087 ctx->m_bRumblePending = SDL_TRUE;
1088 ctx->m_bRumbleZeroPending = SDL_FALSE;
1089 } else {
1090 /* When rumble is complete, turn it off */
1091 ctx->m_bRumbleZeroPending = SDL_TRUE;
1092 }
1093 return 0;
1094 }
1095
1096 #ifdef DEBUG_RUMBLE
1097 SDL_Log("Sent rumble %d/%d\n", low_frequency_rumble, high_frequency_rumble);
1098 #endif
1099
1100 return HIDAPI_DriverSwitch_ActuallyRumbleJoystick(ctx, low_frequency_rumble, high_frequency_rumble);
1101 }
1102
1103 static int
HIDAPI_DriverSwitch_RumbleJoystickTriggers(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,Uint16 left_rumble,Uint16 right_rumble)1104 HIDAPI_DriverSwitch_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
1105 {
1106 return SDL_Unsupported();
1107 }
1108
1109 static Uint32
HIDAPI_DriverSwitch_GetJoystickCapabilities(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)1110 HIDAPI_DriverSwitch_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
1111 {
1112 SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context;
1113 Uint32 result = 0;
1114
1115 if (!ctx->m_bInputOnly) {
1116 /* Doesn't have an RGB LED, so don't return SDL_JOYCAP_LED here */
1117 result |= SDL_JOYCAP_RUMBLE;
1118 }
1119
1120 return result;
1121 }
1122
1123 static int
HIDAPI_DriverSwitch_SetJoystickLED(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,Uint8 red,Uint8 green,Uint8 blue)1124 HIDAPI_DriverSwitch_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
1125 {
1126 return SDL_Unsupported();
1127 }
1128
1129 static int
HIDAPI_DriverSwitch_SendJoystickEffect(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,const void * data,int size)1130 HIDAPI_DriverSwitch_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
1131 {
1132 return SDL_Unsupported();
1133 }
1134
1135 static int
HIDAPI_DriverSwitch_SetJoystickSensorsEnabled(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,SDL_bool enabled)1136 HIDAPI_DriverSwitch_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
1137 {
1138 SDL_DriverSwitch_Context* ctx = (SDL_DriverSwitch_Context*)device->context;
1139
1140 if (!ctx->m_bHasSensors) {
1141 return SDL_Unsupported();
1142 }
1143
1144 SetIMUEnabled(ctx, enabled);
1145 ctx->m_bReportSensors = enabled;
1146
1147 return 0;
1148 }
1149
1150 static float
HIDAPI_DriverSwitch_ScaleGyro(Sint16 value)1151 HIDAPI_DriverSwitch_ScaleGyro(Sint16 value)
1152 {
1153 float result = (value / SWITCH_GYRO_SCALE) * (float)M_PI / 180.0f;
1154 return result;
1155 }
1156
1157 static float
HIDAPI_DriverSwitch_ScaleAccel(Sint16 value)1158 HIDAPI_DriverSwitch_ScaleAccel(Sint16 value)
1159 {
1160 float result = (value / SWITCH_ACCEL_SCALE) * SDL_STANDARD_GRAVITY;
1161 return result;
1162 }
1163
HandleInputOnlyControllerState(SDL_Joystick * joystick,SDL_DriverSwitch_Context * ctx,SwitchInputOnlyControllerStatePacket_t * packet)1164 static void HandleInputOnlyControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchInputOnlyControllerStatePacket_t *packet)
1165 {
1166 Sint16 axis;
1167
1168 if (packet->rgucButtons[0] != ctx->m_lastInputOnlyState.rgucButtons[0]) {
1169 Uint8 data = packet->rgucButtons[0];
1170 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_A), (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
1171 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_B), (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
1172 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_X), (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
1173 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_Y), (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
1174 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
1175 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
1176
1177 axis = (data & 0x40) ? 32767 : -32768;
1178 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
1179
1180 axis = (data & 0x80) ? 32767 : -32768;
1181 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
1182 }
1183
1184 if (packet->rgucButtons[1] != ctx->m_lastInputOnlyState.rgucButtons[1]) {
1185 Uint8 data = packet->rgucButtons[1];
1186 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
1187 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
1188 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
1189 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
1190 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
1191 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
1192 }
1193
1194 if (packet->ucStickHat != ctx->m_lastInputOnlyState.ucStickHat) {
1195 SDL_bool dpad_up = SDL_FALSE;
1196 SDL_bool dpad_down = SDL_FALSE;
1197 SDL_bool dpad_left = SDL_FALSE;
1198 SDL_bool dpad_right = SDL_FALSE;
1199
1200 switch (packet->ucStickHat) {
1201 case 0:
1202 dpad_up = SDL_TRUE;
1203 break;
1204 case 1:
1205 dpad_up = SDL_TRUE;
1206 dpad_right = SDL_TRUE;
1207 break;
1208 case 2:
1209 dpad_right = SDL_TRUE;
1210 break;
1211 case 3:
1212 dpad_right = SDL_TRUE;
1213 dpad_down = SDL_TRUE;
1214 break;
1215 case 4:
1216 dpad_down = SDL_TRUE;
1217 break;
1218 case 5:
1219 dpad_left = SDL_TRUE;
1220 dpad_down = SDL_TRUE;
1221 break;
1222 case 6:
1223 dpad_left = SDL_TRUE;
1224 break;
1225 case 7:
1226 dpad_up = SDL_TRUE;
1227 dpad_left = SDL_TRUE;
1228 break;
1229 default:
1230 break;
1231 }
1232 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
1233 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
1234 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
1235 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
1236 }
1237
1238 if (packet->rgucJoystickLeft[0] != ctx->m_lastInputOnlyState.rgucJoystickLeft[0]) {
1239 axis = (Sint16)HIDAPI_RemapVal(packet->rgucJoystickLeft[0], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16);
1240 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
1241 }
1242
1243 if (packet->rgucJoystickLeft[1] != ctx->m_lastInputOnlyState.rgucJoystickLeft[1]) {
1244 axis = (Sint16)HIDAPI_RemapVal(packet->rgucJoystickLeft[1], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16);
1245 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
1246 }
1247
1248 if (packet->rgucJoystickRight[0] != ctx->m_lastInputOnlyState.rgucJoystickRight[0]) {
1249 axis = (Sint16)HIDAPI_RemapVal(packet->rgucJoystickRight[0], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16);
1250 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
1251 }
1252
1253 if (packet->rgucJoystickRight[1] != ctx->m_lastInputOnlyState.rgucJoystickRight[1]) {
1254 axis = (Sint16)HIDAPI_RemapVal(packet->rgucJoystickRight[1], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16);
1255 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
1256 }
1257
1258 ctx->m_lastInputOnlyState = *packet;
1259 }
1260
HandleSimpleControllerState(SDL_Joystick * joystick,SDL_DriverSwitch_Context * ctx,SwitchSimpleStatePacket_t * packet)1261 static void HandleSimpleControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchSimpleStatePacket_t *packet)
1262 {
1263 /* 0x8000 is the neutral value for all joystick axes */
1264 const Uint16 usJoystickCenter = 0x8000;
1265 Sint16 axis;
1266
1267 if (packet->rgucButtons[0] != ctx->m_lastSimpleState.rgucButtons[0]) {
1268 Uint8 data = packet->rgucButtons[0];
1269 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_A), (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
1270 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_B), (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
1271 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_X), (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
1272 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_Y), (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
1273 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
1274 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
1275
1276 axis = (data & 0x40) ? 32767 : -32768;
1277 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
1278
1279 axis = (data & 0x80) ? 32767 : -32768;
1280 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
1281 }
1282
1283 if (packet->rgucButtons[1] != ctx->m_lastSimpleState.rgucButtons[1]) {
1284 Uint8 data = packet->rgucButtons[1];
1285 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
1286 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
1287 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
1288 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
1289 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
1290 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
1291 }
1292
1293 if (packet->ucStickHat != ctx->m_lastSimpleState.ucStickHat) {
1294 SDL_bool dpad_up = SDL_FALSE;
1295 SDL_bool dpad_down = SDL_FALSE;
1296 SDL_bool dpad_left = SDL_FALSE;
1297 SDL_bool dpad_right = SDL_FALSE;
1298
1299 switch (packet->ucStickHat) {
1300 case 0:
1301 dpad_up = SDL_TRUE;
1302 break;
1303 case 1:
1304 dpad_up = SDL_TRUE;
1305 dpad_right = SDL_TRUE;
1306 break;
1307 case 2:
1308 dpad_right = SDL_TRUE;
1309 break;
1310 case 3:
1311 dpad_right = SDL_TRUE;
1312 dpad_down = SDL_TRUE;
1313 break;
1314 case 4:
1315 dpad_down = SDL_TRUE;
1316 break;
1317 case 5:
1318 dpad_left = SDL_TRUE;
1319 dpad_down = SDL_TRUE;
1320 break;
1321 case 6:
1322 dpad_left = SDL_TRUE;
1323 break;
1324 case 7:
1325 dpad_up = SDL_TRUE;
1326 dpad_left = SDL_TRUE;
1327 break;
1328 default:
1329 break;
1330 }
1331 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
1332 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
1333 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
1334 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
1335 }
1336
1337 axis = ApplyStickCalibrationCentered(ctx, 0, 0, packet->sJoystickLeft[0], (Sint16)usJoystickCenter);
1338 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
1339
1340 axis = ApplyStickCalibrationCentered(ctx, 0, 1, packet->sJoystickLeft[1], (Sint16)usJoystickCenter);
1341 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
1342
1343 axis = ApplyStickCalibrationCentered(ctx, 1, 0, packet->sJoystickRight[0], (Sint16)usJoystickCenter);
1344 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
1345
1346 axis = ApplyStickCalibrationCentered(ctx, 1, 1, packet->sJoystickRight[1], (Sint16)usJoystickCenter);
1347 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
1348
1349 ctx->m_lastSimpleState = *packet;
1350 }
1351
SendSensorUpdate(SDL_Joystick * joystick,SDL_DriverSwitch_Context * ctx,SDL_SensorType type,Sint16 * values)1352 static void SendSensorUpdate(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SDL_SensorType type, Sint16 *values)
1353 {
1354 float data[3];
1355
1356 /* Note the order of components has been shuffled to match PlayStation controllers,
1357 * since that's our de facto standard from already supporting those controllers, and
1358 * users will want consistent axis mappings across devices.
1359 */
1360 if (type == SDL_SENSOR_GYRO) {
1361 data[0] = -HIDAPI_DriverSwitch_ScaleGyro(values[1]);
1362 data[1] = HIDAPI_DriverSwitch_ScaleGyro(values[2]);
1363 data[2] = -HIDAPI_DriverSwitch_ScaleGyro(values[0]);
1364 } else {
1365 data[0] = -HIDAPI_DriverSwitch_ScaleAccel(values[1]);
1366 data[1] = HIDAPI_DriverSwitch_ScaleAccel(values[2]);
1367 data[2] = -HIDAPI_DriverSwitch_ScaleAccel(values[0]);
1368 }
1369
1370 /* Right Joy-Con flips some axes, so let's flip them back for consistency */
1371 if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) {
1372 data[0] = -data[0];
1373 data[1] = -data[1];
1374 }
1375
1376 SDL_PrivateJoystickSensor(joystick, type, data, 3);
1377 }
1378
HandleFullControllerState(SDL_Joystick * joystick,SDL_DriverSwitch_Context * ctx,SwitchStatePacket_t * packet)1379 static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchStatePacket_t *packet)
1380 {
1381 Sint16 axis;
1382
1383 if (packet->controllerState.rgucButtons[0] != ctx->m_lastFullState.controllerState.rgucButtons[0]) {
1384 Uint8 data = packet->controllerState.rgucButtons[0];
1385 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_A), (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
1386 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_B), (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
1387 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_X), (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
1388 SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_Y), (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
1389 if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) {
1390 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_PADDLE1, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
1391 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_PADDLE3, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
1392 }
1393 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED);
1394 axis = (data & 0x80) ? 32767 : -32768;
1395 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
1396 }
1397
1398 if (packet->controllerState.rgucButtons[1] != ctx->m_lastFullState.controllerState.rgucButtons[1]) {
1399 Uint8 data = packet->controllerState.rgucButtons[1];
1400 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
1401 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
1402 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
1403 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
1404
1405 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
1406 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
1407 }
1408
1409 if (packet->controllerState.rgucButtons[2] != ctx->m_lastFullState.controllerState.rgucButtons[2]) {
1410 Uint8 data = packet->controllerState.rgucButtons[2];
1411 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
1412 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
1413 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
1414 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
1415 if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConLeft) {
1416 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_PADDLE4, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
1417 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_PADDLE2, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
1418 }
1419 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED);
1420 axis = (data & 0x80) ? 32767 : -32768;
1421 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
1422 }
1423
1424 axis = packet->controllerState.rgucJoystickLeft[0] | ((packet->controllerState.rgucJoystickLeft[1] & 0xF) << 8);
1425 axis = ApplyStickCalibration(ctx, 0, 0, axis);
1426 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
1427
1428 axis = ((packet->controllerState.rgucJoystickLeft[1] & 0xF0) >> 4) | (packet->controllerState.rgucJoystickLeft[2] << 4);
1429 axis = ApplyStickCalibration(ctx, 0, 1, axis);
1430 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, ~axis);
1431
1432 axis = packet->controllerState.rgucJoystickRight[0] | ((packet->controllerState.rgucJoystickRight[1] & 0xF) << 8);
1433 axis = ApplyStickCalibration(ctx, 1, 0, axis);
1434 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
1435
1436 axis = ((packet->controllerState.rgucJoystickRight[1] & 0xF0) >> 4) | (packet->controllerState.rgucJoystickRight[2] << 4);
1437 axis = ApplyStickCalibration(ctx, 1, 1, axis);
1438 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, ~axis);
1439
1440 /* High nibble of battery/connection byte is battery level, low nibble is connection status
1441 * LSB of connection nibble is USB/Switch connection status
1442 */
1443 if (packet->controllerState.ucBatteryAndConnection & 0x1) {
1444 joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
1445 } else {
1446 /* LSB of the battery nibble is used to report charging.
1447 * The battery level is reported from 0(empty)-8(full)
1448 */
1449 int level = (packet->controllerState.ucBatteryAndConnection & 0xE0) >> 4;
1450 if (level == 0) {
1451 joystick->epowerlevel = SDL_JOYSTICK_POWER_EMPTY;
1452 } else if (level <= 2) {
1453 joystick->epowerlevel = SDL_JOYSTICK_POWER_LOW;
1454 } else if (level <= 6) {
1455 joystick->epowerlevel = SDL_JOYSTICK_POWER_MEDIUM;
1456 } else {
1457 joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL;
1458 }
1459 }
1460
1461 if (ctx->m_bReportSensors) {
1462 SendSensorUpdate(joystick, ctx, SDL_SENSOR_GYRO, &packet->imuState[2].sGyroX);
1463 SendSensorUpdate(joystick, ctx, SDL_SENSOR_GYRO, &packet->imuState[1].sGyroX);
1464 SendSensorUpdate(joystick, ctx, SDL_SENSOR_GYRO, &packet->imuState[0].sGyroX);
1465
1466 SendSensorUpdate(joystick, ctx, SDL_SENSOR_ACCEL, &packet->imuState[2].sAccelX);
1467 SendSensorUpdate(joystick, ctx, SDL_SENSOR_ACCEL, &packet->imuState[1].sAccelX);
1468 SendSensorUpdate(joystick, ctx, SDL_SENSOR_ACCEL, &packet->imuState[0].sAccelX);
1469 }
1470
1471 ctx->m_lastFullState = *packet;
1472 }
1473
1474 static SDL_bool
HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device * device)1475 HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device)
1476 {
1477 SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context;
1478 SDL_Joystick *joystick = NULL;
1479 int size;
1480
1481 if (device->num_joysticks > 0) {
1482 joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
1483 }
1484 if (!joystick) {
1485 return SDL_FALSE;
1486 }
1487
1488 while ((size = ReadInput(ctx)) > 0) {
1489 #ifdef DEBUG_SWITCH_PROTOCOL
1490 HIDAPI_DumpPacket("Nintendo Switch packet: size = %d", ctx->m_rgucReadBuffer, size);
1491 #endif
1492 if (ctx->m_bInputOnly) {
1493 HandleInputOnlyControllerState(joystick, ctx, (SwitchInputOnlyControllerStatePacket_t *)&ctx->m_rgucReadBuffer[0]);
1494 } else {
1495 switch (ctx->m_rgucReadBuffer[0]) {
1496 case k_eSwitchInputReportIDs_SimpleControllerState:
1497 HandleSimpleControllerState(joystick, ctx, (SwitchSimpleStatePacket_t *)&ctx->m_rgucReadBuffer[1]);
1498 break;
1499 case k_eSwitchInputReportIDs_FullControllerState:
1500 HandleFullControllerState(joystick, ctx, (SwitchStatePacket_t *)&ctx->m_rgucReadBuffer[1]);
1501 break;
1502 default:
1503 break;
1504 }
1505 }
1506 }
1507
1508 if (ctx->m_bRumblePending || ctx->m_bRumbleZeroPending) {
1509 HIDAPI_DriverSwitch_SendPendingRumble(ctx);
1510 } else if (ctx->m_bRumbleActive &&
1511 SDL_TICKS_PASSED(SDL_GetTicks(), ctx->m_unRumbleSent + RUMBLE_REFRESH_FREQUENCY_MS)) {
1512 #ifdef DEBUG_RUMBLE
1513 SDL_Log("Sent continuing rumble, %d ms after previous rumble\n", SDL_GetTicks() - ctx->m_unRumbleSent);
1514 #endif
1515 WriteRumble(ctx);
1516 }
1517
1518 if (size < 0) {
1519 /* Read error, device is disconnected */
1520 HIDAPI_JoystickDisconnected(device, joystick->instance_id);
1521 }
1522 return (size >= 0);
1523 }
1524
1525 static void
HIDAPI_DriverSwitch_CloseJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)1526 HIDAPI_DriverSwitch_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
1527 {
1528 SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context;
1529
1530 if (!ctx->m_bInputOnly) {
1531 /* Restore simple input mode for other applications */
1532 SetInputMode(ctx, k_eSwitchInputReportIDs_SimpleControllerState);
1533 }
1534
1535 SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS,
1536 SDL_GameControllerButtonReportingHintChanged, ctx);
1537
1538 SDL_LockMutex(device->dev_lock);
1539 {
1540 SDL_hid_close(device->dev);
1541 device->dev = NULL;
1542
1543 SDL_free(device->context);
1544 device->context = NULL;
1545 }
1546 SDL_UnlockMutex(device->dev_lock);
1547 }
1548
1549 static void
HIDAPI_DriverSwitch_FreeDevice(SDL_HIDAPI_Device * device)1550 HIDAPI_DriverSwitch_FreeDevice(SDL_HIDAPI_Device *device)
1551 {
1552 }
1553
1554 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch =
1555 {
1556 SDL_HINT_JOYSTICK_HIDAPI_SWITCH,
1557 SDL_TRUE,
1558 SDL_TRUE,
1559 HIDAPI_DriverSwitch_IsSupportedDevice,
1560 HIDAPI_DriverSwitch_GetDeviceName,
1561 HIDAPI_DriverSwitch_InitDevice,
1562 HIDAPI_DriverSwitch_GetDevicePlayerIndex,
1563 HIDAPI_DriverSwitch_SetDevicePlayerIndex,
1564 HIDAPI_DriverSwitch_UpdateDevice,
1565 HIDAPI_DriverSwitch_OpenJoystick,
1566 HIDAPI_DriverSwitch_RumbleJoystick,
1567 HIDAPI_DriverSwitch_RumbleJoystickTriggers,
1568 HIDAPI_DriverSwitch_GetJoystickCapabilities,
1569 HIDAPI_DriverSwitch_SetJoystickLED,
1570 HIDAPI_DriverSwitch_SendJoystickEffect,
1571 HIDAPI_DriverSwitch_SetJoystickSensorsEnabled,
1572 HIDAPI_DriverSwitch_CloseJoystick,
1573 HIDAPI_DriverSwitch_FreeDevice,
1574 };
1575
1576 #endif /* SDL_JOYSTICK_HIDAPI_SWITCH */
1577
1578 #endif /* SDL_JOYSTICK_HIDAPI */
1579
1580 /* vi: set ts=4 sw=4 expandtab: */
1581