From 62fb8fbacfb355d1a419a2b55b7ea201566eff99 Mon Sep 17 00:00:00 2001 From: Luke Arntson Date: Wed, 16 Aug 2023 11:51:54 -0400 Subject: [PATCH] PS4 Passthrough Add-on w/ PS5 Compatibility (#457) PS4 Passthrough Add-on w/ PS5 Compatibility, including web config settings, new USB host manager code, TinyUSB HID host extension code, and many other changes. --- CMakeLists.txt | 2 + configs/AlpacaOwO/BoardConfig.h | 2 + configs/BentoBox/BoardConfig.h | 2 + configs/DURAL/BoardConfig.h | 2 + configs/FightboardV3/BoardConfig.h | 2 + configs/FightboardV3Mirrored/BoardConfig.h | 2 + configs/FlatboxRev4/BoardConfig.h | 2 + configs/FlatboxRev5/BoardConfig.h | 2 + configs/FlatboxRev5RGB/BoardConfig.h | 2 + configs/KB2040/BoardConfig.h | 2 + configs/KeyboardConverter/BoardConfig.h | 2 + configs/MavercadeKeebfighter/BoardConfig.h | 2 + configs/Pico/BoardConfig.h | 7 + configs/PicoAnn/BoardConfig.h | 2 + configs/PicoFightingBoard/BoardConfig.h | 2 + .../RP2040AdvancedBreakoutBoard/BoardConfig.h | 2 + configs/RP2040MiniBreakoutBoard/BoardConfig.h | 2 + configs/ReflexEncoder/BoardConfig.h | 2 + configs/SGFDevices/BoardConfig.h | 1 + configs/SparkFunProMicro/BoardConfig.h | 3 + configs/Stress/BoardConfig.h | 2 + configs/WaveshareZero/BoardConfig.h | 2 + headers/addonmanager.h | 3 + headers/addons/keyboard_host.h | 46 +++- headers/addons/pspassthrough.h | 46 ++++ headers/gamepad/GamepadConfig.h | 4 + headers/usbaddon.h | 23 ++ headers/usbhostmanager.h | 41 ++++ lib/TinyUSB_Gamepad/src/ps4_driver.cpp | 15 +- lib/TinyUSB_Gamepad/src/ps4_driver.h | 11 +- proto/config.proto | 9 + proto/enums.proto | 8 + src/addonmanager.cpp | 13 ++ src/addons/i2cdisplay.cpp | 14 +- src/addons/keyboard_host.cpp | 131 ++++------- src/addons/pspassthrough.cpp | 168 ++++++++++++++ src/config_utils.cpp | 7 + src/configs/webconfig.cpp | 12 + src/gamepad.cpp | 7 + src/gp2040.cpp | 20 +- src/gp2040aux.cpp | 15 +- src/usbhostmanager.cpp | 216 ++++++++++++++++++ www/server/app.js | 4 + www/src/Locales/en/AddonsConfig.jsx | 5 + www/src/Locales/en/SettingsPage.jsx | 5 + www/src/Pages/AddonsConfigPage.jsx | 53 +++++ www/src/Pages/SettingsPage.jsx | 33 ++- 47 files changed, 830 insertions(+), 128 deletions(-) create mode 100644 headers/addons/pspassthrough.h create mode 100644 headers/usbaddon.h create mode 100644 headers/usbhostmanager.h create mode 100644 src/addons/pspassthrough.cpp create mode 100644 src/usbhostmanager.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 63b08010d..b139ba843 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,6 +125,7 @@ src/addonmanager.cpp src/configmanager.cpp src/storagemanager.cpp src/system.cpp +src/usbhostmanager.cpp src/config_legacy.cpp src/config_utils.cpp src/configs/webconfig.cpp @@ -143,6 +144,7 @@ src/addons/neopicoleds.cpp src/addons/playernum.cpp src/addons/playerleds.cpp src/addons/ps4mode.cpp +src/addons/pspassthrough.cpp src/addons/reverse.cpp src/addons/turbo.cpp src/addons/slider_socd.cpp diff --git a/configs/AlpacaOwO/BoardConfig.h b/configs/AlpacaOwO/BoardConfig.h index 3091b08c8..fa149e544 100644 --- a/configs/AlpacaOwO/BoardConfig.h +++ b/configs/AlpacaOwO/BoardConfig.h @@ -63,6 +63,8 @@ #define DEFAULT_INPUT_MODE INPUT_MODE_XINPUT //INPUT_MODE_XINPUT (XInput), INPUT_MODE_SWITCH (Nintendo Switch), INPUT_MODE_HID (D-Input), INPUT_MODE_KEYBOARD (Keyboard) #define DEFAULT_DPAD_MODE DPAD_MODE_DIGITAL //DPAD_MODE_DIGITAL, DPAD_MODE_LEFT_ANALOG, DPAD_MODE_RIGHT_ANALOG, +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER + // This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) // The Turbo LED will flash at a speed consistant with the set speed of the Turbo when a Turbo button is active. diff --git a/configs/BentoBox/BoardConfig.h b/configs/BentoBox/BoardConfig.h index c77cf99d2..99355ee68 100644 --- a/configs/BentoBox/BoardConfig.h +++ b/configs/BentoBox/BoardConfig.h @@ -60,6 +60,8 @@ #define DEFAULT_FORCED_SETUP_MODE FORCED_SETUP_MODE_OFF // FORCED_SETUP_MODE_OFF, FORCED_SETUP_MODE_LOCK_MODE_SWITCH, FORCED_SETUP_MODE_LOCK_WEB_CONFIG, FORCED_SETUP_MODE_LOCK_BOTH #define DEFAULT_LOCK_HOTKEYS false // or true +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER + // This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) // The Turbo LED will flash at a speed consistant with the set speed of the Turbo when a Turbo button is active. diff --git a/configs/DURAL/BoardConfig.h b/configs/DURAL/BoardConfig.h index 6b29063bd..f0c135191 100644 --- a/configs/DURAL/BoardConfig.h +++ b/configs/DURAL/BoardConfig.h @@ -60,6 +60,8 @@ #define DEFAULT_FORCED_SETUP_MODE FORCED_SETUP_MODE_OFF // FORCED_SETUP_MODE_OFF, FORCED_SETUP_MODE_LOCK_MODE_SWITCH, FORCED_SETUP_MODE_LOCK_WEB_CONFIG, FORCED_SETUP_MODE_LOCK_BOTH #define DEFAULT_LOCK_HOTKEYS false // or true +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER + // This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) // The Turbo LED will flash at a speed consistant with the set speed of the Turbo when a Turbo button is active. diff --git a/configs/FightboardV3/BoardConfig.h b/configs/FightboardV3/BoardConfig.h index e89ba091f..2f13fdb9c 100644 --- a/configs/FightboardV3/BoardConfig.h +++ b/configs/FightboardV3/BoardConfig.h @@ -61,6 +61,8 @@ #define DEFAULT_FORCED_SETUP_MODE FORCED_SETUP_MODE_OFF // FORCED_SETUP_MODE_OFF, FORCED_SETUP_MODE_LOCK_MODE_SWITCH, FORCED_SETUP_MODE_LOCK_WEB_CONFIG, FORCED_SETUP_MODE_LOCK_BOTH #define DEFAULT_LOCK_HOTKEYS false // or true +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER + // This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) // The Turbo LED will flash at a speed consistant with the set speed of the Turbo when a Turbo button is active. diff --git a/configs/FightboardV3Mirrored/BoardConfig.h b/configs/FightboardV3Mirrored/BoardConfig.h index 6b9c52209..df07c7b7b 100644 --- a/configs/FightboardV3Mirrored/BoardConfig.h +++ b/configs/FightboardV3Mirrored/BoardConfig.h @@ -61,6 +61,8 @@ #define DEFAULT_FORCED_SETUP_MODE FORCED_SETUP_MODE_OFF // FORCED_SETUP_MODE_OFF, FORCED_SETUP_MODE_LOCK_MODE_SWITCH, FORCED_SETUP_MODE_LOCK_WEB_CONFIG, FORCED_SETUP_MODE_LOCK_BOTH #define DEFAULT_LOCK_HOTKEYS false // or true +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER + // This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) // The Turbo LED will flash at a speed consistant with the set speed of the Turbo when a Turbo button is active. diff --git a/configs/FlatboxRev4/BoardConfig.h b/configs/FlatboxRev4/BoardConfig.h index 7201ede80..1b471c711 100644 --- a/configs/FlatboxRev4/BoardConfig.h +++ b/configs/FlatboxRev4/BoardConfig.h @@ -82,6 +82,8 @@ #define DEFAULT_FORCED_SETUP_MODE FORCED_SETUP_MODE_OFF // FORCED_SETUP_MODE_OFF, FORCED_SETUP_MODE_LOCK_MODE_SWITCH, FORCED_SETUP_MODE_LOCK_WEB_CONFIG, FORCED_SETUP_MODE_LOCK_BOTH #define DEFAULT_LOCK_HOTKEYS false // or true +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER + // This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) // The Turbo LED will flash at a speed consistant with the set speed of the Turbo when a Turbo button is active. diff --git a/configs/FlatboxRev5/BoardConfig.h b/configs/FlatboxRev5/BoardConfig.h index 41c2ab315..3ddc55627 100644 --- a/configs/FlatboxRev5/BoardConfig.h +++ b/configs/FlatboxRev5/BoardConfig.h @@ -82,6 +82,8 @@ #define DEFAULT_FORCED_SETUP_MODE FORCED_SETUP_MODE_OFF // FORCED_SETUP_MODE_OFF, FORCED_SETUP_MODE_LOCK_MODE_SWITCH, FORCED_SETUP_MODE_LOCK_WEB_CONFIG, FORCED_SETUP_MODE_LOCK_BOTH #define DEFAULT_LOCK_HOTKEYS false // or true +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER + // This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) // The Turbo LED will flash at a speed consistant with the set speed of the Turbo when a Turbo button is active. diff --git a/configs/FlatboxRev5RGB/BoardConfig.h b/configs/FlatboxRev5RGB/BoardConfig.h index 4b3b2533f..3a86a0d05 100644 --- a/configs/FlatboxRev5RGB/BoardConfig.h +++ b/configs/FlatboxRev5RGB/BoardConfig.h @@ -82,6 +82,8 @@ #define DEFAULT_FORCED_SETUP_MODE FORCED_SETUP_MODE_OFF // FORCED_SETUP_MODE_OFF, FORCED_SETUP_MODE_LOCK_MODE_SWITCH, FORCED_SETUP_MODE_LOCK_WEB_CONFIG, FORCED_SETUP_MODE_LOCK_BOTH #define DEFAULT_LOCK_HOTKEYS false // or true +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER + // This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) // The Turbo LED will flash at a speed consistant with the set speed of the Turbo when a Turbo button is active. diff --git a/configs/KB2040/BoardConfig.h b/configs/KB2040/BoardConfig.h index c79ce1d79..77526f7d3 100644 --- a/configs/KB2040/BoardConfig.h +++ b/configs/KB2040/BoardConfig.h @@ -61,6 +61,8 @@ #define DEFAULT_INPUT_MODE INPUT_MODE_XINPUT //INPUT_MODE_XINPUT (XInput), INPUT_MODE_SWITCH (Nintendo Switch), INPUT_MODE_HID (D-Input), INPUT_MODE_KEYBOARD (Keyboard) #define DEFAULT_DPAD_MODE DPAD_MODE_DIGITAL //DPAD_MODE_DIGITAL, DPAD_MODE_LEFT_ANALOG, DPAD_MODE_RIGHT_ANALOG, +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER + #define DEFAULT_FORCED_SETUP_MODE FORCED_SETUP_MODE_OFF #define DEFAULT_LOCK_HOTKEYS false// This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) diff --git a/configs/KeyboardConverter/BoardConfig.h b/configs/KeyboardConverter/BoardConfig.h index 1e2def2ab..46e9ad3b6 100644 --- a/configs/KeyboardConverter/BoardConfig.h +++ b/configs/KeyboardConverter/BoardConfig.h @@ -63,6 +63,8 @@ #define DEFAULT_FORCED_SETUP_MODE FORCED_SETUP_MODE_OFF // FORCED_SETUP_MODE_OFF, FORCED_SETUP_MODE_LOCK_MODE_SWITCH, FORCED_SETUP_MODE_LOCK_WEB_CONFIG, FORCED_SETUP_MODE_LOCK_BOTH #define DEFAULT_LOCK_HOTKEYS false // or true +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER + // This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) // The Turbo LED will flash at a speed consistant with the set speed of the Turbo when a Turbo button is active. diff --git a/configs/MavercadeKeebfighter/BoardConfig.h b/configs/MavercadeKeebfighter/BoardConfig.h index 026be1eaa..c0dec1b4e 100644 --- a/configs/MavercadeKeebfighter/BoardConfig.h +++ b/configs/MavercadeKeebfighter/BoardConfig.h @@ -82,6 +82,8 @@ #define DEFAULT_FORCED_SETUP_MODE FORCED_SETUP_MODE_OFF // FORCED_SETUP_MODE_OFF, FORCED_SETUP_MODE_LOCK_MODE_SWITCH, FORCED_SETUP_MODE_LOCK_WEB_CONFIG, FORCED_SETUP_MODE_LOCK_BOTH #define DEFAULT_LOCK_HOTKEYS false // or true +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER + // This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) // The Turbo LED will flash at a speed consistant with the set speed of the Turbo when a Turbo button is active. diff --git a/configs/Pico/BoardConfig.h b/configs/Pico/BoardConfig.h index ae9852770..90c281df8 100644 --- a/configs/Pico/BoardConfig.h +++ b/configs/Pico/BoardConfig.h @@ -62,6 +62,8 @@ #define DEFAULT_INPUT_MODE INPUT_MODE_XINPUT //INPUT_MODE_XINPUT (XInput), INPUT_MODE_SWITCH (Nintendo Switch), INPUT_MODE_HID (D-Input), INPUT_MODE_KEYBOARD (Keyboard) #define DEFAULT_DPAD_MODE DPAD_MODE_DIGITAL //DPAD_MODE_DIGITAL, DPAD_MODE_LEFT_ANALOG, DPAD_MODE_RIGHT_ANALOG, +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER + // This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) // The Turbo LED will flash at a speed consistant with the set speed of the Turbo when a Turbo button is active. @@ -296,6 +298,11 @@ #define KEYBOARD_HOST_PIN_DPLUS -1 #define KEYBOARD_HOST_PIN_5V -1 +// PS Passthrough Host Addon defaults +#define PSPASSTHROUGH_HOST_ENABLED 0 +#define PSPASSTHROUGH_HOST_PIN_DPLUS -1 +#define PSPASSTHROUGH_HOST_PIN_5V -1 + // For details on this, see: https://gp2040-ce.info/#/development?id=i2c-display-splash #define DEFAULT_SPLASH \ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \ diff --git a/configs/PicoAnn/BoardConfig.h b/configs/PicoAnn/BoardConfig.h index dd5be22f3..4030f5059 100644 --- a/configs/PicoAnn/BoardConfig.h +++ b/configs/PicoAnn/BoardConfig.h @@ -60,6 +60,8 @@ #define DEFAULT_FORCED_SETUP_MODE FORCED_SETUP_MODE_OFF // FORCED_SETUP_MODE_OFF, FORCED_SETUP_MODE_LOCK_MODE_SWITCH, FORCED_SETUP_MODE_LOCK_WEB_CONFIG, FORCED_SETUP_MODE_LOCK_BOTH #define DEFAULT_LOCK_HOTKEYS false // or true +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER + // This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) // The Turbo LED will flash at a speed consistant with the set speed of the Turbo when a Turbo button is active. diff --git a/configs/PicoFightingBoard/BoardConfig.h b/configs/PicoFightingBoard/BoardConfig.h index 7053e9ff9..394fbc1e2 100644 --- a/configs/PicoFightingBoard/BoardConfig.h +++ b/configs/PicoFightingBoard/BoardConfig.h @@ -60,6 +60,8 @@ #define DEFAULT_FORCED_SETUP_MODE FORCED_SETUP_MODE_OFF // FORCED_SETUP_MODE_OFF, FORCED_SETUP_MODE_LOCK_MODE_SWITCH, FORCED_SETUP_MODE_LOCK_WEB_CONFIG, FORCED_SETUP_MODE_LOCK_BOTH #define DEFAULT_LOCK_HOTKEYS false // or true +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER + // This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) // The Turbo LED will flash at a speed consistant with the set speed of the Turbo when a Turbo button is active. diff --git a/configs/RP2040AdvancedBreakoutBoard/BoardConfig.h b/configs/RP2040AdvancedBreakoutBoard/BoardConfig.h index 1c702a43d..53580b35d 100644 --- a/configs/RP2040AdvancedBreakoutBoard/BoardConfig.h +++ b/configs/RP2040AdvancedBreakoutBoard/BoardConfig.h @@ -60,6 +60,8 @@ #define DEFAULT_FORCED_SETUP_MODE FORCED_SETUP_MODE_OFF // FORCED_SETUP_MODE_OFF, FORCED_SETUP_MODE_LOCK_MODE_SWITCH, FORCED_SETUP_MODE_LOCK_WEB_CONFIG, FORCED_SETUP_MODE_LOCK_BOTH #define DEFAULT_LOCK_HOTKEYS false // or true +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER + // This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) // The Turbo LED will flash at a speed consistant with the set speed of the Turbo when a Turbo button is active. diff --git a/configs/RP2040MiniBreakoutBoard/BoardConfig.h b/configs/RP2040MiniBreakoutBoard/BoardConfig.h index 15fd5eb68..d506ee35f 100644 --- a/configs/RP2040MiniBreakoutBoard/BoardConfig.h +++ b/configs/RP2040MiniBreakoutBoard/BoardConfig.h @@ -60,6 +60,8 @@ #define DEFAULT_FORCED_SETUP_MODE FORCED_SETUP_MODE_OFF // FORCED_SETUP_MODE_OFF, FORCED_SETUP_MODE_LOCK_MODE_SWITCH, FORCED_SETUP_MODE_LOCK_WEB_CONFIG, FORCED_SETUP_MODE_LOCK_BOTH #define DEFAULT_LOCK_HOTKEYS false // or true +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER + // This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) // The Turbo LED will flash at a speed consistant with the set speed of the Turbo when a Turbo button is active. diff --git a/configs/ReflexEncoder/BoardConfig.h b/configs/ReflexEncoder/BoardConfig.h index 64b4b4cdb..a6d5d1753 100644 --- a/configs/ReflexEncoder/BoardConfig.h +++ b/configs/ReflexEncoder/BoardConfig.h @@ -60,6 +60,8 @@ #define DEFAULT_FORCED_SETUP_MODE FORCED_SETUP_MODE_OFF // FORCED_SETUP_MODE_OFF, FORCED_SETUP_MODE_LOCK_MODE_SWITCH, FORCED_SETUP_MODE_LOCK_WEB_CONFIG, FORCED_SETUP_MODE_LOCK_BOTH #define DEFAULT_LOCK_HOTKEYS false // or true +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER + // This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) // The Turbo LED will flash at a speed consistant with the set speed of the Turbo when a Turbo button is active. diff --git a/configs/SGFDevices/BoardConfig.h b/configs/SGFDevices/BoardConfig.h index 4f5373bd2..061f16bc7 100644 --- a/configs/SGFDevices/BoardConfig.h +++ b/configs/SGFDevices/BoardConfig.h @@ -81,6 +81,7 @@ #define DEFAULT_FORCED_SETUP_MODE FORCED_SETUP_MODE_OFF // FORCED_SETUP_MODE_OFF, FORCED_SETUP_MODE_LOCK_MODE_SWITCH, FORCED_SETUP_MODE_LOCK_WEB_CONFIG, FORCED_SETUP_MODE_LOCK_BOTH #define DEFAULT_LOCK_HOTKEYS false // or true +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER // This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) diff --git a/configs/SparkFunProMicro/BoardConfig.h b/configs/SparkFunProMicro/BoardConfig.h index 2a20670a7..1a5119840 100644 --- a/configs/SparkFunProMicro/BoardConfig.h +++ b/configs/SparkFunProMicro/BoardConfig.h @@ -52,6 +52,9 @@ #define DEFAULT_FORCED_SETUP_MODE FORCED_SETUP_MODE_OFF // FORCED_SETUP_MODE_OFF, FORCED_SETUP_MODE_LOCK_MODE_SWITCH, FORCED_SETUP_MODE_LOCK_WEB_CONFIG, FORCED_SETUP_MODE_LOCK_BOTH #define DEFAULT_LOCK_HOTKEYS false // or true + +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER + // This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) // The Turbo LED will flash at a speed consistant with the set speed of the Turbo when a Turbo button is active. diff --git a/configs/Stress/BoardConfig.h b/configs/Stress/BoardConfig.h index 78ecc52ea..3b014fa73 100644 --- a/configs/Stress/BoardConfig.h +++ b/configs/Stress/BoardConfig.h @@ -59,6 +59,8 @@ #define DEFAULT_FORCED_SETUP_MODE FORCED_SETUP_MODE_OFF // FORCED_SETUP_MODE_OFF, FORCED_SETUP_MODE_LOCK_MODE_SWITCH, FORCED_SETUP_MODE_LOCK_WEB_CONFIG, FORCED_SETUP_MODE_LOCK_BOTH #define DEFAULT_LOCK_HOTKEYS false // or true +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER + // This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) // The Turbo LED will flash at a speed consistant with the set speed of the Turbo when a Turbo button is active. diff --git a/configs/WaveshareZero/BoardConfig.h b/configs/WaveshareZero/BoardConfig.h index c67da98c4..a15194afc 100644 --- a/configs/WaveshareZero/BoardConfig.h +++ b/configs/WaveshareZero/BoardConfig.h @@ -60,6 +60,8 @@ #define DEFAULT_FORCED_SETUP_MODE FORCED_SETUP_MODE_OFF // FORCED_SETUP_MODE_OFF, FORCED_SETUP_MODE_LOCK_MODE_SWITCH, FORCED_SETUP_MODE_LOCK_WEB_CONFIG, FORCED_SETUP_MODE_LOCK_BOTH #define DEFAULT_LOCK_HOTKEYS false // or true +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER + // This is the LEDs section. // The default `TURBO_LED_PIN` pin is set to `15` ( it is recommended to run through 3V3(OUT) with a resistor) // The Turbo LED will flash at a speed consistant with the set speed of the Turbo when a Turbo button is active. diff --git a/headers/addonmanager.h b/headers/addonmanager.h index b8fa9ec14..2ea368728 100644 --- a/headers/addonmanager.h +++ b/headers/addonmanager.h @@ -2,6 +2,7 @@ #define _ADDONMANAGER_H_ #include "gpaddon.h" +#include "usbaddon.h" #include #include @@ -9,6 +10,7 @@ enum ADDON_PROCESS { CORE0_INPUT, CORE0_USBREPORT, + CORE1_ALWAYS, CORE1_LOOP }; @@ -22,6 +24,7 @@ class AddonManager { AddonManager() {} ~AddonManager() {} void LoadAddon(GPAddon*, ADDON_PROCESS); + void LoadUSBAddon(USBAddon*, ADDON_PROCESS); void PreprocessAddons(ADDON_PROCESS); void ProcessAddons(ADDON_PROCESS); GPAddon * GetAddon(std::string); // hack for NeoPicoLED diff --git a/headers/addons/keyboard_host.h b/headers/addons/keyboard_host.h index 8ff7761ab..af9c61b04 100644 --- a/headers/addons/keyboard_host.h +++ b/headers/addons/keyboard_host.h @@ -1,7 +1,7 @@ #ifndef _KeyboardHost_H #define _KeyboardHost_H -#include "gpaddon.h" +#include "usbaddon.h" #include "gamepad.h" #ifndef KEYBOARD_HOST_ENABLED @@ -21,12 +21,12 @@ struct KeyboardButtonMapping { - KeyboardButtonMapping(uint16_t bm) : - buttonMask(bm) - {} - uint8_t key; - const uint16_t buttonMask; + uint16_t buttonMask; + + inline void setMask(uint16_t m) { + buttonMask = m; + } inline void setKey(uint8_t p) { @@ -36,14 +36,42 @@ struct KeyboardButtonMapping bool isAssigned() const { return key != 0xff; } }; -class KeyboardHostAddon : public GPAddon { +class KeyboardHostAddon : public USBAddon { public: virtual bool available(); virtual void setup(); // KeyboardHost Setup - virtual void process() {} // KeyboardHost Process + virtual void process() {} // KeyboardHost Process virtual void preprocess(); virtual std::string name() { return KeyboardHostName; } -private: +// USB Add-on Features + virtual void mount(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len); + virtual void unmount(uint8_t dev_addr); + virtual void report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len); + virtual void set_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) {} + virtual void get_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) {} +private: + bool _keyboard_host_enabled; + uint8_t getKeycodeFromModifier(uint8_t modifier); + void process_kbd_report(uint8_t dev_addr, hid_keyboard_report_t const *report); + GamepadState _keyboard_host_state; + KeyboardButtonMapping _keyboard_host_mapDpadUp; + KeyboardButtonMapping _keyboard_host_mapDpadDown; + KeyboardButtonMapping _keyboard_host_mapDpadLeft; + KeyboardButtonMapping _keyboard_host_mapDpadRight; + KeyboardButtonMapping _keyboard_host_mapButtonB1; + KeyboardButtonMapping _keyboard_host_mapButtonB2; + KeyboardButtonMapping _keyboard_host_mapButtonB3; + KeyboardButtonMapping _keyboard_host_mapButtonB4; + KeyboardButtonMapping _keyboard_host_mapButtonL1; + KeyboardButtonMapping _keyboard_host_mapButtonR1; + KeyboardButtonMapping _keyboard_host_mapButtonL2; + KeyboardButtonMapping _keyboard_host_mapButtonR2; + KeyboardButtonMapping _keyboard_host_mapButtonS1; + KeyboardButtonMapping _keyboard_host_mapButtonS2; + KeyboardButtonMapping _keyboard_host_mapButtonL3; + KeyboardButtonMapping _keyboard_host_mapButtonR3; + KeyboardButtonMapping _keyboard_host_mapButtonA1; + KeyboardButtonMapping _keyboard_host_mapButtonA2; }; #endif // _KeyboardHost_H_ \ No newline at end of file diff --git a/headers/addons/pspassthrough.h b/headers/addons/pspassthrough.h new file mode 100644 index 000000000..6275a9520 --- /dev/null +++ b/headers/addons/pspassthrough.h @@ -0,0 +1,46 @@ +#ifndef _PSPassthrough_H +#define _PSPassthrough_H + +#include "usbaddon.h" + +#include "ps4_driver.h" + +#ifndef PSPASSTHROUGH_ENABLED +#define PSPASSTHROUGH_ENABLED 0 +#endif + +#ifndef PPSPASSTHROUGH_PIN_DPLUS +#define PSPASSTHROUGH_PIN_DPLUS -1 +#endif + +#ifndef PSPASSTHROUGH_PIN_5V +#define PSPASSTHROUGH_PIN_5V -1 +#endif + +// KeyboardHost Module Name +#define PSPassthroughName "PSPassthrough" + +class PSPassthroughAddon : public USBAddon { +public: + virtual bool available(); + virtual void setup(); // PSPassthrough Setup + virtual void process(); // PSPassthrough Process + virtual void preprocess() {} + virtual std::string name() { return PSPassthroughName; } +// USB Add-on Features + virtual void mount(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len); + virtual void unmount(uint8_t dev_addr); + virtual void set_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len); + virtual void get_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len); + virtual void report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {} +private: + uint8_t ps_dev_addr; + uint8_t ps_instance; + int8_t nonce_page; + PS4State passthrough_state; + int8_t send_nonce_part; + uint8_t report_buffer[64]; + bool awaiting_cb; +}; + +#endif // _PSPassthrough_H_ \ No newline at end of file diff --git a/headers/gamepad/GamepadConfig.h b/headers/gamepad/GamepadConfig.h index 2a3b184bd..b38802375 100644 --- a/headers/gamepad/GamepadConfig.h +++ b/headers/gamepad/GamepadConfig.h @@ -17,6 +17,10 @@ #define DEFAULT_INPUT_MODE INPUT_MODE_XINPUT #endif +#ifndef DEFAULT_PS4CONTROLLER_TYPE +#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER +#endif + /* hotkeys */ #ifndef HOTKEY_01_AUX_MASK #define HOTKEY_01_AUX_MASK 0 diff --git a/headers/usbaddon.h b/headers/usbaddon.h new file mode 100644 index 000000000..a03ba644c --- /dev/null +++ b/headers/usbaddon.h @@ -0,0 +1,23 @@ +#ifndef _USBAddon_H_ +#define _USBAddon_H_ + +#include "gpaddon.h" + +#include + +class USBAddon : public GPAddon +{ +public: + virtual bool available() = 0; + virtual void setup() = 0; + virtual void process() = 0; + virtual void preprocess() = 0; + virtual std::string name() = 0; + virtual void mount(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) = 0; + virtual void unmount(uint8_t dev_addr) = 0; + virtual void report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) = 0; + virtual void set_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) = 0; + virtual void get_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) = 0; +}; + +#endif \ No newline at end of file diff --git a/headers/usbhostmanager.h b/headers/usbhostmanager.h new file mode 100644 index 000000000..154a0fc34 --- /dev/null +++ b/headers/usbhostmanager.h @@ -0,0 +1,41 @@ +#ifndef _USBHOSTMANAGER_H_ +#define _USBHOSTMANAGER_H_ + +#include "usbaddon.h" +#include + +#include "pio_usb.h" + +// Missing TinyUSB call +bool tuh_hid_get_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, void* report, uint16_t len); + +class USBHostManager { +public: + USBHostManager(USBHostManager const&) = delete; + void operator=(USBHostManager const&) = delete; + static USBHostManager& getInstance() {// Thread-safe storage ensures cross-thread talk + static USBHostManager instance; // Guaranteed to be destroyed. // Instantiated on first use. + return instance; + } + void setDataPin(uint8_t); // start USB host (change CPU, setup PIO PICO usb pin) + void start(); + void pushAddon(USBAddon *); // If anything needs to update in the gpconfig driver + void process(); + void hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len); + void hid_umount_cb(uint8_t daddr, uint8_t instance); + void hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len); + void hid_set_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len); + void hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len); +private: + USBHostManager() : tuh_ready(false), core0Ready(false), core1Ready(false) { + + } + std::vector addons; + usb_device_t *usb_device; + uint8_t dataPin; + bool core0Ready; + bool core1Ready; + bool tuh_ready; +}; + +#endif \ No newline at end of file diff --git a/lib/TinyUSB_Gamepad/src/ps4_driver.cpp b/lib/TinyUSB_Gamepad/src/ps4_driver.cpp index a75235e80..5af9499b8 100644 --- a/lib/TinyUSB_Gamepad/src/ps4_driver.cpp +++ b/lib/TinyUSB_Gamepad/src/ps4_driver.cpp @@ -17,7 +17,7 @@ uint8_t ps4_endpoint_in = 0; uint8_t ps4_endpoint_out = 0; uint8_t ps4_out_buffer[PS4_OUT_SIZE] = {}; -// Alternative version +// Controller descriptor (byte[4] = 0x00 for ps4, 0x07 for ps5) static constexpr uint8_t output_0x03[] = { 0x21, 0x27, 0x04, 0xcf, 0x00, 0x2c, 0x56, 0x08, 0x00, 0x3d, 0x00, 0xe8, 0x03, 0x04, 0x00, @@ -27,13 +27,6 @@ static constexpr uint8_t output_0x03[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -// Passinglink version -/*static constexpr uint8_t output_0x03[] = { - 0x21, 0x27, 0x4, 0x40, 0x7, 0x2c, 0x56, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xd, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 -};*/ - // Nonce Page Size: 0x38 (56) // Response Page Size: 0x38 (56) static constexpr uint8_t output_0xf3[] = { 0x0, 0x38, 0x38, 0, 0, 0, 0 }; @@ -63,12 +56,13 @@ ssize_t get_ps4_report(uint8_t report_id, uint8_t * buf, uint16_t reqlen) uint32_t crc32; ps4_out_buffer[0] = report_id; switch(report_id) { - // Not sure on 0x03? maybe a controller qualifier - case PS4AuthReport::PS4_UNKNOWN_0X03: + // Controller Definition Report + case PS4AuthReport::PS4_DEFINITION: if (reqlen != sizeof(output_0x03)) { return -1; } memcpy(buf, output_0x03, reqlen); + buf[4] = (uint8_t)PS4Data::getInstance().ps4ControllerType; // Change controller type in definition return reqlen; // Use our private RSA key to sign the nonce and return chunks case PS4AuthReport::PS4_GET_SIGNATURE_NONCE: @@ -147,6 +141,7 @@ void set_ps4_report(uint8_t report_id, uint8_t const * data, uint16_t reqlen) if ( nonce_page == 4 ) { // Copy/append data from buffer[4:64-28] into our nonce noncelen = 32; // from 4 to 64 - 24 - 4 + PS4Data::getInstance().nonce_id = nonce_id; // for pass-through only } else { // Copy/append data from buffer[4:64-4] into our nonce noncelen = 56; diff --git a/lib/TinyUSB_Gamepad/src/ps4_driver.h b/lib/TinyUSB_Gamepad/src/ps4_driver.h index 45064eae0..5a40652ec 100644 --- a/lib/TinyUSB_Gamepad/src/ps4_driver.h +++ b/lib/TinyUSB_Gamepad/src/ps4_driver.h @@ -10,11 +10,13 @@ #include "gamepad/descriptors/PS4Descriptors.h" +#include "enums.pb.h" + #define PS4_OUT_SIZE 64 typedef enum { - PS4_UNKNOWN_0X03 = 0x03, // Unknown (PS4 Report 0x03) + PS4_DEFINITION = 0x03, // PS4 Controller Definition PS4_SET_AUTH_PAYLOAD = 0xF0, // Set Auth Payload PS4_GET_SIGNATURE_NONCE = 0xF1, // Get Signature Nonce PS4_GET_SIGNING_STATE = 0xF2, // Get Signing State @@ -34,7 +36,8 @@ typedef enum { no_nonce = 0, receiving_nonce = 1, nonce_ready = 2, - signed_nonce_ready = 3 + signed_nonce_ready = 3, + sending_nonce = 4 } PS4State; // Storage manager for board, LED options, and thread-safe settings @@ -51,6 +54,7 @@ class PS4Data { PS4State ps4State; bool authsent; uint8_t nonce_buffer[256]; + uint8_t nonce_id; // used in pass-through mode // Send back in 56 byte chunks: // 256 byte - nonce signature @@ -63,11 +67,14 @@ class PS4Data { // buffer = 256 + 16 + 256 + 256 + 256 + 24 // == 1064 bytes (almost 1 kb) uint8_t ps4_auth_buffer[1064]; + uint32_t ps4ControllerType; + private: PS4Data() { ps4State = PS4State::no_nonce; authsent = false; memset(nonce_buffer, 0, 256); memset(ps4_auth_buffer, 0, 1064); + ps4ControllerType = PS4ControllerType::PS4_CONTROLLER; } }; diff --git a/proto/config.proto b/proto/config.proto index 70b84a7fa..11a989581 100644 --- a/proto/config.proto +++ b/proto/config.proto @@ -14,6 +14,7 @@ message GamepadOptions optional bool lockHotkeys = 7; optional bool fourWayMode = 8; optional uint32 profileNumber = 9; + optional PS4ControllerType ps4ControllerType = 10; } message KeyboardMapping @@ -420,6 +421,13 @@ message PS4Options optional bytes rsaRN = 12 [(nanopb).max_size = 256]; } +message PSPassthroughOptions +{ + optional bool enabled = 1; + optional int32 pinDplus = 2; + optional int32 pin5V = 3; +} + message WiiOptions { optional bool enabled = 1; @@ -475,6 +483,7 @@ message AddonOptions optional FocusModeOptions focusModeOptions = 16; optional KeyboardHostOptions keyboardHostOptions = 17; optional TiltOptions tiltOptions = 18; + optional PSPassthroughOptions psPassthroughOptions = 19; } message Config diff --git a/proto/enums.proto b/proto/enums.proto index bdfd3ce3f..85fe61951 100644 --- a/proto/enums.proto +++ b/proto/enums.proto @@ -180,3 +180,11 @@ enum ForcedSetupMode FORCED_SETUP_MODE_LOCK_WEB_CONFIG = 2; FORCED_SETUP_MODE_LOCK_BOTH = 3; }; + +enum PS4ControllerType +{ + option (nanopb_enumopt).long_names = false; + + PS4_CONTROLLER = 0; + PS4_ARCADESTICK = 7; +} diff --git a/src/addonmanager.cpp b/src/addonmanager.cpp index 55806f93e..fa1376c95 100644 --- a/src/addonmanager.cpp +++ b/src/addonmanager.cpp @@ -1,4 +1,5 @@ #include "addonmanager.h" +#include "usbhostmanager.h" void AddonManager::LoadAddon(GPAddon* addon, ADDON_PROCESS processAt) { if (addon->available()) { @@ -12,6 +13,18 @@ void AddonManager::LoadAddon(GPAddon* addon, ADDON_PROCESS processAt) { } } +void AddonManager::LoadUSBAddon(USBAddon* addon, ADDON_PROCESS processAt) { + if (addon->available()) { + AddonBlock * block = new AddonBlock; + addon->setup(); + block->ptr = addon; + block->process = processAt; + addons.push_back(block); + USBHostManager::getInstance().pushAddon(addon); + } else { + delete addon; // Don't use the memory if we don't have to + } +} void AddonManager::PreprocessAddons(ADDON_PROCESS processType) { // Loop through all addons and process any that match our type diff --git a/src/addons/i2cdisplay.cpp b/src/addons/i2cdisplay.cpp index 914b5049b..c23df486e 100644 --- a/src/addons/i2cdisplay.cpp +++ b/src/addons/i2cdisplay.cpp @@ -937,10 +937,16 @@ void I2CDisplayAddon::drawStatusBar(Gamepad * gamepad) case INPUT_MODE_SWITCH: statusBar += "SWITCH"; break; case INPUT_MODE_XINPUT: statusBar += "XINPUT"; break; case INPUT_MODE_PS4: - if (PS4Data::getInstance().authsent == true ) { - statusBar += "PS4:AS"; - } else { - statusBar += "PS4 "; + if ( PS4Data::getInstance().ps4ControllerType == PS4ControllerType::PS4_CONTROLLER ) { + if (PS4Data::getInstance().authsent == true ) + statusBar += "PS4:AS"; + else + statusBar += "PS4 "; + } else if ( PS4Data::getInstance().ps4ControllerType == PS4ControllerType::PS4_ARCADESTICK ) { + if (PS4Data::getInstance().authsent == true ) + statusBar += "PS5:AS"; + else + statusBar += "PS5 "; } break; case INPUT_MODE_KEYBOARD: statusBar += "HID-KB"; break; diff --git a/src/addons/keyboard_host.cpp b/src/addons/keyboard_host.cpp index 40e47a9ef..a15dd5985 100644 --- a/src/addons/keyboard_host.cpp +++ b/src/addons/keyboard_host.cpp @@ -1,32 +1,9 @@ #include "addons/keyboard_host.h" #include "storagemanager.h" - -#include "pio_usb.h" - -static bool host_device_mounted = false; -static GamepadState _keyboard_host_state; - -static KeyboardButtonMapping _keyboard_host_mapDpadUp = KeyboardButtonMapping(GAMEPAD_MASK_UP); -static KeyboardButtonMapping _keyboard_host_mapDpadDown = KeyboardButtonMapping(GAMEPAD_MASK_DOWN); -static KeyboardButtonMapping _keyboard_host_mapDpadLeft = KeyboardButtonMapping(GAMEPAD_MASK_LEFT); -static KeyboardButtonMapping _keyboard_host_mapDpadRight = KeyboardButtonMapping(GAMEPAD_MASK_RIGHT); -static KeyboardButtonMapping _keyboard_host_mapButtonB1 = KeyboardButtonMapping(GAMEPAD_MASK_B1); -static KeyboardButtonMapping _keyboard_host_mapButtonB2 = KeyboardButtonMapping(GAMEPAD_MASK_B2); -static KeyboardButtonMapping _keyboard_host_mapButtonB3 = KeyboardButtonMapping(GAMEPAD_MASK_B3); -static KeyboardButtonMapping _keyboard_host_mapButtonB4 = KeyboardButtonMapping(GAMEPAD_MASK_B4); -static KeyboardButtonMapping _keyboard_host_mapButtonL1 = KeyboardButtonMapping(GAMEPAD_MASK_L1); -static KeyboardButtonMapping _keyboard_host_mapButtonR1 = KeyboardButtonMapping(GAMEPAD_MASK_R1); -static KeyboardButtonMapping _keyboard_host_mapButtonL2 = KeyboardButtonMapping(GAMEPAD_MASK_L2); -static KeyboardButtonMapping _keyboard_host_mapButtonR2 = KeyboardButtonMapping(GAMEPAD_MASK_R2); -static KeyboardButtonMapping _keyboard_host_mapButtonS1 = KeyboardButtonMapping(GAMEPAD_MASK_S1); -static KeyboardButtonMapping _keyboard_host_mapButtonS2 = KeyboardButtonMapping(GAMEPAD_MASK_S2); -static KeyboardButtonMapping _keyboard_host_mapButtonL3 = KeyboardButtonMapping(GAMEPAD_MASK_L3); -static KeyboardButtonMapping _keyboard_host_mapButtonR3 = KeyboardButtonMapping(GAMEPAD_MASK_R3); -static KeyboardButtonMapping _keyboard_host_mapButtonA1 = KeyboardButtonMapping(GAMEPAD_MASK_A1); -static KeyboardButtonMapping _keyboard_host_mapButtonA2 = KeyboardButtonMapping(GAMEPAD_MASK_A2); +#include "usbhostmanager.h" bool KeyboardHostAddon::available() { - const KeyboardHostOptions& keyboardHostOptions = Storage::getInstance().getAddonOptions().keyboardHostOptions; + const KeyboardHostOptions& keyboardHostOptions = Storage::getInstance().getAddonOptions().keyboardHostOptions; return keyboardHostOptions.enabled && isValidPin(keyboardHostOptions.pinDplus) && (keyboardHostOptions.pin5V == -1 || isValidPin(keyboardHostOptions.pin5V)); @@ -34,29 +11,38 @@ bool KeyboardHostAddon::available() { void KeyboardHostAddon::setup() { set_sys_clock_khz(120000, true); // Set Clock to 120MHz to avoid potential USB timing issues + const KeyboardHostOptions& keyboardHostOptions = Storage::getInstance().getAddonOptions().keyboardHostOptions; const KeyboardMapping& keyboardMapping = keyboardHostOptions.mapping; - // board_init(); - // board_init() should be doing what the two lines below are doing but doesn't work - // needs tinyusb_board library linked if (keyboardHostOptions.pin5V != -1) { - const int32_t pin5V = keyboardHostOptions.pin5V; + const int32_t pin5V = keyboardHostOptions.pin5V; gpio_init(pin5V); gpio_set_dir(pin5V, GPIO_IN); gpio_pull_up(pin5V); } - pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG; - pio_cfg.pin_dp = keyboardHostOptions.pinDplus; - tuh_configure(1, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, &pio_cfg); - tuh_init(BOARD_TUH_RHPORT); - - while((to_ms_since_boot(get_absolute_time()) < 250)) { - if (host_device_mounted) break; - tuh_task(); - } - + USBHostManager::getInstance().setDataPin((uint8_t)keyboardHostOptions.pinDplus); + + _keyboard_host_enabled = false; + _keyboard_host_mapDpadUp.setMask(GAMEPAD_MASK_UP); + _keyboard_host_mapDpadDown.setMask(GAMEPAD_MASK_DOWN); + _keyboard_host_mapDpadLeft.setMask(GAMEPAD_MASK_LEFT); + _keyboard_host_mapDpadRight.setMask(GAMEPAD_MASK_RIGHT); + _keyboard_host_mapButtonB1.setMask(GAMEPAD_MASK_B1); + _keyboard_host_mapButtonB2.setMask(GAMEPAD_MASK_B2); + _keyboard_host_mapButtonB3.setMask(GAMEPAD_MASK_B3); + _keyboard_host_mapButtonB4.setMask(GAMEPAD_MASK_B4); + _keyboard_host_mapButtonL1.setMask(GAMEPAD_MASK_L1); + _keyboard_host_mapButtonR1.setMask(GAMEPAD_MASK_R1); + _keyboard_host_mapButtonL2.setMask(GAMEPAD_MASK_L2); + _keyboard_host_mapButtonR2.setMask(GAMEPAD_MASK_R2); + _keyboard_host_mapButtonS1.setMask(GAMEPAD_MASK_S1); + _keyboard_host_mapButtonS2.setMask(GAMEPAD_MASK_S2); + _keyboard_host_mapButtonL3.setMask(GAMEPAD_MASK_L3); + _keyboard_host_mapButtonR3.setMask(GAMEPAD_MASK_R3); + _keyboard_host_mapButtonA1.setMask(GAMEPAD_MASK_A1); + _keyboard_host_mapButtonA2.setMask(GAMEPAD_MASK_A2); _keyboard_host_mapDpadUp.setKey(keyboardMapping.keyDpadUp); _keyboard_host_mapDpadDown.setKey(keyboardMapping.keyDpadDown); _keyboard_host_mapDpadLeft.setKey(keyboardMapping.keyDpadLeft); @@ -87,46 +73,31 @@ void KeyboardHostAddon::preprocess() { gamepad->state.ry |= _keyboard_host_state.ry; gamepad->state.lt |= _keyboard_host_state.lt; gamepad->state.rt |= _keyboard_host_state.rt; +} - tuh_task(); +void KeyboardHostAddon::mount(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) { + _keyboard_host_enabled = true; } -// Invoked when device with hid interface is mounted -// Report descriptor is also available for use. tuh_hid_parse_report_descriptor() -// can be used to parse common/simple enough descriptor. -// Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped -// therefore report_desc = NULL, desc_len = 0 -void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) -{ - (void)desc_report; - (void)desc_len; +void KeyboardHostAddon::unmount(uint8_t dev_addr) { + _keyboard_host_enabled = false; +} - host_device_mounted = true; +void KeyboardHostAddon::report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len){ + if ( _keyboard_host_enabled == false ) + return; // do nothing if our add-on is not enabled // Interface protocol (hid_interface_protocol_enum_t) uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance); - uint16_t vid, pid; - tuh_vid_pid_get(dev_addr, &vid, &pid); - // tuh_hid_report_received_cb() will be invoked when report is available - if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) - { - if ( !tuh_hid_receive_report(dev_addr, instance) ) - { - // Error: cannot request report - } - } -} + if (itf_protocol != HID_ITF_PROTOCOL_KEYBOARD) + return; -// Invoked when device with hid interface is un-mounted -void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) -{ - (void) dev_addr; - (void) instance; + process_kbd_report(dev_addr, (hid_keyboard_report_t const*) report ); } -uint8_t getKeycodeFromModifier(uint8_t modifier) { +uint8_t KeyboardHostAddon::getKeycodeFromModifier(uint8_t modifier) { switch (modifier) { case KEYBOARD_MODIFIER_LEFTCTRL : return HID_KEY_CONTROL_LEFT ; case KEYBOARD_MODIFIER_LEFTSHIFT : return HID_KEY_SHIFT_LEFT ; @@ -142,10 +113,8 @@ uint8_t getKeycodeFromModifier(uint8_t modifier) { } // convert hid keycode to ascii and print via usb device CDC (ignore non-printable) -void process_kbd_report(uint8_t dev_addr, hid_keyboard_report_t const *report) +void KeyboardHostAddon::process_kbd_report(uint8_t dev_addr, hid_keyboard_report_t const *report) { - (void) dev_addr; - _keyboard_host_state.dpad = 0; _keyboard_host_state.buttons = 0; _keyboard_host_state.lx = GAMEPAD_JOYSTICK_MID; @@ -194,26 +163,4 @@ void process_kbd_report(uint8_t dev_addr, hid_keyboard_report_t const *report) _keyboard_host_state.rt = 0; } } -} - -// Invoked when received report from device via interrupt endpoint -void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) -{ - (void) len; - uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance); - - switch(itf_protocol) - { - case HID_ITF_PROTOCOL_KEYBOARD: - process_kbd_report(dev_addr, (hid_keyboard_report_t const*) report ); - break; - - default: break; - } - - // continue to request to receive report - if ( !tuh_hid_receive_report(dev_addr, instance) ) - { - //Error: cannot request report - } } \ No newline at end of file diff --git a/src/addons/pspassthrough.cpp b/src/addons/pspassthrough.cpp new file mode 100644 index 000000000..32563da3f --- /dev/null +++ b/src/addons/pspassthrough.cpp @@ -0,0 +1,168 @@ +#include "addons/pspassthrough.h" +#include "storagemanager.h" +#include "usbhostmanager.h" + +#include "CRC32.h" + +// Data passed between PS Passthrough and TinyUSB Host callbacks + +bool PSPassthroughAddon::available() { + const PSPassthroughOptions& psOptions = Storage::getInstance().getAddonOptions().psPassthroughOptions; + return psOptions.enabled && isValidPin(psOptions.pinDplus) && + (psOptions.pin5V == -1 || isValidPin(psOptions.pin5V)); +} + +void PSPassthroughAddon::setup() { + const PSPassthroughOptions& psOptions = Storage::getInstance().getAddonOptions().psPassthroughOptions; + + if (psOptions.pin5V != -1) { // Feather USB-A's require this + const int32_t pin5V = psOptions.pin5V; + gpio_init(pin5V); + gpio_set_dir(pin5V, GPIO_IN); + gpio_pull_up(pin5V); + } + + USBHostManager::getInstance().setDataPin((uint8_t)psOptions.pinDplus); + + nonce_page = 0; // no nonce yet + send_nonce_part = 0; // which part of the nonce are we getting from send? + awaiting_cb = false; // did we receive the sign state yet + passthrough_state = PS4State::no_nonce; +} + +void PSPassthroughAddon::process() { + if (!awaiting_cb) + return; + + switch ( passthrough_state ) { + case PS4State::no_nonce: + // Did we get the nonce? Let's begin auth + if ( PS4Data::getInstance().ps4State == nonce_ready ) { + uint8_t const output_0xf3[] = { 0x0, 0x38, 0x38, 0, 0, 0, 0 }; + uint8_t* buf = report_buffer; + uint16_t len = sizeof(output_0xf3); + memcpy(buf, output_0xf3, len); + awaiting_cb = true; + tuh_hid_get_report(ps_dev_addr, ps_instance, PS4AuthReport::PS4_RESET_AUTH, HID_REPORT_TYPE_FEATURE, buf, len); + } + break; + case PS4State::receiving_nonce: + { + uint8_t noncelen; + uint32_t crc32; + uint8_t nonce_buffer[64]; // [0xF0, ID, Page, 0, nonce(54 or 32 with 0 padding), CRC32 of data] + nonce_buffer[0] = PS4AuthReport::PS4_SET_AUTH_PAYLOAD; + nonce_buffer[1] = PS4Data::getInstance().nonce_id; + nonce_buffer[2] = nonce_page; + nonce_buffer[3] = 0; + if ( nonce_page == 4 ) { + noncelen = 32; // from 4 to 64 - 24 - 4 + memcpy(&nonce_buffer[4], &PS4Data::getInstance().nonce_buffer[nonce_page*56], noncelen); + memset(&nonce_buffer[4+noncelen], 0, 24); // zero padding + } else { + noncelen = 56; + memcpy(&nonce_buffer[4], &PS4Data::getInstance().nonce_buffer[nonce_page*56], noncelen); + } + nonce_page++; + crc32 = CRC32::calculate(nonce_buffer, 60); + memcpy(&nonce_buffer[60], &crc32, sizeof(uint32_t)); + uint8_t* buf = report_buffer; + uint16_t len = sizeof(nonce_buffer); + memcpy(buf, nonce_buffer, len); + awaiting_cb = true; + tuh_hid_set_report(ps_dev_addr, ps_instance, PS4AuthReport::PS4_SET_AUTH_PAYLOAD, HID_REPORT_TYPE_FEATURE, buf, len); + } + break; + case PS4State::signed_nonce_ready: + { + uint8_t state_buffer[16]; + memset(state_buffer, 0, 16); + state_buffer[0] = PS4AuthReport::PS4_GET_SIGNING_STATE; + state_buffer[1] = PS4Data::getInstance().nonce_id; + memset(&state_buffer[2], 0, 14); + uint8_t* buf = report_buffer; + uint16_t len = sizeof(state_buffer); + memcpy(buf, state_buffer, len); + awaiting_cb = true; + tuh_hid_get_report(ps_dev_addr, ps_instance, PS4AuthReport::PS4_GET_SIGNING_STATE, HID_REPORT_TYPE_FEATURE, buf, len); + } + break; + case PS4State::sending_nonce: + { + uint8_t nonce_buffer[64]; + nonce_buffer[0] = PS4AuthReport::PS4_GET_SIGNATURE_NONCE; + nonce_buffer[1] = PS4Data::getInstance().nonce_id; // nonce_id + nonce_buffer[2] = send_nonce_part; // next_part + memset(&nonce_buffer[3], 0, 61); // zero rest of memory + uint8_t* buf = report_buffer; + uint16_t len = sizeof(nonce_buffer); + memcpy(buf, nonce_buffer, len); + send_nonce_part++; // Nonce Part is reset during callback + awaiting_cb = true; + tuh_hid_get_report(ps_dev_addr, ps_instance, PS4AuthReport::PS4_GET_SIGNATURE_NONCE, HID_REPORT_TYPE_FEATURE, buf, len); + } + break; + default: + break; + }; +} + +void PSPassthroughAddon::mount(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) { + ps_dev_addr = dev_addr; + ps_instance = instance; + + // Reset as soon as its connected + memset(report_buffer, 0, sizeof(report_buffer)); + report_buffer[0] = PS4AuthReport::PS4_DEFINITION; + uint8_t* buf = report_buffer; + uint16_t len = 48; + awaiting_cb = true; + tuh_hid_get_report(ps_dev_addr, ps_instance, PS4AuthReport::PS4_DEFINITION, HID_REPORT_TYPE_FEATURE, buf, len); +} + +void PSPassthroughAddon::unmount(uint8_t dev_addr) { + nonce_page = 0; // no nonce yet + send_nonce_part = 0; // which part of the nonce are we getting from send? + awaiting_cb = false; // did we receive the sign state yet + passthrough_state = PS4State::no_nonce; +} + +void PSPassthroughAddon::set_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) { + switch(report_id) { + case PS4AuthReport::PS4_SET_AUTH_PAYLOAD: + if (nonce_page == 5) { + nonce_page = 0; + passthrough_state = PS4State::signed_nonce_ready; + } + break; + default: + break; + }; + awaiting_cb = false; +} + +void PSPassthroughAddon::get_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) { + switch(report_id) { + case PS4AuthReport::PS4_DEFINITION: + break; + case PS4AuthReport::PS4_RESET_AUTH: + if ( PS4Data::getInstance().ps4State == PS4State::nonce_ready) + passthrough_state = PS4State::receiving_nonce; + break; + case PS4AuthReport::PS4_GET_SIGNING_STATE: + if (report_buffer[2] == 0) // 0 = ready, 1 = error in signing, 16 = not ready + passthrough_state = PS4State::sending_nonce; + break; + case PS4AuthReport::PS4_GET_SIGNATURE_NONCE: + memcpy(&PS4Data::getInstance().ps4_auth_buffer[(send_nonce_part-1)*56], &report_buffer[4], 56); + if (send_nonce_part == 19) { + send_nonce_part = 0; + passthrough_state = PS4State::no_nonce; // something we don't support + PS4Data::getInstance().ps4State = PS4State::signed_nonce_ready; + } + break; + default: + break; + }; + awaiting_cb = false; +} diff --git a/src/config_utils.cpp b/src/config_utils.cpp index 260a09b13..6c98b0e11 100644 --- a/src/config_utils.cpp +++ b/src/config_utils.cpp @@ -25,6 +25,7 @@ #include "addons/playernum.h" #include "addons/pleds.h" #include "addons/ps4mode.h" +#include "addons/pspassthrough.h" #include "addons/reverse.h" #include "addons/slider_socd.h" #include "addons/turbo.h" @@ -98,6 +99,7 @@ void ConfigUtils::initUnsetPropertiesWithDefaults(Config& config) INIT_UNSET_PROPERTY(config.gamepadOptions, lockHotkeys, DEFAULT_LOCK_HOTKEYS); INIT_UNSET_PROPERTY(config.gamepadOptions, fourWayMode, false); INIT_UNSET_PROPERTY(config.gamepadOptions, profileNumber, 1); + INIT_UNSET_PROPERTY(config.gamepadOptions, ps4ControllerType, DEFAULT_PS4CONTROLLER_TYPE); // hotkeyOptions HotkeyOptions& hotkeyOptions = config.hotkeyOptions; @@ -514,6 +516,11 @@ void ConfigUtils::initUnsetPropertiesWithDefaults(Config& config) INIT_UNSET_PROPERTY(config.addonOptions.focusModeOptions, oledLockEnabled, !!FOCUS_MODE_OLED_LOCK_ENABLED); INIT_UNSET_PROPERTY(config.addonOptions.focusModeOptions, rgbLockEnabled, !!FOCUS_MODE_RGB_LOCK_ENABLED); INIT_UNSET_PROPERTY(config.addonOptions.focusModeOptions, buttonLockEnabled, !!FOCUS_MODE_BUTTON_LOCK_ENABLED); + + // PS Passthrough + INIT_UNSET_PROPERTY(config.addonOptions.psPassthroughOptions, enabled, PSPASSTHROUGH_ENABLED); + INIT_UNSET_PROPERTY(config.addonOptions.psPassthroughOptions, pinDplus, PSPASSTHROUGH_PIN_DPLUS); + INIT_UNSET_PROPERTY(config.addonOptions.psPassthroughOptions, pin5V, PSPASSTHROUGH_PIN_5V); } diff --git a/src/configs/webconfig.cpp b/src/configs/webconfig.cpp index 2fab38fc3..c0a453fff 100644 --- a/src/configs/webconfig.cpp +++ b/src/configs/webconfig.cpp @@ -570,6 +570,7 @@ std::string setGamepadOptions() readDoc(gamepadOptions.lockHotkeys, doc, "lockHotkeys"); readDoc(gamepadOptions.fourWayMode, doc, "fourWayMode"); readDoc(gamepadOptions.profileNumber, doc, "profileNumber"); + readDoc(gamepadOptions.ps4ControllerType, doc, "ps4ControllerType"); HotkeyOptions& hotkeyOptions = Storage::getInstance().getHotkeyOptions(); save_hotkey(&hotkeyOptions.hotkey01, doc, "hotkey01"); @@ -605,6 +606,7 @@ std::string getGamepadOptions() writeDoc(doc, "lockHotkeys", gamepadOptions.lockHotkeys ? 1 : 0); writeDoc(doc, "fourWayMode", gamepadOptions.fourWayMode ? 1 : 0); writeDoc(doc, "profileNumber", gamepadOptions.profileNumber); + writeDoc(doc, "ps4ControllerType", gamepadOptions.ps4ControllerType); const PinMappings& pinMappings = Storage::getInstance().getPinMappings(); writeDoc(doc, "fnButtonPin", pinMappings.pinButtonFn); @@ -1118,6 +1120,11 @@ std::string setAddonOptions() docToValue(keyboardHostOptions.mapping.keyButtonA1, doc, "keyboardHostMap", "A1"); docToValue(keyboardHostOptions.mapping.keyButtonA2, doc, "keyboardHostMap", "A2"); + PSPassthroughOptions& psPassthroughOptions = Storage::getInstance().getAddonOptions().psPassthroughOptions; + docToValue(psPassthroughOptions.enabled, doc, "PSPassthroughAddonEnabled"); + docToPin(psPassthroughOptions.pinDplus, doc, "psPassthroughPinDplus"); + docToPin(psPassthroughOptions.pin5V, doc, "psPassthroughPin5V"); + Storage::getInstance().save(); return serialize_json(doc); @@ -1351,6 +1358,11 @@ std::string getAddonOptions() writeDoc(doc, "keyboardHostMap", "A1", keyboardHostOptions.mapping.keyButtonA1); writeDoc(doc, "keyboardHostMap", "A2", keyboardHostOptions.mapping.keyButtonA2); + PSPassthroughOptions& psPassthroughOptions = Storage::getInstance().getAddonOptions().psPassthroughOptions; + writeDoc(doc, "PSPassthroughAddonEnabled", psPassthroughOptions.enabled); + writeDoc(doc, "psPassthroughPinDplus", psPassthroughOptions.pinDplus); + writeDoc(doc, "psPassthroughPin5V", psPassthroughOptions.pin5V); + const FocusModeOptions& focusModeOptions = Storage::getInstance().getAddonOptions().focusModeOptions; writeDoc(doc, "focusModePin", cleanPin(focusModeOptions.pin)); writeDoc(doc, "focusModeButtonLockMask", focusModeOptions.buttonLockMask); diff --git a/src/gamepad.cpp b/src/gamepad.cpp index 9d9dd7adc..fb939f39d 100644 --- a/src/gamepad.cpp +++ b/src/gamepad.cpp @@ -13,6 +13,9 @@ #include "storagemanager.h" +// PS5 compatibility +#include "ps4_driver.h" + // MUST BE DEFINED for mpgs uint32_t getMillis() { return to_ms_since_boot(get_absolute_time()); @@ -95,6 +98,7 @@ void Gamepad::setup() { // Configure pin mapping const PinMappings& pinMappings = Storage::getInstance().getProfilePinMappings(); + const GamepadOptions& gamepadOptions = Storage::getInstance().getGamepadOptions(); const auto convertPin = [](int32_t pin) -> uint8_t { return isValidPin(pin) ? pin : 0xff; }; mapDpadUp = new GamepadButtonMapping(convertPin(pinMappings.pinDpadUp), GAMEPAD_MASK_UP); @@ -141,6 +145,9 @@ void Gamepad::setup() gpio_set_dir(pinMappings.pinButtonFn, GPIO_IN); // Set as INPUT gpio_pull_up(pinMappings.pinButtonFn); // Set as PULLUP } + + // setup PS5 compatibility + PS4Data::getInstance().ps4ControllerType = gamepadOptions.ps4ControllerType; } /** diff --git a/src/gp2040.cpp b/src/gp2040.cpp index c5b8d7da6..65f56d975 100644 --- a/src/gp2040.cpp +++ b/src/gp2040.cpp @@ -8,6 +8,7 @@ #include "configmanager.h" // Global Managers #include "storagemanager.h" #include "addonmanager.h" +#include "usbhostmanager.h" #include "addons/analog.h" // Inputs for Core0 #include "addons/bootsel_button.h" @@ -19,6 +20,7 @@ #include "addons/i2canalog1219.h" #include "addons/jslider.h" #include "addons/playernum.h" +#include "addons/pspassthrough.h" #include "addons/reverse.h" #include "addons/turbo.h" #include "addons/slider_socd.h" @@ -48,6 +50,13 @@ GP2040::~GP2040() { } void GP2040::setup() { + // Reduce CPU if any USB host add-on is enabled + const AddonOptions & addonOptions = Storage::getInstance().getAddonOptions(); + if ( addonOptions.keyboardHostOptions.enabled || + addonOptions.psPassthroughOptions.enabled ){ + set_sys_clock_khz(120000, true); // Set Clock to 120MHz to avoid potential USB timing issues + } + // Setup Gamepad and Gamepad Storage Gamepad * gamepad = Storage::getInstance().GetGamepad(); gamepad->setup(); @@ -98,12 +107,14 @@ void GP2040::setup() { break; } } - // Initialize our ADC (various add-ons) adc_init(); - // Setup Add-ons - addons.LoadAddon(new KeyboardHostAddon(), CORE0_INPUT); + // Setup USB add-ons + addons.LoadUSBAddon(new KeyboardHostAddon(), CORE0_INPUT); + addons.LoadUSBAddon(new PSPassthroughAddon(), CORE0_USBREPORT); + + // Setup Regular Add-ons addons.LoadAddon(new AnalogInput(), CORE0_INPUT); addons.LoadAddon(new BootselButtonAddon(), CORE0_INPUT); addons.LoadAddon(new DualDirectionalInput(), CORE0_INPUT); @@ -137,6 +148,9 @@ void GP2040::run() { continue; } + USBHostManager::getInstance().process(); + + // We can't send faster than USB can poll if (nextRuntime > getMicro()) { // fix for unsigned sleep_us(50); // Give some time back to our CPU (lower power consumption) continue; diff --git a/src/gp2040aux.cpp b/src/gp2040aux.cpp index 0f75469ac..85831622a 100644 --- a/src/gp2040aux.cpp +++ b/src/gp2040aux.cpp @@ -4,13 +4,14 @@ #include "storagemanager.h" // Global Managers #include "addonmanager.h" +#include "usbhostmanager.h" -#include "addons/i2cdisplay.h" // Add-Ons -#include "addons/neopicoleds.h" -#include "addons/pleds.h" #include "addons/board_led.h" #include "addons/buzzerspeaker.h" +#include "addons/i2cdisplay.h" // Add-Ons +#include "addons/pleds.h" #include "addons/ps4mode.h" +#include "addons/neopicoleds.h" #include @@ -21,21 +22,25 @@ GP2040Aux::~GP2040Aux() { } void GP2040Aux::setup() { + // Setup Regular Add-ons addons.LoadAddon(new I2CDisplayAddon(), CORE1_LOOP); addons.LoadAddon(new NeoPicoLEDAddon(), CORE1_LOOP); addons.LoadAddon(new PlayerLEDAddon(), CORE1_LOOP); addons.LoadAddon(new BoardLedAddon(), CORE1_LOOP); addons.LoadAddon(new BuzzerSpeakerAddon(), CORE1_LOOP); addons.LoadAddon(new PS4ModeAddon(), CORE1_LOOP); + + USBHostManager::getInstance().start(); } void GP2040Aux::run() { + bool configMode = Storage::getInstance().GetConfigMode(); while (1) { if (nextRuntime > getMicro()) { // fix for unsigned - sleep_us(50); // Give some time back to our CPU (lower power consumption) continue; } - addons.ProcessAddons(CORE1_LOOP); + + addons.ProcessAddons(CORE1_LOOP); nextRuntime = getMicro() + GAMEPAD_POLL_MICRO; } } diff --git a/src/usbhostmanager.cpp b/src/usbhostmanager.cpp new file mode 100644 index 000000000..1041a2ac6 --- /dev/null +++ b/src/usbhostmanager.cpp @@ -0,0 +1,216 @@ +#include "usbhostmanager.h" + +#include "pio_usb.h" +#include "tusb.h" +#include "host/usbh_classdriver.h" + +void USBHostManager::setDataPin(uint8_t inPin) { + dataPin = inPin; +} + +void USBHostManager::start() { + if ( !addons.empty() ) { + pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG; + pio_cfg.pin_dp = dataPin; + tuh_configure(1, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, &pio_cfg); + tuh_init(BOARD_TUH_RHPORT); + sleep_us(10); // ensure we are ready + tuh_ready = true; + } +} + +void USBHostManager::pushAddon(USBAddon * usbAddon) { // If anything needs to update in the gpconfig driver + addons.push_back(usbAddon); +} + +// Host manager should call tuh_task as fast as possible +void USBHostManager::process() { + if ( tuh_ready ){ + tuh_task(); + } +} + +void USBHostManager::hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) { + for( std::vector::iterator it = addons.begin(); it != addons.end(); it++ ){ + (*it)->mount(dev_addr, instance, desc_report, desc_len); + } +} + +void USBHostManager::hid_umount_cb(uint8_t dev_addr, uint8_t instance) { + for( std::vector::iterator it = addons.begin(); it != addons.end(); it++ ){ + (*it)->unmount(dev_addr); + } +} + +void USBHostManager::hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) { + for( std::vector::iterator it = addons.begin(); it != addons.end(); it++ ){ + (*it)->report_received(dev_addr, instance, report, len); + } +} + +void USBHostManager::hid_set_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) { + for( std::vector::iterator it = addons.begin(); it != addons.end(); it++ ){ + (*it)->set_report_complete(dev_addr, instance, report_id, report_type, len); + } +} + +void USBHostManager::hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) { + for( std::vector::iterator it = addons.begin(); it != addons.end(); it++ ){ + (*it)->get_report_complete(dev_addr, instance, report_id, report_type, len); + } +} + +static uint8_t _intf_num = 0; + +// Required helper class for HID_REQ_CONTROL_GET_REPORT addition +uint16_t count_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len) +{ + uint8_t const* p_desc = (uint8_t const*) desc_itf; + uint16_t len = 0; + + while (itf_count--) + { + // Next on interface desc + len += tu_desc_len(desc_itf); + p_desc = tu_desc_next(p_desc); + + while (len < max_len) + { + // return on IAD regardless of itf count + if ( tu_desc_type(p_desc) == TUSB_DESC_INTERFACE_ASSOCIATION ) return len; + + if ( (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) && + ((tusb_desc_interface_t const*) p_desc)->bAlternateSetting == 0 ) + { + break; + } + + len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + } + + return len; +} + +void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) +{ + // Get Interface Number for our HID class + uint16_t temp_buf[128]; + tusb_desc_configuration_t const* desc_cfg; + if (XFER_RESULT_SUCCESS == tuh_descriptor_get_configuration_sync(dev_addr, 0, temp_buf, sizeof(temp_buf))) + { + tusb_desc_configuration_t const* desc_cfg = (tusb_desc_configuration_t*) temp_buf; + uint8_t const* desc_end = ((uint8_t const*) desc_cfg) + tu_le16toh(desc_cfg->wTotalLength); + uint8_t const* p_desc = tu_desc_next(desc_cfg); + + // parse each interfaces + while( p_desc < desc_end ) + { + uint8_t assoc_itf_count = 1; + // Class will always starts with Interface Association (if any) and then Interface descriptor + if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) ) + { + tusb_desc_interface_assoc_t const * desc_iad = (tusb_desc_interface_assoc_t const *) p_desc; + assoc_itf_count = desc_iad->bInterfaceCount; + + p_desc = tu_desc_next(p_desc); // next to Interface + } + + // must be interface from now + if( TUSB_DESC_INTERFACE != tu_desc_type(p_desc) ) return; + tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc; + + // only open and listen to HID endpoint IN + if (desc_itf->bInterfaceClass == TUSB_CLASS_HID) + { + _intf_num = desc_itf->bInterfaceNumber; + break; // we got the interface number + } + + // next Interface or IAD descriptor + uint16_t const drv_len = count_interface_total_len(desc_itf, assoc_itf_count, (uint16_t) (desc_end-p_desc)); + p_desc += drv_len; + } + } // This block can be removed once TinyUSB library incorporates HID_REQ_CONTROL_GET_REPORT callback + + USBHostManager::getInstance().hid_mount_cb(dev_addr, instance, desc_report, desc_len); + if ( !tuh_hid_receive_report(dev_addr, instance) ) { + // Error: cannot request report + } +} + +/// Invoked when device is unmounted (bus reset/unplugged) +void tuh_hid_umount_cb(uint8_t daddr, uint8_t instance) +{ + USBHostManager::getInstance().hid_umount_cb(daddr, instance); +} + +// Invoked when received report from device via interrupt endpoint +void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) +{ + USBHostManager::getInstance().hid_report_received_cb(dev_addr, instance, report, len); + + if ( !tuh_hid_receive_report(dev_addr, instance) ) { + //Error: cannot request report + } +} + +// On IN/OUT/FEATURE set report callback +void tuh_hid_set_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) { + if ( len != 0 ) + USBHostManager::getInstance().hid_set_report_complete_cb(dev_addr, instance, report_id, report_type, len); +} + + +// GET REPORT FEATURE +void tuh_hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) { + if ( len != 0 ) + USBHostManager::getInstance().hid_get_report_complete_cb(dev_addr, instance, report_id, report_type, len); +} + +// Request for HID_REQ_CONTROL_GET_REPORT missing from TinyUSB +static void get_report_complete(tuh_xfer_t* xfer) +{ + if (tuh_hid_get_report_complete_cb) + { + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const instance = 0; + + uint8_t const report_type = tu_u16_high(xfer->setup->wValue); + uint8_t const report_id = tu_u16_low(xfer->setup->wValue); + + tuh_hid_get_report_complete_cb(xfer->daddr, instance, report_id, report_type, + (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0); + } +} + +bool tuh_hid_get_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) +{ + tusb_control_request_t const request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN + }, + .bRequest = HID_REQ_CONTROL_GET_REPORT, + .wValue = tu_u16(report_type, report_id), + .wIndex = _intf_num, // pulled in from tuh_hid_mount_cb() + .wLength = len + }; + + tuh_xfer_t xfer = + { + .daddr = dev_addr, + .ep_addr = 0, + .setup = &request, + .buffer = (uint8_t*)report, + .complete_cb = get_report_complete, + .user_data = 0 + }; + + TU_ASSERT( tuh_control_xfer(&xfer) ); + return true; +} diff --git a/www/server/app.js b/www/server/app.js index d713acd8f..1870dbe8a 100644 --- a/www/server/app.js +++ b/www/server/app.js @@ -93,6 +93,7 @@ app.get("/api/getGamepadOptions", (req, res) => { fourWayMode: 0, fnButtonPin: -1, profileNumber: 1, + ps4ControllerType: 0, hotkey01: { auxMask: 32768, buttonsMask: 66304, @@ -361,6 +362,8 @@ app.get("/api/getAddonsOptions", (req, res) => { keyboardHostPinDplus: 0, keyboardHostPin5V: -1, keyboardHostMap: DEFAULT_KEYBOARD_MAPPING, + psPassthroughPinDplus: 0, + psPassthroughPin5V: -1, AnalogInputEnabled: 1, BoardLedAddonEnabled: 1, FocusModeAddonEnabled: 1, @@ -379,6 +382,7 @@ app.get("/api/getAddonsOptions", (req, res) => { TurboInputEnabled: 1, WiiExtensionAddonEnabled: 1, SNESpadAddonEnabled: 1, + PSPassthroughAddonEnabled: 1, usedPins: Object.values(picoController), }); }); diff --git a/www/src/Locales/en/AddonsConfig.jsx b/www/src/Locales/en/AddonsConfig.jsx index 7a7110b69..8e0876a5e 100644 --- a/www/src/Locales/en/AddonsConfig.jsx +++ b/www/src/Locales/en/AddonsConfig.jsx @@ -118,4 +118,9 @@ export default { 'keyboard-host-d-plus-label': 'D+', 'keyboard-host-d-minus-label': 'D-', 'keyboard-host-five-v-label': '5V Power (optional)', + 'pspassthrough-header-text': 'PS Passthrough', + 'pspassthrough-sub-header-text': 'Following set the data +, - and 5V (optional) pins. Only the + and 5V pin can be configured.', + 'pspassthrough-d-plus-label': 'D+', + 'pspassthrough-d-minus-label': 'D-', + 'pspassthrough-five-v-label': '5V Power (optional)', }; diff --git a/www/src/Locales/en/SettingsPage.jsx b/www/src/Locales/en/SettingsPage.jsx index cdb80ef98..79de1a33f 100644 --- a/www/src/Locales/en/SettingsPage.jsx +++ b/www/src/Locales/en/SettingsPage.jsx @@ -9,6 +9,10 @@ export default { 'keyboard': "Keyboard", 'ps4': "PS4" }, + 'ps4-mode-options': { + 'controller': "Controller", + 'arcadestick': "Arcade Stick", + }, 'd-pad-mode-label': 'D-Pad Mode', 'd-pad-mode-options': { "d-pad": "D-Pad", @@ -25,6 +29,7 @@ export default { 'off': 'Off' }, 'profile-number-label': 'Profile Number', + 'ps4-compatibility-label': 'For PS5 compatibility, use "Arcade Stick" and enable PS Passthrough add-on
For PS4 support, use "Controller" and enable PS4 Mode add-on if you have the necessary files', 'hotkey-settings-label': 'Hotkey Settings', 'hotkey-settings-sub-header': "The <1>Fn slider provides a mappable Function button in the <3 exact='true' to='/pin-mapping'>Pin Mapping page. By selecting the <1>Fn slider option, the Function button must be held along with the selected hotkey settings.<5 />Additionally, select <1>None from the dropdown to unassign any button.", 'hotkey-settings-warning': 'Function button is not mapped. The Fn slider will be disabled.', diff --git a/www/src/Pages/AddonsConfigPage.jsx b/www/src/Pages/AddonsConfigPage.jsx index 0620a195d..951950fd0 100644 --- a/www/src/Pages/AddonsConfigPage.jsx +++ b/www/src/Pages/AddonsConfigPage.jsx @@ -303,6 +303,10 @@ const schema = yup.object().shape({ keyboardHostPinDplus: yup.number().label('Keyboard Host D+ Pin').validatePinWhenValue('KeyboardHostAddonEnabled'), keyboardHostPin5V: yup.number().label('Keyboard Host 5V Power Pin').validatePinWhenValue('KeyboardHostAddonEnabled'), + PSPassthroughAddonEnabled: yup.number().required().label('PS Passthrough Add-On Enabled'), + psPassthroughPinDplus: yup.number().label('PS Passthrough D+ Pin').validatePinWhenValue('PSPassthroughAddonEnabled'), + psPassthroughPin5V: yup.number().label('PS Passthrough 5V Power Pin').validatePinWhenValue('PSPassthroughAddonEnabled'), + PlayerNumAddonEnabled: yup.number().required().label('Player Number Add-On Enabled'), playerNumber: yup.number().label('Player Number').validateRangeWhenValue('PlayerNumAddonEnabled', 1, 4), @@ -1715,6 +1719,55 @@ export default function AddonsConfigPage() { onChange={(e) => {handleCheckbox("PS4ModeAddonEnabled", values); handleChange(e);}} /> +
+ + { handleCheckbox("PSPassthroughAddonEnabled", values); handleChange(e);}} + /> +
o.value)).label('PS4 Controller Type'), }); const FormContext = ({ setButtonLabels }) => { @@ -120,6 +126,8 @@ const FormContext = ({ setButtonLabels }) => { values.fourWayMode = parseInt(values.fourWayMode); if (!!values.profileNumber) values.profileNumber = parseInt(values.profileNumber); + if (!!values.ps4ControllerType) + values.ps4ControllerType = parseInt(values.ps4ControllerType); setButtonLabels({ swapTpShareLabels: (values.switchTpShareForDs4 === 1) && (values.inputMode === 4) }); @@ -184,6 +192,7 @@ export default function SettingsPage() { const translatedSocdModes = translateArray(SOCD_MODES); const translatedHotkeyActions = translateArray(HOTKEY_ACTIONS); const translatedForcedSetupModes = translateArray(FORCED_SETUP_MODES); + const translatedPS4ControllerTypeModes = translateArray(PS4_MODES); return ( @@ -205,16 +214,34 @@ export default function SettingsPage() { {errors.inputMode}
+ {(values.inputMode === PS4Mode) &&
- {values.inputMode === PS4Mode && { setFieldValue("switchTpShareForDs4", e.target.checked ? 1 : 0); }} - />} -
+ /> + } + {(values.inputMode === PS4Mode) && +
+ + {translatedPS4ControllerTypeModes.map((o, i) => )} + +
} + {(values.inputMode === PS4Mode) && +
+ + For PS5 compatibility, use "Arcade Stick" and enable PS Passthrough add-on
For PS4 support, use "Controller" and enable PS4 Mode add-on if you have the necessary files +
+
} {t('SettingsPage:d-pad-mode-label')}