Add switchusb output for controlling Nintendo Switch

This commit is contained in:
Travis Burtrum 2020-12-21 03:48:49 -05:00
parent 927949eacc
commit 83bda3c95c
9 changed files with 196 additions and 36 deletions

7
hwids/switch.py Normal file
View File

@ -0,0 +1,7 @@
Import("env")
board_config = env.BoardConfig()
# should be array of VID:PID pairs
board_config.update("build.hwids", [
["0x0f0d", "0x00c1"], # Hori Co., Ltd HORIPAD for Nintendo Switch
])

View File

@ -13,7 +13,7 @@
# supported values: # supported values:
# $board: micro, esp32 # $board: micro, esp32
# $input: snes, genesis, psx, n64, radio, debug # $input: snes, genesis, psx, n64, radio, debug
# $output: radio, usb, usbradio, bt, debug # $output: radio, usb, usbradio, bt, switchusb, debug
# please note not all boards are compatible with all inputs/outputs # please note not all boards are compatible with all inputs/outputs
# for example esp32 can only do bt # for example esp32 can only do bt
# micro can only do radio or usb # micro can only do radio or usb
@ -67,11 +67,12 @@ extends = out-usb, out-radio
build_flags = -DGAMEPAD_OUTPUT=4 build_flags = -DGAMEPAD_OUTPUT=4
src_filter = ${out-usb.src_filter} ${out-radio.src_filter} src_filter = ${out-usb.src_filter} ${out-radio.src_filter}
[out-switch] [out-switchusb]
build_flags = -DGAMEPAD_OUTPUT=5 # switch only supports 1 controller per dongle
src_filter = +<gamepad/ESP32-BLE-Gamepad> build_flags = -DGAMEPAD_OUTPUT=5 -DGAMEPAD_COUNT=1
# from https://github.com/NathanReeves/BlueCubeMod#build-instructionsv2 src_filter = +<gamepad/Switch-USB-Gamepad>
platform_packages = framework-espidf @ https://github.com/OpenRetroPad/esp-idf lib_deps = https://github.com/OpenRetroPad/HID
extra_scripts = pre:hwids/switch.py
# radio input # radio input
@ -101,6 +102,12 @@ extends = micro, in-radio, out-debug
src_filter = ${in-radio.src_filter} ${out-debug.src_filter} src_filter = ${in-radio.src_filter} ${out-debug.src_filter}
build_flags = ${in-radio.build_flags} ${out-debug.build_flags} build_flags = ${in-radio.build_flags} ${out-debug.build_flags}
[env:micro-radio-switchusb]
extends = micro, in-radio, out-switchusb
src_filter = ${in-radio.src_filter} ${out-switchusb.src_filter}
build_flags = ${in-radio.build_flags} ${out-switchusb.build_flags}
lib_deps = ${in-radio.lib_deps}, ${out-switchusb.lib_deps}
# not enough pins for env:micro-radio-radio , plus it'd be crazy # not enough pins for env:micro-radio-radio , plus it'd be crazy
# snes input # snes input
@ -139,6 +146,11 @@ extends = micro, in-snes, out-usbradio
src_filter = ${in-snes.src_filter} ${out-usbradio.src_filter} src_filter = ${in-snes.src_filter} ${out-usbradio.src_filter}
build_flags = ${in-snes.build_flags} ${out-usbradio.build_flags} build_flags = ${in-snes.build_flags} ${out-usbradio.build_flags}
[env:micro-snes-switchusb]
extends = micro, in-snes, out-switchusb
src_filter = ${in-snes.src_filter} ${out-switchusb.src_filter}
build_flags = ${in-snes.build_flags} ${out-switchusb.build_flags}
# n64 input # n64 input
[in-n64] [in-n64]
@ -176,6 +188,11 @@ extends = micro, in-n64, out-usbradio
src_filter = ${in-n64.src_filter} ${out-usbradio.src_filter} src_filter = ${in-n64.src_filter} ${out-usbradio.src_filter}
build_flags = ${in-n64.build_flags} ${out-usbradio.build_flags} build_flags = ${in-n64.build_flags} ${out-usbradio.build_flags}
[env:micro-n64-switchusb]
extends = micro, in-n64, out-switchusb
src_filter = ${in-n64.src_filter} ${out-switchusb.src_filter}
build_flags = ${in-n64.build_flags} ${out-switchusb.build_flags}
# genesis input # genesis input
[in-genesis] [in-genesis]
@ -215,6 +232,11 @@ extends = micro, in-genesis, out-usbradio
src_filter = ${in-genesis.src_filter} ${out-usbradio.src_filter} src_filter = ${in-genesis.src_filter} ${out-usbradio.src_filter}
build_flags = ${in-genesis.build_flags} ${out-usbradio.build_flags} -DGAMEPAD_COUNT=1 build_flags = ${in-genesis.build_flags} ${out-usbradio.build_flags} -DGAMEPAD_COUNT=1
[env:micro-genesis-switchusb]
extends = micro, in-genesis, out-switchusb
src_filter = ${in-genesis.src_filter} ${out-switchusb.src_filter}
build_flags = ${in-genesis.build_flags} ${out-switchusb.build_flags}
# psx input # psx input
[in-psx] [in-psx]
@ -251,6 +273,11 @@ extends = micro, in-psx, out-usbradio
src_filter = ${in-psx.src_filter} ${out-usbradio.src_filter} src_filter = ${in-psx.src_filter} ${out-usbradio.src_filter}
build_flags = ${in-psx.build_flags} ${out-usbradio.build_flags} build_flags = ${in-psx.build_flags} ${out-usbradio.build_flags}
[env:micro-psx-switchusb]
extends = micro, in-psx, out-switchusb
src_filter = ${in-psx.src_filter} ${out-switchusb.src_filter}
build_flags = ${in-psx.build_flags} ${out-switchusb.build_flags}
# debug input # debug input
[in-debug] [in-debug]
@ -287,3 +314,7 @@ extends = micro, in-debug, out-usbradio
src_filter = ${in-debug.src_filter} ${out-usbradio.src_filter} src_filter = ${in-debug.src_filter} ${out-usbradio.src_filter}
build_flags = ${in-debug.build_flags} ${out-usbradio.build_flags} build_flags = ${in-debug.build_flags} ${out-usbradio.build_flags}
[env:micro-debug-switchusb]
extends = micro, in-debug, out-switchusb
src_filter = ${in-debug.src_filter} ${out-switchusb.src_filter}
build_flags = ${in-debug.build_flags} ${out-switchusb.build_flags}

