mirror of
https://github.com/felis/USB_Host_Shield_2.0.git
synced 2024-03-22 11:31:26 +01:00
The Switch Pro controller now works via USB and we can now read the IMU data as well
This commit is contained in:
parent
f19f610081
commit
2dfb767093
8 changed files with 464 additions and 122 deletions
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
|
@ -8,7 +8,7 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
# find examples -type f -name "*.ino" | rev | cut -d/ -f2- | rev | sort | sed -z 's/\n/, /g'
|
# find examples -type f -name "*.ino" | rev | cut -d/ -f2- | rev | sort | sed -z 's/\n/, /g'
|
||||||
example: [examples/ambx, examples/acm/acm_terminal, examples/adk/adk_barcode, examples/adk/ArduinoBlinkLED, examples/adk/demokit_20, examples/adk/term_test, examples/adk/term_time, examples/Bluetooth/BTHID, examples/Bluetooth/PS3BT, examples/Bluetooth/PS3Multi, examples/Bluetooth/PS3SPP, examples/Bluetooth/PS4BT, examples/Bluetooth/PS5BT, examples/Bluetooth/SPP, examples/Bluetooth/SPPMulti, examples/Bluetooth/SwitchProBT, examples/Bluetooth/Wii, examples/Bluetooth/WiiBalanceBoard, examples/Bluetooth/WiiIRCamera, examples/Bluetooth/WiiMulti, examples/Bluetooth/WiiUProController, examples/board_qc, examples/cdc_XR21B1411/XR_terminal, examples/ftdi/USBFTDILoopback, examples/GPIO/Blink, examples/GPIO/Blink_LowLevel, examples/GPIO/Input, examples/HID/le3dp, examples/HID/scale, examples/HID/SRWS1, examples/HID/t16km, examples/HID/USBHIDBootKbd, examples/HID/USBHIDBootKbdAndMouse, examples/HID/USBHIDBootMouse, examples/HID/USBHID_desc, examples/HID/USBHIDJoystick, examples/HID/USBHIDMultimediaKbd, examples/hub_demo, examples/max_LCD, examples/pl2303/pl2303_gprs_terminal, examples/pl2303/pl2303_gps, examples/pl2303/pl2303_tinygps, examples/pl2303/pl2303_xbee_terminal, examples/PS3USB, examples/PS4USB, examples/PS5USB, examples/PSBuzz, examples/USB_desc, examples/USBH_MIDI/bidirectional_converter, examples/USBH_MIDI/eVY1_sample, examples/USBH_MIDI/USBH_MIDI_dump, examples/USBH_MIDI/USB_MIDI_converter, examples/USBH_MIDI/USB_MIDI_converter_multi, examples/Xbox/XBOXOLD, examples/Xbox/XBOXONE, examples/Xbox/XBOXONESBT, examples/Xbox/XBOXRECV, examples/Xbox/XBOXUSB]
|
example: [examples/ambx, examples/acm/acm_terminal, examples/adk/adk_barcode, examples/adk/ArduinoBlinkLED, examples/adk/demokit_20, examples/adk/term_test, examples/adk/term_time, examples/Bluetooth/BTHID, examples/Bluetooth/PS3BT, examples/Bluetooth/PS3Multi, examples/Bluetooth/PS3SPP, examples/Bluetooth/PS4BT, examples/Bluetooth/PS5BT, examples/Bluetooth/SPP, examples/Bluetooth/SPPMulti, examples/Bluetooth/SwitchProBT, examples/Bluetooth/Wii, examples/Bluetooth/WiiBalanceBoard, examples/Bluetooth/WiiIRCamera, examples/Bluetooth/WiiMulti, examples/Bluetooth/WiiUProController, examples/board_qc, examples/cdc_XR21B1411/XR_terminal, examples/ftdi/USBFTDILoopback, examples/GPIO/Blink, examples/GPIO/Blink_LowLevel, examples/GPIO/Input, examples/HID/le3dp, examples/HID/scale, examples/HID/SRWS1, examples/HID/t16km, examples/HID/USBHIDBootKbd, examples/HID/USBHIDBootKbdAndMouse, examples/HID/USBHIDBootMouse, examples/HID/USBHID_desc, examples/HID/USBHIDJoystick, examples/HID/USBHIDMultimediaKbd, examples/hub_demo, examples/max_LCD, examples/pl2303/pl2303_gprs_terminal, examples/pl2303/pl2303_gps, examples/pl2303/pl2303_tinygps, examples/pl2303/pl2303_xbee_terminal, examples/PS3USB, examples/PS4USB, examples/PS5USB, examples/PSBuzz, examples/SwitchProUSB, examples/USB_desc, examples/USBH_MIDI/bidirectional_converter, examples/USBH_MIDI/eVY1_sample, examples/USBH_MIDI/USBH_MIDI_dump, examples/USBH_MIDI/USB_MIDI_converter, examples/USBH_MIDI/USB_MIDI_converter_multi, examples/Xbox/XBOXOLD, examples/Xbox/XBOXONE, examples/Xbox/XBOXONESBT, examples/Xbox/XBOXRECV, examples/Xbox/XBOXUSB]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-python@v2
|
- uses: actions/setup-python@v2
|
||||||
|
|
18
README.md
18
README.md
|
@ -23,7 +23,7 @@ For more information about the hardware see the [Hardware Manual](https://chome.
|
||||||
* __Alexei Glushchenko__ - <alex-gl@mail.ru>
|
* __Alexei Glushchenko__ - <alex-gl@mail.ru>
|
||||||
* Developers of the USB Core, HID, FTDI, ADK, ACM, and PL2303 libraries
|
* Developers of the USB Core, HID, FTDI, ADK, ACM, and PL2303 libraries
|
||||||
* __Kristian Sloth Lauszus__ - <lauszus@gmail.com>
|
* __Kristian Sloth Lauszus__ - <lauszus@gmail.com>
|
||||||
* Developer of the [BTD](#bluetooth-libraries), [BTHID](#bthid-library), [SPP](#spp-library), [PS5](#ps5-library), [PS4](#ps4-library), [PS3](#ps3-library), [Wii](#wii-library), [Xbox](#xbox-library), and [PSBuzz](#ps-buzz-library) libraries
|
* Developer of the [BTD](#bluetooth-libraries), [BTHID](#bthid-library), [SPP](#spp-library), [PS5](#ps5-library), [PS4](#ps4-library), [PS3](#ps3-library), [Wii](#wii-library), [Switch Pro](#switch-pro-library), [Xbox](#xbox-library), and [PSBuzz](#ps-buzz-library) libraries
|
||||||
* __Andrew Kroll__ - <xxxajk@gmail.com>
|
* __Andrew Kroll__ - <xxxajk@gmail.com>
|
||||||
* Major contributor to mass storage code
|
* Major contributor to mass storage code
|
||||||
* __guruthree__
|
* __guruthree__
|
||||||
|
@ -55,6 +55,7 @@ For more information about the hardware see the [Hardware Manual](https://chome.
|
||||||
* [Xbox ONE Library](#xbox-one-library)
|
* [Xbox ONE Library](#xbox-one-library)
|
||||||
* [Xbox ONE S Library](#xbox-one-s-library)
|
* [Xbox ONE S Library](#xbox-one-s-library)
|
||||||
* [Wii library](#wii-library)
|
* [Wii library](#wii-library)
|
||||||
|
* [Switch Pro Library](#switch-pro-library)
|
||||||
* [PS Buzz Library](#ps-buzz-library)
|
* [PS Buzz Library](#ps-buzz-library)
|
||||||
* [HID Libraries](#hid-libraries)
|
* [HID Libraries](#hid-libraries)
|
||||||
* [MIDI Library](#midi-library)
|
* [MIDI Library](#midi-library)
|
||||||
|
@ -330,6 +331,21 @@ All the information about the Wii controllers are from these sites:
|
||||||
* <http://wiibrew.org/wiki/Wii_Balance_Board>
|
* <http://wiibrew.org/wiki/Wii_Balance_Board>
|
||||||
* The old library created by _Tomoyuki Tanaka_: <https://github.com/moyuchin/WiiRemote_on_Arduino> also helped a lot.
|
* The old library created by _Tomoyuki Tanaka_: <https://github.com/moyuchin/WiiRemote_on_Arduino> also helped a lot.
|
||||||
|
|
||||||
|
### Switch Pro Library
|
||||||
|
|
||||||
|
The Switch Pro library is split up into the [SwitchProBT](SwitchProBT.h) and the [SwitchProUSB](SwitchProUSB.h) library. These allow you to use the Nintendo Switch Pro controller via Bluetooth and USB.
|
||||||
|
|
||||||
|
The [SwitchProBT.ino](examples/Bluetooth/SwitchProBT/SwitchProBT.ino) and [SwitchProUSB.ino](examples/SwitchProUSB/SwitchProUSB.ino) examples shows how to easily read the buttons, joysticks and IMU on the controller via Bluetooth and USB respectively. It is also possible to control the rumble and LEDs on the controller.
|
||||||
|
|
||||||
|
To pair with the Switch Pro controller via Bluetooth you need create the SwitchProBT instance like so: ```SwitchProBT SwitchPro(&Btd, PAIR);``` and then press the Sync button next to the USB connector to put the controller into pairing mode.
|
||||||
|
|
||||||
|
It should then automatically pair the dongle with your controller. This only have to be done once.
|
||||||
|
|
||||||
|
All the information about the controller are from these sites:
|
||||||
|
|
||||||
|
* <https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering>
|
||||||
|
* <https://github.com/Dan611/hid-procon>
|
||||||
|
|
||||||
### [PS Buzz Library](PSBuzz.cpp)
|
### [PS Buzz Library](PSBuzz.cpp)
|
||||||
|
|
||||||
This library implements support for the Playstation Buzz controllers via USB.
|
This library implements support for the Playstation Buzz controllers via USB.
|
||||||
|
|
|
@ -17,18 +17,6 @@
|
||||||
|
|
||||||
#include "SwitchProParser.h"
|
#include "SwitchProParser.h"
|
||||||
|
|
||||||
enum DPADEnum {
|
|
||||||
DPAD_UP = 0x0,
|
|
||||||
DPAD_UP_RIGHT = 0x1,
|
|
||||||
DPAD_RIGHT = 0x2,
|
|
||||||
DPAD_RIGHT_DOWN = 0x3,
|
|
||||||
DPAD_DOWN = 0x4,
|
|
||||||
DPAD_DOWN_LEFT = 0x5,
|
|
||||||
DPAD_LEFT = 0x6,
|
|
||||||
DPAD_LEFT_UP = 0x7,
|
|
||||||
DPAD_OFF = 0x8,
|
|
||||||
};
|
|
||||||
|
|
||||||
// To enable serial debugging see "settings.h"
|
// To enable serial debugging see "settings.h"
|
||||||
//#define PRINTREPORT // Uncomment to print the report send by the Switch Pro Controller
|
//#define PRINTREPORT // Uncomment to print the report send by the Switch Pro Controller
|
||||||
|
|
||||||
|
@ -38,26 +26,8 @@ int8_t SwitchProParser::getButtonIndexSwitchPro(ButtonEnum b) {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SwitchProParser::checkDpad(ButtonEnum b) {
|
|
||||||
switch (b) {
|
|
||||||
case UP:
|
|
||||||
return switchProData.btn.dpad == DPAD_LEFT_UP || switchProData.btn.dpad == DPAD_UP || switchProData.btn.dpad == DPAD_UP_RIGHT;
|
|
||||||
case RIGHT:
|
|
||||||
return switchProData.btn.dpad == DPAD_UP_RIGHT || switchProData.btn.dpad == DPAD_RIGHT || switchProData.btn.dpad == DPAD_RIGHT_DOWN;
|
|
||||||
case DOWN:
|
|
||||||
return switchProData.btn.dpad == DPAD_RIGHT_DOWN || switchProData.btn.dpad == DPAD_DOWN || switchProData.btn.dpad == DPAD_DOWN_LEFT;
|
|
||||||
case LEFT:
|
|
||||||
return switchProData.btn.dpad == DPAD_DOWN_LEFT || switchProData.btn.dpad == DPAD_LEFT || switchProData.btn.dpad == DPAD_LEFT_UP;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SwitchProParser::getButtonPress(ButtonEnum b) {
|
bool SwitchProParser::getButtonPress(ButtonEnum b) {
|
||||||
const int8_t index = getButtonIndexSwitchPro(b); if (index < 0) return 0;
|
const int8_t index = getButtonIndexSwitchPro(b); if (index < 0) return 0;
|
||||||
if (index <= LEFT) // Dpad
|
|
||||||
return checkDpad(b);
|
|
||||||
else
|
|
||||||
return switchProData.btn.val & (1UL << pgm_read_byte(&SWITCH_PRO_BUTTONS[index]));
|
return switchProData.btn.val & (1UL << pgm_read_byte(&SWITCH_PRO_BUTTONS[index]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,11 +40,20 @@ bool SwitchProParser::getButtonClick(ButtonEnum b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t SwitchProParser::getAnalogHat(AnalogHatEnum a) {
|
int16_t SwitchProParser::getAnalogHat(AnalogHatEnum a) {
|
||||||
return switchProData.hatValue[(uint8_t)a] - 0x7FFF; // Subtract the center value
|
switch((uint8_t)a) {
|
||||||
|
case 0:
|
||||||
|
return switchProData.leftHatX - 2048; // Subtract the center value
|
||||||
|
case 1:
|
||||||
|
return 2048 - switchProData.leftHatY; // Invert, so it follows the same coordinate as the simple report
|
||||||
|
case 2:
|
||||||
|
return switchProData.rightHatX - 2048; // Subtract the center value
|
||||||
|
default:
|
||||||
|
return 2048 - switchProData.rightHatY; // Invert, so it follows the same coordinate as the simple report
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitchProParser::Parse(uint8_t len, uint8_t *buf) {
|
void SwitchProParser::Parse(uint8_t len, uint8_t *buf) {
|
||||||
if (len > 1 && buf) {
|
if (len > 0 && buf) {
|
||||||
#ifdef PRINTREPORT
|
#ifdef PRINTREPORT
|
||||||
Notify(PSTR("\r\nLen: "), 0x80); Notify(len, 0x80);
|
Notify(PSTR("\r\nLen: "), 0x80); Notify(len, 0x80);
|
||||||
Notify(PSTR(", data: "), 0x80);
|
Notify(PSTR(", data: "), 0x80);
|
||||||
|
@ -84,51 +63,50 @@ void SwitchProParser::Parse(uint8_t len, uint8_t *buf) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (buf[0] == 0x3F) // Simple input report
|
// This driver always uses the standard full report that includes the IMU data.
|
||||||
memcpy(&switchProData, buf + 1, min((uint8_t)(len - 1), MFK_CASTUINT8T sizeof(switchProData)));
|
// The downside is that it requires more processing power, as the data is send contentiously
|
||||||
else if (buf[0] == 0x21) // Subcommand reply
|
// while the simple input report is only send when the button state changes however the simple
|
||||||
|
// input report is not available via USB and does not include the IMU data.
|
||||||
|
|
||||||
|
if (buf[0] == 0x3F) // Simple input report via Bluetooth
|
||||||
|
switchProOutput.enableFullReportMode = true; // Switch over to the full report
|
||||||
|
else if (buf[0] == 0x30) { // Standard full mode
|
||||||
|
if (len < 4) {
|
||||||
|
#ifdef DEBUG_USB_HOST
|
||||||
|
Notify(PSTR("\r\nReport is too short: "), 0x80);
|
||||||
|
D_PrintHex<uint8_t > (len, 0x80);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
else {
|
}
|
||||||
|
memcpy(&switchProData, buf + 3, min((uint8_t)(len - 3), MFK_CASTUINT8T sizeof(switchProData)));
|
||||||
|
|
||||||
|
if (switchProData.btn.val != oldButtonState.val) { // Check if anything has changed
|
||||||
|
buttonClickState.val = switchProData.btn.val & ~oldButtonState.val; // Update click state variable
|
||||||
|
oldButtonState.val = switchProData.btn.val;
|
||||||
|
}
|
||||||
|
|
||||||
|
message_counter++;
|
||||||
|
} else if (buf[0] == 0x21) {
|
||||||
|
// Subcommand reply via Bluetooth
|
||||||
|
} else if (buf[0] == 0x81) {
|
||||||
|
// Subcommand reply via USB
|
||||||
|
} else {
|
||||||
#ifdef DEBUG_USB_HOST
|
#ifdef DEBUG_USB_HOST
|
||||||
Notify(PSTR("\r\nUnknown report id: "), 0x80);
|
Notify(PSTR("\r\nUnknown report id: "), 0x80);
|
||||||
D_PrintHex<uint8_t > (buf[0], 0x80);
|
D_PrintHex<uint8_t > (buf[0], 0x80);
|
||||||
Notify(PSTR(", len: "), 0x80);
|
Notify(PSTR(", len: "), 0x80);
|
||||||
D_PrintHex<uint8_t > (len, 0x80);
|
D_PrintHex<uint8_t > (len, 0x80);
|
||||||
#endif
|
#endif
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Workaround issue with the controller sending invalid joystick values when it is connected
|
|
||||||
for (uint8_t i = 0; i < sizeof(switchProData.hatValue) / sizeof(switchProData.hatValue[0]); i++) {
|
|
||||||
if (switchProData.hatValue[i] < 1000 || switchProData.hatValue[i] > 0xFFFF - 1000)
|
|
||||||
switchProData.hatValue[i] = 0x7FFF; // Center value
|
|
||||||
}
|
|
||||||
|
|
||||||
if (switchProData.btn.val != oldButtonState.val) { // Check if anything has changed
|
|
||||||
buttonClickState.val = switchProData.btn.val & ~oldButtonState.val; // Update click state variable
|
|
||||||
oldButtonState.val = switchProData.btn.val;
|
|
||||||
|
|
||||||
// The DPAD buttons does not set the different bits, but set a value corresponding to the buttons pressed, we will simply set the bits ourself
|
|
||||||
uint8_t newDpad = 0;
|
|
||||||
if (checkDpad(UP))
|
|
||||||
newDpad |= 1 << UP;
|
|
||||||
if (checkDpad(RIGHT))
|
|
||||||
newDpad |= 1 << RIGHT;
|
|
||||||
if (checkDpad(DOWN))
|
|
||||||
newDpad |= 1 << DOWN;
|
|
||||||
if (checkDpad(LEFT))
|
|
||||||
newDpad |= 1 << LEFT;
|
|
||||||
if (newDpad != oldDpad) {
|
|
||||||
buttonClickState.dpad = newDpad & ~oldDpad; // Override values
|
|
||||||
oldDpad = newDpad;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message_counter++;
|
if (switchProOutput.sendHandshake)
|
||||||
}
|
sendHandshake();
|
||||||
|
else if (switchProOutput.disableTimeout)
|
||||||
if (switchProOutput.ledReportChanged || switchProOutput.ledHomeReportChanged)
|
disableTimeout();
|
||||||
sendLedOutputReport(); // Send output report
|
else if (switchProOutput.ledReportChanged || switchProOutput.ledHomeReportChanged ||
|
||||||
|
switchProOutput.enableFullReportMode || switchProOutput.enableImu != -1)
|
||||||
|
sendOutputCmd();
|
||||||
else if (switchProOutput.leftRumbleOn || switchProOutput.rightRumbleOn) {
|
else if (switchProOutput.leftRumbleOn || switchProOutput.rightRumbleOn) {
|
||||||
// We need to send the rumble report repeatedly to keep it on
|
// We need to send the rumble report repeatedly to keep it on
|
||||||
uint32_t now = millis();
|
uint32_t now = millis();
|
||||||
|
@ -136,11 +114,10 @@ void SwitchProParser::Parse(uint8_t len, uint8_t *buf) {
|
||||||
rumble_on_timer = now;
|
rumble_on_timer = now;
|
||||||
sendRumbleOutputReport();
|
sendRumbleOutputReport();
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
rumble_on_timer = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitchProParser::sendLedOutputReport() {
|
void SwitchProParser::sendOutputCmd() {
|
||||||
// See: https://github.com/Dan611/hid-procon
|
// See: https://github.com/Dan611/hid-procon
|
||||||
// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering
|
// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering
|
||||||
// https://github.com/HisashiKato/USB_Host_Shield_Library_2.0_BTXBOX/blob/master/src/SWProBTParser.h#L152-L153
|
// https://github.com/HisashiKato/USB_Host_Shield_Library_2.0_BTXBOX/blob/master/src/SWProBTParser.h#L152-L153
|
||||||
|
@ -196,6 +173,21 @@ void SwitchProParser::sendLedOutputReport() {
|
||||||
buf[0x0A + 3] = (0xF /* Mini Cycle 1 LED intensity */ << 4) | 0x0 /* Mini Cycle 2 LED intensity */;
|
buf[0x0A + 3] = (0xF /* Mini Cycle 1 LED intensity */ << 4) | 0x0 /* Mini Cycle 2 LED intensity */;
|
||||||
|
|
||||||
sendOutputReport(buf, 10 + 4);
|
sendOutputReport(buf, 10 + 4);
|
||||||
|
} else if (switchProOutput.enableFullReportMode) {
|
||||||
|
switchProOutput.enableFullReportMode = false;
|
||||||
|
|
||||||
|
// See: https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/bluetooth_hid_subcommands_notes.md#subcommand-0x03-set-input-report-mode
|
||||||
|
buf[0x0A + 0] = 0x03; // PROCON_CMD_MODE
|
||||||
|
buf[0x0A + 1] = 0x30; // PROCON_ARG_INPUT_FULL
|
||||||
|
|
||||||
|
sendOutputReport(buf, 10 + 2);
|
||||||
|
} else if (switchProOutput.enableImu != -1) {
|
||||||
|
// See: https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/bluetooth_hid_subcommands_notes.md#subcommand-0x40-enable-imu-6-axis-sensor
|
||||||
|
buf[0x0A + 0] = 0x40; // PROCON_CMD_GYRO
|
||||||
|
buf[0x0A + 1] = switchProOutput.enableImu ? 1 : 0; // The new state is stored in the variable
|
||||||
|
switchProOutput.enableImu = -1;
|
||||||
|
|
||||||
|
sendOutputReport(buf, 12);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,7 +195,6 @@ void SwitchProParser::sendRumbleOutputReport() {
|
||||||
// See: https://github.com/Dan611/hid-procon
|
// See: https://github.com/Dan611/hid-procon
|
||||||
// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering
|
// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering
|
||||||
// https://github.com/HisashiKato/USB_Host_Shield_Library_2.0_BTXBOX/blob/master/src/SWProBTParser.h#L152-L153
|
// https://github.com/HisashiKato/USB_Host_Shield_Library_2.0_BTXBOX/blob/master/src/SWProBTParser.h#L152-L153
|
||||||
|
|
||||||
uint8_t buf[10] = { 0 };
|
uint8_t buf[10] = { 0 };
|
||||||
buf[0x00] = 0x10; // Report ID - PROCON_CMD_RUMBLE_ONLY
|
buf[0x00] = 0x10; // Report ID - PROCON_CMD_RUMBLE_ONLY
|
||||||
buf[0x01] = output_sequence_counter++; // Lowest 4-bit is a sequence number, which needs to be increased for every report
|
buf[0x01] = output_sequence_counter++; // Lowest 4-bit is a sequence number, which needs to be increased for every report
|
||||||
|
@ -238,15 +229,14 @@ void SwitchProParser::sendRumbleOutputReport() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitchProParser::Reset() {
|
void SwitchProParser::Reset() {
|
||||||
for (uint8_t i = 0; i < sizeof(switchProData.hatValue) / sizeof(switchProData.hatValue[0]); i++)
|
// Center joysticks
|
||||||
switchProData.hatValue[i] = 0x7FFF; // Center value
|
switchProData.leftHatX = switchProData.leftHatY = switchProData.rightHatX = switchProData.rightHatY = 2048;
|
||||||
|
|
||||||
|
// Reset buttons variables
|
||||||
switchProData.btn.val = 0;
|
switchProData.btn.val = 0;
|
||||||
oldButtonState.val = 0;
|
oldButtonState.val = 0;
|
||||||
|
buttonClickState.val = 0;
|
||||||
|
|
||||||
switchProData.btn.dpad = DPAD_OFF;
|
|
||||||
oldButtonState.dpad = DPAD_OFF;
|
|
||||||
buttonClickState.dpad = 0;
|
|
||||||
oldDpad = 0;
|
|
||||||
output_sequence_counter = 0;
|
output_sequence_counter = 0;
|
||||||
rumble_on_timer = 0;
|
rumble_on_timer = 0;
|
||||||
|
|
||||||
|
@ -256,4 +246,8 @@ void SwitchProParser::Reset() {
|
||||||
switchProOutput.ledHome = false;
|
switchProOutput.ledHome = false;
|
||||||
switchProOutput.ledReportChanged = false;
|
switchProOutput.ledReportChanged = false;
|
||||||
switchProOutput.ledHomeReportChanged = false;
|
switchProOutput.ledHomeReportChanged = false;
|
||||||
|
switchProOutput.enableFullReportMode = false;
|
||||||
|
switchProOutput.enableImu = -1;
|
||||||
|
switchProOutput.sendHandshake = false;
|
||||||
|
switchProOutput.disableTimeout = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -39,73 +39,99 @@ const uint8_t SWITCH_PRO_LEDS[] PROGMEM = {
|
||||||
|
|
||||||
/** Buttons on the controller */
|
/** Buttons on the controller */
|
||||||
const uint8_t SWITCH_PRO_BUTTONS[] PROGMEM = {
|
const uint8_t SWITCH_PRO_BUTTONS[] PROGMEM = {
|
||||||
0x10, // UP
|
0x11, // UP
|
||||||
0x11, // RIGHT
|
0x12, // RIGHT
|
||||||
0x12, // DOWN
|
0x10, // DOWN
|
||||||
0x13, // LEFT
|
0x13, // LEFT
|
||||||
|
|
||||||
0x0D, // Capture
|
0x0D, // Capture
|
||||||
0x09, // PLUS
|
0x09, // PLUS
|
||||||
0x0A, // L3
|
0x0B, // L3
|
||||||
0x0B, // R3
|
0x0A, // R3
|
||||||
|
|
||||||
0x08, // MINUS
|
0x08, // MINUS
|
||||||
0x0C, // HOME
|
0x0C, // HOME
|
||||||
0, 0, // Skip
|
0, 0, // Skip
|
||||||
|
|
||||||
0x00, // B
|
0x02, // B
|
||||||
0x01, // A
|
0x03, // A
|
||||||
0x03, // X
|
0x01, // X
|
||||||
0x02, // Y
|
0x00, // Y
|
||||||
|
|
||||||
0x04, // L
|
0x16, // L
|
||||||
0x05, // R
|
0x06, // R
|
||||||
0x06, // ZL
|
0x17, // ZL
|
||||||
0x07, // ZR
|
0x07, // ZR
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/bluetooth_hid_notes.md#standard-input-report-format
|
||||||
union SwitchProButtons {
|
union SwitchProButtons {
|
||||||
struct {
|
struct {
|
||||||
uint8_t b : 1;
|
|
||||||
uint8_t a : 1;
|
|
||||||
uint8_t y : 1;
|
uint8_t y : 1;
|
||||||
uint8_t x : 1;
|
uint8_t x : 1;
|
||||||
|
uint8_t b : 1;
|
||||||
|
uint8_t a : 1;
|
||||||
|
|
||||||
uint8_t l : 1;
|
uint8_t dummy1 : 2;
|
||||||
uint8_t r : 1;
|
uint8_t r : 1;
|
||||||
uint8_t zl : 1;
|
|
||||||
uint8_t zr : 1;
|
uint8_t zr : 1;
|
||||||
|
|
||||||
uint8_t minus : 1;
|
uint8_t minus : 1;
|
||||||
uint8_t plus : 1;
|
uint8_t plus : 1;
|
||||||
uint8_t l3 : 1;
|
|
||||||
uint8_t r3 : 1;
|
uint8_t r3 : 1;
|
||||||
|
uint8_t l3 : 1;
|
||||||
|
|
||||||
uint8_t home : 1;
|
uint8_t home : 1;
|
||||||
uint8_t capture : 1;
|
uint8_t capture : 1;
|
||||||
uint8_t dummy1 : 2;
|
uint8_t dummy2 : 2;
|
||||||
|
|
||||||
uint8_t dpad : 4;
|
uint8_t dpad : 4;
|
||||||
uint8_t dummy2 : 4;
|
|
||||||
|
uint8_t dummy3 : 2;
|
||||||
|
uint8_t l : 1;
|
||||||
|
uint8_t zl : 1;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
uint32_t val : 24;
|
uint32_t val : 24;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct ImuData {
|
||||||
|
int16_t accX, accY, accZ;
|
||||||
|
int16_t gyroX, gyroY, gyroZ;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
struct SwitchProData {
|
struct SwitchProData {
|
||||||
|
// TODO: Add byte 2 containing battery level and connection info
|
||||||
|
|
||||||
/* Button and joystick values */
|
/* Button and joystick values */
|
||||||
SwitchProButtons btn; // 0-2 bytes
|
SwitchProButtons btn; // Bytes 3-5
|
||||||
uint16_t hatValue[4]; // 3-10 bytes
|
|
||||||
|
// Bytes 6-11
|
||||||
|
uint16_t leftHatX : 12;
|
||||||
|
uint16_t leftHatY : 12;
|
||||||
|
uint16_t rightHatX : 12;
|
||||||
|
uint16_t rightHatY : 12;
|
||||||
|
|
||||||
|
uint8_t vibratorInput; // What is this used for?
|
||||||
|
|
||||||
|
// Bytes 13-48
|
||||||
|
// Three samples of the IMU is sent in one message
|
||||||
|
// See: https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/imu_sensor_notes.md
|
||||||
|
ImuData imu[3];
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
struct SwitchProOutput {
|
struct SwitchProOutput {
|
||||||
bool leftRumbleOn;
|
bool leftRumbleOn;
|
||||||
bool rightRumbleOn;
|
bool rightRumbleOn;
|
||||||
uint8_t ledMask; // Higher nibble flashes the LEDs, lower nibble set them on/off
|
uint8_t ledMask; // Higher nibble flashes the LEDs, lower nibble sets them on/off
|
||||||
bool ledHome;
|
bool ledHome;
|
||||||
|
|
||||||
// Used to only send the report when the state changes
|
// Used to send the reports at the same rate as the controller is sending messages
|
||||||
bool ledReportChanged;
|
bool ledReportChanged;
|
||||||
bool ledHomeReportChanged;
|
bool ledHomeReportChanged;
|
||||||
|
bool enableFullReportMode;
|
||||||
|
int8_t enableImu; // -1 == Do nothing, 0 == disable IMU, 1 == enable IMU
|
||||||
|
bool sendHandshake;
|
||||||
|
bool disableTimeout;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
/** This class parses all the data sent by the Switch Pro controller */
|
/** This class parses all the data sent by the Switch Pro controller */
|
||||||
|
@ -138,7 +164,15 @@ public:
|
||||||
*/
|
*/
|
||||||
int16_t getAnalogHat(AnalogHatEnum a);
|
int16_t getAnalogHat(AnalogHatEnum a);
|
||||||
|
|
||||||
#if 0
|
/**
|
||||||
|
* Used to enable/disable the IMU. By default it is disabled.
|
||||||
|
* @param enable Enable/disable the IMU.
|
||||||
|
*/
|
||||||
|
void enableImu(bool enable) {
|
||||||
|
// TODO: Should we just always enable it?
|
||||||
|
switchProOutput.enableImu = enable ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the angle of the controller calculated using the accelerometer.
|
* Get the angle of the controller calculated using the accelerometer.
|
||||||
* @param a Either ::Pitch or ::Roll.
|
* @param a Either ::Pitch or ::Roll.
|
||||||
|
@ -146,9 +180,9 @@ public:
|
||||||
*/
|
*/
|
||||||
float getAngle(AngleEnum a) {
|
float getAngle(AngleEnum a) {
|
||||||
if (a == Pitch)
|
if (a == Pitch)
|
||||||
return (atan2f(-ps5Data.accY, -ps5Data.accZ) + PI) * RAD_TO_DEG;
|
return (atan2f(-switchProData.imu[0].accY, -switchProData.imu[0].accZ) + PI) * RAD_TO_DEG;
|
||||||
else
|
else
|
||||||
return (atan2f(ps5Data.accX, -ps5Data.accZ) + PI) * RAD_TO_DEG;
|
return (atan2f(switchProData.imu[0].accX, -switchProData.imu[0].accZ) + PI) * RAD_TO_DEG;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -159,22 +193,21 @@ public:
|
||||||
int16_t getSensor(SensorEnum s) {
|
int16_t getSensor(SensorEnum s) {
|
||||||
switch(s) {
|
switch(s) {
|
||||||
case gX:
|
case gX:
|
||||||
return ps5Data.gyroX;
|
return switchProData.imu[0].gyroX;
|
||||||
case gY:
|
case gY:
|
||||||
return ps5Data.gyroY;
|
return switchProData.imu[0].gyroY;
|
||||||
case gZ:
|
case gZ:
|
||||||
return ps5Data.gyroZ;
|
return switchProData.imu[0].gyroZ;
|
||||||
case aX:
|
case aX:
|
||||||
return ps5Data.accX;
|
return switchProData.imu[0].accX;
|
||||||
case aY:
|
case aY:
|
||||||
return ps5Data.accY;
|
return switchProData.imu[0].accY;
|
||||||
case aZ:
|
case aZ:
|
||||||
return ps5Data.accZ;
|
return switchProData.imu[0].accZ;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|
||||||
/** Turn both rumble and the LEDs off. */
|
/** Turn both rumble and the LEDs off. */
|
||||||
void setAllOff() {
|
void setAllOff() {
|
||||||
|
@ -305,17 +338,27 @@ protected:
|
||||||
*/
|
*/
|
||||||
virtual void sendOutputReport(uint8_t *data, uint8_t len) = 0;
|
virtual void sendOutputReport(uint8_t *data, uint8_t len) = 0;
|
||||||
|
|
||||||
|
/** Used to send a handshake command via USB before disabling the timeout. */
|
||||||
|
virtual void sendHandshake() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Needed to disable USB timeout for the controller,
|
||||||
|
* so it sends out data without the host having to send data continuously.
|
||||||
|
*/
|
||||||
|
virtual void disableTimeout() {}
|
||||||
|
|
||||||
|
/** Allow derived classes to access the output variables. */
|
||||||
|
SwitchProOutput switchProOutput;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static int8_t getButtonIndexSwitchPro(ButtonEnum b);
|
static int8_t getButtonIndexSwitchPro(ButtonEnum b);
|
||||||
bool checkDpad(ButtonEnum b); // Used to check Switch Pro DPAD buttons
|
bool checkDpad(ButtonEnum b); // Used to check Switch Pro DPAD buttons
|
||||||
|
|
||||||
void sendLedOutputReport();
|
void sendOutputCmd();
|
||||||
void sendRumbleOutputReport();
|
void sendRumbleOutputReport();
|
||||||
|
|
||||||
SwitchProData switchProData;
|
SwitchProData switchProData;
|
||||||
SwitchProButtons oldButtonState, buttonClickState;
|
SwitchProButtons oldButtonState, buttonClickState;
|
||||||
SwitchProOutput switchProOutput;
|
|
||||||
uint8_t oldDpad;
|
|
||||||
uint16_t message_counter = 0;
|
uint16_t message_counter = 0;
|
||||||
uint8_t output_sequence_counter : 4;
|
uint8_t output_sequence_counter : 4;
|
||||||
uint32_t rumble_on_timer = 0;
|
uint32_t rumble_on_timer = 0;
|
||||||
|
|
145
SwitchProUSB.h
Normal file
145
SwitchProUSB.h
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
/* Copyright (C) 2021 Kristian Sloth Lauszus. All rights reserved.
|
||||||
|
|
||||||
|
This software may be distributed and modified under the terms of the GNU
|
||||||
|
General Public License version 2 (GPL2) as published by the Free Software
|
||||||
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||||
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||||
|
on this software must also be made publicly available under the terms of
|
||||||
|
the GPL2 ("Copyleft").
|
||||||
|
|
||||||
|
Contact information
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Kristian Sloth Lauszus
|
||||||
|
Web : https://lauszus.com
|
||||||
|
e-mail : lauszus@gmail.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _switch_pro_usb_h_
|
||||||
|
#define _switch_pro_usb_h_
|
||||||
|
|
||||||
|
#include "hiduniversal.h"
|
||||||
|
#include "SwitchProParser.h"
|
||||||
|
|
||||||
|
#define SWITCH_PRO_VID 0x057E // Nintendo Corporation
|
||||||
|
#define SWITCH_PRO_PID 0x2009 // Switch Pro Controller
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class implements support for the Switch Pro controller via USB.
|
||||||
|
* It uses the HIDUniversal class for all the USB communication.
|
||||||
|
*/
|
||||||
|
class SwitchProUSB : public HIDUniversal, public SwitchProParser {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor for the SwitchProUSB class.
|
||||||
|
* @param p Pointer to the USB class instance.
|
||||||
|
*/
|
||||||
|
SwitchProUSB(USB *p) :
|
||||||
|
HIDUniversal(p) {
|
||||||
|
SwitchProParser::Reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to check if a Switch Pro controller is connected.
|
||||||
|
* @return Returns true if it is connected.
|
||||||
|
*/
|
||||||
|
bool connected() {
|
||||||
|
return HIDUniversal::isReady() && HIDUniversal::VID == SWITCH_PRO_VID && HIDUniversal::PID == SWITCH_PRO_PID;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to call your own function when the device is successfully initialized.
|
||||||
|
* @param funcOnInit Function to call.
|
||||||
|
*/
|
||||||
|
void attachOnInit(void (*funcOnInit)(void)) {
|
||||||
|
pFuncOnInit = funcOnInit;
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** @name HIDUniversal implementation */
|
||||||
|
/**
|
||||||
|
* Used to parse USB HID data.
|
||||||
|
* @param hid Pointer to the HID class.
|
||||||
|
* @param is_rpt_id Only used for Hubs.
|
||||||
|
* @param len The length of the incoming data.
|
||||||
|
* @param buf Pointer to the data buffer.
|
||||||
|
*/
|
||||||
|
virtual void ParseHIDData(USBHID *hid __attribute__((unused)), bool is_rpt_id __attribute__((unused)), uint8_t len, uint8_t *buf) {
|
||||||
|
if (HIDUniversal::VID == SWITCH_PRO_VID && HIDUniversal::PID == SWITCH_PRO_PID)
|
||||||
|
SwitchProParser::Parse(len, buf);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a device is successfully initialized.
|
||||||
|
* Use attachOnInit(void (*funcOnInit)(void)) to call your own function.
|
||||||
|
* This is useful for instance if you want to set the LEDs in a specific way.
|
||||||
|
*/
|
||||||
|
virtual uint8_t OnInitSuccessful() {
|
||||||
|
if (HIDUniversal::VID == SWITCH_PRO_VID && HIDUniversal::PID == SWITCH_PRO_PID) {
|
||||||
|
SwitchProParser::Reset();
|
||||||
|
|
||||||
|
// We need to send a handshake and disable the timeout or the Pro controller will stop sending data via USB
|
||||||
|
// We can not send the commands quickly after each other, so we simply send out the commands at the same
|
||||||
|
// rate as the controller is sending data
|
||||||
|
switchProOutput.sendHandshake = switchProOutput.disableTimeout = true;
|
||||||
|
|
||||||
|
if (pFuncOnInit)
|
||||||
|
pFuncOnInit(); // Call the user function
|
||||||
|
else {
|
||||||
|
setLedOn(LED1); // Turn on the LED1
|
||||||
|
setLedHomeOn(); // Turn on the home LED
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
/** @name SwitchProParser implementation */
|
||||||
|
virtual void sendOutputReport(uint8_t *data, uint8_t len) {
|
||||||
|
// The first 8 bytes are always the same. The actual report follows
|
||||||
|
uint8_t buf[8 + len] = { 0x80 /* PROCON_REPORT_SEND_USB */, 0x92 /*PROCON_USB_DO_CMD */, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
memcpy(buf + 8, data, len);
|
||||||
|
|
||||||
|
// Endpoint (control endpoint), Interface (0x00), Report Type (Output 0x02), Report ID (0x80), nbytes, data
|
||||||
|
SetReport(epInfo[0].epAddr, 0, 0x02, buf[0], sizeof(buf), buf);
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void sendHandshake() {
|
||||||
|
switchProOutput.sendHandshake = false;
|
||||||
|
|
||||||
|
// See: https://github.com/Dan611/hid-procon/blob/master/hid-procon.c
|
||||||
|
// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/USB-HID-Notes.md
|
||||||
|
uint8_t buf[2] = { 0x80 /* PROCON_REPORT_SEND_USB */, 0x02 /* PROCON_USB_HANDSHAKE */ };
|
||||||
|
|
||||||
|
// Endpoint (control endpoint), Interface (0x00), Report Type (Output 0x02), Report ID (0x80), nbytes, data
|
||||||
|
SetReport(epInfo[0].epAddr, 0, 0x02, buf[0], sizeof(buf), buf);
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void disableTimeout() {
|
||||||
|
switchProOutput.disableTimeout = false;
|
||||||
|
|
||||||
|
// See: https://github.com/Dan611/hid-procon/blob/master/hid-procon.c
|
||||||
|
// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/USB-HID-Notes.md
|
||||||
|
uint8_t buf[2] = { 0x80 /* PROCON_REPORT_SEND_USB */, 0x04 /* PROCON_USB_ENABLE */ };
|
||||||
|
|
||||||
|
// Endpoint (control endpoint), Interface (0x00), Report Type (Output 0x02), Report ID (0x80), nbytes, data
|
||||||
|
SetReport(epInfo[0].epAddr, 0, 0x02, buf[0], sizeof(buf), buf);
|
||||||
|
};
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
/** @name USBDeviceConfig implementation */
|
||||||
|
/**
|
||||||
|
* Used by the USB core to check what this driver support.
|
||||||
|
* @param vid The device's VID.
|
||||||
|
* @param pid The device's PID.
|
||||||
|
* @return Returns true if the device's VID and PID matches this driver.
|
||||||
|
*/
|
||||||
|
virtual bool VIDPIDOK(uint16_t vid, uint16_t pid) {
|
||||||
|
return (vid == SWITCH_PRO_VID && pid == SWITCH_PRO_PID);
|
||||||
|
};
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
private:
|
||||||
|
void (*pFuncOnInit)(void); // Pointer to function called in onInit()
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -25,6 +25,7 @@ SwitchProBT SwitchPro(&Btd, PAIR);
|
||||||
// After that you can simply create the instance like so and then press a button on the device
|
// After that you can simply create the instance like so and then press a button on the device
|
||||||
//SwitchProBT SwitchPro(&Btd);
|
//SwitchProBT SwitchPro(&Btd);
|
||||||
|
|
||||||
|
bool printAngle = false;
|
||||||
uint16_t lastMessageCounter = -1;
|
uint16_t lastMessageCounter = -1;
|
||||||
uint32_t capture_timer;
|
uint32_t capture_timer;
|
||||||
|
|
||||||
|
@ -46,10 +47,11 @@ void loop() {
|
||||||
if (SwitchPro.connected() && lastMessageCounter != SwitchPro.getMessageCounter()) {
|
if (SwitchPro.connected() && lastMessageCounter != SwitchPro.getMessageCounter()) {
|
||||||
lastMessageCounter = SwitchPro.getMessageCounter();
|
lastMessageCounter = SwitchPro.getMessageCounter();
|
||||||
|
|
||||||
if (SwitchPro.getAnalogHat(LeftHatX) > 5000 || SwitchPro.getAnalogHat(LeftHatX) < -5000 ||
|
// The joysticks values are uncalibrated
|
||||||
SwitchPro.getAnalogHat(LeftHatY) > 5000 || SwitchPro.getAnalogHat(LeftHatY) < -5000 ||
|
if (SwitchPro.getAnalogHat(LeftHatX) > 500 || SwitchPro.getAnalogHat(LeftHatX) < -500 ||
|
||||||
SwitchPro.getAnalogHat(RightHatX) > 5000 || SwitchPro.getAnalogHat(RightHatX) < -5000 ||
|
SwitchPro.getAnalogHat(LeftHatY) > 500 || SwitchPro.getAnalogHat(LeftHatY) < -500 ||
|
||||||
SwitchPro.getAnalogHat(RightHatY) > 5000 || SwitchPro.getAnalogHat(RightHatY) < -5000) {
|
SwitchPro.getAnalogHat(RightHatX) > 500 || SwitchPro.getAnalogHat(RightHatX) < -500 ||
|
||||||
|
SwitchPro.getAnalogHat(RightHatY) > 500 || SwitchPro.getAnalogHat(RightHatY) < -500) {
|
||||||
Serial.print(F("\r\nLeftHatX: "));
|
Serial.print(F("\r\nLeftHatX: "));
|
||||||
Serial.print(SwitchPro.getAnalogHat(LeftHatX));
|
Serial.print(SwitchPro.getAnalogHat(LeftHatX));
|
||||||
Serial.print(F("\tLeftHatY: "));
|
Serial.print(F("\tLeftHatY: "));
|
||||||
|
@ -97,8 +99,11 @@ void loop() {
|
||||||
Serial.print(F("\r\nDown"));
|
Serial.print(F("\r\nDown"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SwitchPro.getButtonClick(PLUS))
|
if (SwitchPro.getButtonClick(PLUS)) {
|
||||||
|
printAngle = !printAngle;
|
||||||
|
SwitchPro.enableImu(printAngle);
|
||||||
Serial.print(F("\r\nPlus"));
|
Serial.print(F("\r\nPlus"));
|
||||||
|
}
|
||||||
if (SwitchPro.getButtonClick(MINUS))
|
if (SwitchPro.getButtonClick(MINUS))
|
||||||
Serial.print(F("\r\nMinus"));
|
Serial.print(F("\r\nMinus"));
|
||||||
|
|
||||||
|
@ -131,5 +136,12 @@ void loop() {
|
||||||
Serial.print(F("\r\nL3"));
|
Serial.print(F("\r\nL3"));
|
||||||
if (SwitchPro.getButtonClick(R3))
|
if (SwitchPro.getButtonClick(R3))
|
||||||
Serial.print(F("\r\nR3"));
|
Serial.print(F("\r\nR3"));
|
||||||
|
|
||||||
|
if (printAngle) { // Print angle calculated using the accelerometer only
|
||||||
|
Serial.print(F("\r\nPitch: "));
|
||||||
|
Serial.print(SwitchPro.getAngle(Pitch));
|
||||||
|
Serial.print(F("\tRoll: "));
|
||||||
|
Serial.print(SwitchPro.getAngle(Roll));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
128
examples/SwitchProUSB/SwitchProUSB.ino
Normal file
128
examples/SwitchProUSB/SwitchProUSB.ino
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
/*
|
||||||
|
Example sketch for the Switch Pro USB library - developed by Kristian Sloth Lauszus
|
||||||
|
For more information visit the Github repository: github.com/felis/USB_Host_Shield_2.0 or
|
||||||
|
send me an e-mail: lauszus@gmail.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <SwitchProUSB.h>
|
||||||
|
|
||||||
|
// Satisfy the IDE, which needs to see the include statement in the ino too.
|
||||||
|
#ifdef dobogusinclude
|
||||||
|
#include <spi4teensy3.h>
|
||||||
|
#endif
|
||||||
|
#include <SPI.h>
|
||||||
|
|
||||||
|
USB Usb;
|
||||||
|
SwitchProUSB SwitchPro(&Usb);
|
||||||
|
|
||||||
|
bool printAngle = false;
|
||||||
|
uint16_t lastMessageCounter = -1;
|
||||||
|
uint32_t capture_timer;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
#if !defined(__MIPSEL__)
|
||||||
|
while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
|
||||||
|
#endif
|
||||||
|
if (Usb.Init() == -1) {
|
||||||
|
Serial.print(F("\r\nOSC did not start"));
|
||||||
|
while (1); // Halt
|
||||||
|
}
|
||||||
|
Serial.print(F("\r\nSwitch Pro USB Library Started"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
Usb.Task();
|
||||||
|
|
||||||
|
if (SwitchPro.connected() && lastMessageCounter != SwitchPro.getMessageCounter()) {
|
||||||
|
lastMessageCounter = SwitchPro.getMessageCounter();
|
||||||
|
|
||||||
|
// The joysticks values are uncalibrated
|
||||||
|
if (SwitchPro.getAnalogHat(LeftHatX) > 500 || SwitchPro.getAnalogHat(LeftHatX) < -500 ||
|
||||||
|
SwitchPro.getAnalogHat(LeftHatY) > 500 || SwitchPro.getAnalogHat(LeftHatY) < -500 ||
|
||||||
|
SwitchPro.getAnalogHat(RightHatX) > 500 || SwitchPro.getAnalogHat(RightHatX) < -500 ||
|
||||||
|
SwitchPro.getAnalogHat(RightHatY) > 500 || SwitchPro.getAnalogHat(RightHatY) < -500) {
|
||||||
|
Serial.print(F("\r\nLeftHatX: "));
|
||||||
|
Serial.print(SwitchPro.getAnalogHat(LeftHatX));
|
||||||
|
Serial.print(F("\tLeftHatY: "));
|
||||||
|
Serial.print(SwitchPro.getAnalogHat(LeftHatY));
|
||||||
|
Serial.print(F("\tRightHatX: "));
|
||||||
|
Serial.print(SwitchPro.getAnalogHat(RightHatX));
|
||||||
|
Serial.print(F("\tRightHatY: "));
|
||||||
|
Serial.print(SwitchPro.getAnalogHat(RightHatY));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SwitchPro.getButtonClick(CAPTURE))
|
||||||
|
Serial.print(F("\r\nCapture"));
|
||||||
|
if (SwitchPro.getButtonClick(HOME)) {
|
||||||
|
Serial.print(F("\r\nHome"));
|
||||||
|
SwitchPro.setLedHomeToggle();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SwitchPro.getButtonClick(LEFT)) {
|
||||||
|
SwitchPro.setLedOff();
|
||||||
|
SwitchPro.setLedOn(LED1);
|
||||||
|
Serial.print(F("\r\nLeft"));
|
||||||
|
}
|
||||||
|
if (SwitchPro.getButtonClick(UP)) {
|
||||||
|
SwitchPro.setLedOff();
|
||||||
|
SwitchPro.setLedOn(LED2);
|
||||||
|
Serial.print(F("\r\nUp"));
|
||||||
|
}
|
||||||
|
if (SwitchPro.getButtonClick(RIGHT)) {
|
||||||
|
SwitchPro.setLedOff();
|
||||||
|
SwitchPro.setLedOn(LED3);
|
||||||
|
Serial.print(F("\r\nRight"));
|
||||||
|
}
|
||||||
|
if (SwitchPro.getButtonClick(DOWN)) {
|
||||||
|
SwitchPro.setLedOff();
|
||||||
|
SwitchPro.setLedOn(LED4);
|
||||||
|
Serial.print(F("\r\nDown"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SwitchPro.getButtonClick(PLUS)) {
|
||||||
|
printAngle = !printAngle;
|
||||||
|
SwitchPro.enableImu(printAngle);
|
||||||
|
Serial.print(F("\r\nPlus"));
|
||||||
|
}
|
||||||
|
if (SwitchPro.getButtonClick(MINUS))
|
||||||
|
Serial.print(F("\r\nMinus"));
|
||||||
|
|
||||||
|
if (SwitchPro.getButtonClick(A))
|
||||||
|
Serial.print(F("\r\nA"));
|
||||||
|
if (SwitchPro.getButtonClick(B))
|
||||||
|
Serial.print(F("\r\nB"));
|
||||||
|
if (SwitchPro.getButtonClick(X))
|
||||||
|
Serial.print(F("\r\nX"));
|
||||||
|
if (SwitchPro.getButtonClick(Y))
|
||||||
|
Serial.print(F("\r\nY"));
|
||||||
|
|
||||||
|
if (SwitchPro.getButtonClick(L)) {
|
||||||
|
SwitchPro.setRumbleLeft(false);
|
||||||
|
Serial.print(F("\r\nL"));
|
||||||
|
}
|
||||||
|
if (SwitchPro.getButtonClick(R)) {
|
||||||
|
SwitchPro.setRumbleRight(false);
|
||||||
|
Serial.print(F("\r\nR"));
|
||||||
|
}
|
||||||
|
if (SwitchPro.getButtonClick(ZL)) {
|
||||||
|
SwitchPro.setRumbleLeft(true);
|
||||||
|
Serial.print(F("\r\nZL"));
|
||||||
|
}
|
||||||
|
if (SwitchPro.getButtonClick(ZR)) {
|
||||||
|
SwitchPro.setRumbleRight(true);
|
||||||
|
Serial.print(F("\r\nZR"));
|
||||||
|
}
|
||||||
|
if (SwitchPro.getButtonClick(L3))
|
||||||
|
Serial.print(F("\r\nL3"));
|
||||||
|
if (SwitchPro.getButtonClick(R3))
|
||||||
|
Serial.print(F("\r\nR3"));
|
||||||
|
|
||||||
|
if (printAngle) { // Print angle calculated using the accelerometer only
|
||||||
|
Serial.print(F("\r\nPitch: "));
|
||||||
|
Serial.print(SwitchPro.getAngle(Pitch));
|
||||||
|
Serial.print(F("\tRoll: "));
|
||||||
|
Serial.print(SwitchPro.getAngle(Roll));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,6 +39,7 @@ PS4USB KEYWORD1
|
||||||
PS5BT KEYWORD1
|
PS5BT KEYWORD1
|
||||||
PS5USB KEYWORD1
|
PS5USB KEYWORD1
|
||||||
SwitchProBT KEYWORD1
|
SwitchProBT KEYWORD1
|
||||||
|
SwitchProUSB KEYWORD1
|
||||||
|
|
||||||
####################################################
|
####################################################
|
||||||
# Methods and Functions (KEYWORD2)
|
# Methods and Functions (KEYWORD2)
|
||||||
|
@ -62,8 +63,11 @@ getTemperature KEYWORD2
|
||||||
disconnect KEYWORD2
|
disconnect KEYWORD2
|
||||||
|
|
||||||
setAllOff KEYWORD2
|
setAllOff KEYWORD2
|
||||||
|
setRumble KEYWORD2
|
||||||
setRumbleOff KEYWORD2
|
setRumbleOff KEYWORD2
|
||||||
setRumbleOn KEYWORD2
|
setRumbleOn KEYWORD2
|
||||||
|
setRumbleLeft KEYWORD2
|
||||||
|
setRumbleRight KEYWORD2
|
||||||
setLedOff KEYWORD2
|
setLedOff KEYWORD2
|
||||||
setLedOn KEYWORD2
|
setLedOn KEYWORD2
|
||||||
setLedToggle KEYWORD2
|
setLedToggle KEYWORD2
|
||||||
|
|
Loading…
Reference in a new issue