USB Host Shield 2.0
SwitchProParser.h
Go to the documentation of this file.
1 /* Copyright (C) 2021 Kristian Sloth Lauszus. All rights reserved.
2 
3  This software may be distributed and modified under the terms of the GNU
4  General Public License version 2 (GPL2) as published by the Free Software
5  Foundation and appearing in the file GPL2.TXT included in the packaging of
6  this file. Please note that GPL2 Section 2[b] requires that all works based
7  on this software must also be made publicly available under the terms of
8  the GPL2 ("Copyleft").
9 
10  Contact information
11  -------------------
12 
13  Kristian Sloth Lauszus
14  Web : https://lauszus.com
15  e-mail : lauszus@gmail.com
16  */
17 
18 #ifndef _switch_pro_parser_h_
19 #define _switch_pro_parser_h_
20 
21 #include "Usb.h"
22 #include "controllerEnums.h"
23 
25 const uint8_t SWITCH_PRO_LEDS[] PROGMEM = {
26  0x00, // OFF
27  0x01, // LED1
28  0x02, // LED2
29  0x04, // LED3
30  0x08, // LED4
31 
32  0x09, // LED5
33  0x0A, // LED6
34  0x0C, // LED7
35  0x0D, // LED8
36  0x0E, // LED9
37  0x0F, // LED10
38 };
39 
41 const uint8_t SWITCH_PRO_BUTTONS[] PROGMEM = {
42  0x11, // UP
43  0x12, // RIGHT
44  0x10, // DOWN
45  0x13, // LEFT
46 
47  0x0D, // Capture
48  0x09, // PLUS
49  0x0B, // L3
50  0x0A, // R3
51 
52  0x08, // MINUS
53  0x0C, // HOME
54  0, 0, // Skip
55 
56  0x02, // B
57  0x03, // A
58  0x01, // X
59  0x00, // Y
60 
61  0x16, // L
62  0x06, // R
63  0x17, // ZL
64  0x07, // ZR
65 };
66 
67 // https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/bluetooth_hid_notes.md#standard-input-report-format
69  struct {
70  uint8_t y : 1;
71  uint8_t x : 1;
72  uint8_t b : 1;
73  uint8_t a : 1;
74 
75  uint8_t dummy1 : 2;
76  uint8_t r : 1;
77  uint8_t zr : 1;
78 
79  uint8_t minus : 1;
80  uint8_t plus : 1;
81  uint8_t r3 : 1;
82  uint8_t l3 : 1;
83 
84  uint8_t home : 1;
85  uint8_t capture : 1;
86  uint8_t dummy2 : 2;
87 
88  uint8_t dpad : 4;
89 
90  uint8_t dummy3 : 2;
91  uint8_t l : 1;
92  uint8_t zl : 1;
93  } __attribute__((packed));
94  uint32_t val : 24;
95 } __attribute__((packed));
96 
97 struct ImuData {
98  int16_t accX, accY, accZ;
99  int16_t gyroX, gyroY, gyroZ;
100 } __attribute__((packed));
101 
103  struct {
104  uint8_t connection_info : 4;
105  uint8_t battery_level : 4;
106  } __attribute__((packed));
107 
108  /* Button and joystick values */
109  SwitchProButtons btn; // Bytes 3-5
110 
111  // Bytes 6-11
112  uint16_t leftHatX : 12;
113  uint16_t leftHatY : 12;
114  uint16_t rightHatX : 12;
115  uint16_t rightHatY : 12;
116 
117  uint8_t vibratorInput; // What is this used for?
118 
119  // Bytes 13-48
120  // Three samples of the IMU is sent in one message
121  // See: https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/imu_sensor_notes.md
123 } __attribute__((packed));
124 
128  uint8_t ledMask; // Higher nibble flashes the LEDs, lower nibble sets them on/off
129  bool ledHome;
130 
131  // Used to send the reports at the same rate as the controller is sending messages
135  int8_t enableImu; // -1 == Do nothing, 0 == disable IMU, 1 == enable IMU
138 } __attribute__((packed));
139 
142 public:
144  SwitchProParser() : output_sequence_counter(0) {
145  Reset();
146  };
147 
159  bool getButtonPress(ButtonEnum b);
160  bool getButtonClick(ButtonEnum b);
168  int16_t getAnalogHat(AnalogHatEnum a);
169 
174  void enableImu(bool enable) {
175  // TODO: Should we just always enable it?
176  switchProOutput.enableImu = enable ? 1 : 0;
177  }
178 
184  float getAngle(AngleEnum a) {
185  if (a == Pitch)
186  return (atan2f(-switchProData.imu[0].accY, -switchProData.imu[0].accZ) + PI) * RAD_TO_DEG;
187  else
188  return (atan2f(switchProData.imu[0].accX, -switchProData.imu[0].accZ) + PI) * RAD_TO_DEG;
189  };
190 
196  int16_t getSensor(SensorEnum s) {
197  switch(s) {
198  case gX:
199  return switchProData.imu[0].gyroX;
200  case gY:
201  return switchProData.imu[0].gyroY;
202  case gZ:
203  return switchProData.imu[0].gyroZ;
204  case aX:
205  return switchProData.imu[0].accX;
206  case aY:
207  return switchProData.imu[0].accY;
208  case aZ:
209  return switchProData.imu[0].accZ;
210  default:
211  return 0;
212  }
213  };
214 
216  void setAllOff() {
217  setRumbleOff();
218  setLedOff();
219  setLedHomeOff();
220  };
221 
223  void setRumbleOff() {
224  setRumble(false, false);
225  }
226 
230  }
231 
237  void setRumble(bool leftRumbleOn, bool rightRumbleOn) {
238  switchProOutput.leftRumbleOn = leftRumbleOn;
239  switchProOutput.rightRumbleOn = rightRumbleOn;
240  switchProOutput.ledReportChanged = true; // Set this, so the rumble effect gets changed immediately
241  }
242 
247  void setRumbleLeft(bool on) {
249  switchProOutput.ledReportChanged = true; // Set this, so the rumble effect gets changed immediately
250  }
251 
256  void setRumbleRight(bool on) {
258  switchProOutput.ledReportChanged = true; // Set this, so the rumble effect gets changed immediately
259  }
260 
266  void setLedRaw(uint8_t mask) {
267  switchProOutput.ledMask = mask;
269  }
270 
272  void setLedOff() {
273  setLedRaw(0);
274  }
275 
280  void setLedOff(LEDEnum a) {
281  switchProOutput.ledMask &= ~((uint8_t)(pgm_read_byte(&SWITCH_PRO_LEDS[(uint8_t)a]) & 0x0f));
283  }
284 
289  void setLedOn(LEDEnum a) {
290  switchProOutput.ledMask |= (uint8_t)(pgm_read_byte(&SWITCH_PRO_LEDS[(uint8_t)a]) & 0x0f);
292  }
293 
299  switchProOutput.ledMask ^= (uint8_t)(pgm_read_byte(&SWITCH_PRO_LEDS[(uint8_t)a]) & 0x0f);
301  }
302 
304  void setLedHomeOff() {
305  switchProOutput.ledHome = false;
307  }
308 
310  void setLedHomeOn() {
311  switchProOutput.ledHome = true;
313  }
314 
319  }
320 
322  uint16_t getMessageCounter() {
323  return message_counter;
324  }
325 
331  uint8_t getBatteryLevel() {
332  return switchProData.battery_level >> 1;
333  }
334 
339  bool isCharging() {
340  return switchProData.battery_level & 0x01;
341  }
342 
343 protected:
349  void Parse(uint8_t len, uint8_t *buf);
350 
352  void Reset();
353 
359  virtual void sendOutputReport(uint8_t *data, uint8_t len) = 0;
360 
362  virtual void sendHandshake() {}
363 
368  virtual void disableTimeout() {}
369 
372 
373 private:
374  static int8_t getButtonIndexSwitchPro(ButtonEnum b);
375 
376  void sendOutputCmd();
377  void sendRumbleOutputReport();
378 
379  SwitchProData switchProData;
380  SwitchProButtons oldButtonState, buttonClickState;
381  uint16_t message_counter = 0;
382  uint8_t output_sequence_counter : 4;
383  uint32_t rumble_on_timer = 0;
384 };
385 #endif
SwitchProParser::setRumbleToggle
void setRumbleToggle()
Definition: SwitchProParser.h:228
SwitchProParser::disableTimeout
virtual void disableTimeout()
Definition: SwitchProParser.h:368
SwitchProOutput::ledMask
uint8_t ledMask
Definition: SwitchProParser.h:128
ImuData
Definition: SwitchProParser.h:97
SwitchProButtons::capture
uint8_t capture
Definition: SwitchProParser.h:85
SwitchProButtons::dummy1
uint8_t dummy1
Definition: SwitchProParser.h:75
SwitchProButtons::plus
uint8_t plus
Definition: SwitchProParser.h:80
SwitchProParser
Definition: SwitchProParser.h:141
SwitchProButtons::r3
uint8_t r3
Definition: SwitchProParser.h:81
SwitchProButtons::minus
uint8_t minus
Definition: SwitchProParser.h:79
gX
@ gX
Definition: controllerEnums.h:238
SwitchProData::btn
SwitchProButtons btn
Definition: SwitchProParser.h:109
ImuData::accX
int16_t accX
Definition: SwitchProParser.h:98
SwitchProParser::getAngle
float getAngle(AngleEnum a)
Definition: SwitchProParser.h:184
SwitchProData::battery_level
uint8_t battery_level
Definition: SwitchProParser.h:105
ImuData::accY
int16_t accY
Definition: SwitchProParser.h:98
SwitchProParser::Parse
void Parse(uint8_t len, uint8_t *buf)
Definition: SwitchProParser.cpp:55
SwitchProOutput::ledHome
bool ledHome
Definition: SwitchProParser.h:129
aZ
@ aZ
Definition: controllerEnums.h:235
SwitchProButtons::dpad
uint8_t dpad
Definition: SwitchProParser.h:88
SwitchProParser::Reset
void Reset()
Definition: SwitchProParser.cpp:231
SwitchProParser::setRumbleRight
void setRumbleRight(bool on)
Definition: SwitchProParser.h:256
SwitchProOutput::ledHomeReportChanged
bool ledHomeReportChanged
Definition: SwitchProParser.h:133
SwitchProButtons::x
uint8_t x
Definition: SwitchProParser.h:71
SensorEnum
SensorEnum
Definition: controllerEnums.h:233
SwitchProParser::sendOutputReport
virtual void sendOutputReport(uint8_t *data, uint8_t len)=0
AngleEnum
AngleEnum
Definition: controllerEnums.h:266
SwitchProButtons::dummy2
uint8_t dummy2
Definition: SwitchProParser.h:86
SwitchProParser::setLedOff
void setLedOff()
Definition: SwitchProParser.h:272
SwitchProParser::setLedRaw
void setLedRaw(uint8_t mask)
Definition: SwitchProParser.h:266
SwitchProOutput::ledReportChanged
bool ledReportChanged
Definition: SwitchProParser.h:132
SwitchProParser::setLedHomeToggle
void setLedHomeToggle()
Definition: SwitchProParser.h:316
aY
@ aY
Definition: controllerEnums.h:235
SwitchProParser::setLedToggle
void setLedToggle(LEDEnum a)
Definition: SwitchProParser.h:298
SwitchProButtons
Definition: SwitchProParser.h:68
SwitchProParser::getButtonClick
bool getButtonClick(ButtonEnum b)
Definition: SwitchProParser.cpp:34
SwitchProOutput::enableImu
int8_t enableImu
Definition: SwitchProParser.h:135
ImuData::gyroY
int16_t gyroY
Definition: SwitchProParser.h:99
ImuData::accZ
int16_t accZ
Definition: SwitchProParser.h:98
SwitchProParser::sendHandshake
virtual void sendHandshake()
Definition: SwitchProParser.h:362
LEDEnum
LEDEnum
Definition: controllerEnums.h:31
SwitchProButtons::zl
uint8_t zl
Definition: SwitchProParser.h:92
Pitch
@ Pitch
Definition: controllerEnums.h:267
SwitchProOutput::sendHandshake
bool sendHandshake
Definition: SwitchProParser.h:136
SwitchProParser::getAnalogHat
int16_t getAnalogHat(AnalogHatEnum a)
Definition: SwitchProParser.cpp:42
SwitchProParser::getSensor
int16_t getSensor(SensorEnum s)
Definition: SwitchProParser.h:196
SwitchProParser::setLedOn
void setLedOn(LEDEnum a)
Definition: SwitchProParser.h:289
SwitchProButtons::y
uint8_t y
Definition: SwitchProParser.h:70
SwitchProParser::setRumble
void setRumble(bool leftRumbleOn, bool rightRumbleOn)
Definition: SwitchProParser.h:237
SwitchProParser::enableImu
void enableImu(bool enable)
Definition: SwitchProParser.h:174
SwitchProButtons::l3
uint8_t l3
Definition: SwitchProParser.h:82
SwitchProParser::setLedHomeOn
void setLedHomeOn()
Definition: SwitchProParser.h:310
SwitchProParser::getBatteryLevel
uint8_t getBatteryLevel()
Definition: SwitchProParser.h:331
SwitchProButtons::r
uint8_t r
Definition: SwitchProParser.h:76
controllerEnums.h
SwitchProData
Definition: SwitchProParser.h:102
SwitchProOutput::disableTimeout
bool disableTimeout
Definition: SwitchProParser.h:137
SwitchProData::leftHatY
uint16_t leftHatY
Definition: SwitchProParser.h:113
ImuData::gyroX
int16_t gyroX
Definition: SwitchProParser.h:99
SwitchProData::connection_info
uint8_t connection_info
Definition: SwitchProParser.h:104
SwitchProParser::setRumbleOff
void setRumbleOff()
Definition: SwitchProParser.h:223
SwitchProParser::setLedOff
void setLedOff(LEDEnum a)
Definition: SwitchProParser.h:280
SwitchProButtons::b
uint8_t b
Definition: SwitchProParser.h:72
gZ
@ gZ
Definition: controllerEnums.h:237
SwitchProData::rightHatX
uint16_t rightHatX
Definition: SwitchProParser.h:114
SwitchProParser::getMessageCounter
uint16_t getMessageCounter()
Definition: SwitchProParser.h:322
SwitchProParser::isCharging
bool isCharging()
Definition: SwitchProParser.h:339
pgm_read_byte
#define pgm_read_byte(addr)
Definition: version_helper.h:161
ImuData::gyroZ
int16_t gyroZ
Definition: SwitchProParser.h:99
SwitchProButtons::val
uint32_t val
Definition: SwitchProParser.h:94
SwitchProData::imu
ImuData imu[3]
Definition: SwitchProParser.h:122
SwitchProParser::setAllOff
void setAllOff()
Definition: SwitchProParser.h:216
SWITCH_PRO_LEDS
const uint8_t SWITCH_PRO_LEDS[]
Definition: SwitchProParser.h:25
SwitchProParser::switchProOutput
SwitchProOutput switchProOutput
Definition: SwitchProParser.h:371
SwitchProOutput::enableFullReportMode
bool enableFullReportMode
Definition: SwitchProParser.h:134
Usb.h
SwitchProOutput::leftRumbleOn
bool leftRumbleOn
Definition: SwitchProParser.h:126
SwitchProParser::SwitchProParser
SwitchProParser()
Definition: SwitchProParser.h:144
SwitchProParser::getButtonPress
bool getButtonPress(ButtonEnum b)
Definition: SwitchProParser.cpp:29
SwitchProButtons::l
uint8_t l
Definition: SwitchProParser.h:91
SwitchProData::vibratorInput
uint8_t vibratorInput
Definition: SwitchProParser.h:117
aX
@ aX
Definition: controllerEnums.h:235
SwitchProParser::setLedHomeOff
void setLedHomeOff()
Definition: SwitchProParser.h:304
SwitchProButtons::home
uint8_t home
Definition: SwitchProParser.h:84
SwitchProOutput::rightRumbleOn
bool rightRumbleOn
Definition: SwitchProParser.h:127
SWITCH_PRO_BUTTONS
const uint8_t SWITCH_PRO_BUTTONS[]
Definition: SwitchProParser.h:41
SwitchProData::rightHatY
uint16_t rightHatY
Definition: SwitchProParser.h:115
ButtonEnum
ButtonEnum
Definition: controllerEnums.h:78
SwitchProData::leftHatX
uint16_t leftHatX
Definition: SwitchProParser.h:112
AnalogHatEnum
AnalogHatEnum
Definition: controllerEnums.h:218
SwitchProButtons::a
uint8_t a
Definition: SwitchProParser.h:73
SwitchProButtons::zr
uint8_t zr
Definition: SwitchProParser.h:77
gY
@ gY
Definition: controllerEnums.h:238
SwitchProButtons::dummy3
uint8_t dummy3
Definition: SwitchProParser.h:90
SwitchProParser::setRumbleLeft
void setRumbleLeft(bool on)
Definition: SwitchProParser.h:247
SwitchProOutput
Definition: SwitchProParser.h:125