summaryrefslogtreecommitdiff
path: root/src/input_common/helpers/joycon_protocol
diff options
context:
space:
mode:
authorGravatar Narr the Reg2022-12-20 11:34:33 -0600
committerGravatar Narr the Reg2023-01-19 18:05:20 -0600
commitd80e6c399bf8196646cca5ac1265d122638bb96b (patch)
tree328254642e4edcd5e0aadfe9190f3f133d34708e /src/input_common/helpers/joycon_protocol
parentMerge pull request #9556 from vonchenplus/draw_texture (diff)
downloadyuzu-d80e6c399bf8196646cca5ac1265d122638bb96b.tar.gz
yuzu-d80e6c399bf8196646cca5ac1265d122638bb96b.tar.xz
yuzu-d80e6c399bf8196646cca5ac1265d122638bb96b.zip
input_common: Initial skeleton for custom joycon driver
Diffstat (limited to 'src/input_common/helpers/joycon_protocol')
-rw-r--r--src/input_common/helpers/joycon_protocol/joycon_types.h494
1 files changed, 494 insertions, 0 deletions
diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h
new file mode 100644
index 000000000..de512fe63
--- /dev/null
+++ b/src/input_common/helpers/joycon_protocol/joycon_types.h
@@ -0,0 +1,494 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4// Based on dkms-hid-nintendo implementation, CTCaer joycon toolkit and dekuNukem reverse
5// engineering https://github.com/nicman23/dkms-hid-nintendo/blob/master/src/hid-nintendo.c
6// https://github.com/CTCaer/jc_toolkit
7// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering
8
9#pragma once
10
11#include <array>
12#include <functional>
13#include <SDL_hidapi.h>
14
15#include "common/bit_field.h"
16#include "common/common_funcs.h"
17#include "common/common_types.h"
18
19namespace InputCommon::Joycon {
20constexpr u32 MaxErrorCount = 50;
21constexpr u32 MaxBufferSize = 60;
22constexpr u32 MaxResponseSize = 49;
23constexpr u32 MaxSubCommandResponseSize = 64;
24constexpr std::array<u8, 8> DefaultVibrationBuffer{0x0, 0x1, 0x40, 0x40, 0x0, 0x1, 0x40, 0x40};
25
26using MacAddress = std::array<u8, 6>;
27using SerialNumber = std::array<u8, 15>;
28
29enum class ControllerType {
30 None,
31 Left,
32 Right,
33 Pro,
34 Grip,
35 Dual,
36};
37
38enum class PadAxes {
39 LeftStickX,
40 LeftStickY,
41 RightStickX,
42 RightStickY,
43 Undefined,
44};
45
46enum class PadMotion {
47 LeftMotion,
48 RightMotion,
49 Undefined,
50};
51
52enum class PadButton : u32 {
53 Down = 0x000001,
54 Up = 0x000002,
55 Right = 0x000004,
56 Left = 0x000008,
57 LeftSR = 0x000010,
58 LeftSL = 0x000020,
59 L = 0x000040,
60 ZL = 0x000080,
61 Y = 0x000100,
62 X = 0x000200,
63 B = 0x000400,
64 A = 0x000800,
65 RightSR = 0x001000,
66 RightSL = 0x002000,
67 R = 0x004000,
68 ZR = 0x008000,
69 Minus = 0x010000,
70 Plus = 0x020000,
71 StickR = 0x040000,
72 StickL = 0x080000,
73 Home = 0x100000,
74 Capture = 0x200000,
75};
76
77enum class PasivePadButton : u32 {
78 Down_A = 0x0001,
79 Right_X = 0x0002,
80 Left_B = 0x0004,
81 Up_Y = 0x0008,
82 SL = 0x0010,
83 SR = 0x0020,
84 Minus = 0x0100,
85 Plus = 0x0200,
86 StickL = 0x0400,
87 StickR = 0x0800,
88 Home = 0x1000,
89 Capture = 0x2000,
90 L_R = 0x4000,
91 ZL_ZR = 0x8000,
92};
93
94enum class OutputReport : u8 {
95 RUMBLE_AND_SUBCMD = 0x01,
96 FW_UPDATE_PKT = 0x03,
97 RUMBLE_ONLY = 0x10,
98 MCU_DATA = 0x11,
99 USB_CMD = 0x80,
100};
101
102enum class InputReport : u8 {
103 SUBCMD_REPLY = 0x21,
104 STANDARD_FULL_60HZ = 0x30,
105 NFC_IR_MODE_60HZ = 0x31,
106 SIMPLE_HID_MODE = 0x3F,
107 INPUT_USB_RESPONSE = 0x81,
108};
109
110enum class FeatureReport : u8 {
111 Last_SUBCMD = 0x02,
112 OTA_GW_UPGRADE = 0x70,
113 SETUP_MEM_READ = 0x71,
114 MEM_READ = 0x72,
115 ERASE_MEM_SECTOR = 0x73,
116 MEM_WRITE = 0x74,
117 LAUNCH = 0x75,
118};
119
120enum class SubCommand : u8 {
121 STATE = 0x00,
122 MANUAL_BT_PAIRING = 0x01,
123 REQ_DEV_INFO = 0x02,
124 SET_REPORT_MODE = 0x03,
125 TRIGGERS_ELAPSED = 0x04,
126 GET_PAGE_LIST_STATE = 0x05,
127 SET_HCI_STATE = 0x06,
128 RESET_PAIRING_INFO = 0x07,
129 LOW_POWER_MODE = 0x08,
130 SPI_FLASH_READ = 0x10,
131 SPI_FLASH_WRITE = 0x11,
132 RESET_MCU = 0x20,
133 SET_MCU_CONFIG = 0x21,
134 SET_MCU_STATE = 0x22,
135 SET_PLAYER_LIGHTS = 0x30,
136 GET_PLAYER_LIGHTS = 0x31,
137 SET_HOME_LIGHT = 0x38,
138 ENABLE_IMU = 0x40,
139 SET_IMU_SENSITIVITY = 0x41,
140 WRITE_IMU_REG = 0x42,
141 READ_IMU_REG = 0x43,
142 ENABLE_VIBRATION = 0x48,
143 GET_REGULATED_VOLTAGE = 0x50,
144 SET_EXTERNAL_CONFIG = 0x58,
145 UNKNOWN_RINGCON = 0x59,
146 UNKNOWN_RINGCON2 = 0x5A,
147 UNKNOWN_RINGCON3 = 0x5C,
148};
149
150enum class UsbSubCommand : u8 {
151 CONN_STATUS = 0x01,
152 HADSHAKE = 0x02,
153 BAUDRATE_3M = 0x03,
154 NO_TIMEOUT = 0x04,
155 EN_TIMEOUT = 0x05,
156 RESET = 0x06,
157 PRE_HANDSHAKE = 0x91,
158 SEND_UART = 0x92,
159};
160
161enum class CalMagic : u8 {
162 USR_MAGIC_0 = 0xB2,
163 USR_MAGIC_1 = 0xA1,
164 USRR_MAGI_SIZE = 2,
165};
166
167enum class CalAddr {
168 SERIAL_NUMBER = 0X6000,
169 DEVICE_TYPE = 0X6012,
170 COLOR_EXIST = 0X601B,
171 FACT_LEFT_DATA = 0X603d,
172 FACT_RIGHT_DATA = 0X6046,
173 COLOR_DATA = 0X6050,
174 FACT_IMU_DATA = 0X6020,
175 USER_LEFT_MAGIC = 0X8010,
176 USER_LEFT_DATA = 0X8012,
177 USER_RIGHT_MAGIC = 0X801B,
178 USER_RIGHT_DATA = 0X801D,
179 USER_IMU_MAGIC = 0X8026,
180 USER_IMU_DATA = 0X8028,
181};
182
183enum class ReportMode : u8 {
184 ACTIVE_POLLING_NFC_IR_CAMERA_DATA = 0x00,
185 ACTIVE_POLLING_NFC_IR_CAMERA_CONFIGURATION = 0x01,
186 ACTIVE_POLLING_NFC_IR_CAMERA_DATA_CONFIGURATION = 0x02,
187 ACTIVE_POLLING_IR_CAMERA_DATA = 0x03,
188 MCU_UPDATE_STATE = 0x23,
189 STANDARD_FULL_60HZ = 0x30,
190 NFC_IR_MODE_60HZ = 0x31,
191 SIMPLE_HID_MODE = 0x3F,
192};
193
194enum class GyroSensitivity : u8 {
195 DPS250,
196 DPS500,
197 DPS1000,
198 DPS2000, // Default
199};
200
201enum class AccelerometerSensitivity : u8 {
202 G8, // Default
203 G4,
204 G2,
205 G16,
206};
207
208enum class GyroPerformance : u8 {
209 HZ833,
210 HZ208, // Default
211};
212
213enum class AccelerometerPerformance : u8 {
214 HZ200,
215 HZ100, // Default
216};
217
218enum class MCUCommand : u8 {
219 ConfigureMCU = 0x21,
220 ConfigureIR = 0x23,
221};
222
223enum class MCUSubCommand : u8 {
224 SetMCUMode = 0x0,
225 SetDeviceMode = 0x1,
226 ReadDeviceMode = 0x02,
227 WriteDeviceRegisters = 0x4,
228};
229
230enum class MCUMode : u8 {
231 Suspend = 0,
232 Standby = 1,
233 Ringcon = 3,
234 NFC = 4,
235 IR = 5,
236 MaybeFWUpdate = 6,
237};
238
239enum class MCURequest : u8 {
240 GetMCUStatus = 1,
241 GetNFCData = 2,
242 GetIRData = 3,
243};
244
245enum class MCUReport : u8 {
246 Empty = 0x00,
247 StateReport = 0x01,
248 IRData = 0x03,
249 BusyInitializing = 0x0b,
250 IRStatus = 0x13,
251 IRRegisters = 0x1b,
252 NFCState = 0x2a,
253 NFCReadData = 0x3a,
254 EmptyAwaitingCmd = 0xff,
255};
256
257enum class MCUPacketFlag : u8 {
258 MorePacketsRemaining = 0x00,
259 LastCommandPacket = 0x08,
260};
261
262enum class NFCReadCommand : u8 {
263 CancelAll = 0x00,
264 StartPolling = 0x01,
265 StopPolling = 0x02,
266 StartWaitingRecieve = 0x04,
267 Ntag = 0x06,
268 Mifare = 0x0F,
269};
270
271enum class NFCTagType : u8 {
272 AllTags = 0x00,
273 Ntag215 = 0x01,
274};
275
276enum class DriverResult {
277 Success,
278 WrongReply,
279 Timeout,
280 UnsupportedControllerType,
281 HandleInUse,
282 ErrorReadingData,
283 ErrorWritingData,
284 NoDeviceDetected,
285 InvalidHandle,
286 NotSupported,
287 Unknown,
288};
289
290struct MotionSensorCalibration {
291 s16 offset;
292 s16 scale;
293};
294
295struct MotionCalibration {
296 std::array<MotionSensorCalibration, 3> accelerometer;
297 std::array<MotionSensorCalibration, 3> gyro;
298};
299
300// Basic motion data containing data from the sensors and a timestamp in microseconds
301struct MotionData {
302 float gyro_x{};
303 float gyro_y{};
304 float gyro_z{};
305 float accel_x{};
306 float accel_y{};
307 float accel_z{};
308 u64 delta_timestamp{};
309};
310
311struct JoyStickAxisCalibration {
312 u16 max{1};
313 u16 min{1};
314 u16 center{0};
315};
316
317struct JoyStickCalibration {
318 JoyStickAxisCalibration x;
319 JoyStickAxisCalibration y;
320};
321
322struct RingCalibration {
323 s16 default_value;
324 s16 max_value;
325 s16 min_value;
326};
327
328struct Color {
329 u32 body;
330 u32 buttons;
331 u32 left_grip;
332 u32 right_grip;
333};
334
335struct Battery {
336 union {
337 u8 raw{};
338
339 BitField<0, 4, u8> unknown;
340 BitField<4, 1, u8> charging;
341 BitField<5, 3, u8> status;
342 };
343};
344
345struct VibrationValue {
346 f32 low_amplitude;
347 f32 low_frequency;
348 f32 high_amplitude;
349 f32 high_frequency;
350};
351
352struct JoyconHandle {
353 SDL_hid_device* handle = nullptr;
354 u8 packet_counter{};
355};
356
357struct MCUConfig {
358 MCUCommand command;
359 MCUSubCommand sub_command;
360 MCUMode mode;
361 INSERT_PADDING_BYTES(0x22);
362 u8 crc;
363};
364static_assert(sizeof(MCUConfig) == 0x26, "MCUConfig is an invalid size");
365
366#pragma pack(push, 1)
367struct InputReportPassive {
368 InputReport report_mode;
369 u16 button_input;
370 u8 stick_state;
371 std::array<u8, 10> unknown_data;
372};
373static_assert(sizeof(InputReportPassive) == 0xE, "InputReportPassive is an invalid size");
374
375struct InputReportActive {
376 InputReport report_mode;
377 u8 packet_id;
378 Battery battery_status;
379 std::array<u8, 3> button_input;
380 std::array<u8, 3> left_stick_state;
381 std::array<u8, 3> right_stick_state;
382 u8 vibration_code;
383 std::array<s16, 6 * 2> motion_input;
384 INSERT_PADDING_BYTES(0x2);
385 s16 ring_input;
386};
387static_assert(sizeof(InputReportActive) == 0x29, "InputReportActive is an invalid size");
388
389struct InputReportNfcIr {
390 InputReport report_mode;
391 u8 packet_id;
392 Battery battery_status;
393 std::array<u8, 3> button_input;
394 std::array<u8, 3> left_stick_state;
395 std::array<u8, 3> right_stick_state;
396 u8 vibration_code;
397 std::array<s16, 6 * 2> motion_input;
398 INSERT_PADDING_BYTES(0x4);
399};
400static_assert(sizeof(InputReportNfcIr) == 0x29, "InputReportNfcIr is an invalid size");
401#pragma pack(pop)
402
403struct IMUCalibration {
404 std::array<s16, 3> accelerometer_offset;
405 std::array<s16, 3> accelerometer_scale;
406 std::array<s16, 3> gyroscope_offset;
407 std::array<s16, 3> gyroscope_scale;
408};
409static_assert(sizeof(IMUCalibration) == 0x18, "IMUCalibration is an invalid size");
410
411struct NFCReadBlock {
412 u8 start;
413 u8 end;
414};
415static_assert(sizeof(NFCReadBlock) == 0x2, "NFCReadBlock is an invalid size");
416
417struct NFCReadBlockCommand {
418 u8 block_count{};
419 std::array<NFCReadBlock, 4> blocks{};
420};
421static_assert(sizeof(NFCReadBlockCommand) == 0x9, "NFCReadBlockCommand is an invalid size");
422
423struct NFCReadCommandData {
424 u8 unknown;
425 u8 uuid_length;
426 u8 unknown_2;
427 std::array<u8, 6> uid;
428 NFCTagType tag_type;
429 NFCReadBlockCommand read_block;
430};
431static_assert(sizeof(NFCReadCommandData) == 0x13, "NFCReadCommandData is an invalid size");
432
433struct NFCPollingCommandData {
434 u8 enable_mifare;
435 u8 unknown_1;
436 u8 unknown_2;
437 u8 unknown_3;
438 u8 unknown_4;
439};
440static_assert(sizeof(NFCPollingCommandData) == 0x05, "NFCPollingCommandData is an invalid size");
441
442struct NFCRequestState {
443 MCUSubCommand sub_command;
444 NFCReadCommand command_argument;
445 u8 packet_id;
446 INSERT_PADDING_BYTES(0x1);
447 MCUPacketFlag packet_flag;
448 u8 data_length;
449 union {
450 std::array<u8, 0x1F> raw_data;
451 NFCReadCommandData nfc_read;
452 NFCPollingCommandData nfc_polling;
453 };
454 u8 crc;
455};
456static_assert(sizeof(NFCRequestState) == 0x26, "NFCRequestState is an invalid size");
457
458struct FirmwareVersion {
459 u8 major;
460 u8 minor;
461};
462static_assert(sizeof(FirmwareVersion) == 0x2, "FirmwareVersion is an invalid size");
463
464struct DeviceInfo {
465 FirmwareVersion firmware;
466 MacAddress mac_address;
467};
468static_assert(sizeof(DeviceInfo) == 0x8, "DeviceInfo is an invalid size");
469
470struct MotionStatus {
471 bool is_enabled;
472 u64 delta_time;
473 GyroSensitivity gyro_sensitivity;
474 AccelerometerSensitivity accelerometer_sensitivity;
475};
476
477struct RingStatus {
478 bool is_enabled;
479 s16 default_value;
480 s16 max_value;
481 s16 min_value;
482};
483
484struct JoyconCallbacks {
485 std::function<void(Battery)> on_battery_data;
486 std::function<void(Color)> on_color_data;
487 std::function<void(int, bool)> on_button_data;
488 std::function<void(int, f32)> on_stick_data;
489 std::function<void(int, const MotionData&)> on_motion_data;
490 std::function<void(f32)> on_ring_data;
491 std::function<void(const std::vector<u8>&)> on_amiibo_data;
492};
493
494} // namespace InputCommon::Joycon