1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "device/gamepad/nintendo_controller.h"
6
7 #include <algorithm>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/numerics/ranges.h"
12 #include "base/strings/stringprintf.h"
13 #include "device/gamepad/gamepad_data_fetcher.h"
14 #include "device/gamepad/gamepad_id_list.h"
15
16 namespace device {
17 namespace {
18 // Device IDs for the Switch Charging Grip, also used for composite devices.
19 const uint16_t kVendorNintendo = 0x057e;
20 const uint16_t kProductSwitchChargingGrip = 0x200e;
21
22 // Maximum output report sizes, used to distinguish USB and Bluetooth.
23 const size_t kSwitchProMaxOutputReportSizeBytesUsb = 63;
24 const size_t kSwitchProMaxOutputReportSizeBytesBluetooth = 48;
25
26 // Input report size.
27 const size_t kMaxInputReportSizeBytes = 64;
28
29 // Device name for a composite Joy-Con device.
30 const char kProductNameSwitchCompositeDevice[] = "Joy-Con L+R";
31
32 // Report IDs.
33 const uint8_t kReportIdOutput01 = 0x01;
34 const uint8_t kReportIdOutput10 = 0x10;
35 const uint8_t kReportIdInput21 = 0x21;
36 const uint8_t kReportIdInput30 = 0x30;
37 const uint8_t kUsbReportIdOutput80 = 0x80;
38 const uint8_t kUsbReportIdInput81 = 0x81;
39
40 // Sub-types of the 0x80 output report, used for initialization.
41 const uint8_t kSubTypeRequestMac = 0x01;
42 const uint8_t kSubTypeHandshake = 0x02;
43 const uint8_t kSubTypeBaudRate = 0x03;
44 const uint8_t kSubTypeDisableUsbTimeout = 0x04;
45 const uint8_t kSubTypeEnableUsbTimeout = 0x05;
46
47 // UART subcommands.
48 const uint8_t kSubCommandSetInputReportMode = 0x03;
49 const uint8_t kSubCommandReadSpi = 0x10;
50 const uint8_t kSubCommandSetPlayerLights = 0x30;
51 const uint8_t kSubCommand33 = 0x33;
52 const uint8_t kSubCommandSetHomeLight = 0x38;
53 const uint8_t kSubCommandEnableImu = 0x40;
54 const uint8_t kSubCommandSetImuSensitivity = 0x41;
55 const uint8_t kSubCommandEnableVibration = 0x48;
56
57 // SPI memory regions.
58 const uint16_t kSpiImuCalibrationAddress = 0x6020;
59 const size_t kSpiImuCalibrationSize = 24;
60 const uint16_t kSpiAnalogStickCalibrationAddress = 0x603d;
61 const size_t kSpiAnalogStickCalibrationSize = 18;
62 const uint16_t kSpiImuHorizontalOffsetsAddress = 0x6080;
63 const size_t kSpiImuHorizontalOffsetsSize = 6;
64 const uint16_t kSpiAnalogStickParametersAddress = 0x6086;
65 const size_t kSpiAnalogStickParametersSize = 18;
66
67 // Byte index for the first byte of subcommand data in 0x80 output reports.
68 const size_t kSubCommandDataOffset = 11;
69 // Byte index for the first byte of SPI data in SPI read responses.
70 const size_t kSpiDataOffset = 20;
71
72 // Values for the |device_type| field reported in the MAC reply.
73 const uint8_t kUsbDeviceTypeChargingGripNoDevice = 0x00;
74 const uint8_t kUsbDeviceTypeChargingGripJoyConL = 0x01;
75 const uint8_t kUsbDeviceTypeChargingGripJoyConR = 0x02;
76 const uint8_t kUsbDeviceTypeProController = 0x03;
77
78 // During initialization, the current initialization step will be retried if
79 // the client does not respond within |kTimeoutDuration|. After |kMaxRetryCount|
80 // retries, initialization is restarted from the first step.
81 //
82 // The timeout duration was chosen through experimentation. A shorter duration
83 // (~1 second) works for Pro controllers, but Joy-Cons sometimes fail to
84 // initialize correctly.
85 const base::TimeDelta kTimeoutDuration =
86 base::TimeDelta::FromMilliseconds(3000);
87 const size_t kMaxRetryCount = 3;
88
89 const size_t kMaxVibrationEffectDurationMillis = 100;
90
91 // Initialization parameters.
92 const uint8_t kGyroSensitivity2000Dps = 0x03;
93 const uint8_t kAccelerometerSensitivity8G = 0x00;
94 const uint8_t kGyroPerformance208Hz = 0x01;
95 const uint8_t kAccelerometerFilterBandwidth100Hz = 0x01;
96 const uint8_t kPlayerLightPattern1 = 0x01;
97
98 // Bogus calibration value that should be ignored.
99 const uint16_t kCalBogusValue = 0xfff;
100
101 // Default calibration values to use if the controller returns bogus values.
102 const uint16_t kCalDefaultDeadzone = 160;
103 const uint16_t kCalDefaultMin = 550;
104 const uint16_t kCalDefaultCenter = 2050;
105 const uint16_t kCalDefaultMax = 3550;
106
107 // Parameters for the "strong" and "weak" components of the dual-rumble effect.
108 const double kVibrationFrequencyStrongRumble = 141.0;
109 const double kVibrationFrequencyWeakRumble = 182.0;
110 const double kVibrationAmplitudeStrongRumbleMax = 0.9;
111 const double kVibrationAmplitudeWeakRumbleMax = 0.1;
112
113 const int kVibrationFrequencyHzMin = 41;
114 const int kVibrationFrequencyHzMax = 1253;
115 const int kVibrationAmplitudeMax = 1000;
116
117 // https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md
118 struct VibrationFrequency {
119 uint16_t hf;
120 uint8_t lf;
121 int freq_hz; // rounded
122 } kVibrationFrequency[] = {
123 // The linear resonant actuators (LRAs) on Switch devices are capable of
124 // producing vibration effects at a wide range of frequencies, but the
125 // Gamepad API assumes "dual-rumble" style vibration which is typically
126 // implemented by a pair of eccentric rotating mass (ERM) actuators. To
127 // simulate "dual-rumble" with Switch LRAs, the strong and weak vibration
128 // magnitudes are translated into low and high frequency vibration effects.
129 // Only the frequencies used for this translation are included; unused
130 // frequencies have been removed.
131 //
132 // This list must be kept sorted.
133 {0x0068, 0x3a, 141},
134 {0x0098, 0x46, 182}};
135 const size_t kVibrationFrequencySize = base::size(kVibrationFrequency);
136
137 // https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md
138 struct VibrationAmplitude {
139 uint8_t hfa;
140 uint16_t lfa;
141 int amp; // rounded, max 1000 (kVibrationAmplitudeMax)
142 } kVibrationAmplitude[]{
143 // Only include safe amplitudes.
144 {0x00, 0x0040, 0}, {0x02, 0x8040, 10}, {0x04, 0x0041, 12},
145 {0x06, 0x8041, 14}, {0x08, 0x0042, 17}, {0x0a, 0x8042, 20},
146 {0x0c, 0x0043, 24}, {0x0e, 0x8043, 28}, {0x10, 0x0044, 33},
147 {0x12, 0x8044, 40}, {0x14, 0x0045, 47}, {0x16, 0x8045, 56},
148 {0x18, 0x0046, 67}, {0x1a, 0x8046, 80}, {0x1c, 0x0047, 95},
149 {0x1e, 0x8047, 112}, {0x20, 0x0048, 117}, {0x22, 0x8048, 123},
150 {0x24, 0x0049, 128}, {0x26, 0x8049, 134}, {0x28, 0x004a, 140},
151 {0x2a, 0x804a, 146}, {0x2c, 0x004b, 152}, {0x2e, 0x804b, 159},
152 {0x30, 0x004c, 166}, {0x32, 0x804c, 173}, {0x34, 0x004d, 181},
153 {0x36, 0x804d, 189}, {0x38, 0x004e, 198}, {0x3a, 0x804e, 206},
154 {0x3c, 0x004f, 215}, {0x3e, 0x804f, 225}, {0x40, 0x0050, 230},
155 {0x42, 0x8050, 235}, {0x44, 0x0051, 240}, {0x46, 0x8051, 245},
156 {0x48, 0x0052, 251}, {0x4a, 0x8052, 256}, {0x4c, 0x0053, 262},
157 {0x4e, 0x8053, 268}, {0x50, 0x0054, 273}, {0x52, 0x8054, 279},
158 {0x54, 0x0055, 286}, {0x56, 0x8055, 292}, {0x58, 0x0056, 298},
159 {0x5a, 0x8056, 305}, {0x5c, 0x0057, 311}, {0x5e, 0x8057, 318},
160 {0x60, 0x0058, 325}, {0x62, 0x8058, 332}, {0x64, 0x0059, 340},
161 {0x66, 0x8059, 347}, {0x68, 0x005a, 355}, {0x6a, 0x805a, 362},
162 {0x6c, 0x005b, 370}, {0x6e, 0x805b, 378}, {0x70, 0x005c, 387},
163 {0x72, 0x805c, 395}, {0x74, 0x005d, 404}, {0x76, 0x805d, 413},
164 {0x78, 0x005e, 422}, {0x7a, 0x805e, 431}, {0x7c, 0x005f, 440},
165 {0x7e, 0x805f, 450}, {0x80, 0x0060, 460}, {0x82, 0x8060, 470},
166 {0x84, 0x0061, 480}, {0x86, 0x8061, 491}, {0x88, 0x0062, 501},
167 {0x8a, 0x8062, 512}, {0x8c, 0x0063, 524}, {0x8e, 0x8063, 535},
168 {0x90, 0x0064, 547}, {0x92, 0x8064, 559}, {0x94, 0x0065, 571},
169 {0x96, 0x8065, 584}, {0x98, 0x0066, 596}, {0x9a, 0x8066, 609},
170 {0x9c, 0x0067, 623}, {0x9e, 0x8067, 636}, {0xa0, 0x0068, 650},
171 {0xa2, 0x8068, 665}, {0xa4, 0x0069, 679}, {0xa6, 0x8069, 694},
172 {0xa8, 0x006a, 709}, {0xaa, 0x806a, 725}, {0xac, 0x006b, 741},
173 {0xae, 0x806b, 757}, {0xb0, 0x006c, 773}, {0xb2, 0x806c, 790},
174 {0xb4, 0x006d, 808}, {0xb6, 0x806d, 825}, {0xb8, 0x006e, 843},
175 {0xba, 0x806e, 862}, {0xbc, 0x006f, 881}, {0xbe, 0x806f, 900},
176 {0xc0, 0x0070, 920}, {0xc2, 0x8070, 940}, {0xc4, 0x0071, 960},
177 {0xc6, 0x8071, 981}, {0xc8, 0x0072, 1000},
178 };
179 const size_t kVibrationAmplitudeSize = base::size(kVibrationAmplitude);
180
181 // Define indices for the additional buttons on Switch controllers.
182 enum SWITCH_BUTTON_INDICES {
183 SWITCH_BUTTON_INDEX_CAPTURE = BUTTON_INDEX_META + 1,
184 SWITCH_BUTTON_INDEX_LEFT_SL,
185 SWITCH_BUTTON_INDEX_LEFT_SR,
186 SWITCH_BUTTON_INDEX_RIGHT_SL,
187 SWITCH_BUTTON_INDEX_RIGHT_SR,
188 SWITCH_BUTTON_INDEX_COUNT
189 };
190
191 // Input reports with ID 0x81 are replies to commands sent during the
192 // initialization sequence.
193 #pragma pack(push, 1)
194 struct UsbInputReport81 {
195 uint8_t subtype;
196 uint8_t data[kMaxInputReportSizeBytes - 2];
197 };
198 #pragma pack(pop)
199 static_assert(sizeof(UsbInputReport81) == kMaxInputReportSizeBytes - 1,
200 "UsbInputReport81 has incorrect size");
201
202 // When connected over USB, the initialization sequence includes a step to
203 // request the MAC address. The MAC is returned in an input report with ID 0x81
204 // and subtype 0x01.
205 #pragma pack(push, 1)
206 struct MacAddressReport {
207 uint8_t subtype; // 0x01
208 uint8_t padding;
209 uint8_t device_type;
210 uint8_t mac_data[6];
211 uint8_t padding2[kMaxInputReportSizeBytes - 10];
212 };
213 #pragma pack(pop)
214 static_assert(sizeof(MacAddressReport) == kMaxInputReportSizeBytes - 1,
215 "MacAddressReport has incorrect size");
216
217 // When configured for standard full input report mode, controller data is
218 // reported at regular intervals. The data format is the same for all Switch
219 // devices, although some buttons are not present on all devices.
220 #pragma pack(push, 1)
221 struct ControllerData {
222 uint8_t timestamp;
223 uint8_t battery_level : 4;
224 uint8_t connection_info : 4;
225 bool button_y : 1;
226 bool button_x : 1;
227 bool button_b : 1;
228 bool button_a : 1;
229 bool button_right_sr : 1;
230 bool button_right_sl : 1;
231 bool button_r : 1;
232 bool button_zr : 1;
233 bool button_minus : 1;
234 bool button_plus : 1;
235 bool button_thumb_r : 1;
236 bool button_thumb_l : 1;
237 bool button_home : 1;
238 bool button_capture : 1;
239 uint8_t dummy : 1;
240 bool charging_grip : 1;
241 bool dpad_down : 1;
242 bool dpad_up : 1;
243 bool dpad_right : 1;
244 bool dpad_left : 1;
245 bool button_left_sr : 1;
246 bool button_left_sl : 1;
247 bool button_l : 1;
248 bool button_zl : 1;
249 uint8_t analog[6];
250 uint8_t vibrator_input_report;
251 };
252 #pragma pack(pop)
253 static_assert(sizeof(ControllerData) == 12,
254 "ControllerData has incorrect size");
255
256 // In standard full input report mode, controller data is reported with IMU data
257 // in reports with ID 0x30.
258 #pragma pack(push, 1)
259 struct ControllerDataReport {
260 ControllerData controller_data; // 12 bytes
261 uint8_t imu_data[36];
262 uint8_t padding[kMaxInputReportSizeBytes - 49];
263 };
264 #pragma pack(pop)
265 static_assert(sizeof(ControllerDataReport) == kMaxInputReportSizeBytes - 1,
266 "ControllerDataReport has incorrect size");
267
268 // Responses to SPI read requests are sent in reports with ID 0x21. These
269 // reports also include controller data.
270 #pragma pack(push, 1)
271 struct SpiReadReport {
272 ControllerData controller_data; // 12 bytes
273 uint8_t subcommand_ack; // 0x90
274 uint8_t subcommand; // 0x10
275 uint8_t addrl;
276 uint8_t addrh;
277 uint8_t padding[2]; // 0x00 0x00
278 uint8_t length;
279 uint8_t spi_data[kMaxInputReportSizeBytes - kSpiDataOffset];
280 };
281 #pragma pack(pop)
282 static_assert(sizeof(SpiReadReport) == kMaxInputReportSizeBytes - 1,
283 "SpiReadReport has incorrect size");
284
285 // Unpack two packed 12-bit values.
UnpackShorts(uint8_t byte0,uint8_t byte1,uint8_t byte2,uint16_t * short1,uint16_t * short2)286 void UnpackShorts(uint8_t byte0,
287 uint8_t byte1,
288 uint8_t byte2,
289 uint16_t* short1,
290 uint16_t* short2) {
291 DCHECK(short1);
292 DCHECK(short2);
293 *short1 = ((byte1 << 8) & 0x0f00) | byte0;
294 *short2 = (byte2 << 4) | (byte1 >> 4);
295 }
296
297 // Unpack a 6-byte MAC address.
UnpackSwitchMacAddress(const uint8_t * data)298 uint64_t UnpackSwitchMacAddress(const uint8_t* data) {
299 DCHECK(data);
300 uint64_t acc = data[5];
301 acc = (acc << 8) | data[4];
302 acc = (acc << 8) | data[3];
303 acc = (acc << 8) | data[2];
304 acc = (acc << 8) | data[1];
305 acc = (acc << 8) | data[0];
306 return acc;
307 }
308
309 // Unpack the analog stick parameters into |cal|.
UnpackSwitchAnalogStickParameters(const uint8_t * data,NintendoController::SwitchCalibrationData & cal)310 void UnpackSwitchAnalogStickParameters(
311 const uint8_t* data,
312 NintendoController::SwitchCalibrationData& cal) {
313 DCHECK(data);
314 // Only fetch the dead zone and range ratio. The other parameters are unknown.
315 UnpackShorts(data[3], data[4], data[5], &cal.dead_zone, &cal.range_ratio);
316 if (cal.dead_zone == kCalBogusValue) {
317 // If the controller reports an invalid dead zone, default to something
318 // reasonable.
319 cal.dead_zone = kCalDefaultDeadzone;
320 }
321 }
322
323 // Unpack the IMU calibration data into |cal|
UnpackSwitchImuCalibration(const uint8_t * data,NintendoController::SwitchCalibrationData & cal)324 void UnpackSwitchImuCalibration(
325 const uint8_t* data,
326 NintendoController::SwitchCalibrationData& cal) {
327 DCHECK(data);
328 // 24 bytes, as 4 groups of 3 16-bit little-endian values.
329 cal.accelerometer_origin_x = (data[1] << 8) | data[0];
330 cal.accelerometer_origin_y = (data[3] << 8) | data[2];
331 cal.accelerometer_origin_z = (data[5] << 8) | data[4];
332 cal.accelerometer_sensitivity_x = (data[7] << 8) | data[6];
333 cal.accelerometer_sensitivity_y = (data[9] << 8) | data[8];
334 cal.accelerometer_sensitivity_z = (data[11] << 8) | data[10];
335 cal.gyro_origin_x = (data[13] << 8) | data[12];
336 cal.gyro_origin_y = (data[15] << 8) | data[14];
337 cal.gyro_origin_z = (data[17] << 8) | data[16];
338 cal.gyro_sensitivity_x = (data[19] << 8) | data[18];
339 cal.gyro_sensitivity_y = (data[21] << 8) | data[20];
340 cal.gyro_sensitivity_z = (data[23] << 8) | data[22];
341 }
342
343 // Unpack the IMU horizontal offsets into |cal|.
UnpackSwitchImuHorizontalOffsets(const uint8_t * data,NintendoController::SwitchCalibrationData & cal)344 void UnpackSwitchImuHorizontalOffsets(
345 const uint8_t* data,
346 NintendoController::SwitchCalibrationData& cal) {
347 DCHECK(data);
348 // 6 bytes, as 3 16-bit little-endian values.
349 cal.horizontal_offset_x = (data[1] << 8) | data[0];
350 cal.horizontal_offset_y = (data[3] << 8) | data[2];
351 cal.horizontal_offset_z = (data[5] << 8) | data[4];
352 }
353
354 // Unpack the analog stick calibration data into |cal|.
UnpackSwitchAnalogStickCalibration(const uint8_t * data,NintendoController::SwitchCalibrationData & cal)355 void UnpackSwitchAnalogStickCalibration(
356 const uint8_t* data,
357 NintendoController::SwitchCalibrationData& cal) {
358 DCHECK(data);
359 // 18 bytes, as 2 groups of 6 packed 12-bit values.
360 UnpackShorts(data[0], data[1], data[2], &cal.lx_max, &cal.ly_max);
361 UnpackShorts(data[3], data[4], data[5], &cal.lx_center, &cal.ly_center);
362 UnpackShorts(data[6], data[7], data[8], &cal.lx_min, &cal.ly_min);
363 UnpackShorts(data[9], data[10], data[11], &cal.rx_center, &cal.ry_center);
364 UnpackShorts(data[12], data[13], data[14], &cal.rx_min, &cal.ry_min);
365 UnpackShorts(data[15], data[16], data[17], &cal.rx_max, &cal.ry_max);
366 if (cal.lx_min == kCalBogusValue && cal.ly_max == kCalBogusValue) {
367 // If the controller reports bogus values, default to something reasonable.
368 cal.lx_min = kCalDefaultMin;
369 cal.lx_center = kCalDefaultCenter;
370 cal.lx_max = kCalDefaultMax;
371 cal.ly_min = kCalDefaultMin;
372 cal.ly_center = kCalDefaultCenter;
373 cal.ly_max = kCalDefaultMax;
374 cal.rx_min = kCalDefaultMin;
375 cal.rx_center = kCalDefaultCenter;
376 cal.rx_max = kCalDefaultMax;
377 cal.ry_min = kCalDefaultMin;
378 cal.ry_center = kCalDefaultCenter;
379 cal.ry_max = kCalDefaultMax;
380 } else {
381 cal.lx_min = cal.lx_center - cal.lx_min;
382 cal.lx_max = cal.lx_center + cal.lx_max;
383 cal.ly_min = cal.ly_center - cal.ly_min;
384 cal.ly_max = cal.ly_center + cal.ly_max;
385 cal.rx_min = cal.rx_center - cal.rx_min;
386 cal.rx_max = cal.rx_center + cal.rx_max;
387 cal.ry_min = cal.ry_center - cal.ry_min;
388 cal.ry_max = cal.ry_center + cal.ry_max;
389 }
390 }
391
392 // Unpack one frame of IMU data into |imu_data|.
UnpackSwitchImuData(const uint8_t * data,NintendoController::SwitchImuData * imu_data)393 void UnpackSwitchImuData(const uint8_t* data,
394 NintendoController::SwitchImuData* imu_data) {
395 DCHECK(data);
396 DCHECK(imu_data);
397 // 12 bytes of IMU data containing 6 16-bit little-endian values.
398 imu_data->accelerometer_x = (data[1] << 8) | data[0];
399 imu_data->accelerometer_y = (data[3] << 8) | data[2];
400 imu_data->accelerometer_z = (data[5] << 8) | data[4];
401 imu_data->gyro_x = (data[7] << 8) | data[6];
402 imu_data->gyro_y = (data[9] << 8) | data[8];
403 imu_data->gyro_z = (data[11] << 8) | data[10];
404 }
405
406 // Given joystick input |x|,|y|, apply a radial deadzone with radius
407 // |dead_zone| centered at |x_center|,|y_center|. If the input is within the
408 // dead zone region, the value is snapped to the center of the dead zone.
ApplyDeadZone(uint16_t & x,uint16_t & y,uint16_t x_center,uint16_t y_center,uint16_t dead_zone)409 bool ApplyDeadZone(uint16_t& x,
410 uint16_t& y,
411 uint16_t x_center,
412 uint16_t y_center,
413 uint16_t dead_zone) {
414 int dx = x - x_center;
415 int dy = y - y_center;
416 if (dx * dx + dy * dy < dead_zone * dead_zone) {
417 x = x_center;
418 y = y_center;
419 return true;
420 }
421 return false;
422 }
423
424 // Normalize |value| to the range [|min|,|max|]. If |value| is outside this
425 // range, clamp it.
NormalizeAndClampAxis(int value,int min,int max)426 double NormalizeAndClampAxis(int value, int min, int max) {
427 if (value <= min)
428 return -1.0;
429 if (value >= max)
430 return 1.0;
431 return (2.0 * (value - min) / static_cast<double>(max - min)) - 1.0;
432 }
433
434 // Update the button and axis state in |pad| with the new controller data in
435 // |data|, using the calibration data |cal|. Returns true if the new data
436 // differs from the previous data.
UpdateGamepadFromControllerData(const ControllerData & data,const NintendoController::SwitchCalibrationData & cal,Gamepad & pad)437 bool UpdateGamepadFromControllerData(
438 const ControllerData& data,
439 const NintendoController::SwitchCalibrationData& cal,
440 Gamepad& pad) {
441 bool buttons_changed =
442 pad.buttons_length != SWITCH_BUTTON_INDEX_COUNT ||
443 pad.buttons[BUTTON_INDEX_PRIMARY].pressed != data.button_b ||
444 pad.buttons[BUTTON_INDEX_SECONDARY].pressed != data.button_a ||
445 pad.buttons[BUTTON_INDEX_TERTIARY].pressed != data.button_y ||
446 pad.buttons[BUTTON_INDEX_QUATERNARY].pressed != data.button_x ||
447 pad.buttons[BUTTON_INDEX_LEFT_SHOULDER].pressed != data.button_l ||
448 pad.buttons[BUTTON_INDEX_RIGHT_SHOULDER].pressed != data.button_r ||
449 pad.buttons[BUTTON_INDEX_LEFT_TRIGGER].pressed != data.button_zl ||
450 pad.buttons[BUTTON_INDEX_RIGHT_TRIGGER].pressed != data.button_zr ||
451 pad.buttons[BUTTON_INDEX_BACK_SELECT].pressed != data.button_minus ||
452 pad.buttons[BUTTON_INDEX_START].pressed != data.button_plus ||
453 pad.buttons[BUTTON_INDEX_LEFT_THUMBSTICK].pressed !=
454 data.button_thumb_l ||
455 pad.buttons[BUTTON_INDEX_RIGHT_THUMBSTICK].pressed !=
456 data.button_thumb_r ||
457 pad.buttons[BUTTON_INDEX_DPAD_UP].pressed != data.dpad_up ||
458 pad.buttons[BUTTON_INDEX_DPAD_DOWN].pressed != data.dpad_down ||
459 pad.buttons[BUTTON_INDEX_DPAD_LEFT].pressed != data.dpad_left ||
460 pad.buttons[BUTTON_INDEX_DPAD_RIGHT].pressed != data.dpad_right ||
461 pad.buttons[BUTTON_INDEX_META].pressed != data.button_home ||
462 pad.buttons[SWITCH_BUTTON_INDEX_CAPTURE].pressed != data.button_capture ||
463 pad.buttons[SWITCH_BUTTON_INDEX_LEFT_SL].pressed != data.button_left_sl ||
464 pad.buttons[SWITCH_BUTTON_INDEX_LEFT_SR].pressed != data.button_left_sr ||
465 pad.buttons[SWITCH_BUTTON_INDEX_RIGHT_SL].pressed !=
466 data.button_right_sl ||
467 pad.buttons[SWITCH_BUTTON_INDEX_RIGHT_SR].pressed != data.button_right_sr;
468
469 if (buttons_changed) {
470 pad.buttons_length = SWITCH_BUTTON_INDEX_COUNT;
471 pad.buttons[BUTTON_INDEX_PRIMARY].pressed = data.button_b;
472 pad.buttons[BUTTON_INDEX_PRIMARY].value = data.button_b ? 1.0 : 0.0;
473 pad.buttons[BUTTON_INDEX_SECONDARY].pressed = data.button_a;
474 pad.buttons[BUTTON_INDEX_SECONDARY].value = data.button_a ? 1.0 : 0.0;
475 pad.buttons[BUTTON_INDEX_TERTIARY].pressed = data.button_y;
476 pad.buttons[BUTTON_INDEX_TERTIARY].value = data.button_y ? 1.0 : 0.0;
477 pad.buttons[BUTTON_INDEX_QUATERNARY].pressed = data.button_x;
478 pad.buttons[BUTTON_INDEX_QUATERNARY].value = data.button_x ? 1.0 : 0.0;
479 pad.buttons[BUTTON_INDEX_LEFT_SHOULDER].pressed = data.button_l;
480 pad.buttons[BUTTON_INDEX_LEFT_SHOULDER].value = data.button_l ? 1.0 : 0.0;
481 pad.buttons[BUTTON_INDEX_RIGHT_SHOULDER].pressed = data.button_r;
482 pad.buttons[BUTTON_INDEX_RIGHT_SHOULDER].value = data.button_r ? 1.0 : 0.0;
483 pad.buttons[BUTTON_INDEX_LEFT_TRIGGER].pressed = data.button_zl;
484 pad.buttons[BUTTON_INDEX_LEFT_TRIGGER].value = data.button_zl ? 1.0 : 0.0;
485 pad.buttons[BUTTON_INDEX_RIGHT_TRIGGER].pressed = data.button_zr;
486 pad.buttons[BUTTON_INDEX_RIGHT_TRIGGER].value = data.button_zr ? 1.0 : 0.0;
487 pad.buttons[BUTTON_INDEX_BACK_SELECT].pressed = data.button_minus;
488 pad.buttons[BUTTON_INDEX_BACK_SELECT].value = data.button_minus ? 1.0 : 0.0;
489 pad.buttons[BUTTON_INDEX_START].pressed = data.button_plus;
490 pad.buttons[BUTTON_INDEX_START].value = data.button_plus ? 1.0 : 0.0;
491 pad.buttons[BUTTON_INDEX_LEFT_THUMBSTICK].pressed = data.button_thumb_l;
492 pad.buttons[BUTTON_INDEX_LEFT_THUMBSTICK].value =
493 data.button_thumb_l ? 1.0 : 0.0;
494 pad.buttons[BUTTON_INDEX_RIGHT_THUMBSTICK].pressed = data.button_thumb_r;
495 pad.buttons[BUTTON_INDEX_RIGHT_THUMBSTICK].value =
496 data.button_thumb_r ? 1.0 : 0.0;
497 pad.buttons[BUTTON_INDEX_DPAD_UP].pressed = data.dpad_up;
498 pad.buttons[BUTTON_INDEX_DPAD_UP].value = data.dpad_up ? 1.0 : 0.0;
499 pad.buttons[BUTTON_INDEX_DPAD_DOWN].pressed = data.dpad_down;
500 pad.buttons[BUTTON_INDEX_DPAD_DOWN].value = data.dpad_down ? 1.0 : 0.0;
501 pad.buttons[BUTTON_INDEX_DPAD_LEFT].pressed = data.dpad_left;
502 pad.buttons[BUTTON_INDEX_DPAD_LEFT].value = data.dpad_left ? 1.0 : 0.0;
503 pad.buttons[BUTTON_INDEX_DPAD_RIGHT].pressed = data.dpad_right;
504 pad.buttons[BUTTON_INDEX_DPAD_RIGHT].value = data.dpad_right ? 1.0 : 0.0;
505 pad.buttons[BUTTON_INDEX_META].pressed = data.button_home;
506 pad.buttons[BUTTON_INDEX_META].value = data.button_home ? 1.0 : 0.0;
507 pad.buttons[SWITCH_BUTTON_INDEX_CAPTURE].pressed = data.button_capture;
508 pad.buttons[SWITCH_BUTTON_INDEX_CAPTURE].value =
509 data.button_capture ? 1.0 : 0.0;
510 pad.buttons[SWITCH_BUTTON_INDEX_LEFT_SL].pressed = data.button_left_sl;
511 pad.buttons[SWITCH_BUTTON_INDEX_LEFT_SL].value =
512 data.button_left_sl ? 1.0 : 0.0;
513 pad.buttons[SWITCH_BUTTON_INDEX_LEFT_SR].pressed = data.button_left_sr;
514 pad.buttons[SWITCH_BUTTON_INDEX_LEFT_SR].value =
515 data.button_left_sr ? 1.0 : 0.0;
516 pad.buttons[SWITCH_BUTTON_INDEX_RIGHT_SL].pressed = data.button_right_sl;
517 pad.buttons[SWITCH_BUTTON_INDEX_RIGHT_SL].value =
518 data.button_right_sl ? 1.0 : 0.0;
519 pad.buttons[SWITCH_BUTTON_INDEX_RIGHT_SR].pressed = data.button_right_sr;
520 pad.buttons[SWITCH_BUTTON_INDEX_RIGHT_SR].value =
521 data.button_right_sr ? 1.0 : 0.0;
522 }
523
524 uint16_t axis_lx;
525 uint16_t axis_ly;
526 uint16_t axis_rx;
527 uint16_t axis_ry;
528 UnpackShorts(data.analog[0], data.analog[1], data.analog[2], &axis_lx,
529 &axis_ly);
530 UnpackShorts(data.analog[3], data.analog[4], data.analog[5], &axis_rx,
531 &axis_ry);
532 // Apply a radial dead zone to both sticks.
533 bool ldead = ApplyDeadZone(axis_lx, axis_ly, cal.lx_center, cal.ly_center,
534 cal.dead_zone);
535 bool rdead = ApplyDeadZone(axis_rx, axis_ry, cal.rx_center, cal.ry_center,
536 cal.dead_zone);
537 // Normalize using calibration data.
538 double lx =
539 ldead ? 0.0 : NormalizeAndClampAxis(axis_lx, cal.lx_min, cal.lx_max);
540 double ly =
541 ldead ? 0.0 : -NormalizeAndClampAxis(axis_ly, cal.ly_min, cal.ly_max);
542 double rx =
543 rdead ? 0.0 : NormalizeAndClampAxis(axis_rx, cal.rx_min, cal.rx_max);
544 double ry =
545 rdead ? 0.0 : -NormalizeAndClampAxis(axis_ry, cal.ry_min, cal.ry_max);
546 bool axes_changed = pad.axes_length != AXIS_INDEX_COUNT ||
547 pad.axes[device::AXIS_INDEX_LEFT_STICK_X] != lx ||
548 pad.axes[device::AXIS_INDEX_LEFT_STICK_Y] != ly ||
549 pad.axes[device::AXIS_INDEX_RIGHT_STICK_X] != rx ||
550 pad.axes[device::AXIS_INDEX_RIGHT_STICK_Y] != ry;
551 if (axes_changed) {
552 pad.axes_length = AXIS_INDEX_COUNT;
553 pad.axes[device::AXIS_INDEX_LEFT_STICK_X] = lx;
554 pad.axes[device::AXIS_INDEX_LEFT_STICK_Y] = ly;
555 pad.axes[device::AXIS_INDEX_RIGHT_STICK_X] = rx;
556 pad.axes[device::AXIS_INDEX_RIGHT_STICK_Y] = ry;
557 }
558
559 return buttons_changed || axes_changed;
560 }
561
562 // Update the state for a single button. The button state is taken from
563 // the button at index |button_index| in |src_pad|. If this is a composite
564 // device, |src_pad| holds the state for the left component. If |horizontal| is
565 // true, the button index is remapped for horizontal orientation before updating
566 // the state in |dst_pad|.
UpdateButtonForLeftSide(const Gamepad & src_pad,Gamepad & dst_pad,size_t button_index,bool horizontal)567 void UpdateButtonForLeftSide(const Gamepad& src_pad,
568 Gamepad& dst_pad,
569 size_t button_index,
570 bool horizontal) {
571 size_t remapped_index = button_index;
572 // The internal button mapping assumes a docked orientation for Joy-Cons. If
573 // a Joy-Con is used by itself, remap the buttons so they match the Standard
574 // Gamepad spec when held horizontally.
575 if (horizontal) {
576 switch (button_index) {
577 // Map the D-pad buttons to action buttons.
578 case BUTTON_INDEX_DPAD_LEFT:
579 remapped_index = BUTTON_INDEX_PRIMARY;
580 break;
581 case BUTTON_INDEX_DPAD_DOWN:
582 remapped_index = BUTTON_INDEX_SECONDARY;
583 break;
584 case BUTTON_INDEX_DPAD_UP:
585 remapped_index = BUTTON_INDEX_TERTIARY;
586 break;
587 case BUTTON_INDEX_DPAD_RIGHT:
588 remapped_index = BUTTON_INDEX_QUATERNARY;
589 break;
590 // Map L to Select.
591 case BUTTON_INDEX_LEFT_SHOULDER:
592 remapped_index = BUTTON_INDEX_BACK_SELECT;
593 break;
594 // Map Minus to Start.
595 case BUTTON_INDEX_BACK_SELECT:
596 remapped_index = BUTTON_INDEX_START;
597 break;
598 // Map Capture to Meta.
599 case SWITCH_BUTTON_INDEX_CAPTURE:
600 remapped_index = BUTTON_INDEX_META;
601 break;
602 // Map SL and SR to the left and right shoulders.
603 case SWITCH_BUTTON_INDEX_LEFT_SL:
604 remapped_index = BUTTON_INDEX_LEFT_SHOULDER;
605 break;
606 case SWITCH_BUTTON_INDEX_LEFT_SR:
607 remapped_index = BUTTON_INDEX_RIGHT_SHOULDER;
608 break;
609 // ZL and the left thumbstick are unmodified.
610 case BUTTON_INDEX_LEFT_TRIGGER:
611 case BUTTON_INDEX_LEFT_THUMBSTICK:
612 break;
613 default:
614 NOTREACHED();
615 break;
616 }
617 }
618 dst_pad.buttons[remapped_index] = src_pad.buttons[button_index];
619 }
620
621 // Update the state for a single button. The button state is taken from
622 // the button at index |button_index| in |src_pad|. If this is a composite
623 // device, |src_pad| holds the state for the right component. If |horizontal| is
624 // true, the button index is remapped for horizontal orientation before updating
625 // the state in |dst_pad|.
UpdateButtonForRightSide(const Gamepad & src_pad,Gamepad & dst_pad,size_t button_index,bool horizontal)626 void UpdateButtonForRightSide(const Gamepad& src_pad,
627 Gamepad& dst_pad,
628 size_t button_index,
629 bool horizontal) {
630 size_t remapped_index = button_index;
631 // The internal button mapping assumes a docked orientation for Joy-Cons. If
632 // a Joy-Con is used by itself, remap the buttons so they match the Standard
633 // Gamepad spec when held horizontally.
634 if (horizontal) {
635 switch (button_index) {
636 // Re-map the action buttons to rotate them.
637 case BUTTON_INDEX_PRIMARY:
638 remapped_index = BUTTON_INDEX_TERTIARY;
639 break;
640 case BUTTON_INDEX_TERTIARY:
641 remapped_index = BUTTON_INDEX_QUATERNARY;
642 break;
643 case BUTTON_INDEX_QUATERNARY:
644 remapped_index = BUTTON_INDEX_SECONDARY;
645 break;
646 case BUTTON_INDEX_SECONDARY:
647 remapped_index = BUTTON_INDEX_PRIMARY;
648 break;
649 // Map R to Select.
650 case BUTTON_INDEX_RIGHT_SHOULDER:
651 remapped_index = BUTTON_INDEX_BACK_SELECT;
652 break;
653 // Map SL and SR to the left and right shoulders.
654 case SWITCH_BUTTON_INDEX_RIGHT_SL:
655 remapped_index = BUTTON_INDEX_LEFT_SHOULDER;
656 break;
657 case SWITCH_BUTTON_INDEX_RIGHT_SR:
658 remapped_index = BUTTON_INDEX_RIGHT_SHOULDER;
659 break;
660 // Map right thumbstick button to left thumbstick button.
661 case BUTTON_INDEX_RIGHT_THUMBSTICK:
662 remapped_index = BUTTON_INDEX_LEFT_THUMBSTICK;
663 break;
664 // The Plus, Home, and ZR buttons are unmodified.
665 case BUTTON_INDEX_START:
666 case BUTTON_INDEX_META:
667 case BUTTON_INDEX_RIGHT_TRIGGER:
668 break;
669 default:
670 NOTREACHED();
671 break;
672 }
673 }
674 dst_pad.buttons[remapped_index] = src_pad.buttons[button_index];
675 }
676
677 // Update the state for a single axis. The axis state is taken from the axis at
678 // index |axis_index| in |src_pad|. If this is a composite device, |src_pad|
679 // holds the state for the left component. If |horizontal| is true, the axis
680 // index and value are remapped for horizontal orientation before updating the
681 // state in |dst_pad|.
UpdateAxisForLeftSide(const Gamepad & src_pad,Gamepad & dst_pad,size_t axis_index,bool horizontal)682 void UpdateAxisForLeftSide(const Gamepad& src_pad,
683 Gamepad& dst_pad,
684 size_t axis_index,
685 bool horizontal) {
686 size_t remapped_index = axis_index;
687 double axis_value = src_pad.axes[axis_index];
688 // The internal axis values assume a docked orientation for Joy-Cons. If a
689 // Joy-Con is used by itself, remap the axis indices and adjust the sign on
690 // the axis value for a horizontal orientation.
691 if (horizontal) {
692 switch (axis_index) {
693 case AXIS_INDEX_LEFT_STICK_X:
694 // Map +X to -Y.
695 axis_value = -axis_value;
696 remapped_index = AXIS_INDEX_LEFT_STICK_Y;
697 break;
698 case AXIS_INDEX_LEFT_STICK_Y:
699 // Map +Y to +X.
700 remapped_index = AXIS_INDEX_LEFT_STICK_X;
701 break;
702 default:
703 NOTREACHED();
704 break;
705 }
706 }
707 dst_pad.axes[remapped_index] = axis_value;
708 }
709
710 // Update the state for a single axis. The axis state is taken from the axis at
711 // index |axis_index| in |src_pad|. If this is a composite device, |src_pad|
712 // holds the state for the right component. If |horizontal| is true, the axis
713 // index and value are remapped for horizontal orientation before updating the
714 // state in |dst_pad|.
UpdateAxisForRightSide(const Gamepad & src_pad,Gamepad & dst_pad,size_t axis_index,bool horizontal)715 void UpdateAxisForRightSide(const Gamepad& src_pad,
716 Gamepad& dst_pad,
717 size_t axis_index,
718 bool horizontal) {
719 size_t remapped_index = axis_index;
720 double axis_value = src_pad.axes[axis_index];
721 // The internal axis values assume a docked orientation for Joy-Cons. If a
722 // Joy-Con is used by itself, remap the axis indices and adjust the sign on
723 // the axis value for a horizontal orientation.
724 if (horizontal) {
725 switch (axis_index) {
726 case AXIS_INDEX_RIGHT_STICK_X:
727 // Map +X to +Y.
728 remapped_index = AXIS_INDEX_LEFT_STICK_Y;
729 break;
730 case AXIS_INDEX_RIGHT_STICK_Y:
731 // Map +Y to -X.
732 axis_value = -axis_value;
733 remapped_index = AXIS_INDEX_LEFT_STICK_X;
734 break;
735 default:
736 NOTREACHED();
737 break;
738 }
739 }
740 dst_pad.axes[remapped_index] = axis_value;
741 }
742
743 // Convert the vibration parameters |frequency| and |amplitude| into a set of
744 // parameters that can be sent to the vibration actuator.
FrequencyToHex(float frequency,float amplitude,uint16_t * hf,uint8_t * lf,uint8_t * hf_amp,uint16_t * lf_amp)745 void FrequencyToHex(float frequency,
746 float amplitude,
747 uint16_t* hf,
748 uint8_t* lf,
749 uint8_t* hf_amp,
750 uint16_t* lf_amp) {
751 int freq = static_cast<int>(frequency);
752 int amp = static_cast<int>(amplitude * kVibrationAmplitudeMax);
753 // Clamp the target frequency and amplitude to a safe range.
754 freq = base::ClampToRange(freq, kVibrationFrequencyHzMin,
755 kVibrationFrequencyHzMax);
756 amp = base::ClampToRange(amp, 0, kVibrationAmplitudeMax);
757 const auto* best_vf = &kVibrationFrequency[0];
758 for (size_t i = 1; i < kVibrationFrequencySize; ++i) {
759 const auto* vf = &kVibrationFrequency[i];
760 if (vf->freq_hz < freq) {
761 best_vf = vf;
762 } else {
763 // The candidate frequency is higher than the target frequency. Check if
764 // it is closer than the current best.
765 int vf_error_above = vf->freq_hz - freq;
766 int best_vf_error_below = freq - best_vf->freq_hz;
767 if (vf_error_above < best_vf_error_below)
768 best_vf = vf;
769 break;
770 }
771 }
772 const auto* best_va = &kVibrationAmplitude[0];
773 for (size_t i = 0; i < kVibrationAmplitudeSize; ++i) {
774 const auto* va = &kVibrationAmplitude[i];
775 if (va->amp < amp) {
776 best_va = va;
777 } else {
778 // The candidate amplitude is higher than the target amplitude. Check if
779 // it is closer than the current best.
780 int va_error_above = va->amp - amp;
781 int best_va_error_below = amp - best_va->amp;
782 if (va_error_above < best_va_error_below)
783 best_va = va;
784 break;
785 }
786 }
787 DCHECK(best_vf);
788 DCHECK(best_va);
789 *hf = best_vf->hf;
790 *lf = best_vf->lf;
791 *hf_amp = best_va->hfa;
792 *lf_amp = best_va->lfa;
793 }
794
795 // Return the bus type of the Switch device described by |device_info|. This is
796 // needed for Windows which does not report the bus type in the HID API.
BusTypeFromDeviceInfo(const mojom::HidDeviceInfo * device_info)797 GamepadBusType BusTypeFromDeviceInfo(const mojom::HidDeviceInfo* device_info) {
798 DCHECK(device_info);
799 // If the |device_info| indicates the device is connected over Bluetooth, it's
800 // probably right. On some platforms the bus type is reported as USB
801 // regardless of the actual connection.
802 if (device_info->bus_type == mojom::HidBusType::kHIDBusTypeBluetooth)
803 return GAMEPAD_BUS_BLUETOOTH;
804 auto gamepad_id = GamepadIdList::Get().GetGamepadId(device_info->product_name,
805 device_info->vendor_id,
806 device_info->product_id);
807 switch (gamepad_id) {
808 case GamepadId::kNintendoProduct2009:
809 // The Switch Pro Controller may be connected over USB or Bluetooth.
810 // Determine which connection is in use by comparing the max output report
811 // size against known values.
812 switch (device_info->max_output_report_size) {
813 case kSwitchProMaxOutputReportSizeBytesUsb:
814 return GAMEPAD_BUS_USB;
815 case kSwitchProMaxOutputReportSizeBytesBluetooth:
816 return GAMEPAD_BUS_BLUETOOTH;
817 default:
818 break;
819 }
820 break;
821 case GamepadId::kNintendoProduct200e:
822 // The Charging Grip can only be connected over USB.
823 return GAMEPAD_BUS_USB;
824 case GamepadId::kNintendoProduct2006:
825 case GamepadId::kNintendoProduct2007:
826 // Joy Cons can only be connected over Bluetooth. When connected through
827 // a Charging Grip, the grip's ID is reported instead.
828 return GAMEPAD_BUS_BLUETOOTH;
829 case GamepadId::kPowerALicPro:
830 // The PowerA controller can only be connected over Bluetooth.
831 return GAMEPAD_BUS_BLUETOOTH;
832 default:
833 break;
834 }
835 NOTREACHED();
836 return GAMEPAD_BUS_UNKNOWN;
837 }
838 } // namespace
839
840 NintendoController::SwitchCalibrationData::SwitchCalibrationData() = default;
841 NintendoController::SwitchCalibrationData::~SwitchCalibrationData() = default;
842
843 NintendoController::SwitchImuData::SwitchImuData() = default;
844 NintendoController::SwitchImuData::~SwitchImuData() = default;
845
NintendoController(int source_id,mojom::HidDeviceInfoPtr device_info,mojom::HidManager * hid_manager)846 NintendoController::NintendoController(int source_id,
847 mojom::HidDeviceInfoPtr device_info,
848 mojom::HidManager* hid_manager)
849 : source_id_(source_id),
850 is_composite_(false),
851 bus_type_(GAMEPAD_BUS_UNKNOWN),
852 output_report_size_bytes_(0),
853 device_info_(std::move(device_info)),
854 hid_manager_(hid_manager) {
855 if (device_info_) {
856 bus_type_ = BusTypeFromDeviceInfo(device_info_.get());
857 output_report_size_bytes_ = device_info_->max_output_report_size;
858 gamepad_id_ = GamepadIdList::Get().GetGamepadId(device_info_->product_name,
859 device_info_->vendor_id,
860 device_info_->product_id);
861 } else {
862 gamepad_id_ = GamepadId::kUnknownGamepad;
863 }
864 }
865
NintendoController(int source_id,std::unique_ptr<NintendoController> composite1,std::unique_ptr<NintendoController> composite2,mojom::HidManager * hid_manager)866 NintendoController::NintendoController(
867 int source_id,
868 std::unique_ptr<NintendoController> composite1,
869 std::unique_ptr<NintendoController> composite2,
870 mojom::HidManager* hid_manager)
871 : source_id_(source_id), is_composite_(true), hid_manager_(hid_manager) {
872 // Require exactly one left component and one right component, but allow them
873 // to be provided in either order.
874 DCHECK(composite1);
875 DCHECK(composite2);
876 composite_left_ = std::move(composite1);
877 composite_right_ = std::move(composite2);
878 if (composite_left_->GetGamepadHand() != GamepadHand::kLeft)
879 composite_left_.swap(composite_right_);
880 DCHECK_EQ(composite_left_->GetGamepadHand(), GamepadHand::kLeft);
881 DCHECK_EQ(composite_right_->GetGamepadHand(), GamepadHand::kRight);
882 DCHECK_EQ(composite_left_->GetBusType(), composite_right_->GetBusType());
883 bus_type_ = composite_left_->GetBusType();
884 }
885
886 NintendoController::~NintendoController() = default;
887
888 // static
Create(int source_id,mojom::HidDeviceInfoPtr device_info,mojom::HidManager * hid_manager)889 std::unique_ptr<NintendoController> NintendoController::Create(
890 int source_id,
891 mojom::HidDeviceInfoPtr device_info,
892 mojom::HidManager* hid_manager) {
893 return std::make_unique<NintendoController>(source_id, std::move(device_info),
894 hid_manager);
895 }
896
897 // static
CreateComposite(int source_id,std::unique_ptr<NintendoController> composite1,std::unique_ptr<NintendoController> composite2,mojom::HidManager * hid_manager)898 std::unique_ptr<NintendoController> NintendoController::CreateComposite(
899 int source_id,
900 std::unique_ptr<NintendoController> composite1,
901 std::unique_ptr<NintendoController> composite2,
902 mojom::HidManager* hid_manager) {
903 return std::make_unique<NintendoController>(
904 source_id, std::move(composite1), std::move(composite2), hid_manager);
905 }
906
907 // static
IsNintendoController(GamepadId gamepad_id)908 bool NintendoController::IsNintendoController(GamepadId gamepad_id) {
909 switch (gamepad_id) {
910 case GamepadId::kNintendoProduct2006:
911 case GamepadId::kNintendoProduct2007:
912 case GamepadId::kNintendoProduct2009:
913 case GamepadId::kNintendoProduct200e:
914 case GamepadId::kPowerALicPro:
915 return true;
916 default:
917 break;
918 }
919 return false;
920 }
921
922 std::vector<std::unique_ptr<NintendoController>>
Decompose()923 NintendoController::Decompose() {
924 // Stop any ongoing vibration effects before decomposing the device.
925 SetZeroVibration();
926
927 std::vector<std::unique_ptr<NintendoController>> decomposed_devices;
928 if (composite_left_)
929 decomposed_devices.push_back(std::move(composite_left_));
930 if (composite_right_)
931 decomposed_devices.push_back(std::move(composite_right_));
932 return decomposed_devices;
933 }
934
Open(base::OnceClosure device_ready_closure)935 void NintendoController::Open(base::OnceClosure device_ready_closure) {
936 device_ready_closure_ = std::move(device_ready_closure);
937 if (is_composite_) {
938 StartInitSequence();
939 } else {
940 GamepadId gamepad_id = GamepadIdList::Get().GetGamepadId(
941 device_info_->product_name, device_info_->vendor_id,
942 device_info_->product_id);
943 if (IsNintendoController(gamepad_id)) {
944 Connect(base::BindOnce(&NintendoController::OnConnect,
945 weak_factory_.GetWeakPtr()));
946 }
947 }
948 }
949
GetGamepadHand() const950 GamepadHand NintendoController::GetGamepadHand() const {
951 if (is_composite_)
952 return GamepadHand::kNone;
953 switch (gamepad_id_) {
954 case GamepadId::kNintendoProduct2009:
955 case GamepadId::kPowerALicPro:
956 // Switch Pro and PowerA are held in both hands.
957 return GamepadHand::kNone;
958 case GamepadId::kNintendoProduct2006:
959 // Joy-Con L is held in the left hand.
960 return GamepadHand::kLeft;
961 case GamepadId::kNintendoProduct2007:
962 // Joy-Con R is held in the right hand.
963 return GamepadHand::kRight;
964 case GamepadId::kNintendoProduct200e:
965 // Refer to |usb_device_type_| to determine the handedness of Joy-Cons
966 // connected to a Charging Grip.
967 if (state_ == kInitialized) {
968 switch (usb_device_type_) {
969 case kUsbDeviceTypeChargingGripJoyConL:
970 return GamepadHand::kLeft;
971 case kUsbDeviceTypeChargingGripJoyConR:
972 return GamepadHand::kRight;
973 case kUsbDeviceTypeChargingGripNoDevice:
974 case kUsbDeviceTypeProController:
975 return GamepadHand::kNone;
976 default:
977 break;
978 }
979 } else {
980 return GamepadHand::kNone;
981 }
982 break;
983 default:
984 break;
985 }
986 NOTREACHED();
987 return GamepadHand::kNone;
988 }
989
IsUsable() const990 bool NintendoController::IsUsable() const {
991 if (state_ != kInitialized)
992 return false;
993 if (is_composite_)
994 return composite_left_ && composite_right_;
995 switch (gamepad_id_) {
996 case GamepadId::kNintendoProduct2009:
997 case GamepadId::kNintendoProduct2006:
998 case GamepadId::kNintendoProduct2007:
999 case GamepadId::kPowerALicPro:
1000 return true;
1001 case GamepadId::kNintendoProduct200e:
1002 // Only usable as a composite device.
1003 return false;
1004 default:
1005 break;
1006 }
1007 NOTREACHED();
1008 return false;
1009 }
1010
HasGuid(const std::string & guid) const1011 bool NintendoController::HasGuid(const std::string& guid) const {
1012 if (is_composite_) {
1013 DCHECK(composite_left_);
1014 DCHECK(composite_right_);
1015 return composite_left_->HasGuid(guid) || composite_right_->HasGuid(guid);
1016 }
1017 return device_info_->guid == guid;
1018 }
1019
GetMappingFunction() const1020 GamepadStandardMappingFunction NintendoController::GetMappingFunction() const {
1021 if (is_composite_) {
1022 // In composite mode, we use the same mapping as the Charging Grip.
1023 return GetGamepadStandardMappingFunction(
1024 kProductNameSwitchCompositeDevice, kVendorNintendo,
1025 kProductSwitchChargingGrip,
1026 /*hid_specification_version=*/0, /*version_number=*/0, bus_type_);
1027 } else {
1028 return GetGamepadStandardMappingFunction(
1029 device_info_->product_name, device_info_->vendor_id,
1030 device_info_->product_id,
1031
1032 /*hid_specification_version=*/0, /*version_number=*/0, bus_type_);
1033 }
1034 }
1035
InitializeGamepadState(bool has_standard_mapping,Gamepad & pad) const1036 void NintendoController::InitializeGamepadState(bool has_standard_mapping,
1037 Gamepad& pad) const {
1038 pad.buttons_length = SWITCH_BUTTON_INDEX_COUNT;
1039 pad.axes_length = device::AXIS_INDEX_COUNT;
1040 if (gamepad_id_ == GamepadId::kPowerALicPro) {
1041 pad.vibration_actuator.not_null = false;
1042 } else {
1043 pad.vibration_actuator.type = GamepadHapticActuatorType::kDualRumble;
1044 pad.vibration_actuator.not_null = true;
1045 }
1046 pad.timestamp = GamepadDataFetcher::CurrentTimeInMicroseconds();
1047 if (is_composite_) {
1048 // Composite devices use the same product ID as the Switch Charging Grip.
1049 GamepadDataFetcher::UpdateGamepadStrings(
1050 kProductNameSwitchCompositeDevice, kVendorNintendo,
1051 kProductSwitchChargingGrip, has_standard_mapping, pad);
1052 } else {
1053 GamepadDataFetcher::UpdateGamepadStrings(
1054 device_info_->product_name, device_info_->vendor_id,
1055 device_info_->product_id, has_standard_mapping, pad);
1056 }
1057 }
1058
UpdatePadConnected()1059 void NintendoController::UpdatePadConnected() {
1060 if (is_composite_) {
1061 // Composite devices are always connected.
1062 pad_.connected = true;
1063 return;
1064 }
1065
1066 if (gamepad_id_ == GamepadId::kNintendoProduct200e &&
1067 usb_device_type_ == kUsbDeviceTypeChargingGripNoDevice) {
1068 // If the Charging Grip reports that no Joy-Con is docked, mark the gamepad
1069 // disconnected.
1070 pad_.connected = false;
1071 return;
1072 }
1073
1074 // All other devices are considered connected after completing initialization.
1075 pad_.connected = (state_ == kInitialized);
1076 }
1077
UpdateGamepadState(Gamepad & pad) const1078 void NintendoController::UpdateGamepadState(Gamepad& pad) const {
1079 if (is_composite_) {
1080 DCHECK(composite_left_);
1081 DCHECK(composite_right_);
1082 // If this is a composite device, update the gamepad state using the state
1083 // of the subcomponents.
1084 pad.connected = true;
1085 composite_left_->UpdateLeftGamepadState(pad, false);
1086 composite_right_->UpdateRightGamepadState(pad, false);
1087 } else {
1088 switch (GetGamepadHand()) {
1089 case GamepadHand::kLeft:
1090 // Update state for a Joy-Con L, remapping buttons and axes to match the
1091 // Standard Gamepad when the device is held horizontally.
1092 UpdateLeftGamepadState(pad, true);
1093 break;
1094 case GamepadHand::kRight:
1095 // Update state for a Joy-Con R, remapping buttons and axes to match the
1096 // Standard Gamepad when the device is held horizontally.
1097 UpdateRightGamepadState(pad, true);
1098 break;
1099 case GamepadHand::kNone:
1100 // Update state for a Pro Controller.
1101 UpdateLeftGamepadState(pad, false);
1102 UpdateRightGamepadState(pad, false);
1103 break;
1104 default:
1105 NOTREACHED();
1106 break;
1107 }
1108 pad.connected = pad_.connected;
1109 }
1110 }
1111
UpdateLeftGamepadState(Gamepad & pad,bool horizontal) const1112 void NintendoController::UpdateLeftGamepadState(Gamepad& pad,
1113 bool horizontal) const {
1114 // Buttons associated with the left Joy-Con.
1115 const size_t kLeftButtonIndices[] = {
1116 BUTTON_INDEX_LEFT_SHOULDER, // ZL button
1117 BUTTON_INDEX_LEFT_TRIGGER, // L button
1118 BUTTON_INDEX_BACK_SELECT, // - button
1119 BUTTON_INDEX_LEFT_THUMBSTICK,
1120 BUTTON_INDEX_DPAD_UP, // D-pad directions for the composite gamepad
1121 BUTTON_INDEX_DPAD_DOWN, // assume the Joy-Con is held in the vertical
1122 BUTTON_INDEX_DPAD_LEFT, // orientation or is attached to a grip.
1123 BUTTON_INDEX_DPAD_RIGHT, SWITCH_BUTTON_INDEX_CAPTURE,
1124 SWITCH_BUTTON_INDEX_LEFT_SL, SWITCH_BUTTON_INDEX_LEFT_SR,
1125 };
1126 const size_t kLeftButtonIndicesSize = base::size(kLeftButtonIndices);
1127
1128 // Axes associated with the left Joy-Con thumbstick.
1129 const size_t kLeftAxisIndices[] = {
1130 AXIS_INDEX_LEFT_STICK_X, // Axes assume the Joy-Con is held vertically
1131 AXIS_INDEX_LEFT_STICK_Y, // or is attached to a grip.
1132 };
1133 const size_t kLeftAxisIndicesSize = base::size(kLeftAxisIndices);
1134
1135 if (pad_.buttons_length == SWITCH_BUTTON_INDEX_COUNT) {
1136 for (size_t i = 0; i < kLeftButtonIndicesSize; ++i)
1137 UpdateButtonForLeftSide(pad_, pad, kLeftButtonIndices[i], horizontal);
1138 }
1139 if (pad_.axes_length == AXIS_INDEX_COUNT) {
1140 for (size_t i = 0; i < kLeftAxisIndicesSize; ++i)
1141 UpdateAxisForLeftSide(pad_, pad, kLeftAxisIndices[i], horizontal);
1142 }
1143 pad.timestamp = std::max(pad.timestamp, pad_.timestamp);
1144 if (!pad_.connected)
1145 pad.connected = false;
1146 }
1147
UpdateRightGamepadState(Gamepad & pad,bool horizontal) const1148 void NintendoController::UpdateRightGamepadState(Gamepad& pad,
1149 bool horizontal) const {
1150 // Buttons associated with the right Joy-Con.
1151 const size_t kRightButtonIndices[]{
1152 BUTTON_INDEX_PRIMARY, // B button
1153 BUTTON_INDEX_SECONDARY, // A button
1154 BUTTON_INDEX_TERTIARY, // Y button
1155 BUTTON_INDEX_QUATERNARY, // X button
1156 BUTTON_INDEX_RIGHT_SHOULDER, // R button
1157 BUTTON_INDEX_RIGHT_TRIGGER, // ZR button
1158 BUTTON_INDEX_START, // + button
1159 BUTTON_INDEX_RIGHT_THUMBSTICK,
1160 BUTTON_INDEX_META, // Home button
1161 SWITCH_BUTTON_INDEX_RIGHT_SL,
1162 SWITCH_BUTTON_INDEX_RIGHT_SR,
1163 };
1164 const size_t kRightButtonIndicesSize = base::size(kRightButtonIndices);
1165
1166 // Axes associated with the right Joy-Con thumbstick.
1167 const size_t kRightAxisIndices[] = {
1168 AXIS_INDEX_RIGHT_STICK_X, // Axes assume the Joy-Con is held vertically
1169 AXIS_INDEX_RIGHT_STICK_Y, // or is attached to a grip.
1170 };
1171 const size_t kRightAxisIndicesSize = base::size(kRightAxisIndices);
1172
1173 if (pad_.buttons_length == SWITCH_BUTTON_INDEX_COUNT) {
1174 for (size_t i = 0; i < kRightButtonIndicesSize; ++i)
1175 UpdateButtonForRightSide(pad_, pad, kRightButtonIndices[i], horizontal);
1176 }
1177 if (pad_.axes_length == AXIS_INDEX_COUNT) {
1178 for (size_t i = 0; i < kRightAxisIndicesSize; ++i)
1179 UpdateAxisForRightSide(pad_, pad, kRightAxisIndices[i], horizontal);
1180 }
1181 pad.timestamp = std::max(pad.timestamp, pad_.timestamp);
1182 if (!pad_.connected)
1183 pad.connected = false;
1184 }
1185
Connect(mojom::HidManager::ConnectCallback callback)1186 void NintendoController::Connect(mojom::HidManager::ConnectCallback callback) {
1187 DCHECK(!is_composite_);
1188 DCHECK(hid_manager_);
1189 hid_manager_->Connect(device_info_->guid,
1190 /*connection_client=*/mojo::NullRemote(),
1191 /*watcher=*/mojo::NullRemote(), std::move(callback));
1192 }
1193
OnConnect(mojo::PendingRemote<mojom::HidConnection> connection)1194 void NintendoController::OnConnect(
1195 mojo::PendingRemote<mojom::HidConnection> connection) {
1196 if (connection) {
1197 connection_.Bind(std::move(connection));
1198 ReadInputReport();
1199 StartInitSequence();
1200 }
1201 }
1202
StartInitSequence()1203 void NintendoController::StartInitSequence() {
1204 if (is_composite_) {
1205 if (composite_left_ && composite_left_->IsOpen() && composite_right_ &&
1206 composite_right_->IsOpen()) {
1207 DCHECK_EQ(composite_left_->GetGamepadHand(), GamepadHand::kLeft);
1208 DCHECK_EQ(composite_right_->GetGamepadHand(), GamepadHand::kRight);
1209 FinishInitSequence();
1210 } else {
1211 FailInitSequence();
1212 }
1213 return;
1214 }
1215
1216 switch (bus_type_) {
1217 case GAMEPAD_BUS_USB:
1218 DCHECK(timeout_callback_.IsCancelled());
1219 MakeInitSequenceRequests(kPendingMacAddress);
1220 break;
1221 case GAMEPAD_BUS_BLUETOOTH:
1222 DCHECK(timeout_callback_.IsCancelled());
1223 MakeInitSequenceRequests(kPendingSetPlayerLights);
1224 break;
1225 default:
1226 NOTREACHED();
1227 break;
1228 }
1229 }
1230
FinishInitSequence()1231 void NintendoController::FinishInitSequence() {
1232 state_ = kInitialized;
1233 UpdatePadConnected();
1234 if (device_ready_closure_)
1235 std::move(device_ready_closure_).Run();
1236 }
1237
FailInitSequence()1238 void NintendoController::FailInitSequence() {
1239 state_ = kUninitialized;
1240 UpdatePadConnected();
1241 }
1242
HandleInputReport(uint8_t report_id,const std::vector<uint8_t> & report_bytes)1243 void NintendoController::HandleInputReport(
1244 uint8_t report_id,
1245 const std::vector<uint8_t>& report_bytes) {
1246 // Register to receive the next input report.
1247 ReadInputReport();
1248
1249 // Listen for reports related to the initialization sequence or gamepad state.
1250 // Other reports are ignored.
1251 if (bus_type_ == GAMEPAD_BUS_USB && report_id == kUsbReportIdInput81)
1252 HandleUsbInputReport81(report_bytes);
1253 else if (report_id == kReportIdInput21)
1254 HandleInputReport21(report_bytes);
1255 else if (report_id == kReportIdInput30)
1256 HandleInputReport30(report_bytes);
1257
1258 // Check whether the input report should cause us to transition to the next
1259 // initialization step.
1260 if (state_ != kInitialized && state_ != kUninitialized)
1261 ContinueInitSequence(report_id, report_bytes);
1262 }
1263
HandleUsbInputReport81(const std::vector<uint8_t> & report_bytes)1264 void NintendoController::HandleUsbInputReport81(
1265 const std::vector<uint8_t>& report_bytes) {
1266 const auto* ack_report =
1267 reinterpret_cast<const UsbInputReport81*>(report_bytes.data());
1268 switch (ack_report->subtype) {
1269 case kSubTypeRequestMac: {
1270 const auto* mac_report =
1271 reinterpret_cast<const MacAddressReport*>(report_bytes.data());
1272 mac_address_ = UnpackSwitchMacAddress(mac_report->mac_data);
1273 if (usb_device_type_ != mac_report->device_type) {
1274 usb_device_type_ = mac_report->device_type;
1275 switch (usb_device_type_) {
1276 case kUsbDeviceTypeChargingGripNoDevice:
1277 UpdatePadConnected();
1278 // If this was received from an initialized gamepad it means one of
1279 // the Joy-Cons was disconnected from the charging grip. The HID
1280 // device does not disconnect; de-initialize the device so the
1281 // composite device will be hidden.
1282 if (state_ == kInitialized)
1283 FailInitSequence();
1284 break;
1285 case kUsbDeviceTypeChargingGripJoyConL:
1286 case kUsbDeviceTypeChargingGripJoyConR:
1287 UpdatePadConnected();
1288 // A Joy-Con was connected to a de-initialized device. Restart the
1289 // initialization sequence.
1290 if (state_ == kUninitialized)
1291 StartInitSequence();
1292 break;
1293 default:
1294 break;
1295 }
1296 }
1297 break;
1298 }
1299 default:
1300 break;
1301 }
1302 }
1303
HandleInputReport21(const std::vector<uint8_t> & report_bytes)1304 void NintendoController::HandleInputReport21(
1305 const std::vector<uint8_t>& report_bytes) {
1306 const auto* spi_report =
1307 reinterpret_cast<const SpiReadReport*>(report_bytes.data());
1308 if (UpdateGamepadFromControllerData(spi_report->controller_data, cal_data_,
1309 pad_)) {
1310 pad_.timestamp = GamepadDataFetcher::CurrentTimeInMicroseconds();
1311 }
1312 // The input report includes the parameters for the SPI read request along
1313 // with the data that was read. Use the read address to determine how to
1314 // unpack the data.
1315 if (spi_report->subcommand == kSubCommandReadSpi) {
1316 uint16_t address = (spi_report->addrh << 8) | spi_report->addrl;
1317 switch (address) {
1318 case kSpiImuCalibrationAddress:
1319 UnpackSwitchImuCalibration(spi_report->spi_data, cal_data_);
1320 break;
1321 case kSpiImuHorizontalOffsetsAddress:
1322 UnpackSwitchImuHorizontalOffsets(spi_report->spi_data, cal_data_);
1323 break;
1324 case kSpiAnalogStickCalibrationAddress:
1325 UnpackSwitchAnalogStickCalibration(spi_report->spi_data, cal_data_);
1326 break;
1327 case kSpiAnalogStickParametersAddress:
1328 UnpackSwitchAnalogStickParameters(spi_report->spi_data, cal_data_);
1329 break;
1330 default:
1331 break;
1332 }
1333 }
1334 }
1335
HandleInputReport30(const std::vector<uint8_t> & report_bytes)1336 void NintendoController::HandleInputReport30(
1337 const std::vector<uint8_t>& report_bytes) {
1338 const auto* controller_report =
1339 reinterpret_cast<const ControllerDataReport*>(report_bytes.data());
1340 // Each input report contains three frames of IMU data.
1341 UnpackSwitchImuData(&controller_report->imu_data[0], &imu_data_[0]);
1342 UnpackSwitchImuData(&controller_report->imu_data[12], &imu_data_[1]);
1343 UnpackSwitchImuData(&controller_report->imu_data[24], &imu_data_[2]);
1344 if (UpdateGamepadFromControllerData(controller_report->controller_data,
1345 cal_data_, pad_)) {
1346 pad_.timestamp = GamepadDataFetcher::CurrentTimeInMicroseconds();
1347 }
1348 }
1349
ContinueInitSequence(uint8_t report_id,const std::vector<uint8_t> & report_bytes)1350 void NintendoController::ContinueInitSequence(
1351 uint8_t report_id,
1352 const std::vector<uint8_t>& report_bytes) {
1353 const auto* ack_report =
1354 reinterpret_cast<const UsbInputReport81*>(report_bytes.data());
1355 const auto* spi_report =
1356 reinterpret_cast<const SpiReadReport*>(report_bytes.data());
1357 const uint8_t ack_subtype =
1358 (report_id == kUsbReportIdInput81) ? ack_report->subtype : 0;
1359 const uint8_t spi_subcommand =
1360 (report_id == kReportIdInput21) ? spi_report->subcommand : 0;
1361 const bool is_spi_read =
1362 (report_id == kReportIdInput21 && spi_subcommand == kSubCommandReadSpi);
1363 const uint16_t spi_read_address =
1364 is_spi_read ? ((spi_report->addrh << 8) | spi_report->addrl) : 0;
1365 const uint16_t spi_read_length = is_spi_read ? spi_report->length : 0;
1366
1367 switch (state_) {
1368 case kPendingMacAddress:
1369 if (ack_subtype == kSubTypeRequestMac) {
1370 CancelTimeout();
1371 if (mac_address_)
1372 MakeInitSequenceRequests(kPendingHandshake1);
1373 else
1374 FailInitSequence();
1375 }
1376 break;
1377 case kPendingHandshake1:
1378 if (ack_subtype == kSubTypeHandshake) {
1379 CancelTimeout();
1380 MakeInitSequenceRequests(kPendingBaudRate);
1381 }
1382 break;
1383 case kPendingBaudRate:
1384 if (ack_subtype == kSubTypeBaudRate) {
1385 CancelTimeout();
1386 MakeInitSequenceRequests(kPendingHandshake2);
1387 }
1388 break;
1389 case kPendingHandshake2:
1390 if (ack_subtype == kSubTypeHandshake) {
1391 CancelTimeout();
1392 MakeInitSequenceRequests(kPendingDisableUsbTimeout);
1393 }
1394 break;
1395 case kPendingDisableUsbTimeout:
1396 if (spi_subcommand == kSubCommand33) {
1397 CancelTimeout();
1398 MakeInitSequenceRequests(kPendingSetPlayerLights);
1399 }
1400 break;
1401 case kPendingSetPlayerLights:
1402 if (spi_subcommand == kSubCommandSetPlayerLights) {
1403 CancelTimeout();
1404 MakeInitSequenceRequests(kPendingEnableImu);
1405 }
1406 break;
1407 case kPendingEnableImu:
1408 if (spi_subcommand == kSubCommandEnableImu) {
1409 CancelTimeout();
1410 MakeInitSequenceRequests(kPendingSetImuSensitivity);
1411 }
1412 break;
1413 case kPendingSetImuSensitivity:
1414 if (spi_subcommand == kSubCommandSetImuSensitivity) {
1415 CancelTimeout();
1416 MakeInitSequenceRequests(kPendingReadImuCalibration);
1417 }
1418 break;
1419 case kPendingReadImuCalibration:
1420 if (spi_read_address == kSpiImuCalibrationAddress &&
1421 spi_read_length == kSpiImuCalibrationSize) {
1422 CancelTimeout();
1423 MakeInitSequenceRequests(kPendingReadHorizontalOffsets);
1424 }
1425 break;
1426 case kPendingReadHorizontalOffsets:
1427 if (spi_read_address == kSpiImuHorizontalOffsetsAddress &&
1428 spi_read_length == kSpiImuHorizontalOffsetsSize) {
1429 CancelTimeout();
1430 MakeInitSequenceRequests(kPendingReadAnalogStickCalibration);
1431 }
1432 break;
1433 case kPendingReadAnalogStickCalibration:
1434 if (spi_read_address == kSpiAnalogStickCalibrationAddress &&
1435 spi_read_length == kSpiAnalogStickCalibrationSize) {
1436 CancelTimeout();
1437 MakeInitSequenceRequests(kPendingReadAnalogStickParameters);
1438 }
1439 break;
1440 case kPendingReadAnalogStickParameters:
1441 if (spi_read_address == kSpiAnalogStickParametersAddress &&
1442 spi_read_length == kSpiAnalogStickParametersSize) {
1443 CancelTimeout();
1444 MakeInitSequenceRequests(kPendingEnableVibration);
1445 }
1446 break;
1447 case kPendingEnableVibration:
1448 if (spi_subcommand == kSubCommandEnableVibration) {
1449 CancelTimeout();
1450 // PowerA controller doesn't have a home light and trying to set it will
1451 // fail, so skip this step.
1452 if (gamepad_id_ == GamepadId::kPowerALicPro) {
1453 MakeInitSequenceRequests(kPendingSetInputReportMode);
1454 } else {
1455 MakeInitSequenceRequests(kPendingSetHomeLight);
1456 }
1457 }
1458 break;
1459 case kPendingSetHomeLight:
1460 if (spi_subcommand == kSubCommandSetHomeLight) {
1461 CancelTimeout();
1462 MakeInitSequenceRequests(kPendingSetInputReportMode);
1463 }
1464 break;
1465 case kPendingSetInputReportMode:
1466 if (spi_subcommand == kSubCommandSetInputReportMode) {
1467 CancelTimeout();
1468 MakeInitSequenceRequests(kPendingControllerData);
1469 }
1470 break;
1471 case kPendingControllerData:
1472 if (report_id == kReportIdInput30) {
1473 CancelTimeout();
1474 FinishInitSequence();
1475 }
1476 break;
1477 case kInitialized:
1478 case kUninitialized:
1479 NOTREACHED();
1480 break;
1481 default:
1482 break;
1483 }
1484 }
1485
MakeInitSequenceRequests(InitializationState state)1486 void NintendoController::MakeInitSequenceRequests(InitializationState state) {
1487 DCHECK(timeout_callback_.IsCancelled());
1488 state_ = state;
1489 switch (state_) {
1490 case kPendingMacAddress:
1491 RequestMacAddress();
1492 break;
1493 case kPendingHandshake1:
1494 case kPendingHandshake2:
1495 RequestHandshake();
1496 break;
1497 case kPendingBaudRate:
1498 RequestBaudRate();
1499 break;
1500 case kPendingDisableUsbTimeout:
1501 RequestEnableUsbTimeout(false);
1502 break;
1503 case kPendingSetPlayerLights:
1504 RequestSetPlayerLights(kPlayerLightPattern1); // Player 1 indicator on.
1505 break;
1506 case kPendingEnableImu:
1507 RequestEnableImu(false); // IMU disabled.
1508 break;
1509 case kPendingSetImuSensitivity:
1510 RequestSetImuSensitivity(
1511 kGyroSensitivity2000Dps, kAccelerometerSensitivity8G,
1512 kGyroPerformance208Hz, kAccelerometerFilterBandwidth100Hz);
1513 break;
1514 case kPendingReadImuCalibration:
1515 RequestImuCalibration();
1516 break;
1517 case kPendingReadHorizontalOffsets:
1518 RequestHorizontalOffsets();
1519 break;
1520 case kPendingReadAnalogStickCalibration:
1521 RequestAnalogCalibration();
1522 break;
1523 case kPendingReadAnalogStickParameters:
1524 RequestAnalogParameters();
1525 break;
1526 case kPendingEnableVibration:
1527 RequestEnableVibration(true);
1528 break;
1529 case kPendingSetHomeLight:
1530 RequestSetHomeLightIntensity(1.0); // 100% intensity.
1531 break;
1532 case kPendingSetInputReportMode:
1533 RequestSetInputReportMode(0x30); // Standard full mode reported at 60Hz.
1534 break;
1535 case kPendingControllerData:
1536 ArmTimeout();
1537 break;
1538 case kInitialized:
1539 case kUninitialized:
1540 default:
1541 NOTREACHED();
1542 break;
1543 }
1544 }
1545
SubCommand(uint8_t sub_command,const std::vector<uint8_t> & bytes)1546 void NintendoController::SubCommand(uint8_t sub_command,
1547 const std::vector<uint8_t>& bytes) {
1548 std::vector<uint8_t> report_bytes(output_report_size_bytes_ - 1);
1549 // Serial subcommands also carry vibration data. Configure the vibration
1550 // portion of the report for a neutral vibration effect (zero amplitude).
1551 // https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/bluetooth_hid_notes.md#output-0x12
1552 report_bytes[0] = uint8_t{output_report_counter_++ & 0xff};
1553 report_bytes[1] = 0x00;
1554 report_bytes[2] = 0x01;
1555 report_bytes[3] = 0x40;
1556 report_bytes[4] = 0x40;
1557 report_bytes[5] = 0x00;
1558 report_bytes[6] = 0x01;
1559 report_bytes[7] = 0x40;
1560 report_bytes[8] = 0x40;
1561 report_bytes[9] = sub_command;
1562 DCHECK_LT(bytes.size() + kSubCommandDataOffset, output_report_size_bytes_);
1563 std::copy(bytes.begin(), bytes.end(),
1564 &report_bytes[kSubCommandDataOffset - 1]);
1565 WriteOutputReport(kReportIdOutput01, report_bytes, true);
1566 }
1567
RequestMacAddress()1568 void NintendoController::RequestMacAddress() {
1569 std::vector<uint8_t> report_bytes(output_report_size_bytes_ - 1);
1570 report_bytes[0] = kSubTypeRequestMac;
1571 WriteOutputReport(kUsbReportIdOutput80, report_bytes, true);
1572 }
1573
RequestHandshake()1574 void NintendoController::RequestHandshake() {
1575 std::vector<uint8_t> report_bytes(output_report_size_bytes_ - 1);
1576 report_bytes[0] = kSubTypeHandshake;
1577 WriteOutputReport(kUsbReportIdOutput80, report_bytes, true);
1578 }
1579
RequestBaudRate()1580 void NintendoController::RequestBaudRate() {
1581 std::vector<uint8_t> report_bytes(output_report_size_bytes_ - 1);
1582 report_bytes[0] = kSubTypeBaudRate;
1583 WriteOutputReport(kUsbReportIdOutput80, report_bytes, true);
1584 }
1585
RequestSubCommand33()1586 void NintendoController::RequestSubCommand33() {
1587 // Unrecognized commands do nothing, but still generate a reply.
1588 SubCommand(kSubCommand33, {});
1589 }
1590
RequestVibration(double left_frequency,double left_magnitude,double right_frequency,double right_magnitude)1591 void NintendoController::RequestVibration(double left_frequency,
1592 double left_magnitude,
1593 double right_frequency,
1594 double right_magnitude) {
1595 uint16_t lhf;
1596 uint8_t llf;
1597 uint8_t lhfa;
1598 uint16_t llfa;
1599 uint16_t rhf;
1600 uint8_t rlf;
1601 uint8_t rhfa;
1602 uint16_t rlfa;
1603 FrequencyToHex(left_frequency, left_magnitude, &lhf, &llf, &lhfa, &llfa);
1604 FrequencyToHex(right_frequency, right_magnitude, &rhf, &rlf, &rhfa, &rlfa);
1605 std::vector<uint8_t> report_bytes(output_report_size_bytes_ - 1);
1606 uint8_t counter = uint8_t{output_report_counter_++ & 0x0f};
1607 report_bytes[0] = counter;
1608 report_bytes[1] = lhf & 0xff;
1609 report_bytes[2] = lhfa + ((lhf >> 8) & 0xff);
1610 report_bytes[3] = llf + ((llfa >> 8) & 0xff);
1611 report_bytes[4] = llfa & 0xff;
1612 report_bytes[5] = rhf & 0xff;
1613 report_bytes[6] = rhfa + ((rhf >> 8) & 0xff);
1614 report_bytes[7] = rlf + ((rlfa >> 8) & 0xff);
1615 report_bytes[8] = rlfa & 0xff;
1616 WriteOutputReport(kReportIdOutput10, report_bytes, false);
1617 }
1618
RequestEnableUsbTimeout(bool enable)1619 void NintendoController::RequestEnableUsbTimeout(bool enable) {
1620 // By default, Switch Pro will revert to Bluetooth mode if it does not
1621 // receive any USB HID commands within a timeout window. Disabling the
1622 // timeout keeps the device in USB mode.
1623 std::vector<uint8_t> report_bytes(output_report_size_bytes_ - 1);
1624 report_bytes[0] =
1625 enable ? kSubTypeEnableUsbTimeout : kSubTypeDisableUsbTimeout;
1626 // This report may not be acked due to a software bug on the device.
1627 WriteOutputReport(kUsbReportIdOutput80, report_bytes, false);
1628 // Send an unused subcommand (0x33) which is acked.
1629 RequestSubCommand33();
1630 }
1631
RequestEnableImu(bool enable)1632 void NintendoController::RequestEnableImu(bool enable) {
1633 SubCommand(kSubCommandEnableImu, {enable ? 0x01 : 0x00});
1634 }
1635
RequestEnableVibration(bool enable)1636 void NintendoController::RequestEnableVibration(bool enable) {
1637 SubCommand(kSubCommandEnableVibration, {enable ? 0x01 : 0x00});
1638 }
1639
RequestSetPlayerLights(uint8_t light_pattern)1640 void NintendoController::RequestSetPlayerLights(uint8_t light_pattern) {
1641 SubCommand(kSubCommandSetPlayerLights, {light_pattern});
1642 }
1643
RequestSetHomeLight(uint8_t minicycle_count,uint8_t minicycle_duration,uint8_t start_intensity,uint8_t cycle_count,const std::vector<uint8_t> & minicycle_data)1644 void NintendoController::RequestSetHomeLight(
1645 uint8_t minicycle_count,
1646 uint8_t minicycle_duration,
1647 uint8_t start_intensity,
1648 uint8_t cycle_count,
1649 const std::vector<uint8_t>& minicycle_data) {
1650 DCHECK_LE(minicycle_count, 0xf);
1651 DCHECK_LE(minicycle_duration, 0xf);
1652 DCHECK_LE(start_intensity, 0xf);
1653 DCHECK_LE(cycle_count, 0xf);
1654 if ((cycle_count > 0 && minicycle_count == 1) || minicycle_duration == 0)
1655 minicycle_count = 0;
1656 std::vector<uint8_t> bytes = {(minicycle_count << 4) | minicycle_duration,
1657 (start_intensity << 4) | cycle_count};
1658 bytes.insert(bytes.end(), minicycle_data.begin(), minicycle_data.end());
1659 SubCommand(kSubCommandSetHomeLight, bytes);
1660 }
1661
RequestSetHomeLightIntensity(double intensity)1662 void NintendoController::RequestSetHomeLightIntensity(double intensity) {
1663 intensity = base::ClampToRange(intensity, 0.0, 1.0);
1664 uint8_t led_intensity = std::round(intensity * 0x0f);
1665 // Each pair of bytes in the minicycle data describes two minicyles.
1666 // The first byte holds two 4-bit values encoding minicycle intensities.
1667 // The second byte holds two 4-bit multipliers for the duration of each
1668 // transition.
1669 //
1670 // This command encodes one minicycle that transitions to 100% intensity after
1671 // 1x minicycle duration. Because |minicycle_count| and |cycle_count| are
1672 // both zero, the device will transition to the 1st minicycle and then stay at
1673 // |led_intensity|.
1674 RequestSetHomeLight(0, 1, led_intensity, 0, {led_intensity << 4, 0x00});
1675 }
1676
RequestSetImuSensitivity(uint8_t gyro_sensitivity,uint8_t accelerometer_sensitivity,uint8_t gyro_performance_rate,uint8_t accelerometer_filter_bandwidth)1677 void NintendoController::RequestSetImuSensitivity(
1678 uint8_t gyro_sensitivity,
1679 uint8_t accelerometer_sensitivity,
1680 uint8_t gyro_performance_rate,
1681 uint8_t accelerometer_filter_bandwidth) {
1682 SubCommand(kSubCommandSetImuSensitivity,
1683 {gyro_sensitivity, accelerometer_sensitivity,
1684 gyro_performance_rate, accelerometer_filter_bandwidth});
1685 }
1686
RequestSetInputReportMode(uint8_t mode)1687 void NintendoController::RequestSetInputReportMode(uint8_t mode) {
1688 SubCommand(kSubCommandSetInputReportMode, {mode});
1689 }
1690
ReadSpi(uint16_t address,size_t length)1691 void NintendoController::ReadSpi(uint16_t address, size_t length) {
1692 DCHECK_LE(length + kSpiDataOffset, output_report_size_bytes_);
1693 length = std::min(length, output_report_size_bytes_ - kSpiDataOffset);
1694 uint8_t address_high = (address >> 8) & 0xff;
1695 uint8_t address_low = address & 0xff;
1696 SubCommand(kSubCommandReadSpi,
1697 {address_low, address_high, 0x00, 0x00, uint8_t{length}});
1698 }
1699
RequestImuCalibration()1700 void NintendoController::RequestImuCalibration() {
1701 ReadSpi(kSpiImuCalibrationAddress, kSpiImuCalibrationSize);
1702 }
1703
RequestHorizontalOffsets()1704 void NintendoController::RequestHorizontalOffsets() {
1705 ReadSpi(kSpiImuHorizontalOffsetsAddress, kSpiImuHorizontalOffsetsSize);
1706 }
1707
RequestAnalogCalibration()1708 void NintendoController::RequestAnalogCalibration() {
1709 ReadSpi(kSpiAnalogStickCalibrationAddress, kSpiAnalogStickCalibrationSize);
1710 }
1711
RequestAnalogParameters()1712 void NintendoController::RequestAnalogParameters() {
1713 ReadSpi(kSpiAnalogStickParametersAddress, kSpiAnalogStickParametersSize);
1714 }
1715
ReadInputReport()1716 void NintendoController::ReadInputReport() {
1717 DCHECK(connection_);
1718 connection_->Read(base::BindOnce(&NintendoController::OnReadInputReport,
1719 weak_factory_.GetWeakPtr()));
1720 }
1721
OnReadInputReport(bool success,uint8_t report_id,const base::Optional<std::vector<uint8_t>> & report_bytes)1722 void NintendoController::OnReadInputReport(
1723 bool success,
1724 uint8_t report_id,
1725 const base::Optional<std::vector<uint8_t>>& report_bytes) {
1726 if (success) {
1727 DCHECK(report_bytes);
1728 HandleInputReport(report_id, *report_bytes);
1729 } else {
1730 CancelTimeout();
1731 FailInitSequence();
1732 }
1733 }
1734
WriteOutputReport(uint8_t report_id,const std::vector<uint8_t> & report_bytes,bool expect_reply)1735 void NintendoController::WriteOutputReport(
1736 uint8_t report_id,
1737 const std::vector<uint8_t>& report_bytes,
1738 bool expect_reply) {
1739 DCHECK(connection_);
1740 DCHECK(timeout_callback_.IsCancelled());
1741 connection_->Write(report_id, report_bytes,
1742 base::BindOnce(&NintendoController::OnWriteOutputReport,
1743 weak_factory_.GetWeakPtr()));
1744 if (expect_reply)
1745 ArmTimeout();
1746 }
1747
OnWriteOutputReport(bool success)1748 void NintendoController::OnWriteOutputReport(bool success) {
1749 if (!success) {
1750 CancelTimeout();
1751 FailInitSequence();
1752 }
1753 }
1754
DoShutdown()1755 void NintendoController::DoShutdown() {
1756 if (composite_left_)
1757 composite_left_->Shutdown();
1758 composite_left_.reset();
1759 if (composite_right_)
1760 composite_right_->Shutdown();
1761 composite_right_.reset();
1762 connection_.reset();
1763 device_info_.reset();
1764 }
1765
SetVibration(double strong_magnitude,double weak_magnitude)1766 void NintendoController::SetVibration(double strong_magnitude,
1767 double weak_magnitude) {
1768 if (is_composite_) {
1769 // Split the vibration effect between the left and right subdevices.
1770 if (composite_left_ && composite_right_) {
1771 composite_left_->SetVibration(strong_magnitude, 0);
1772 composite_right_->SetVibration(0, weak_magnitude);
1773 }
1774 } else {
1775 RequestVibration(kVibrationFrequencyStrongRumble,
1776 kVibrationAmplitudeStrongRumbleMax * strong_magnitude,
1777 kVibrationFrequencyWeakRumble,
1778 kVibrationAmplitudeWeakRumbleMax * weak_magnitude);
1779 }
1780 }
1781
GetMaxEffectDurationMillis()1782 double NintendoController::GetMaxEffectDurationMillis() {
1783 return kMaxVibrationEffectDurationMillis;
1784 }
1785
ArmTimeout()1786 void NintendoController::ArmTimeout() {
1787 DCHECK(timeout_callback_.IsCancelled());
1788 timeout_callback_.Reset(base::BindOnce(&NintendoController::OnTimeout,
1789 weak_factory_.GetWeakPtr()));
1790 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
1791 FROM_HERE, timeout_callback_.callback(), kTimeoutDuration);
1792 }
1793
CancelTimeout()1794 void NintendoController::CancelTimeout() {
1795 timeout_callback_.Cancel();
1796 retry_count_ = 0;
1797 }
1798
OnTimeout()1799 void NintendoController::OnTimeout() {
1800 ++retry_count_;
1801 if (retry_count_ <= kMaxRetryCount)
1802 MakeInitSequenceRequests(state_);
1803 else {
1804 retry_count_ = 0;
1805 StartInitSequence();
1806 }
1807 }
1808
GetWeakPtr()1809 base::WeakPtr<AbstractHapticGamepad> NintendoController::GetWeakPtr() {
1810 return weak_factory_.GetWeakPtr();
1811 }
1812
1813 } // namespace device
1814