View File

@ -9,7 +9,7 @@ env's are laid out like `$board-$input-$output`
supported values: supported values:
* $board: micro, esp32 * $board: micro, esp32
* $input: snes, genesis, psx, n64, radio, debug * $input: snes, genesis, psx, n64, radio, debug
* $output: radio, usb, usbradio, bt, debug * $output: radio, usb, usbradio, switchusb, bt, debug
* please note not all boards are compatible with all inputs/outputs, for example esp32 can only do bt, micro can only do radio or usb * please note not all boards are compatible with all inputs/outputs, for example esp32 can only do bt, micro can only do radio or usb
Credits / Links Credits / Links
@ -21,7 +21,9 @@ Code and/or inspiration was (or will be) taken from these places, in no particul
* [DaemonBite-Retro-Controllers-USB](https://github.com/MickGyver/DaemonBite-Retro-Controllers-USB) * [DaemonBite-Retro-Controllers-USB](https://github.com/MickGyver/DaemonBite-Retro-Controllers-USB)
* [Arduino-USB-HID-RetroJoystickAdapter](https://github.com/mcgurk/Arduino-USB-HID-RetroJoystickAdapter) * [Arduino-USB-HID-RetroJoystickAdapter](https://github.com/mcgurk/Arduino-USB-HID-RetroJoystickAdapter)
* [BlueCubeMod](https://github.com/NathanReeves/BlueCubeMod) * [BlueCubeMod](https://github.com/NathanReeves/BlueCubeMod)
* [OpenSwitchPad](https://github.com/agustincampeny/OpenSwitchPad)
* [arduino-n64-controller-library](https://github.com/pothos/arduino-n64-controller-library) * [arduino-n64-controller-library](https://github.com/pothos/arduino-n64-controller-library)
* [N64toiQue](https://github.com/mnzlmstr/N64toiQue) * [N64toiQue](https://github.com/mnzlmstr/N64toiQue)
* [dreamcast_usb](https://github.com/raphnet/dreamcast_usb) * [dreamcast_usb](https://github.com/raphnet/dreamcast_usb)
* [SNES-NRF24](https://github.com/baldengineer/SNES-NRF24) * [SNES-NRF24](https://github.com/baldengineer/SNES-NRF24)
* https://github.com/NicoHood/Nintendo

View File

@ -16,9 +16,9 @@ void setup() {
void loop() { void loop() {
if (gamepad.isConnected()) { if (gamepad.isConnected()) {
// test code to automate sending to test RadioReceiver (or any gamepad impl) // test code to automate sending to test RadioReceiver (or any gamepad impl)
Serial.println("Press buttons 1 and 32. Move all axes to center. Set DPAD to down right."); Serial.println("Press buttons A and Y. Move all axes to center. Set DPAD to down right.");
gamepad.press(c, BUTTON_1); gamepad.press(c, BUTTON_A);
gamepad.press(c, BUTTON_32); gamepad.press(c, BUTTON_Y);
gamepad.setAxis(c, 0, 0, 0, 0, 0, 0, DPAD_DOWN_RIGHT); gamepad.setAxis(c, 0, 0, 0, 0, 0, 0, DPAD_DOWN_RIGHT);
delay(500); delay(500);
Serial.println("Release all buttons. Move all axes to center. Set DPAD to center."); Serial.println("Release all buttons. Move all axes to center. Set DPAD to center.");

View File

@ -167,7 +167,8 @@ class Joystick_ {
int16_t translateAxis(uint8_t v) { int16_t translateAxis(uint8_t v) {
//map(value, fromLow, fromHigh, toLow, toHigh) //map(value, fromLow, fromHigh, toLow, toHigh)
return v == 128 ? 0 : map(v, 0, 255, -32767, 32767); // todo: don't map at all if translation isn't required...
return v == 128 ? AXIS_CENTER : map(v, 0, 255, AXIS_MIN, AXIS_MAX);
} }
void sendState(uint8_t c) { void sendState(uint8_t c) {
@ -322,5 +323,5 @@ void loop() {
Joystick[i].updateState(i); Joystick[i].updateState(i);
} }
delayMicroseconds(1000); delayMicroseconds(500); // todo: proper value for this... does it depend on number of gamepads/multitap ?
} }

View File

@ -7,7 +7,18 @@
#define BUTTON_COUNT 12 // SNES has 12, NES only has 8 #define BUTTON_COUNT 12 // SNES has 12, NES only has 8
//individual data pin for each controller //individual data pin for each controller
static const int DATA_PIN[GAMEPAD_COUNT] = {18, 19}; // grey, 20, 21 are the next logical ones static const int DATA_PIN[GAMEPAD_COUNT] = {
18,
#if GAMEPAD_COUNT > 1
19,
#endif
#if GAMEPAD_COUNT > 2
20,
#endif
#if GAMEPAD_COUNT > 3
21,
#endif
};
//shared pins between all controllers //shared pins between all controllers
#if defined(CONFIG_BT_ENABLED) #if defined(CONFIG_BT_ENABLED)

View File

@ -39,6 +39,10 @@
#include "UsbRadio-Gamepad/UsbRadioGamepad.h" #include "UsbRadio-Gamepad/UsbRadioGamepad.h"
#elif GAMEPAD_OUTPUT == 5
#include "Switch-USB-Gamepad/SwitchUsbGamepad.h"
#else #else
#error Unsupported value for GAMEPAD_OUTPUT, must be 0-3 #error Unsupported value for GAMEPAD_OUTPUT, must be 0-3

View File

@ -0,0 +1,63 @@
#ifndef SWITCH_USB_GAMEPAD_H
#define SWITCH_USB_GAMEPAD_H
#ifndef GAMEPAD_CLASS
#define GAMEPAD_CLASS SwitchUsbGamepad
#endif
#include "../common.h"
#include "HID-Project.h"
class SwitchUsbGamepad : public AbstractGamepad {
public:
SwitchUsbGamepad() : AbstractGamepad() {
}
virtual void begin(void) {
NSGamepad.begin();
}
virtual void end(void) {
NSGamepad.end();
}
virtual void setAxis(const uint8_t cIdx, int16_t x, int16_t y, int16_t z, int16_t rZ, char rX, char rY, signed char hat) {
// Move x/y Axis to a new position (16bit)
NSGamepad.leftXAxis(x);
NSGamepad.leftYAxis(y);
NSGamepad.rightXAxis(z);
NSGamepad.rightYAxis(rZ);
NSGamepad.dPad(hat);
this->sync(cIdx);
}
virtual void setHatSync(const uint8_t cIdx, signed char hat) {
setAxis(cIdx, 0, 0, 0, 0, 0, 0, hat);
}
virtual void buttons(const uint8_t cIdx, uint32_t b) {
NSGamepad.buttons(b);
}
virtual void press(const uint8_t cIdx, uint32_t b) {
NSGamepad.press(b);
}
virtual void release(const uint8_t cIdx, uint32_t b) {
NSGamepad.release(b);
}
virtual void sync(const uint8_t cIdx) {
// todo: something to make this play nice with radio
sendHidReport(cIdx, &gamepadReport, GAMEPAD_REPORT_LEN);
}
virtual void sendHidReport(const uint8_t cIdx, const void* d, int len) {
//gamepad[cIdx].send(d, len);]]
NSGamepad.write();
}
};
#endif // SWITCH_USB_GAMEPAD_H

View File

@ -7,28 +7,83 @@
#define ARDUINO_ARCH_ESP32 1 #define ARDUINO_ARCH_ESP32 1
#include "HIDTypes.h" #include "HIDTypes.h"
#if GAMEPAD_OUTPUT == 5 // nintendo switch
#define BUTTON_A NSButton_A
#define BUTTON_B NSButton_B
#define BUTTON_MENU NSButton_Home
#define BUTTON_X NSButton_X
#define BUTTON_Y NSButton_Y
#define BUTTON_TL NSButton_LeftTrigger
#define BUTTON_TR NSButton_RightTrigger
#define BUTTON_TL2 NSButton_LeftThrottle
#define BUTTON_TR2 NSButton_RightThrottle
#define BUTTON_SELECT NSButton_Minus
#define BUTTON_START NSButton_Plus
#define BUTTON_THUMBL NSButton_LeftStick
#define BUTTON_THUMBR NSButton_RightStick
#define DPAD_CENTER NSGAMEPAD_DPAD_CENTERED
#define DPAD_UP NSGAMEPAD_DPAD_UP
#define DPAD_UP_RIGHT NSGAMEPAD_DPAD_UP_RIGHT
#define DPAD_RIGHT NSGAMEPAD_DPAD_RIGHT
#define DPAD_DOWN_RIGHT NSGAMEPAD_DPAD_DOWN_RIGHT
#define DPAD_DOWN NSGAMEPAD_DPAD_DOWN
#define DPAD_DOWN_LEFT NSGAMEPAD_DPAD_DOWN_LEFT
#define DPAD_LEFT NSGAMEPAD_DPAD_LEFT
#define DPAD_UP_LEFT NSGAMEPAD_DPAD_UP_LEFT
#define AXIS_CENTER 128
#define AXIS_MAX 255
#define AXIS_MIN 0
#else
#define BUTTON_A 1 #define BUTTON_A 1
#define BUTTON_B 2 #define BUTTON_B 2
#define BUTTON_MENU 4 #define BUTTON_MENU 4
#define BUTTON_X 8 #define BUTTON_X 8
#define BUTTON_Y 16 #define BUTTON_Y 16
#define BUTTON_TL 64 #define BUTTON_TL 64
#define BUTTON_L 64
#define BUTTON_L1 64
#define BUTTON_TR 128 #define BUTTON_TR 128
#define BUTTON_R 128
#define BUTTON_R1 128
#define BUTTON_TL2 256 #define BUTTON_TL2 256
#define BUTTON_L2 256
#define BUTTON_TR2 512 #define BUTTON_TR2 512
#define BUTTON_R2 512
#define BUTTON_SELECT 1024 #define BUTTON_SELECT 1024
#define BUTTON_START 2048 #define BUTTON_START 2048
#define BUTTON_THUMBL 8192 #define BUTTON_THUMBL 8192
#define BUTTON_L3 8192
#define BUTTON_THUMBR 16384 #define BUTTON_THUMBR 16384
#define BUTTON_R3 16384
#define DPAD_CENTER 0
#define DPAD_UP 1
#define DPAD_UP_RIGHT 2
#define DPAD_RIGHT 3
#define DPAD_DOWN_RIGHT 4
#define DPAD_DOWN 5
#define DPAD_DOWN_LEFT 6
#define DPAD_LEFT 7
#define DPAD_UP_LEFT 8
#define AXIS_CENTER 0
#define AXIS_MAX 32768
#define AXIS_MIN -32767
#endif // nintendo switch
// aliases
#define BUTTON_HOME BUTTON_MENU
#define BUTTON_L BUTTON_TL
#define BUTTON_L1 BUTTON_TL
#define BUTTON_R BUTTON_TR
#define BUTTON_R1 BUTTON_TR
#define BUTTON_L2 BUTTON_TL2
#define BUTTON_R2 BUTTON_TR2
#define BUTTON_L3 BUTTON_THUMBL
#define BUTTON_R3 BUTTON_THUMBR
#define DPAD_CENTERED DPAD_CENTER
// end aliases
#if 0
#define BUTTON_1 1 #define BUTTON_1 1
#define BUTTON_2 2 #define BUTTON_2 2
#define BUTTON_3 4 #define BUTTON_3 4
@ -61,21 +116,7 @@
#define BUTTON_30 536870912 #define BUTTON_30 536870912
#define BUTTON_31 1073741824 #define BUTTON_31 1073741824
#define BUTTON_32 2147483648 #define BUTTON_32 2147483648
#endif
#define DPAD_CENTER 0
#define DPAD_CENTERED 0
#define DPAD_UP 1
#define DPAD_UP_RIGHT 2
#define DPAD_RIGHT 3
#define DPAD_DOWN_RIGHT 4
#define DPAD_DOWN 5
#define DPAD_DOWN_LEFT 6
#define DPAD_LEFT 7
#define DPAD_UP_LEFT 8
#define AXIS_CENTER 0
#define AXIS_MAX 32768
#define AXIS_MIN -32767
#ifndef GAMEPAD_REPORT_ARRAY_ADD #ifndef GAMEPAD_REPORT_ARRAY_ADD
// this is used by radio gamepad to send additional info // this is used by radio gamepad to send additional info