Merge pull request #632 from felis/switch_pro

Added support for the Switch Pro controller
This commit is contained in:
Kristian Sloth Lauszus 2021-05-09 22:37:16 +02:00 committed by GitHub
commit 2fa4976e06
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 1209 additions and 5 deletions

View file

@ -8,7 +8,7 @@ jobs:
strategy:
matrix:
# 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/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:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2

View file

@ -23,7 +23,7 @@ For more information about the hardware see the [Hardware Manual](https://chome.
* __Alexei Glushchenko__ - <alex-gl@mail.ru>
* Developers of the USB Core, HID, FTDI, ADK, ACM, and PL2303 libraries
* __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>
* Major contributor to mass storage code
* __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 S Library](#xbox-one-s-library)
* [Wii library](#wii-library)
* [Switch Pro Library](#switch-pro-library)
* [PS Buzz Library](#ps-buzz-library)
* [HID Libraries](#hid-libraries)
* [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>
* 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)
This library implements support for the Playstation Buzz controllers via USB.

94
SwitchProBT.h Normal file
View file

@ -0,0 +1,94 @@
/* 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_bt_h_
#define _switch_pro_bt_h_
#include "BTHID.h"
#include "SwitchProParser.h"
/**
* This class implements support for the Switch Pro controller via Bluetooth.
* It uses the BTHID class for all the Bluetooth communication.
*/
class SwitchProBT : public BTHID, public SwitchProParser {
public:
/**
* Constructor for the SwitchProBT class.
* @param p Pointer to the BTD class instance.
* @param pair Set this to true in order to pair with the device. If the argument is omitted then it will not pair with it. One can use ::PAIR to set it to true.
* @param pin Write the pin to BTD#btdPin. If argument is omitted, then "0000" will be used.
*/
SwitchProBT(BTD *p, bool pair = false, const char *pin = "0000") :
BTHID(p, pair, pin) {
SwitchProParser::Reset();
};
/**
* Used to check if a Switch Pro controller is connected.
* @return Returns true if it is connected.
*/
bool connected() {
return BTHID::connected;
};
protected:
/** @name BTHID implementation */
/**
* Used to parse Bluetooth HID data.
* @param len The length of the incoming data.
* @param buf Pointer to the data buffer.
*/
virtual void ParseBTHIDData(uint8_t len, uint8_t *buf) {
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 void OnInitBTHID() {
SwitchProParser::Reset();
// Only call this is a user function has not been set
if (!pFuncOnInit) {
setLedOn(LED1); // Turn on the LED1
setLedHomeOn(); // Turn on the home LED
}
};
/** Used to reset the different buffers to there default values */
virtual void ResetBTHID() {
SwitchProParser::Reset();
};
/**@}*/
/** @name SwitchProParser implementation */
virtual void sendOutputReport(uint8_t *data, uint8_t len) {
uint8_t buf[1 /* BT DATA Output Report */ + len];
// Send as a Bluetooth HID DATA output report on the interrupt channel
buf[0] = 0xA2; // HID BT DATA (0xA0) | Report Type (Output 0x02)
memcpy(&buf[1], data, len);
// Send the Bluetooth DATA output report on the interrupt channel
pBtd->L2CAP_Command(hci_handle, buf, sizeof(buf), interrupt_scid[0], interrupt_scid[1]);
};
/**@}*/
};
#endif

253
SwitchProParser.cpp Normal file
View file

@ -0,0 +1,253 @@
/* 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
*/
#include "SwitchProParser.h"
// To enable serial debugging see "settings.h"
//#define PRINTREPORT // Uncomment to print the report send by the Switch Pro Controller
int8_t SwitchProParser::getButtonIndexSwitchPro(ButtonEnum b) {
const int8_t index = ButtonIndex(b);
if ((uint8_t) index >= (sizeof(SWITCH_PRO_BUTTONS) / sizeof(SWITCH_PRO_BUTTONS[0]))) return -1;
return index;
}
bool SwitchProParser::getButtonPress(ButtonEnum b) {
const int8_t index = getButtonIndexSwitchPro(b); if (index < 0) return 0;
return switchProData.btn.val & (1UL << pgm_read_byte(&SWITCH_PRO_BUTTONS[index]));
}
bool SwitchProParser::getButtonClick(ButtonEnum b) {
const int8_t index = getButtonIndexSwitchPro(b); if (index < 0) return 0;
uint32_t mask = 1UL << pgm_read_byte(&SWITCH_PRO_BUTTONS[index]);
bool click = buttonClickState.val & mask;
buttonClickState.val &= ~mask; // Clear "click" event
return click;
}
int16_t SwitchProParser::getAnalogHat(AnalogHatEnum a) {
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) {
if (len > 0 && buf) {
#ifdef PRINTREPORT
Notify(PSTR("\r\nLen: "), 0x80); Notify(len, 0x80);
Notify(PSTR(", data: "), 0x80);
for (uint8_t i = 0; i < len; i++) {
D_PrintHex<uint8_t > (buf[i], 0x80);
Notify(PSTR(" "), 0x80);
}
#endif
// This driver always uses the standard full report that includes the IMU data.
// The downside is that it requires more processing power, as the data is send contentiously
// 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 < 3) {
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nReport is too short: "), 0x80);
D_PrintHex<uint8_t > (len, 0x80);
#endif
return;
}
memcpy(&switchProData, buf + 2, min((uint8_t)(len - 2), 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
Notify(PSTR("\r\nUnknown report id: "), 0x80);
D_PrintHex<uint8_t > (buf[0], 0x80);
Notify(PSTR(", len: "), 0x80);
D_PrintHex<uint8_t > (len, 0x80);
#endif
}
}
if (switchProOutput.sendHandshake)
sendHandshake();
else if (switchProOutput.disableTimeout)
disableTimeout();
else if (switchProOutput.ledReportChanged || switchProOutput.ledHomeReportChanged ||
switchProOutput.enableFullReportMode || switchProOutput.enableImu != -1)
sendOutputCmd();
else if (switchProOutput.leftRumbleOn || switchProOutput.rightRumbleOn) {
// We need to send the rumble report repeatedly to keep it on
uint32_t now = millis();
if (now - rumble_on_timer > 1000) {
rumble_on_timer = now;
sendRumbleOutputReport();
}
}
}
void SwitchProParser::sendOutputCmd() {
// See: https://github.com/Dan611/hid-procon
// 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
uint8_t buf[14] = { 0 };
buf[0x00] = 0x01; // Report ID - PROCON_CMD_AND_RUMBLE
buf[0x01] = output_sequence_counter++; // Lowest 4-bit is a sequence number, which needs to be increased for every report
// Left rumble data
if (switchProOutput.leftRumbleOn) {
buf[0x02 + 0] = 0x28;
buf[0x02 + 1] = 0x88;
buf[0x02 + 2] = 0x60;
buf[0x02 + 3] = 0x61;
} else {
buf[0x02 + 0] = 0x00;
buf[0x02 + 1] = 0x01;
buf[0x02 + 2] = 0x40;
buf[0x02 + 3] = 0x40;
}
// Right rumble data
if (switchProOutput.rightRumbleOn) {
buf[0x02 + 4] = 0x28;
buf[0x02 + 5] = 0x88;
buf[0x02 + 6] = 0x60;
buf[0x02 + 7] = 0x61;
} else {
buf[0x02 + 4] = 0x00;
buf[0x02 + 5] = 0x01;
buf[0x02 + 6] = 0x40;
buf[0x02 + 7] = 0x40;
}
// Sub commands
if (switchProOutput.ledReportChanged) {
switchProOutput.ledReportChanged = false;
// See: https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/bluetooth_hid_subcommands_notes.md#subcommand-0x30-set-player-lights
buf[0x0A + 0] = 0x30; // PROCON_CMD_LED
buf[0x0A + 1] = switchProOutput.ledMask; // Lower 4-bits sets the LEDs constantly on, the higher 4-bits can be used to flash the LEDs
sendOutputReport(buf, 10 + 2);
} else if (switchProOutput.ledHomeReportChanged) {
switchProOutput.ledHomeReportChanged = false;
// It is possible set up to 15 mini cycles, but we simply just set the LED constantly on/off
// See: https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/bluetooth_hid_subcommands_notes.md#subcommand-0x38-set-home-light
buf[0x0A + 0] = 0x38; // PROCON_CMD_LED_HOME
buf[0x0A + 1] = (0 /* Number of cycles */ << 4) | (switchProOutput.ledHome ? 0xF : 0) /* Global mini cycle duration */;
buf[0x0A + 2] = (0xF /* LED start intensity */ << 4) | 0x0 /* Number of full cycles */;
buf[0x0A + 3] = (0xF /* Mini Cycle 1 LED intensity */ << 4) | 0x0 /* Mini Cycle 2 LED intensity */;
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);
}
}
void SwitchProParser::sendRumbleOutputReport() {
// See: https://github.com/Dan611/hid-procon
// 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
uint8_t buf[10] = { 0 };
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
// Left rumble data
if (switchProOutput.leftRumbleOn) {
buf[0x02 + 0] = 0x28;
buf[0x02 + 1] = 0x88;
buf[0x02 + 2] = 0x60;
buf[0x02 + 3] = 0x61;
} else {
buf[0x02 + 0] = 0x00;
buf[0x02 + 1] = 0x01;
buf[0x02 + 2] = 0x40;
buf[0x02 + 3] = 0x40;
}
// Right rumble data
if (switchProOutput.rightRumbleOn) {
buf[0x02 + 4] = 0x28;
buf[0x02 + 5] = 0x88;
buf[0x02 + 6] = 0x60;
buf[0x02 + 7] = 0x61;
} else {
buf[0x02 + 4] = 0x00;
buf[0x02 + 5] = 0x01;
buf[0x02 + 6] = 0x40;
buf[0x02 + 7] = 0x40;
}
sendOutputReport(buf, 10);
}
void SwitchProParser::Reset() {
// Center joysticks
switchProData.leftHatX = switchProData.leftHatY = switchProData.rightHatX = switchProData.rightHatY = 2048;
// Reset buttons variables
switchProData.btn.val = 0;
oldButtonState.val = 0;
buttonClickState.val = 0;
output_sequence_counter = 0;
rumble_on_timer = 0;
switchProOutput.leftRumbleOn = false;
switchProOutput.rightRumbleOn = false;
switchProOutput.ledMask = 0;
switchProOutput.ledHome = false;
switchProOutput.ledReportChanged = false;
switchProOutput.ledHomeReportChanged = false;
switchProOutput.enableFullReportMode = false;
switchProOutput.enableImu = -1;
switchProOutput.sendHandshake = false;
switchProOutput.disableTimeout = false;
}

385
SwitchProParser.h Normal file
View file

@ -0,0 +1,385 @@
/* 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_parser_h_
#define _switch_pro_parser_h_
#include "Usb.h"
#include "controllerEnums.h"
/** Used to set the LEDs on the controller */
const uint8_t SWITCH_PRO_LEDS[] PROGMEM = {
0x00, // OFF
0x01, // LED1
0x02, // LED2
0x04, // LED3
0x08, // LED4
0x09, // LED5
0x0A, // LED6
0x0C, // LED7
0x0D, // LED8
0x0E, // LED9
0x0F, // LED10
};
/** Buttons on the controller */
const uint8_t SWITCH_PRO_BUTTONS[] PROGMEM = {
0x11, // UP
0x12, // RIGHT
0x10, // DOWN
0x13, // LEFT
0x0D, // Capture
0x09, // PLUS
0x0B, // L3
0x0A, // R3
0x08, // MINUS
0x0C, // HOME
0, 0, // Skip
0x02, // B
0x03, // A
0x01, // X
0x00, // Y
0x16, // L
0x06, // R
0x17, // ZL
0x07, // ZR
};
// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/bluetooth_hid_notes.md#standard-input-report-format
union SwitchProButtons {
struct {
uint8_t y : 1;
uint8_t x : 1;
uint8_t b : 1;
uint8_t a : 1;
uint8_t dummy1 : 2;
uint8_t r : 1;
uint8_t zr : 1;
uint8_t minus : 1;
uint8_t plus : 1;
uint8_t r3 : 1;
uint8_t l3 : 1;
uint8_t home : 1;
uint8_t capture : 1;
uint8_t dummy2 : 2;
uint8_t dpad : 4;
uint8_t dummy3 : 2;
uint8_t l : 1;
uint8_t zl : 1;
} __attribute__((packed));
uint32_t val : 24;
} __attribute__((packed));
struct ImuData {
int16_t accX, accY, accZ;
int16_t gyroX, gyroY, gyroZ;
} __attribute__((packed));
struct SwitchProData {
struct {
uint8_t connection_info : 4;
uint8_t battery_level : 4;
} __attribute__((packed));
/* Button and joystick values */
SwitchProButtons btn; // Bytes 3-5
// 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));
struct SwitchProOutput {
bool leftRumbleOn;
bool rightRumbleOn;
uint8_t ledMask; // Higher nibble flashes the LEDs, lower nibble sets them on/off
bool ledHome;
// Used to send the reports at the same rate as the controller is sending messages
bool ledReportChanged;
bool ledHomeReportChanged;
bool enableFullReportMode;
int8_t enableImu; // -1 == Do nothing, 0 == disable IMU, 1 == enable IMU
bool sendHandshake;
bool disableTimeout;
} __attribute__((packed));
/** This class parses all the data sent by the Switch Pro controller */
class SwitchProParser {
public:
/** Constructor for the SwitchProParser class. */
SwitchProParser() : output_sequence_counter(0) {
Reset();
};
/** @name Switch Pro Controller functions */
/**
* getButtonPress(ButtonEnum b) will return true as long as the button is held down.
*
* While getButtonClick(ButtonEnum b) will only return it once.
*
* So you instance if you need to increase a variable once you would use getButtonClick(ButtonEnum b),
* but if you need to drive a robot forward you would use getButtonPress(ButtonEnum b).
* @param b ::ButtonEnum to read.
* @return getButtonPress(ButtonEnum b) will return a true as long as a button is held down, while getButtonClick(ButtonEnum b) will return true once for each button press.
*/
bool getButtonPress(ButtonEnum b);
bool getButtonClick(ButtonEnum b);
/**@}*/
/** @name Switch Pro Controller functions */
/**
* Used to read the analog joystick.
* @param a ::LeftHatX, ::LeftHatY, ::RightHatX, and ::RightHatY.
* @return Return the analog value as a signed 16-bit value.
*/
int16_t getAnalogHat(AnalogHatEnum a);
/**
* 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.
* @param a Either ::Pitch or ::Roll.
* @return Return the angle in the range of 0-360.
*/
float getAngle(AngleEnum a) {
if (a == Pitch)
return (atan2f(-switchProData.imu[0].accY, -switchProData.imu[0].accZ) + PI) * RAD_TO_DEG;
else
return (atan2f(switchProData.imu[0].accX, -switchProData.imu[0].accZ) + PI) * RAD_TO_DEG;
};
/**
* Used to get the raw values from the 3-axis gyroscope and 3-axis accelerometer inside the PS5 controller.
* @param s The sensor to read.
* @return Returns the raw sensor reading.
*/
int16_t getSensor(SensorEnum s) {
switch(s) {
case gX:
return switchProData.imu[0].gyroX;
case gY:
return switchProData.imu[0].gyroY;
case gZ:
return switchProData.imu[0].gyroZ;
case aX:
return switchProData.imu[0].accX;
case aY:
return switchProData.imu[0].accY;
case aZ:
return switchProData.imu[0].accZ;
default:
return 0;
}
};
/** Turn both rumble and the LEDs off. */
void setAllOff() {
setRumbleOff();
setLedOff();
setLedHomeOff();
};
/** Set rumble off. */
void setRumbleOff() {
setRumble(false, false);
}
/** Toggle rumble. */
void setRumbleToggle() {
setRumble(!switchProOutput.leftRumbleOn, !switchProOutput.rightRumbleOn);
}
/**
* Turn on/off rumble.
* @param leftRumbleOn Turn on/off left rumble motor.
* @param rightRumbleOn Turn on/off right rumble motor.
*/
void setRumble(bool leftRumbleOn, bool rightRumbleOn) {
switchProOutput.leftRumbleOn = leftRumbleOn;
switchProOutput.rightRumbleOn = rightRumbleOn;
switchProOutput.ledReportChanged = true; // Set this, so the rumble effect gets changed immediately
}
/**
* Turn on/off the left rumble.
* @param on Turn on/off left rumble motor.
*/
void setRumbleLeft(bool on) {
switchProOutput.leftRumbleOn = on;
switchProOutput.ledReportChanged = true; // Set this, so the rumble effect gets changed immediately
}
/**
* Turn on/off the right rumble.
* @param on Turn on/off right rumble motor.
*/
void setRumbleRight(bool on) {
switchProOutput.rightRumbleOn = on;
switchProOutput.ledReportChanged = true; // Set this, so the rumble effect gets changed immediately
}
/**
* Set LED value without using the ::LEDEnum.
* This can also be used to flash the LEDs by setting the high 4-bits of the mask.
* @param value See: ::LEDEnum.
*/
void setLedRaw(uint8_t mask) {
switchProOutput.ledMask = mask;
switchProOutput.ledReportChanged = true;
}
/** Turn all LEDs off. */
void setLedOff() {
setLedRaw(0);
}
/**
* Turn the specific ::LEDEnum off.
* @param a The ::LEDEnum to turn off.
*/
void setLedOff(LEDEnum a) {
switchProOutput.ledMask &= ~((uint8_t)(pgm_read_byte(&SWITCH_PRO_LEDS[(uint8_t)a]) & 0x0f));
switchProOutput.ledReportChanged = true;
}
/**
* Turn the specific ::LEDEnum on.
* @param a The ::LEDEnum to turn on.
*/
void setLedOn(LEDEnum a) {
switchProOutput.ledMask |= (uint8_t)(pgm_read_byte(&SWITCH_PRO_LEDS[(uint8_t)a]) & 0x0f);
switchProOutput.ledReportChanged = true;
}
/**
* Toggle the specific ::LEDEnum.
* @param a The ::LEDEnum to toggle.
*/
void setLedToggle(LEDEnum a) {
switchProOutput.ledMask ^= (uint8_t)(pgm_read_byte(&SWITCH_PRO_LEDS[(uint8_t)a]) & 0x0f);
switchProOutput.ledReportChanged = true;
}
/** Turn home LED off. */
void setLedHomeOff() {
switchProOutput.ledHome = false;
switchProOutput.ledHomeReportChanged = true;
}
/** Turn home LED on. */
void setLedHomeOn() {
switchProOutput.ledHome = true;
switchProOutput.ledHomeReportChanged = true;
}
/** Toggle home LED. */
void setLedHomeToggle() {
switchProOutput.ledHome = !switchProOutput.ledHome;
switchProOutput.ledHomeReportChanged = true;
}
/** Get the incoming message count. */
uint16_t getMessageCounter() {
return message_counter;
}
/**
* Return the battery level of the Switch Pro Controller.
* @return The battery level as a bit mask according to ::SwitchProBatteryLevel:
* 4=full, 3=medium, 2=low, 1=critical, 0=empty.
*/
uint8_t getBatteryLevel() {
return switchProData.battery_level >> 1;
}
/**
* Returns whenever the controller is plugged in and charging.
* @return Returns True if the controller is charging.
*/
bool isCharging() {
return switchProData.battery_level & 0x01;
}
protected:
/**
* Used to parse data sent from the Switch Pro controller.
* @param len Length of the data.
* @param buf Pointer to the data buffer.
*/
void Parse(uint8_t len, uint8_t *buf);
/** Used to reset the different buffers to their default values */
void Reset();
/**
* Send the output to the Switch Pro controller. This is implemented in SwitchProBT.h and SwitchProUSB.h.
* @param data Pointer to buffer to send by the derived class.
* @param len Length of buffer.
*/
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:
static int8_t getButtonIndexSwitchPro(ButtonEnum b);
void sendOutputCmd();
void sendRumbleOutputReport();
SwitchProData switchProData;
SwitchProButtons oldButtonState, buttonClickState;
uint16_t message_counter = 0;
uint8_t output_sequence_counter : 4;
uint32_t rumble_on_timer = 0;
};
#endif

156
SwitchProUSB.h Normal file
View file

@ -0,0 +1,156 @@
/* 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) {
// Based on: https://github.com/Dan611/hid-procon
// The first 8 bytes are always the same. The actual report follows
uint8_t buf[8 + len];
buf[0] = 0x80; // PROCON_REPORT_SEND_USB
buf[1] = 0x92; // PROCON_USB_DO_CMD
buf[2] = 0x00;
buf[3] = 0x31;
buf[4] = 0x00;
buf[5] = 0x00;
buf[6] = 0x00;
buf[7] = 0x00;
// Cope over the report
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

View file

@ -181,6 +181,11 @@ enum ButtonEnum {
ZL,
ZR,
/**@}*/
/**@{*/
/** Switch Pro Controller */
CAPTURE,
/**@}*/
};
inline constexpr int8_t ButtonIndex(ButtonEnum key) {
@ -190,7 +195,7 @@ inline constexpr int8_t ButtonIndex(ButtonEnum key) {
(key == RIGHT || key == YELLOW) ? 1 :
(key == DOWN || key == GREEN) ? 2 :
(key == LEFT || key == ORANGE) ? 3 :
(key == SELECT || key == SHARE || key == BACK || key == VIEW || key == BLUE || key == CREATE) ? 4 :
(key == SELECT || key == SHARE || key == BACK || key == VIEW || key == BLUE || key == CREATE || key == CAPTURE) ? 4 :
(key == START || key == OPTIONS || key == MENU || key == PLUS) ? 5 :
(key == L3 || key == TWO) ? 6 :
(key == R3 || key == ONE) ? 7 :

View file

@ -0,0 +1,152 @@
/*
Example sketch for the Switch Pro Bluetooth 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 <SwitchProBT.h>
#include <usbhub.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;
//USBHub Hub1(&Usb); // Some dongles have a hub inside
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
/* You can create the instance of the SwitchProBT class in two ways */
// This will start an inquiry and then pair with the Switch Pro controller - you only have to do this once
// You will need to press the Sync button next to the USB connector to put the controller into pairing mode.
SwitchProBT SwitchPro(&Btd, PAIR);
// After that you can simply create the instance like so and then press a button on the device
//SwitchProBT SwitchPro(&Btd);
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 Bluetooth 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));
}
// Hold the CAPTURE button for 1 second to disconnect the controller
// This prevents the controller from disconnecting when it is reconnected,
// as the CAPTURE button is sent when it reconnects
if (SwitchPro.getButtonPress(CAPTURE)) {
if (millis() - capture_timer > 1000)
SwitchPro.disconnect();
} else
capture_timer = millis();
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"));
Serial.print(F("\r\nBattery level: "));
Serial.print(SwitchPro.getBatteryLevel());
Serial.print(F(", charging: "));
Serial.print(SwitchPro.isCharging());
}
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));
}
}
}

View file

@ -0,0 +1,133 @@
/*
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"));
Serial.print(F("\r\nBattery level: "));
Serial.print(SwitchPro.getBatteryLevel());
Serial.print(F(", charging: "));
Serial.print(SwitchPro.isCharging());
}
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));
}
}
}

View file

@ -38,6 +38,8 @@ PS4BT KEYWORD1
PS4USB KEYWORD1
PS5BT KEYWORD1
PS5USB KEYWORD1
SwitchProBT KEYWORD1
SwitchProUSB KEYWORD1
####################################################
# Methods and Functions (KEYWORD2)
@ -61,8 +63,11 @@ getTemperature KEYWORD2
disconnect KEYWORD2
setAllOff KEYWORD2
setRumble KEYWORD2
setRumbleOff KEYWORD2
setRumbleOn KEYWORD2
setRumbleLeft KEYWORD2
setRumbleRight KEYWORD2
setLedOff KEYWORD2
setLedOn KEYWORD2
setLedToggle KEYWORD2
@ -70,6 +75,10 @@ setLedFlash KEYWORD2
moveSetBulb KEYWORD2
moveSetRumble KEYWORD2
setLedHomeOff KEYWORD2
setLedHomeOn KEYWORD2
setLedHomeToggle KEYWORD2
attachOnInit KEYWORD2
PS3Connected KEYWORD2
@ -317,6 +326,7 @@ TopRight LITERAL1
BotRight LITERAL1
TopLeft LITERAL1
BotLeft LITERAL1
CAPTURE LITERAL1
####################################################
# Methods and Functions for the IR Camera

View file

@ -1,6 +1,6 @@
{
"name": "USB-Host-Shield-20",
"keywords": "usb, host, ftdi, adk, acm, pl2303, hid, bluetooth, spp, ps3, ps4, ps5, buzz, xbox, wii, mass storage",
"keywords": "usb, host, ftdi, adk, acm, pl2303, hid, bluetooth, spp, ps3, ps4, ps5, buzz, xbox, wii, switch pro, mass storage",
"description": "Revision 2.0 of MAX3421E-based USB Host Shield Library",
"authors":
[

View file

@ -3,7 +3,7 @@ version=1.5.0
author=Oleg Mazurov (Circuits@Home) <mazurov@circuitsathome.com>, Kristian Sloth Lauszus <lauszus@gmail.com>, Andrew Kroll <xxxajk@gmail.com>, Alexei Glushchenko (Circuits@Home) <alex-gl@mail.ru>
maintainer=Oleg Mazurov (Circuits@Home) <mazurov@circuitsathome.com>, Kristian Sloth Lauszus <lauszus@gmail.com>, Andrew Kroll <xxxajk@gmail.com>
sentence=Revision 2.0 of MAX3421E-based USB Host Shield Library.
paragraph=Supports HID devices, FTDI, ADK, ACM, PL2303, Bluetooth HID devices, SPP communication and mass storage devices. Furthermore it supports PS3, PS4, PS5, PS Buzz, Wii and Xbox controllers.
paragraph=Supports HID devices, FTDI, ADK, ACM, PL2303, Bluetooth HID devices, SPP communication and mass storage devices. Furthermore it supports PS3, PS4, PS5, PS Buzz, Wii, Switch Pro and Xbox controllers.
category=Other
url=https://github.com/felis/USB_Host_Shield_2.0
architectures=*