diff --git a/CMakeLists.txt b/CMakeLists.txt index 1503b534a..bec17b987 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,11 +142,36 @@ src/main.cpp src/gp2040.cpp src/gp2040aux.cpp src/gamepad.cpp +src/gamepad/GamepadDebouncer.cpp +src/gamepad/GamepadState.cpp src/addonmanager.cpp src/configmanager.cpp +src/drivers/shared/xinput_host.cpp +src/drivers/shared/xgip_protocol.cpp +src/drivers/astro/AstroDriver.cpp +src/drivers/egret/EgretDriver.cpp +src/drivers/hid/HIDDriver.cpp +src/drivers/keyboard/KeyboardDriver.cpp +src/drivers/mdmini/MDMiniDriver.cpp +src/drivers/neogeo/NeoGeoDriver.cpp +src/drivers/net/NetDriver.cpp +src/drivers/pcengine/PCEngineDriver.cpp +src/drivers/ps4/PS4Driver.cpp +src/drivers/psclassic/PSClassicDriver.cpp +src/drivers/switch/SwitchDriver.cpp +src/drivers/xbone/XBOneDriver.cpp +src/drivers/xboxog/xid/xid_driver.c +src/drivers/xboxog/xid/xid_gamepad.c +src/drivers/xboxog/xid/xid_remote.c +src/drivers/xboxog/xid/xid_steelbattalion.c +src/drivers/xboxog/xid/xid.c +src/drivers/xboxog/XboxOriginalDriver.cpp +src/drivers/xinput/XInputDriver.cpp +src/drivermanager.cpp src/peripheralmanager.cpp src/storagemanager.cpp src/system.cpp +src/usbdriver.cpp src/usbhostmanager.cpp src/config_legacy.cpp src/config_utils.cpp @@ -173,8 +198,6 @@ src/addons/wiiext.cpp src/addons/input_macro.cpp src/addons/snes_input.cpp src/addons/inputhistory.cpp -src/gamepad/GamepadDebouncer.cpp -src/gamepad/GamepadDescriptors.cpp src/addons/tilt.cpp src/addons/xbonepassthrough.cpp ${PROTO_OUTPUT_DIR}/enums.pb.c @@ -205,7 +228,6 @@ PicoPeripherals WiiExtension SNESpad pico_mbedtls -TinyUSB_Gamepad nanopb ) @@ -213,6 +235,7 @@ target_include_directories(${PROJECT_NAME} PUBLIC headers headers/addons headers/configs +headers/drivers headers/gamepad configs/${GP2040_BOARDCONFIG} ${PROTO_OUTPUT_DIR} diff --git a/headers/addons/keyboard_host.h b/headers/addons/keyboard_host.h index 87512e152..4a32c56cb 100644 --- a/headers/addons/keyboard_host.h +++ b/headers/addons/keyboard_host.h @@ -3,6 +3,7 @@ #include "usbaddon.h" #include "gamepad.h" +#include "class/hid/hid.h" #ifndef KEYBOARD_HOST_ENABLED #define KEYBOARD_HOST_ENABLED 0 diff --git a/headers/addons/pspassthrough.h b/headers/addons/pspassthrough.h index a950bcdf6..79534d8d3 100644 --- a/headers/addons/pspassthrough.h +++ b/headers/addons/pspassthrough.h @@ -2,8 +2,7 @@ #define _PSPassthrough_H #include "usbaddon.h" - -#include "ps4_driver.h" +#include "drivers/shared/ps4data.h" #ifndef PSPASSTHROUGH_ENABLED #define PSPASSTHROUGH_ENABLED 0 diff --git a/headers/addons/xbonepassthrough.h b/headers/addons/xbonepassthrough.h index 419834d2b..e450d8bef 100644 --- a/headers/addons/xbonepassthrough.h +++ b/headers/addons/xbonepassthrough.h @@ -3,7 +3,7 @@ #include "usbaddon.h" -#include "xgip_protocol.h" +#include "drivers/shared/xgip_protocol.h" #ifndef XBONEPASSTHROUGH_ENABLED #define XBONEPASSTHROUGH_ENABLED 0 diff --git a/headers/drivermanager.h b/headers/drivermanager.h new file mode 100644 index 000000000..9ecbccf87 --- /dev/null +++ b/headers/drivermanager.h @@ -0,0 +1,24 @@ +#ifndef _DRIVERMANAGER_H +#define _DRIVERMANAGER_H + +#include "enums.pb.h" +#include "gpdriver.h" + +class GPDriver; + +class DriverManager { +public: + DriverManager(DriverManager const&) = delete; + void operator=(DriverManager const&) = delete; + static DriverManager& getInstance() {// Thread-safe storage ensures cross-thread talk + static DriverManager instance; // Guaranteed to be destroyed. // Instantiated on first use. + return instance; + } + GPDriver * getDriver() { return driver; } + void setup(InputMode); +private: + DriverManager() {} + GPDriver * driver; +}; + +#endif \ No newline at end of file diff --git a/headers/gamepad/descriptors/AstroDescriptors.h b/headers/drivers/astro/AstroDescriptors.h similarity index 100% rename from headers/gamepad/descriptors/AstroDescriptors.h rename to headers/drivers/astro/AstroDescriptors.h diff --git a/headers/drivers/astro/AstroDriver.h b/headers/drivers/astro/AstroDriver.h new file mode 100644 index 000000000..f8b184a13 --- /dev/null +++ b/headers/drivers/astro/AstroDriver.h @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#ifndef _ASTRO_DRIVER_H_ +#define _ASTRO_DRIVER_H_ + +#include "gpdriver.h" +#include "drivers/astro/AstroDescriptors.h" + +class AstroDriver : public GPDriver { +public: + virtual void initialize(); + virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); + virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize); + virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); + virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid); + virtual const uint8_t * get_descriptor_device_cb(); + virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ; + virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index); + virtual const uint8_t * get_descriptor_device_qualifier_cb(); + virtual uint16_t GetJoystickMidValue(); +private: + uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; + AstroReport astroReport; +}; + +#endif // _ASTRO_DRIVER_H_ diff --git a/headers/gamepad/descriptors/EgretDescriptors.h b/headers/drivers/egret/EgretDescriptors.h similarity index 100% rename from headers/gamepad/descriptors/EgretDescriptors.h rename to headers/drivers/egret/EgretDescriptors.h diff --git a/headers/drivers/egret/EgretDriver.h b/headers/drivers/egret/EgretDriver.h new file mode 100644 index 000000000..381e62a0b --- /dev/null +++ b/headers/drivers/egret/EgretDriver.h @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#ifndef _EGRET_DRIVER_H_ +#define _EGRET_DRIVER_H_ + +#include "gpdriver.h" +#include "drivers/egret/EgretDescriptors.h" + +class EgretDriver : public GPDriver { +public: + virtual void initialize(); + virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); + virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize); + virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); + virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid); + virtual const uint8_t * get_descriptor_device_cb(); + virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ; + virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index); + virtual const uint8_t * get_descriptor_device_qualifier_cb(); + virtual uint16_t GetJoystickMidValue(); +private: + uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; + EgretReport egretReport; +}; + +#endif // _EGRET_DRIVER_H_ diff --git a/headers/gamepad/descriptors/HIDDescriptors.h b/headers/drivers/hid/HIDDescriptors.h similarity index 100% rename from headers/gamepad/descriptors/HIDDescriptors.h rename to headers/drivers/hid/HIDDescriptors.h diff --git a/headers/drivers/hid/HIDDriver.h b/headers/drivers/hid/HIDDriver.h new file mode 100644 index 000000000..1f3b0377f --- /dev/null +++ b/headers/drivers/hid/HIDDriver.h @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#ifndef _HID_DRIVER_H_ +#define _HID_DRIVER_H_ + +#include "gpdriver.h" +#include "drivers/hid/HIDDescriptors.h" + +class HIDDriver : public GPDriver { +public: + virtual void initialize(); + virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); + virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize); + virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); + virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid); + virtual const uint8_t * get_descriptor_device_cb(); + virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ; + virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index); + virtual const uint8_t * get_descriptor_device_qualifier_cb(); + virtual uint16_t GetJoystickMidValue(); +private: + uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; + HIDReport hidReport; +}; + +#endif // _HID_DRIVER_H_ diff --git a/headers/gamepad/descriptors/KeyboardDescriptors.h b/headers/drivers/keyboard/KeyboardDescriptors.h similarity index 100% rename from headers/gamepad/descriptors/KeyboardDescriptors.h rename to headers/drivers/keyboard/KeyboardDescriptors.h diff --git a/headers/drivers/keyboard/KeyboardDriver.h b/headers/drivers/keyboard/KeyboardDriver.h new file mode 100644 index 000000000..2ab9e8c79 --- /dev/null +++ b/headers/drivers/keyboard/KeyboardDriver.h @@ -0,0 +1,35 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#ifndef _KEYBOARD_DRIVER_H_ +#define _KEYBOARD_DRIVER_H_ + +#include "gpdriver.h" +#include "drivers/keyboard/KeyboardDescriptors.h" + +class KeyboardDriver : public GPDriver { +public: + virtual void initialize(); + virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); + virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize); + virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); + virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid); + virtual const uint8_t * get_descriptor_device_cb(); + virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ; + virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index); + virtual const uint8_t * get_descriptor_device_qualifier_cb(); + virtual uint16_t GetJoystickMidValue(); +private: + void releaseAllKeys(void); + void pressKey(uint8_t code); + uint8_t getModifier(uint8_t code); + uint8_t getMultimedia(uint8_t code); + uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; + uint16_t last_report_size; + KeyboardReport keyboardReport; +}; + +#endif // _KEYBOARD_DRIVER_H_ diff --git a/headers/gamepad/descriptors/MDMiniDescriptors.h b/headers/drivers/mdmini/MDMiniDescriptors.h similarity index 100% rename from headers/gamepad/descriptors/MDMiniDescriptors.h rename to headers/drivers/mdmini/MDMiniDescriptors.h diff --git a/headers/drivers/mdmini/MDMiniDriver.h b/headers/drivers/mdmini/MDMiniDriver.h new file mode 100644 index 000000000..f86da10e6 --- /dev/null +++ b/headers/drivers/mdmini/MDMiniDriver.h @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#ifndef _MDMINI_DRIVER_H_ +#define _MDMINI_DRIVER_H_ + +#include "gpdriver.h" +#include "drivers/mdmini/MDMiniDescriptors.h" + +class MDMiniDriver : public GPDriver { +public: + virtual void initialize(); + virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); + virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize); + virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); + virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid); + virtual const uint8_t * get_descriptor_device_cb(); + virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ; + virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index); + virtual const uint8_t * get_descriptor_device_qualifier_cb(); + virtual uint16_t GetJoystickMidValue(); +private: + uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; + MDMiniReport mdminiReport; +}; + +#endif // _MDMINI_DRIVER_H_ diff --git a/headers/gamepad/descriptors/NeogeoDescriptors.h b/headers/drivers/neogeo/NeoGeoDescriptors.h similarity index 100% rename from headers/gamepad/descriptors/NeogeoDescriptors.h rename to headers/drivers/neogeo/NeoGeoDescriptors.h diff --git a/headers/drivers/neogeo/NeoGeoDriver.h b/headers/drivers/neogeo/NeoGeoDriver.h new file mode 100644 index 000000000..89bf425f5 --- /dev/null +++ b/headers/drivers/neogeo/NeoGeoDriver.h @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#ifndef _NEOGEO_DRIVER_H_ +#define _NEOGEO_DRIVER_H_ + +#include "gpdriver.h" +#include "drivers/neogeo/NeoGeoDescriptors.h" + +class NeoGeoDriver : public GPDriver { +public: + virtual void initialize(); + virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); + virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize); + virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); + virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid); + virtual const uint8_t * get_descriptor_device_cb(); + virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ; + virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index); + virtual const uint8_t * get_descriptor_device_qualifier_cb(); + virtual uint16_t GetJoystickMidValue(); +private: + uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; + NeogeoReport neogeoReport; +}; + +#endif // _NEOGEO_DRIVER_H_ diff --git a/headers/drivers/net/NetDriver.h b/headers/drivers/net/NetDriver.h new file mode 100644 index 000000000..d928535d0 --- /dev/null +++ b/headers/drivers/net/NetDriver.h @@ -0,0 +1,27 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#ifndef _NET_DRIVER_H_ +#define _NET_DRIVER_H_ + +#include "gpdriver.h" + +class NetDriver : public GPDriver { +public: + virtual void initialize(); + virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); + virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize); + virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); + virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid); + virtual const uint8_t * get_descriptor_device_cb(); + virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ; + virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index); + virtual const uint8_t * get_descriptor_device_qualifier_cb(); + virtual uint16_t GetJoystickMidValue(); +private: +}; + +#endif // _NET_DRIVER_H_ diff --git a/headers/gamepad/descriptors/PCEngineDescriptors.h b/headers/drivers/pcengine/PCEngineDescriptors.h similarity index 100% rename from headers/gamepad/descriptors/PCEngineDescriptors.h rename to headers/drivers/pcengine/PCEngineDescriptors.h diff --git a/headers/drivers/pcengine/PCEngineDriver.h b/headers/drivers/pcengine/PCEngineDriver.h new file mode 100644 index 000000000..cf65f527a --- /dev/null +++ b/headers/drivers/pcengine/PCEngineDriver.h @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#ifndef _PCENGINE_DRIVER_H_ +#define _PCENGINE_DRIVER_H_ + +#include "gpdriver.h" +#include "drivers/pcengine/PCEngineDescriptors.h" + +class PCEngineDriver : public GPDriver { +public: + virtual void initialize(); + virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); + virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize); + virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); + virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid); + virtual const uint8_t * get_descriptor_device_cb(); + virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ; + virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index); + virtual const uint8_t * get_descriptor_device_qualifier_cb(); + virtual uint16_t GetJoystickMidValue(); +private: + uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; + PCEngineReport pcengineReport; +}; + +#endif // _PCENGINE_DRIVER_H_ diff --git a/headers/gamepad/descriptors/PS4Descriptors.h b/headers/drivers/ps4/PS4Descriptors.h similarity index 100% rename from headers/gamepad/descriptors/PS4Descriptors.h rename to headers/drivers/ps4/PS4Descriptors.h diff --git a/headers/drivers/ps4/PS4Driver.h b/headers/drivers/ps4/PS4Driver.h new file mode 100644 index 000000000..d13bbe765 --- /dev/null +++ b/headers/drivers/ps4/PS4Driver.h @@ -0,0 +1,38 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#ifndef _PS4_DRIVER_H_ +#define _PS4_DRIVER_H_ + +#include "gpdriver.h" +#include "drivers/ps4/PS4Descriptors.h" + +class PS4Driver : public GPDriver { +public: + virtual void initialize(); + virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); + virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize); + virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); + virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid); + virtual const uint8_t * get_descriptor_device_cb(); + virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ; + virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index); + virtual const uint8_t * get_descriptor_device_qualifier_cb(); + virtual uint16_t GetJoystickMidValue(); +private: + // Lots of things here + void save_nonce(uint8_t nonce_id, uint8_t nonce_page, uint8_t * buffer, uint16_t buflen); + uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; + uint8_t last_report_counter; + uint16_t last_axis_counter; + uint8_t cur_nonce_id; + PS4Report ps4Report; + TouchpadData touchpadData; + uint32_t keep_alive_timer; + uint8_t send_nonce_part; +}; + +#endif // _PS4_DRIVER_H_ diff --git a/headers/gamepad/descriptors/PSClassicDescriptors.h b/headers/drivers/psclassic/PSClassicDescriptors.h similarity index 100% rename from headers/gamepad/descriptors/PSClassicDescriptors.h rename to headers/drivers/psclassic/PSClassicDescriptors.h diff --git a/headers/drivers/psclassic/PSClassicDriver.h b/headers/drivers/psclassic/PSClassicDriver.h new file mode 100644 index 000000000..1b8c48f2e --- /dev/null +++ b/headers/drivers/psclassic/PSClassicDriver.h @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#ifndef _PSCLASSIC_DRIVER_H_ +#define _PSCLASSIC_DRIVER_H_ + +#include "gpdriver.h" +#include "drivers/psclassic/PSClassicDescriptors.h" + +class PSClassicDriver : public GPDriver { +public: + virtual void initialize(); + virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); + virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize); + virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); + virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid); + virtual const uint8_t * get_descriptor_device_cb(); + virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ; + virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index); + virtual const uint8_t * get_descriptor_device_qualifier_cb(); + virtual uint16_t GetJoystickMidValue(); +private: + uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; + PSClassicReport psClassicReport; +}; + +#endif // _PSCLASSIC_DRIVER_H_ diff --git a/headers/drivers/shared/driverhelper.h b/headers/drivers/shared/driverhelper.h new file mode 100644 index 000000000..543aec383 --- /dev/null +++ b/headers/drivers/shared/driverhelper.h @@ -0,0 +1,26 @@ +#ifndef _DRIVER_HELPER_H_ +#define _DRIVER_HELPER_H_ + +static uint16_t * getStringDescriptor(const char * value, uint8_t index) +{ + static uint16_t descriptorStringBuffer[32]; // Max 64 bytes, 31 unicode characters + size_t charCount; + if ( index == 0 ) // language always has a character count of 1 + charCount = 1; + else { + charCount = strlen(value); + if (charCount > 31) + charCount = 31; + } + // Fill descriptionStringBuffer[1] .. [32] + for (uint8_t i = 0; i < charCount; i++) + descriptorStringBuffer[i + 1] = value[i]; + + // first byte (descriptionStringBuffer[0]) is length (including header), second byte is string type + descriptorStringBuffer[0] = (0x03 << 8) | (2 * (uint8_t)charCount + 2); + + // Cast temp buffer to final result + return descriptorStringBuffer; +} + +#endif // _DRIVER_HELPER_H_ diff --git a/lib/TinyUSB_Gamepad/src/ps4_driver.h b/headers/drivers/shared/ps4data.h similarity index 67% rename from lib/TinyUSB_Gamepad/src/ps4_driver.h rename to headers/drivers/shared/ps4data.h index a60843d87..5f9bfc824 100644 --- a/lib/TinyUSB_Gamepad/src/ps4_driver.h +++ b/headers/drivers/shared/ps4data.h @@ -1,18 +1,13 @@ -/* - * SPDX-License-Identifier: MIT - * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) - */ +#ifndef _PS4_DATA_H_ +#define _PS4_DATA_H_ -#pragma once - -#include "tusb.h" -#include "device/usbd_pvt.h" - -#include "gamepad/descriptors/PS4Descriptors.h" - -#include "enums.pb.h" - -#define PS4_OUT_SIZE 64 +typedef enum { + no_nonce = 0, + receiving_nonce = 1, + nonce_ready = 2, + signed_nonce_ready = 3, + sending_nonce = 4 +} PS4State; typedef enum { @@ -23,23 +18,6 @@ typedef enum PS4_RESET_AUTH = 0xF3 // Unknown (PS4 Report 0xF3) } PS4AuthReport; -// USB endpoint state vars -extern const usbd_class_driver_t ps4_driver; - -ssize_t get_ps4_report(uint8_t report_id, uint8_t * buf, uint16_t reqlen); -void set_ps4_report(uint8_t report_id, uint8_t const * buf, uint16_t reqlen); -void receive_ps4_report(void); -bool send_ps4_report(void *report, uint8_t report_size); -void save_nonce(uint8_t nonce_id, uint8_t nonce_page, uint8_t * data, uint16_t size); - -typedef enum { - no_nonce = 0, - receiving_nonce = 1, - nonce_ready = 2, - signed_nonce_ready = 3, - sending_nonce = 4 -} PS4State; - // Storage manager for board, LED options, and thread-safe settings class PS4Data { public: @@ -78,3 +56,5 @@ class PS4Data { ps4ControllerType = PS4ControllerType::PS4_CONTROLLER; } }; + +#endif // _PS4_DATA_H_ diff --git a/lib/TinyUSB_Gamepad/src/xbone_driver.h b/headers/drivers/shared/xbonedata.h similarity index 68% rename from lib/TinyUSB_Gamepad/src/xbone_driver.h rename to headers/drivers/shared/xbonedata.h index 3050a4357..da2f1fcaf 100644 --- a/lib/TinyUSB_Gamepad/src/xbone_driver.h +++ b/headers/drivers/shared/xbonedata.h @@ -1,33 +1,5 @@ -/* - * SPDX-License-Identifier: MIT - * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) - */ - -#pragma once - -#include -#include "tusb.h" -#include "device/usbd_pvt.h" - -#include "gamepad/descriptors/XBOneDescriptors.h" - -#include "xgip_protocol.h" - -#define XBONE_OUT_SIZE 64 - -// USB endpoint state vars -extern uint8_t xbone_out_buffer[XBONE_OUT_SIZE]; -extern const usbd_class_driver_t xbone_driver; - -//extern void send_xbhost_report(void *report, uint16_t report_size); - -extern bool send_xbone_report(void *report, uint16_t report_size); -extern bool xbone_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, - tusb_control_request_t const *request); - -extern uint32_t timer_wait_for_auth; - -extern void xbone_driver_update(); +#ifndef _XBONE_DATA_H_ +#define _XBONE_DATA_H_ typedef enum { auth_idle_state = 0, @@ -112,3 +84,5 @@ class XboxOneData { uint16_t authLen; uint8_t authType; }; + +#endif // _XBONE_DATA_H_ diff --git a/lib/TinyUSB_Gamepad/src/xgip_protocol.h b/headers/drivers/shared/xgip_protocol.h similarity index 86% rename from lib/TinyUSB_Gamepad/src/xgip_protocol.h rename to headers/drivers/shared/xgip_protocol.h index 768d3f069..b4f9bfc25 100644 --- a/lib/TinyUSB_Gamepad/src/xgip_protocol.h +++ b/headers/drivers/shared/xgip_protocol.h @@ -51,11 +51,31 @@ #include -#include "gamepad/descriptors/XBOneDescriptors.h" - // All max chunks are this size #define GIP_MAX_CHUNK_SIZE 0x3A +typedef struct +{ + uint8_t command; + uint8_t client : 4; + uint8_t needsAck : 1; + uint8_t internal : 1; + uint8_t chunkStart : 1; + uint8_t chunked : 1; + uint8_t sequence; + uint8_t length; +} __attribute__((packed)) GipHeader_t; + +#define GIP_HEADER(packet, cmd, isInternal, seq) \ + packet->Header.command = cmd; \ + packet->Header.internal = isInternal; \ + packet->Header.sequence = seq; \ + packet->Header.client = 0; \ + packet->Header.needsAck = 0; \ + packet->Header.chunkStart = 0; \ + packet->Header.chunked = 0; \ + packet->Header.length = sizeof(*packet) - sizeof(GipHeader_t); + class XGIPProtocol { public: XGIPProtocol(); diff --git a/lib/TinyUSB_Gamepad/src/xinput_host.h b/headers/drivers/shared/xinput_host.h similarity index 100% rename from lib/TinyUSB_Gamepad/src/xinput_host.h rename to headers/drivers/shared/xinput_host.h diff --git a/headers/gamepad/descriptors/SwitchDescriptors.h b/headers/drivers/switch/SwitchDescriptors.h similarity index 100% rename from headers/gamepad/descriptors/SwitchDescriptors.h rename to headers/drivers/switch/SwitchDescriptors.h diff --git a/headers/drivers/switch/SwitchDriver.h b/headers/drivers/switch/SwitchDriver.h new file mode 100644 index 000000000..080e2409b --- /dev/null +++ b/headers/drivers/switch/SwitchDriver.h @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#ifndef _SWITCH_DRIVER_H_ +#define _SWITCH_DRIVER_H_ + +#include "gpdriver.h" +#include "drivers/switch/SwitchDescriptors.h" + +class SwitchDriver : public GPDriver { +public: + virtual void initialize(); + virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); + virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize); + virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); + virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid); + virtual const uint8_t * get_descriptor_device_cb(); + virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ; + virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index); + virtual const uint8_t * get_descriptor_device_qualifier_cb(); + virtual uint16_t GetJoystickMidValue(); +private: + uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; + SwitchReport switchReport; +}; + +#endif // _SWITCH_DRIVER_H_ diff --git a/headers/gamepad/descriptors/XBOneDescriptors.h b/headers/drivers/xbone/XBOneDescriptors.h similarity index 88% rename from headers/gamepad/descriptors/XBOneDescriptors.h rename to headers/drivers/xbone/XBOneDescriptors.h index d82e9da4a..dae34a32f 100644 --- a/headers/gamepad/descriptors/XBOneDescriptors.h +++ b/headers/drivers/xbone/XBOneDescriptors.h @@ -9,6 +9,8 @@ #include #include +#include "drivers/shared/xgip_protocol.h" + #define XBONE_ENDPOINT_SIZE 64 // 0x80 = std. device @@ -64,28 +66,6 @@ typedef enum GIP_HID_REPORT = 0x21, // Xbox One HID Report } XboxOneReport; -typedef struct -{ - uint8_t command; - uint8_t client : 4; - uint8_t needsAck : 1; - uint8_t internal : 1; - uint8_t chunkStart : 1; - uint8_t chunked : 1; - uint8_t sequence; - uint8_t length; -} __attribute__((packed)) GipHeader_t; - -#define GIP_HEADER(packet, cmd, isInternal, seq) \ - packet->Header.command = cmd; \ - packet->Header.internal = isInternal; \ - packet->Header.sequence = seq; \ - packet->Header.client = 0; \ - packet->Header.needsAck = 0; \ - packet->Header.chunkStart = 0; \ - packet->Header.chunked = 0; \ - packet->Header.length = sizeof(*packet) - sizeof(GipHeader_t); - typedef struct { GipHeader_t Header; diff --git a/headers/drivers/xbone/XBOneDriver.h b/headers/drivers/xbone/XBOneDriver.h new file mode 100644 index 000000000..174f5ad74 --- /dev/null +++ b/headers/drivers/xbone/XBOneDriver.h @@ -0,0 +1,39 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#ifndef _XBONE_DRIVER_H_ +#define _XBONE_DRIVER_H_ + +#include "gpdriver.h" +#include "drivers/xbone/XBOneDescriptors.h" +#include "drivers/shared/xgip_protocol.h" + +class XBOneDriver : public GPDriver { +public: + virtual void initialize(); + virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); + virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize); + virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); + virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid); + virtual const uint8_t * get_descriptor_device_cb(); + virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ; + virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index); + virtual const uint8_t * get_descriptor_device_qualifier_cb(); + virtual uint16_t GetJoystickMidValue(); +private: + virtual void update(); + bool send_xbone_usb(uint8_t const *buffer, uint16_t bufsize); + void set_ack_wait(); + uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; + uint8_t last_report_counter; + XboxOneGamepad_Data_t xboneReport; + uint32_t keep_alive_timer; + uint8_t keep_alive_sequence; + uint8_t virtual_keycode_sequence; + bool xb1_guide_pressed; +}; + +#endif // _XBONE_DRIVER_H_ diff --git a/headers/gamepad/descriptors/XboxOriginalDescriptors.h b/headers/drivers/xboxog/XboxOriginalDescriptors.h similarity index 94% rename from headers/gamepad/descriptors/XboxOriginalDescriptors.h rename to headers/drivers/xboxog/XboxOriginalDescriptors.h index cf02232db..6709f3a29 100644 --- a/headers/gamepad/descriptors/XboxOriginalDescriptors.h +++ b/headers/drivers/xboxog/XboxOriginalDescriptors.h @@ -1,7 +1,7 @@ #pragma once #include -#include "xid_driver.h" +#include "drivers/xboxog/xid/xid_driver.h" #define XboxOriginalReport USB_XboxGamepad_InReport_t diff --git a/headers/drivers/xboxog/XboxOriginalDriver.h b/headers/drivers/xboxog/XboxOriginalDriver.h new file mode 100644 index 000000000..92488c8bc --- /dev/null +++ b/headers/drivers/xboxog/XboxOriginalDriver.h @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#ifndef _XBOX_ORIGINAL_DRIVER_H_ +#define _XBOX_ORIGINAL_DRIVER_H_ + +#include "gpdriver.h" +#include "drivers/xboxog/XboxOriginalDescriptors.h" + +class XboxOriginalDriver : public GPDriver { +public: + virtual void initialize(); + virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); + virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize); + virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); + virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid); + virtual const uint8_t * get_descriptor_device_cb(); + virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ; + virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index); + virtual const uint8_t * get_descriptor_device_qualifier_cb(); + virtual uint16_t GetJoystickMidValue(); +private: + uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; + XboxOriginalReport xboxOriginalReport; +}; + +#endif // _XBOX_ORIGINAL_DRIVER_H_ diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/LICENSE b/headers/drivers/xboxog/xid/LICENSE similarity index 100% rename from lib/TinyUSB_Gamepad/src/xid_driver/LICENSE rename to headers/drivers/xboxog/xid/LICENSE diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/xid.h b/headers/drivers/xboxog/xid/xid.h similarity index 88% rename from lib/TinyUSB_Gamepad/src/xid_driver/xid.h rename to headers/drivers/xboxog/xid/xid.h index 94fe3d2f2..939ec8a99 100644 --- a/lib/TinyUSB_Gamepad/src/xid_driver/xid.h +++ b/headers/drivers/xboxog/xid/xid.h @@ -9,9 +9,9 @@ extern "C" #include #include #include -#include "xid_gamepad.h" -#include "xid_remote.h" -#include "xid_steelbattalion.h" +#include "drivers/xboxog/xid/xid_gamepad.h" +#include "drivers/xboxog/xid/xid_remote.h" +#include "drivers/xboxog/xid/xid_steelbattalion.h" #define XID_DUKE 1 #define XID_STEELBATTALION 0 diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/xid_driver.h b/headers/drivers/xboxog/xid/xid_driver.h similarity index 98% rename from lib/TinyUSB_Gamepad/src/xid_driver/xid_driver.h rename to headers/drivers/xboxog/xid/xid_driver.h index 7d0113218..37b3f055c 100644 --- a/lib/TinyUSB_Gamepad/src/xid_driver/xid_driver.h +++ b/headers/drivers/xboxog/xid/xid_driver.h @@ -9,7 +9,7 @@ extern "C" #include #include #include -#include "xid.h" +#include "drivers/xboxog/xid/xid.h" static const tusb_desc_device_t XID_DESC_DEVICE = { diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/xid_gamepad.h b/headers/drivers/xboxog/xid/xid_gamepad.h similarity index 100% rename from lib/TinyUSB_Gamepad/src/xid_driver/xid_gamepad.h rename to headers/drivers/xboxog/xid/xid_gamepad.h diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/xid_remote.h b/headers/drivers/xboxog/xid/xid_remote.h similarity index 98% rename from lib/TinyUSB_Gamepad/src/xid_driver/xid_remote.h rename to headers/drivers/xboxog/xid/xid_remote.h index 591695df5..ee0a401e9 100644 --- a/lib/TinyUSB_Gamepad/src/xid_driver/xid_remote.h +++ b/headers/drivers/xboxog/xid/xid_remote.h @@ -7,7 +7,7 @@ extern "C" #endif #include -#include "tusb.h" +#include #define XID_XREMOTE_ROM_CLASS 0x59 diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/xid_steelbattalion.h b/headers/drivers/xboxog/xid/xid_steelbattalion.h similarity index 100% rename from lib/TinyUSB_Gamepad/src/xid_driver/xid_steelbattalion.h rename to headers/drivers/xboxog/xid/xid_steelbattalion.h diff --git a/headers/gamepad/descriptors/XInputDescriptors.h b/headers/drivers/xinput/XInputDescriptors.h similarity index 100% rename from headers/gamepad/descriptors/XInputDescriptors.h rename to headers/drivers/xinput/XInputDescriptors.h diff --git a/headers/drivers/xinput/XInputDriver.h b/headers/drivers/xinput/XInputDriver.h new file mode 100644 index 000000000..917bc44ae --- /dev/null +++ b/headers/drivers/xinput/XInputDriver.h @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#ifndef _XINPUT_DRIVER_H_ +#define _XINPUT_DRIVER_H_ + +#include "gpdriver.h" +#include "drivers/xinput/XInputDescriptors.h" + +class XInputDriver : public GPDriver { +public: + virtual void initialize(); + virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); + virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize); + virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); + virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid); + virtual const uint8_t * get_descriptor_device_cb(); + virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ; + virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index); + virtual const uint8_t * get_descriptor_device_qualifier_cb(); + virtual uint16_t GetJoystickMidValue(); +private: + uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; + XInputReport xinputReport; +}; + +#endif diff --git a/headers/gamepad.h b/headers/gamepad.h index 8394c52d1..d928e7f3c 100644 --- a/headers/gamepad.h +++ b/headers/gamepad.h @@ -8,19 +8,6 @@ #include "enums.pb.h" #include "gamepad/GamepadDebouncer.h" #include "gamepad/GamepadState.h" -#include "gamepad/descriptors/HIDDescriptors.h" -#include "gamepad/descriptors/SwitchDescriptors.h" -#include "gamepad/descriptors/XInputDescriptors.h" -#include "gamepad/descriptors/KeyboardDescriptors.h" -#include "gamepad/descriptors/PS4Descriptors.h" -#include "gamepad/descriptors/NeogeoDescriptors.h" -#include "gamepad/descriptors/MDMiniDescriptors.h" -#include "gamepad/descriptors/PCEngineDescriptors.h" -#include "gamepad/descriptors/EgretDescriptors.h" -#include "gamepad/descriptors/AstroDescriptors.h" -#include "gamepad/descriptors/PSClassicDescriptors.h" -#include "gamepad/descriptors/XboxOriginalDescriptors.h" -#include "gamepad/descriptors/XBOneDescriptors.h" #include "pico/stdlib.h" @@ -73,27 +60,6 @@ class Gamepad { */ bool hasRightAnalogStick {false}; - void sendReportSuccess(); - void *getReport(); - uint16_t getReportSize(); - HIDReport *getHIDReport(); - SwitchReport *getSwitchReport(); - XInputReport *getXInputReport(); - XboxOneGamepad_Data_t *getXBOneReport(); - KeyboardReport *getKeyboardReport(); - PS4Report *getPS4Report(); - NeogeoReport *getNeogeoReport(); - MDMiniReport *getMDMiniReport(); - PCEngineReport *getPCEngineReport(); - EgretReport *getEgretReport(); - AstroReport *getAstroReport(); - PSClassicReport *getPSClassicReport(); - XboxOriginalReport *getXboxOriginalReport(); - - uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; - uint8_t last_report_counter = 0; - uint16_t last_axis_counter = 0; - /** * @brief Check for a button press. Used by `pressed[Button]` helper methods. */ @@ -104,7 +70,9 @@ class Gamepad { /** * @brief Check for a dpad press. Used by `pressed[Dpad]` helper methods. */ - inline bool __attribute__((always_inline)) pressedDpad(const uint8_t mask) { return (state.dpad & mask) == mask; } + inline bool __attribute__((always_inline)) pressedDpad(const uint8_t mask) { + return (state.dpad & mask) == mask; + } /** * @brief Check for an aux button press. Same idea as `pressedButton`. @@ -181,21 +149,21 @@ class Gamepad { bool userRequestedReinit = false; + // These are special to SOCD inline static const SOCDMode resolveSOCDMode(const GamepadOptions& options) { - return (options.socdMode == SOCD_MODE_BYPASS && - (options.inputMode == INPUT_MODE_HID || - options.inputMode == INPUT_MODE_SWITCH || - options.inputMode == INPUT_MODE_NEOGEO || - options.inputMode == INPUT_MODE_PS4)) ? - SOCD_MODE_NEUTRAL : options.socdMode; + return (options.socdMode == SOCD_MODE_BYPASS && + (options.inputMode == INPUT_MODE_HID || + options.inputMode == INPUT_MODE_SWITCH || + options.inputMode == INPUT_MODE_NEOGEO || + options.inputMode == INPUT_MODE_PS4)) ? + SOCD_MODE_NEUTRAL : options.socdMode; }; private: - void releaseAllKeys(void); - void pressKey(uint8_t code); + uint8_t getModifier(uint8_t code); uint8_t getMultimedia(uint8_t code); - void processHotkeyIfNewAction(GamepadHotkey action); + void processHotkeyAction(GamepadHotkey action); GamepadOptions& options; const HotkeyOptions& hotkeyOptions; diff --git a/headers/gamepad/GamepadConfig.h b/headers/gamepad/GamepadConfig.h index c07998ab5..2d09ac61c 100644 --- a/headers/gamepad/GamepadConfig.h +++ b/headers/gamepad/GamepadConfig.h @@ -5,26 +5,6 @@ #pragma once -#ifndef DEFAULT_SOCD_MODE -#define DEFAULT_SOCD_MODE SOCD_MODE_NEUTRAL -#endif - -#ifndef DEFAULT_DPAD_MODE -#define DEFAULT_DPAD_MODE DPAD_MODE_DIGITAL -#endif - -#ifndef DEFAULT_INPUT_MODE -#define DEFAULT_INPUT_MODE INPUT_MODE_XINPUT -#endif - -#ifndef DEFAULT_PS4CONTROLLER_TYPE -#define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER -#endif - -#ifndef DEFAULT_PS4_REPORTHACK -#define DEFAULT_PS4_REPORTHACK false -#endif - /* hotkeys */ #ifndef HOTKEY_01_AUX_MASK #define HOTKEY_01_AUX_MASK 0 diff --git a/headers/gamepad/GamepadDescriptors.h b/headers/gamepad/GamepadDescriptors.h deleted file mode 100644 index b4e86384a..000000000 --- a/headers/gamepad/GamepadDescriptors.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com) - */ - -#pragma once - -#include -#include "GamepadEnums.h" -#include "descriptors/HIDDescriptors.h" -#include "descriptors/SwitchDescriptors.h" -#include "descriptors/XInputDescriptors.h" -#include "descriptors/KeyboardDescriptors.h" -#include "descriptors/PS4Descriptors.h" -#include "descriptors/NeogeoDescriptors.h" -#include "descriptors/MDMiniDescriptors.h" -#include "descriptors/PCEngineDescriptors.h" -#include "descriptors/EgretDescriptors.h" -#include "descriptors/AstroDescriptors.h" -#include "descriptors/PSClassicDescriptors.h" -#include "descriptors/XboxOriginalDescriptors.h" -#include "descriptors/XBOneDescriptors.h" - -#include "enums.pb.h" - -// Default value used for networking, override if necessary -static uint8_t macAddress[6] = { 0x02, 0x02, 0x84, 0x6A, 0x96, 0x00 }; - -static const uint8_t *getHIDDescriptor(uint16_t *size, InputMode mode); -static const uint8_t *getHIDReport(uint16_t *size, InputMode mode); - -// Convert ASCII string into UTF-16 -static const uint16_t *convertStringDescriptor(uint16_t *payloadSize, const char *str, int charCount) -{ - static uint16_t payload[32]; - - // Cap at max char - if (charCount > 31) - charCount = 31; - - for (uint8_t i = 0; i < charCount; i++) - payload[1 + i] = str[i]; - - // first byte is length (including header), second byte is string type - *payloadSize = (2 * charCount + 2); - payload[0] = (0x03 << 8) | *payloadSize; - return payload; -} - -static const uint16_t *getStringDescriptor(uint16_t *size, InputMode mode, uint8_t index) -{ - uint8_t charCount = 0; - char *str = 0; - - if (index == 5) - { - // Convert MAC address into UTF-16 - for (int i = 0; i < 6; i++) - { - str[1 + charCount++] = "0123456789ABCDEF"[(macAddress[i] >> 4) & 0xf]; - str[1 + charCount++] = "0123456789ABCDEF"[(macAddress[i] >> 0) & 0xf]; - } - } - else - { - switch (mode) - { - case INPUT_MODE_XINPUT: - str = (char *)xinput_string_descriptors[index]; - break; - - case INPUT_MODE_XBONE: - str = (char*)xbone_get_string_descriptor(index); - break; - - case INPUT_MODE_SWITCH: - str = (char *)switch_string_descriptors[index]; - break; - - case INPUT_MODE_KEYBOARD: - str = (char *)keyboard_string_descriptors[index]; - break; - - case INPUT_MODE_PS4: - str = (char *)ps4_string_descriptors[index]; - break; - - case INPUT_MODE_NEOGEO: - str = (char *)neogeo_string_descriptors[index]; - break; - - case INPUT_MODE_MDMINI: - str = (char *)mdmini_string_descriptors[index]; - break; - - case INPUT_MODE_PCEMINI: - str = (char *)pcengine_string_descriptors[index]; - break; - - case INPUT_MODE_EGRET: - str = (char *)egret_string_descriptors[index]; - break; - - case INPUT_MODE_ASTRO: - str = (char *)astro_string_descriptors[index]; - break; - - case INPUT_MODE_PSCLASSIC: - str = (char *)psclassic_string_descriptors[index]; - break; - - case INPUT_MODE_XBOXORIGINAL: - str = (char *)xboxoriginal_string_descriptors[index]; - break; - - default: - str = (char *)hid_string_descriptors[index]; - break; - } - if ( index == 0 ) // language always has a character count of 1 - charCount = 1; - else - charCount = strlen(str); - } - - return convertStringDescriptor(size, str, charCount); -} \ No newline at end of file diff --git a/headers/gamepad/GamepadOptions.h b/headers/gamepad/GamepadOptions.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/headers/gamepad/GamepadState.h b/headers/gamepad/GamepadState.h index 66be6e32c..339ad17ae 100644 --- a/headers/gamepad/GamepadState.h +++ b/headers/gamepad/GamepadState.h @@ -11,17 +11,6 @@ using namespace std; #include "GamepadEnums.h" #include "enums.pb.h" -#include "gamepad/descriptors/HIDDescriptors.h" -#include "gamepad/descriptors/SwitchDescriptors.h" -#include "gamepad/descriptors/XInputDescriptors.h" -#include "gamepad/descriptors/PS4Descriptors.h" -#include "gamepad/descriptors/NeogeoDescriptors.h" -#include "gamepad/descriptors/MDMiniDescriptors.h" -#include "gamepad/descriptors/PCEngineDescriptors.h" -#include "gamepad/descriptors/EgretDescriptors.h" -#include "gamepad/descriptors/AstroDescriptors.h" -#include "gamepad/descriptors/PSClassicDescriptors.h" -#include "gamepad/descriptors/XboxOriginalDescriptors.h" #define GAMEPAD_BUTTON_COUNT 14 @@ -136,120 +125,15 @@ struct GamepadState uint8_t rt {0}; }; -// Move the values for the 8-bit modes to the MSB of a 16-bit for conversion later -// Resolves issues where 0x80 is center and 0x7F is not -inline uint16_t GetJoystickMidValue(uint8_t mode) { - switch (mode) { - case INPUT_MODE_XINPUT: - return GAMEPAD_JOYSTICK_MID; - - case INPUT_MODE_XBONE: - return GAMEPAD_JOYSTICK_MID; - - case INPUT_MODE_SWITCH: - return SWITCH_JOYSTICK_MID << 8; - - case INPUT_MODE_HID: - return HID_JOYSTICK_MID << 8; - - case INPUT_MODE_KEYBOARD: - return HID_JOYSTICK_MID << 8; - - case INPUT_MODE_PS4: - return PS4_JOYSTICK_MID << 8; - - case INPUT_MODE_NEOGEO: - return NEOGEO_JOYSTICK_MID << 8; - - case INPUT_MODE_MDMINI: - return GAMEPAD_JOYSTICK_MID; - - case INPUT_MODE_PCEMINI: - return GAMEPAD_JOYSTICK_MID; - - case INPUT_MODE_EGRET: - return GAMEPAD_JOYSTICK_MID; - - case INPUT_MODE_ASTRO: - return GAMEPAD_JOYSTICK_MID; - - case INPUT_MODE_PSCLASSIC: - return GAMEPAD_JOYSTICK_MID; - - case INPUT_MODE_XBOXORIGINAL: - return GAMEPAD_JOYSTICK_MID; - - default: - return GAMEPAD_JOYSTICK_MID; - } -} - // Convert the horizontal GamepadState dpad axis value into an analog value -inline uint16_t dpadToAnalogX(uint8_t dpad, uint8_t mode) -{ - switch (dpad & (GAMEPAD_MASK_LEFT | GAMEPAD_MASK_RIGHT)) - { - case GAMEPAD_MASK_LEFT: - return GAMEPAD_JOYSTICK_MIN; - - case GAMEPAD_MASK_RIGHT: - return GAMEPAD_JOYSTICK_MAX; - - default: - return GetJoystickMidValue(mode); - } -} +uint16_t dpadToAnalogX(uint8_t dpad); // Convert the vertical GamepadState dpad axis value into an analog value -inline uint16_t dpadToAnalogY(uint8_t dpad, uint8_t mode) -{ - switch (dpad & (GAMEPAD_MASK_UP | GAMEPAD_MASK_DOWN)) - { - case GAMEPAD_MASK_UP: - return GAMEPAD_JOYSTICK_MIN; +uint16_t dpadToAnalogY(uint8_t dpad); - case GAMEPAD_MASK_DOWN: - return GAMEPAD_JOYSTICK_MAX; +uint8_t getMaskFromDirection(DpadDirection direction); - default: - return GetJoystickMidValue(mode); - } -} - -inline uint8_t getMaskFromDirection(DpadDirection direction) -{ - return dpadMasks[direction-1]; -} - -inline uint8_t updateDpad(uint8_t dpad, DpadDirection direction) -{ - static bool inList[] = {false, false, false, false, false}; // correspond to DpadDirection: none, up, down, left, right - static list dpadList; - - if(dpad & getMaskFromDirection(direction)) - { - if(!inList[direction]) - { - dpadList.push_back(direction); - inList[direction] = true; - } - } - else - { - if(inList[direction]) - { - dpadList.remove(direction); - inList[direction] = false; - } - } - - if(dpadList.empty()) { - return 0; - } - else { - return getMaskFromDirection(dpadList.back()); - } -} +uint8_t updateDpad(uint8_t dpad, DpadDirection direction); /** * @brief Filter diagonals out of the dpad, making the device work as a 4-way lever. @@ -259,13 +143,7 @@ inline uint8_t updateDpad(uint8_t dpad, DpadDirection direction) * @param dpad The GameState.dpad value. * @return uint8_t The new dpad value. */ -inline uint8_t filterToFourWayMode(uint8_t dpad) -{ - updateDpad(dpad, DIRECTION_UP); - updateDpad(dpad, DIRECTION_DOWN); - updateDpad(dpad, DIRECTION_LEFT); - return updateDpad(dpad, DIRECTION_RIGHT); -} +uint8_t filterToFourWayMode(uint8_t dpad); /** * @brief Run SOCD cleaning against a D-pad value. @@ -274,72 +152,4 @@ inline uint8_t filterToFourWayMode(uint8_t dpad) * @param dpad The GamepadState.dpad value. * @return uint8_t The clean D-pad value. */ -inline uint8_t runSOCDCleaner(SOCDMode mode, uint8_t dpad) -{ - if (mode == SOCD_MODE_BYPASS) { - return dpad; - } - - static DpadDirection lastUD = DIRECTION_NONE; - static DpadDirection lastLR = DIRECTION_NONE; - uint8_t newDpad = 0; - - switch (dpad & (GAMEPAD_MASK_UP | GAMEPAD_MASK_DOWN)) - { - case (GAMEPAD_MASK_UP | GAMEPAD_MASK_DOWN): - if (mode == SOCD_MODE_UP_PRIORITY) - { - newDpad |= GAMEPAD_MASK_UP; - lastUD = DIRECTION_UP; - } - else if (mode == SOCD_MODE_SECOND_INPUT_PRIORITY && lastUD != DIRECTION_NONE) - newDpad |= (lastUD == DIRECTION_UP) ? GAMEPAD_MASK_DOWN : GAMEPAD_MASK_UP; - else if (mode == SOCD_MODE_FIRST_INPUT_PRIORITY && lastUD != DIRECTION_NONE) - newDpad |= (lastUD == DIRECTION_UP) ? GAMEPAD_MASK_UP : GAMEPAD_MASK_DOWN; - else - lastUD = DIRECTION_NONE; - break; - - case GAMEPAD_MASK_UP: - newDpad |= GAMEPAD_MASK_UP; - lastUD = DIRECTION_UP; - break; - - case GAMEPAD_MASK_DOWN: - newDpad |= GAMEPAD_MASK_DOWN; - lastUD = DIRECTION_DOWN; - break; - - default: - lastUD = DIRECTION_NONE; - break; - } - - switch (dpad & (GAMEPAD_MASK_LEFT | GAMEPAD_MASK_RIGHT)) - { - case (GAMEPAD_MASK_LEFT | GAMEPAD_MASK_RIGHT): - if (mode == SOCD_MODE_SECOND_INPUT_PRIORITY && lastLR != DIRECTION_NONE) - newDpad |= (lastLR == DIRECTION_LEFT) ? GAMEPAD_MASK_RIGHT : GAMEPAD_MASK_LEFT; - else if (mode == SOCD_MODE_FIRST_INPUT_PRIORITY && lastLR != DIRECTION_NONE) - newDpad |= (lastLR == DIRECTION_LEFT) ? GAMEPAD_MASK_LEFT : GAMEPAD_MASK_RIGHT; - else - lastLR = DIRECTION_NONE; - break; - - case GAMEPAD_MASK_LEFT: - newDpad |= GAMEPAD_MASK_LEFT; - lastLR = DIRECTION_LEFT; - break; - - case GAMEPAD_MASK_RIGHT: - newDpad |= GAMEPAD_MASK_RIGHT; - lastLR = DIRECTION_RIGHT; - break; - - default: - lastLR = DIRECTION_NONE; - break; - } - - return newDpad; -} +uint8_t runSOCDCleaner(SOCDMode mode, uint8_t dpad); \ No newline at end of file diff --git a/headers/gamepad/descriptors/MouseDescriptors.h b/headers/gamepad/descriptors/MouseDescriptors.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/headers/gp2040.h b/headers/gp2040.h index 5d1bbec95..f13766834 100644 --- a/headers/gp2040.h +++ b/headers/gp2040.h @@ -12,6 +12,7 @@ #include "gamepad.h" #include "addonmanager.h" #include "peripheralmanager.h" +#include "gpdriver.h" #include "pico/types.h" @@ -58,6 +59,7 @@ class GP2040 { SET_INPUT_MODE_XBOXORIGINAL }; BootAction getBootAction(); + void getReinitGamepad(Gamepad * gamepad); // GPIO manipulation for setup and profile reinit void initializeStandardGpio(); diff --git a/headers/gpconfig.h b/headers/gpconfig.h index a7aab0e94..ce24b1939 100644 --- a/headers/gpconfig.h +++ b/headers/gpconfig.h @@ -1,3 +1,8 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + #ifndef _GPCONFIG_H_ #define _GPCONFIG_H_ diff --git a/headers/gpdriver.h b/headers/gpdriver.h new file mode 100644 index 000000000..73bc8af9a --- /dev/null +++ b/headers/gpdriver.h @@ -0,0 +1,42 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#ifndef _GPDRIVER_H_ +#define _GPDRIVER_H_ + +#include "enums.pb.h" + +#include "gamepad.h" + +#include "tusb_config.h" +#include "tusb.h" +#include "class/hid/hid.h" +#include "device/usbd_pvt.h" + +// Forward declare gamepad +class Gamepad; + +// +// GP2040-CE USB Device Class Driver +// +class GPDriver { +public: + virtual void initialize() = 0; + virtual void process(Gamepad * gamepad, uint8_t * outBuffer) = 0; + virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) = 0; + virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) = 0; + virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) = 0; + virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid) = 0; + virtual const uint8_t * get_descriptor_device_cb() = 0; + virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) = 0; + virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index) = 0; + virtual const uint8_t * get_descriptor_device_qualifier_cb() = 0; + virtual uint16_t GetJoystickMidValue() = 0; + const usbd_class_driver_t * get_class_driver() { return &class_driver; } +protected: + usbd_class_driver_t class_driver; +}; + +#endif diff --git a/headers/helper.h b/headers/helper.h index 615be9bda..313948c46 100644 --- a/headers/helper.h +++ b/headers/helper.h @@ -8,7 +8,6 @@ #include #include "AnimationStation.hpp" #include "PlayerLEDs.h" -#include "xinput_driver.h" // GP2040-CE Board Config (64 character limit) #ifndef GP2040_BOARDCONFIG diff --git a/headers/usbdriver.h b/headers/usbdriver.h new file mode 100644 index 000000000..b80de9443 --- /dev/null +++ b/headers/usbdriver.h @@ -0,0 +1,7 @@ +#ifndef _USB_DRIVER_H_ +#define _USB_DRIVER_H_ + +bool get_usb_mounted(void); +bool get_usb_suspended(void); + +#endif // #ifndef _USB_DRIVER_H_ \ No newline at end of file diff --git a/headers/usbhostmanager.h b/headers/usbhostmanager.h index 9f656f658..b455eb07c 100644 --- a/headers/usbhostmanager.h +++ b/headers/usbhostmanager.h @@ -6,6 +6,7 @@ #include "pio_usb.h" +#include "host/usbh.h" #include "host/usbh_pvt.h" // USB Host manager decides on TinyUSB Host driver diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index fdf03e705..b7ec761b0 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -10,6 +10,5 @@ add_subdirectory(OneBitDisplay) add_subdirectory(PicoPeripherals) add_subdirectory(PlayerLEDs) add_subdirectory(rndis) -add_subdirectory(TinyUSB_Gamepad) add_subdirectory(WiiExtension) add_subdirectory(SNESpad) diff --git a/lib/TinyUSB_Gamepad/CMakeLists.txt b/lib/TinyUSB_Gamepad/CMakeLists.txt deleted file mode 100644 index 11add49c6..000000000 --- a/lib/TinyUSB_Gamepad/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -include(../../compile_proto.cmake) -compile_proto() - -add_library(TinyUSB_Gamepad -src/hid_driver.cpp -src/net_driver.cpp -src/tusb_driver.cpp -src/usb_descriptors.cpp -src/xinput_driver.cpp -src/ps4_driver.cpp -src/xid_driver/xid_driver.c -src/xid_driver/xid.c -src/xid_driver/xid_gamepad.c -src/xid_driver/xid_remote.c -src/xid_driver/xid_steelbattalion.c -src/xgip_protocol.cpp -src/xinput_host.cpp -src/xbone_driver.cpp -${PROTO_OUTPUT_DIR}/enums.pb.h -) -target_include_directories(TinyUSB_Gamepad PUBLIC -${CMAKE_CURRENT_SOURCE_DIR}/src -${CMAKE_CURRENT_SOURCE_DIR}/src/xid_driver -${CMAKE_SOURCE_DIR}/headers -${CMAKE_SOURCE_DIR}/lib/CRC32/src -${CMAKE_SOURCE_DIR}/lib/mbedtls/include -${CMAKE_SOURCE_DIR}/lib/nanopb -${PROTO_OUTPUT_DIR} -) -target_link_libraries(TinyUSB_Gamepad -pico_stdlib -pico_mbedtls -tinyusb_device -rndis -) diff --git a/lib/TinyUSB_Gamepad/library.json b/lib/TinyUSB_Gamepad/library.json deleted file mode 100644 index c79fd83fc..000000000 --- a/lib/TinyUSB_Gamepad/library.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "tinyusb-gamepad-driver", - "version": "0.0.1", - "description": "C library for handling USB HID/XID gamepads via TinyUSB.", - "keywords": "tinyusb gamepad hid xinput switch", - "authors": [ - { - "name": "Jason Skuby", - "url": "https://mytechtoybox.com" - } - ], - "license": "MIT" -} diff --git a/lib/TinyUSB_Gamepad/src/hid_driver.cpp b/lib/TinyUSB_Gamepad/src/hid_driver.cpp deleted file mode 100644 index 1a8d917a0..000000000 --- a/lib/TinyUSB_Gamepad/src/hid_driver.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com) - */ - -#include "hid_driver.h" -#include "usb_driver.h" -#include "device/usbd.h" - -#include "device/usbd_pvt.h" -#include "class/hid/hid_device.h" -#include "gamepad/GamepadDescriptors.h" - -#include "enums.pb.h" - -// Magic byte sequence to enable PS button on PS3 -static const uint8_t magic_init_bytes[8] = {0x21, 0x26, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00}; - -bool send_hid_report(uint8_t report_id, void *report, uint8_t report_size) -{ - if (tud_hid_ready()) - return tud_hid_report(report_id, report, report_size); - - return false; -} - -bool send_keyboard_report(void *report) -{ - if (tud_hid_ready()) { - KeyboardReport *keyboard_report = ((KeyboardReport *)report); - void *keyboard_report_payload = keyboard_report->reportId == KEYBOARD_KEY_REPORT_ID ? (void *)keyboard_report->keycode : (void *)&keyboard_report->multimedia; - uint16_t keyboard_report_size = keyboard_report->reportId == KEYBOARD_KEY_REPORT_ID ? sizeof(KeyboardReport::keycode) : sizeof(KeyboardReport::multimedia); - - return tud_hid_report(keyboard_report->reportId, keyboard_report_payload, keyboard_report_size); - } - - return false; -} - -bool hid_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - if ( - get_input_mode() == INPUT_MODE_HID && - request->bmRequestType == 0xA1 && - request->bRequest == HID_REQ_CONTROL_GET_REPORT && - request->wValue == 0x0300 - ) - { - return tud_control_xfer(rhport, request, (void *) magic_init_bytes, sizeof(magic_init_bytes)); - } - else - { - return hidd_control_xfer_cb(rhport, stage, request); - } -} - -const usbd_class_driver_t hid_driver = { -#if CFG_TUSB_DEBUG >= 2 - .name = "HID", -#endif - .init = hidd_init, - .reset = hidd_reset, - .open = hidd_open, - .control_xfer_cb = hid_control_xfer_cb, - .xfer_cb = hidd_xfer_cb, - .sof = NULL}; \ No newline at end of file diff --git a/lib/TinyUSB_Gamepad/src/hid_driver.h b/lib/TinyUSB_Gamepad/src/hid_driver.h deleted file mode 100644 index 1486bb82b..000000000 --- a/lib/TinyUSB_Gamepad/src/hid_driver.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com) - */ - -#pragma once - -#include "device/usbd_pvt.h" -#include "gamepad/descriptors/HIDDescriptors.h" -#include "gamepad/descriptors/SwitchDescriptors.h" -#include "gamepad/descriptors/NeogeoDescriptors.h" -#include "gamepad/descriptors/MDMiniDescriptors.h" -#include "gamepad/descriptors/PCEngineDescriptors.h" -#include "gamepad/descriptors/EgretDescriptors.h" -#include "gamepad/descriptors/AstroDescriptors.h" -#include "gamepad/descriptors/PSClassicDescriptors.h" - -extern const usbd_class_driver_t hid_driver; - -bool send_hid_report(uint8_t report_id, void *report, uint8_t report_size); -bool send_keyboard_report(void *report); diff --git a/lib/TinyUSB_Gamepad/src/net_driver.cpp b/lib/TinyUSB_Gamepad/src/net_driver.cpp deleted file mode 100644 index 16e138678..000000000 --- a/lib/TinyUSB_Gamepad/src/net_driver.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "net_driver.h" - -const usbd_class_driver_t net_driver = { -#if CFG_TUSB_DEBUG >= 2 - .name = "NET", -#endif - .init = netd_init, - .reset = netd_reset, - .open = netd_open, - .control_xfer_cb = netd_control_xfer_cb, - .xfer_cb = netd_xfer_cb, - .sof = NULL, -}; diff --git a/lib/TinyUSB_Gamepad/src/net_driver.h b/lib/TinyUSB_Gamepad/src/net_driver.h deleted file mode 100644 index bc57b06dc..000000000 --- a/lib/TinyUSB_Gamepad/src/net_driver.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com) - */ - -#pragma once - -#include "device/usbd_pvt.h" -#include "class/net/net_device.h" - -extern const usbd_class_driver_t net_driver; - -bool send_hid_report(uint8_t report_id, uint8_t *report, uint8_t report_size); diff --git a/lib/TinyUSB_Gamepad/src/ps4_driver.cpp b/lib/TinyUSB_Gamepad/src/ps4_driver.cpp deleted file mode 100644 index 51f37e1bc..000000000 --- a/lib/TinyUSB_Gamepad/src/ps4_driver.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) - */ - -#include "ps4_driver.h" - -#include "CRC32.h" - -#include "mbedtls/error.h" -#include "mbedtls/rsa.h" -#include "mbedtls/sha256.h" - -#include - -uint8_t ps4_endpoint_in = 0; -uint8_t ps4_endpoint_out = 0; -uint8_t ps4_out_buffer[PS4_OUT_SIZE] = {}; - -// 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, - 0xff, 0x7f, 0x0d, 0x0d, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -// Nonce Page Size: 0x38 (56) -// Response Page Size: 0x38 (56) -static constexpr uint8_t output_0xf3[] = { 0x0, 0x38, 0x38, 0, 0, 0, 0 }; - -static uint8_t cur_nonce_id = 1; - -// debug -static int rss_error = 0; - -static uint8_t send_nonce_part = 0; - -struct PS4Key { - unsigned char serial[16]; - unsigned char signature[256]; - struct mbedtls_rsa_context* rsa_context; -}; - -struct SignaturePart { - size_t length; - size_t (*function)(uint8_t * buf, size_t offset, const void* arg, size_t expected_size); - const void* arg; -}; - -ssize_t get_ps4_report(uint8_t report_id, uint8_t * buf, uint16_t reqlen) -{ - uint8_t data[64] = {}; - uint32_t crc32; - ps4_out_buffer[0] = report_id; - switch(report_id) { - // 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: - // We send 56 byte chunks back to the PS4, we've already calculated these - data[0] = 0xF1; - data[1] = cur_nonce_id; // nonce_id - data[2] = send_nonce_part; // next_part - data[3] = 0; - - // 56 byte chunks - memcpy(&data[4], &PS4Data::getInstance().ps4_auth_buffer[send_nonce_part*56], 56); - - // calculate the CRC32 of the buffer and write it back - crc32 = CRC32::calculate(data, 60); - memcpy(&data[60], &crc32, sizeof(uint32_t)); - memcpy(buf, &data[1], 63); // move data over to buffer - if ( (++send_nonce_part) == 19 ) { - PS4Data::getInstance().ps4State = PS4State::no_nonce; - PS4Data::getInstance().authsent = true; - send_nonce_part = 0; - } - return 63; - // Are we ready to sign? - case PS4AuthReport::PS4_GET_SIGNING_STATE: - data[0] = 0xF2; - data[1] = cur_nonce_id; - data[2] = PS4Data::getInstance().ps4State == PS4State::signed_nonce_ready ? 0 : 16; // 0 means auth is ready, 16 means we're still signing - memset(&data[3], 0, 9); - crc32 = CRC32::calculate(data, 12); - memcpy(&data[12], &crc32, sizeof(uint32_t)); - memcpy(buf, &data[1], 15); // move data over to buffer - return 15; - case PS4AuthReport::PS4_RESET_AUTH: // Reset the Authentication - if (reqlen != sizeof(output_0xf3)) { - return -1; - } - memcpy(buf, output_0xf3, reqlen); - PS4Data::getInstance().ps4State = PS4State::no_nonce; - return reqlen; - default: - break; - }; - return -1; -} - -void set_ps4_report(uint8_t report_id, uint8_t const * data, uint16_t reqlen) -{ - uint8_t nonce_id; - uint8_t nonce_page; - uint32_t crc32; - uint8_t buffer[64]; - uint8_t nonce[56]; // max nonce data - uint16_t noncelen; - uint16_t buflen; - - if (report_id == PS4AuthReport::PS4_SET_AUTH_PAYLOAD) { - if (reqlen != 63 ) { - return; - } - - // Setup CRC32 buffer - buffer[0] = report_id; - memcpy(&buffer[1], data, reqlen); - buflen = reqlen + 1; - - nonce_id = data[0]; - nonce_page = data[1]; - // data[2] is zero padding - - crc32 = CRC32::calculate(buffer, buflen-sizeof(uint32_t)); - if ( crc32 != *((unsigned int*)&buffer[buflen-sizeof(uint32_t)])) { - return; // CRC32 failed on set report - } - - // 256 byte nonce, with 56 byte packets leaves 24 extra bytes on the last packet? - 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; - // from 4 to 64 - 4 - } - - memcpy(nonce, &buffer[4], noncelen); - save_nonce(nonce_id, nonce_page, nonce, noncelen); - } -} - - -void save_nonce(uint8_t nonce_id, uint8_t nonce_page, uint8_t * buffer, uint16_t buflen) { - if ( nonce_page != 0 && nonce_id != cur_nonce_id ) { - PS4Data::getInstance().ps4State = PS4State::no_nonce; - return; // setting nonce with mismatched id - } - - memcpy(&PS4Data::getInstance().nonce_buffer[nonce_page*56], buffer, buflen); - if ( nonce_page == 4 ) { - PS4Data::getInstance().ps4State = PS4State::nonce_ready; - } else if ( nonce_page == 0 ) { - cur_nonce_id = nonce_id; - PS4Data::getInstance().ps4State = PS4State::receiving_nonce; - } -} - -void receive_ps4_report(void) -{ - if ( - tud_ready() && - (ps4_endpoint_out != 0) && (!usbd_edpt_busy(0, ps4_endpoint_out))) - { - usbd_edpt_claim(0, ps4_endpoint_out); // Take control of OUT endpoint - usbd_edpt_xfer(0, ps4_endpoint_out, ps4_out_buffer, PS4_OUT_SIZE); // Retrieve report buffer - usbd_edpt_release(0, ps4_endpoint_out); // Release control of OUT endpoint - } -} - -bool send_ps4_report(void *report, uint8_t report_size) -{ - bool sent = false; - - if ( - tud_ready() && // Is the device ready? - (ps4_endpoint_in != 0) && (!usbd_edpt_busy(0, ps4_endpoint_in)) // Is the IN endpoint available? - ) - { - usbd_edpt_claim(0, ps4_endpoint_in); // Take control of IN endpoint - usbd_edpt_xfer(0, ps4_endpoint_in, (uint8_t *)report, report_size); // Send report buffer - usbd_edpt_release(0, ps4_endpoint_in); // Release control of IN endpoint - sent = true; - } - - return sent; -} - -const usbd_class_driver_t ps4_driver = - { -#if CFG_TUSB_DEBUG >= 2 - .name = "PS4", -#endif - .init = hidd_init, - .reset = hidd_reset, - .open = hidd_open, - .control_xfer_cb = hidd_control_xfer_cb, - .xfer_cb = hidd_xfer_cb, - .sof = NULL}; diff --git a/lib/TinyUSB_Gamepad/src/tusb_driver.cpp b/lib/TinyUSB_Gamepad/src/tusb_driver.cpp deleted file mode 100644 index 550d78439..000000000 --- a/lib/TinyUSB_Gamepad/src/tusb_driver.cpp +++ /dev/null @@ -1,288 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com) - */ - -#include - -#include "tusb_config.h" -#include "tusb.h" -#include "class/hid/hid.h" -#include "device/usbd_pvt.h" - -#include "gamepad/GamepadDescriptors.h" - -#include "usb_driver.h" -#include "net_driver.h" -#include "hid_driver.h" -#include "xinput_driver.h" -#include "ps4_driver.h" -#include "xid_driver/xid_driver.h" -#include "xbone_driver.h" - -UsbMode usb_mode = USB_MODE_HID; -InputMode input_mode = INPUT_MODE_XINPUT; -static bool usb_mounted = false; -static bool usb_suspended = false; - -InputMode get_input_mode(void) -{ - return input_mode; -} - -bool get_usb_mounted(void) -{ - return usb_mounted; -} - -bool get_usb_suspended(void) -{ - return usb_suspended; -} - -void initialize_driver(InputMode mode) -{ - input_mode = mode; - if (mode == INPUT_MODE_CONFIG) - usb_mode = USB_MODE_NET; - - tud_init(TUD_OPT_RHPORT); -} - -void receive_report(uint8_t *buffer) -{ - if (input_mode == INPUT_MODE_XINPUT) - { - receive_xinput_report(); - memcpy(buffer, xinput_out_buffer, XINPUT_OUT_SIZE); - } -} - -bool send_report(void *report, uint16_t report_size) -{ - static uint8_t previous_report[CFG_TUD_ENDPOINT0_SIZE] = { }; - - uint8_t xIndex = 0; - if (input_mode == INPUT_MODE_XBOXORIGINAL) { - xIndex = xid_get_index_by_type(0, XID_TYPE_GAMECONTROLLER); - } - - bool sent = false; - - if (tud_suspended()) - tud_remote_wakeup(); - - if (memcmp(previous_report, report, report_size) != 0) - { - switch (input_mode) - { - case INPUT_MODE_XBOXORIGINAL: - sent = xid_send_report(xIndex, report, report_size); - break; - case INPUT_MODE_XINPUT: - sent = send_xinput_report(report, report_size); - break; - case INPUT_MODE_XBONE: - sent = send_xbone_report(report, report_size); - break; - case INPUT_MODE_KEYBOARD: - sent = send_keyboard_report(report); - break; - default: - sent = send_hid_report(0, report, report_size); - break; - } - - if (sent) - memcpy(previous_report, report, report_size); - } - - return sent; -} - -// Some input drivers need their own process/update logic -void update_input_driver() { - switch (input_mode) - { - case INPUT_MODE_XBONE: - xbone_driver_update(); - break; - default: - break; - }; -} - -/* USB Driver Callback (Required for XInput) */ - -const usbd_class_driver_t *usbd_app_driver_get_cb(uint8_t *driver_count) -{ - *driver_count = 1; - - if (usb_mode == USB_MODE_NET) - { - return &net_driver; - } - else - { - switch (input_mode) - { - case INPUT_MODE_XINPUT: - return &xinput_driver; - - case INPUT_MODE_PS4: - return &ps4_driver; - - case INPUT_MODE_XBOXORIGINAL: - return xid_get_driver(); - - case INPUT_MODE_XBONE: - return &xbone_driver; - - default: - return &hid_driver; - } - } -} - -/* USB HID Callbacks (Required) */ - -// Invoked when received GET_REPORT control request -// Application must fill buffer report's content and return its length. -// Return zero will cause the stack to STALL request -uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) -{ - // TODO: Handle the correct report type, if required - (void)itf; - - uint8_t report_size = 0; - SwitchReport switch_report; - HIDReport hid_report; - KeyboardReport keyboard_report; - PS4Report ps4_report; - NeogeoReport neogeo_report; - MDMiniReport mdmini_report; - PCEngineReport pcengine_report; - EgretReport egret_report; - AstroReport astro_report; - PSClassicReport psclassic_report; - switch (input_mode) - { - case INPUT_MODE_SWITCH: - report_size = sizeof(SwitchReport); - memcpy(buffer, &switch_report, report_size); - break; - case INPUT_MODE_NEOGEO: - report_size = sizeof(NeogeoReport); - memcpy(buffer, &neogeo_report, report_size); - break; - case INPUT_MODE_MDMINI: - report_size = sizeof(MDMiniReport); - memcpy(buffer, &mdmini_report, report_size); - break; - case INPUT_MODE_PCEMINI: - report_size = sizeof(PCEngineReport); - memcpy(buffer, &pcengine_report, report_size); - break; - case INPUT_MODE_EGRET: - report_size = sizeof(EgretReport); - memcpy(buffer, &egret_report, report_size); - break; - case INPUT_MODE_ASTRO: - report_size = sizeof(AstroReport); - memcpy(buffer, &astro_report, report_size); - break; - case INPUT_MODE_PSCLASSIC: - report_size = sizeof(PSClassicReport); - memcpy(buffer, &psclassic_report, report_size); - break; - case INPUT_MODE_KEYBOARD: - report_size = report_id == KEYBOARD_KEY_REPORT_ID ? sizeof(KeyboardReport::keycode) : sizeof(KeyboardReport::multimedia); - memcpy(buffer, report_id == KEYBOARD_KEY_REPORT_ID ? - (void*) keyboard_report.keycode : (void*) &keyboard_report.multimedia, report_size); - break; - case INPUT_MODE_PS4: - if ( report_type == HID_REPORT_TYPE_FEATURE ) { - // Get feature report (for Auth) - report_size = get_ps4_report(report_id, buffer, reqlen); - } else { - report_size = sizeof(PS4Report); - memcpy(buffer, &ps4_report, report_size); - } - break; - default: - report_size = sizeof(HIDReport); - memcpy(buffer, &hid_report, report_size); - break; - } - - return report_size; -} - -// Invoked when received SET_REPORT control request or -// received data on OUT endpoint ( Report ID = 0, Type = 0 ) -void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) -{ - (void) itf; - switch (input_mode) - { - case INPUT_MODE_PS4: - if ( report_type == HID_REPORT_TYPE_FEATURE ) { - set_ps4_report(report_id, buffer, bufsize); - } - break; - default: - break; - } - - // echo back anything we received from host - tud_hid_report(report_id, buffer, bufsize); -} - - -/* Device callbacks (Optional) */ - -// Invoked when device is mounted -void tud_mount_cb(void) -{ - usb_mounted = true; -} - -// Invoked when device is unmounted -void tud_umount_cb(void) -{ - usb_mounted = false; -} - -// Invoked when usb bus is suspended -// remote_wakeup_en : if host allow us to perform remote wakeup -// Within 7ms, device must draw an average of current less than 2.5 mA from bus -void tud_suspend_cb(bool remote_wakeup_en) -{ - (void)remote_wakeup_en; - usb_suspended = true; -} - -// Invoked when usb bus is resumed -void tud_resume_cb(void) -{ - usb_suspended = false; -} - -// Vendor Controlled XFER occured -bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, - tusb_control_request_t const *request) -{ - bool ret = false; - switch (input_mode) - { - case INPUT_MODE_XBOXORIGINAL: - ret |= xid_get_driver()->control_xfer_cb(rhport, stage, request); - break; - case INPUT_MODE_XBONE: - ret = xbone_vendor_control_xfer_cb(rhport, stage, request); - break; - default: - break; - } - return ret; -} diff --git a/lib/TinyUSB_Gamepad/src/usb_descriptors.cpp b/lib/TinyUSB_Gamepad/src/usb_descriptors.cpp deleted file mode 100644 index 1678c97be..000000000 --- a/lib/TinyUSB_Gamepad/src/usb_descriptors.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com) - * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org) - */ - -#include -#include "tusb.h" -#include "usb_driver.h" -#include "gamepad/GamepadDescriptors.h" -#include "webserver_descriptors.h" - -// Invoked when received GET STRING DESCRIPTOR request -// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete -uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) -{ - (void)langid; - - if (get_input_mode() == INPUT_MODE_CONFIG) - { - return web_tud_descriptor_string_cb(index, langid); - } - else - { - uint16_t size = 0; - return getStringDescriptor(&size, get_input_mode(), index); - } -} - -// Invoked when received GET DEVICE DESCRIPTOR -// Application return pointer to descriptor -uint8_t const *tud_descriptor_device_cb() -{ - switch (get_input_mode()) - { - case INPUT_MODE_CONFIG: - return web_tud_descriptor_device_cb(); - - case INPUT_MODE_XINPUT: - return xinput_device_descriptor; - - case INPUT_MODE_XBONE: - return xbone_device_descriptor; - - case INPUT_MODE_PS4: - return ps4_device_descriptor; - - case INPUT_MODE_SWITCH: - return switch_device_descriptor; - - case INPUT_MODE_KEYBOARD: - return keyboard_device_descriptor; - - case INPUT_MODE_NEOGEO: - return neogeo_device_descriptor; - - case INPUT_MODE_MDMINI: - return mdmini_device_descriptor; - - case INPUT_MODE_PCEMINI: - return pcengine_device_descriptor; - - case INPUT_MODE_EGRET: - return egret_device_descriptor; - - case INPUT_MODE_ASTRO: - return astro_device_descriptor; - - case INPUT_MODE_PSCLASSIC: - return psclassic_device_descriptor; - - case INPUT_MODE_XBOXORIGINAL: - return xboxoriginal_device_descriptor; - - default: - return hid_device_descriptor; - } -} - -// Invoked when received GET HID REPORT DESCRIPTOR -// Application return pointer to descriptor -// Descriptor contents must exist long enough for transfer to complete -uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf) -{ - (void) itf; - switch (get_input_mode()) - { - case INPUT_MODE_SWITCH: - return switch_report_descriptor; - - case INPUT_MODE_PS4: - return ps4_report_descriptor; - - case INPUT_MODE_KEYBOARD: - return keyboard_report_descriptor; - - case INPUT_MODE_NEOGEO: - return neogeo_report_descriptor; - - case INPUT_MODE_MDMINI: - return mdmini_report_descriptor; - - case INPUT_MODE_PCEMINI: - return pcengine_report_descriptor; - - case INPUT_MODE_EGRET: - return egret_report_descriptor; - - case INPUT_MODE_ASTRO: - return astro_report_descriptor; - - case INPUT_MODE_PSCLASSIC: - return psclassic_report_descriptor; - - default: - return hid_report_descriptor; - } -} - -// Invoked when received GET CONFIGURATION DESCRIPTOR -// Application return pointer to descriptor -// Descriptor contents must exist long enough for transfer to complete -uint8_t const *tud_descriptor_configuration_cb(uint8_t index) -{ - switch (get_input_mode()) - { - case INPUT_MODE_CONFIG: - return web_tud_descriptor_configuration_cb(index); - - case INPUT_MODE_XINPUT: - return xinput_configuration_descriptor; - - case INPUT_MODE_XBONE: - return xbone_configuration_descriptor_cb(index); - - case INPUT_MODE_PS4: - return ps4_configuration_descriptor; - - case INPUT_MODE_SWITCH: - return switch_configuration_descriptor; - - case INPUT_MODE_KEYBOARD: - return keyboard_configuration_descriptor; - - case INPUT_MODE_NEOGEO: - return neogeo_configuration_descriptor; - - case INPUT_MODE_MDMINI: - return mdmini_configuration_descriptor; - - case INPUT_MODE_PCEMINI: - return pcengine_configuration_descriptor; - - case INPUT_MODE_EGRET: - return egret_configuration_descriptor; - - case INPUT_MODE_ASTRO: - return astro_configuration_descriptor; - - case INPUT_MODE_PSCLASSIC: - return psclassic_configuration_descriptor; - - case INPUT_MODE_XBOXORIGINAL: - return xboxoriginal_configuration_descriptor; - - default: - return hid_configuration_descriptor; - } -} - -uint8_t const* tud_descriptor_device_qualifier_cb(void) { - switch (get_input_mode()) - { - case INPUT_MODE_XBONE: - return xbone_device_qualifier; - default: - return nullptr; - } -} \ No newline at end of file diff --git a/lib/TinyUSB_Gamepad/src/usb_driver.h b/lib/TinyUSB_Gamepad/src/usb_driver.h deleted file mode 100644 index f60b3da4a..000000000 --- a/lib/TinyUSB_Gamepad/src/usb_driver.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com) - */ - -#pragma once - -#include "gamepad/GamepadDescriptors.h" -#include "enums.pb.h" - -typedef enum -{ - USB_MODE_HID, - USB_MODE_NET, -} UsbMode; - -InputMode get_input_mode(void); -bool get_usb_mounted(void); -bool get_usb_suspended(void); -void initialize_driver(InputMode mode); -void receive_report(uint8_t *buffer); -bool send_report(void *report, uint16_t report_size); -void update_input_driver(); - diff --git a/lib/TinyUSB_Gamepad/src/xinput_driver.cpp b/lib/TinyUSB_Gamepad/src/xinput_driver.cpp deleted file mode 100644 index bdcbb84b3..000000000 --- a/lib/TinyUSB_Gamepad/src/xinput_driver.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com) - */ - -#include "xinput_driver.h" - -uint8_t endpoint_in = 0; -uint8_t endpoint_out = 0; -uint8_t xinput_out_buffer[XINPUT_OUT_SIZE] = {}; - -void receive_xinput_report(void) -{ - if ( - tud_ready() && - (endpoint_out != 0) && (!usbd_edpt_busy(0, endpoint_out))) - { - usbd_edpt_claim(0, endpoint_out); // Take control of OUT endpoint - usbd_edpt_xfer(0, endpoint_out, xinput_out_buffer, XINPUT_OUT_SIZE); // Retrieve report buffer - usbd_edpt_release(0, endpoint_out); // Release control of OUT endpoint - } -} - -bool send_xinput_report(void *report, uint8_t report_size) -{ - bool sent = false; - - if ( - tud_ready() && // Is the device ready? - (endpoint_in != 0) && (!usbd_edpt_busy(0, endpoint_in)) // Is the IN endpoint available? - ) - { - usbd_edpt_claim(0, endpoint_in); // Take control of IN endpoint - usbd_edpt_xfer(0, endpoint_in, (uint8_t *)report, report_size); // Send report buffer - usbd_edpt_release(0, endpoint_in); // Release control of IN endpoint - sent = true; - } - - return sent; -} - -static void xinput_init(void) -{ -} - -static void xinput_reset(uint8_t rhport) -{ - (void)rhport; -} - -static uint16_t xinput_open(uint8_t rhport, tusb_desc_interface_t const *itf_descriptor, uint16_t max_length) -{ - uint16_t driver_length = sizeof(tusb_desc_interface_t) + (itf_descriptor->bNumEndpoints * sizeof(tusb_desc_endpoint_t)) + 16; - - TU_VERIFY(max_length >= driver_length, 0); - - uint8_t const *current_descriptor = tu_desc_next(itf_descriptor); - uint8_t found_endpoints = 0; - while ((found_endpoints < itf_descriptor->bNumEndpoints) && (driver_length <= max_length)) - { - tusb_desc_endpoint_t const *endpoint_descriptor = (tusb_desc_endpoint_t const *)current_descriptor; - if (TUSB_DESC_ENDPOINT == tu_desc_type(endpoint_descriptor)) - { - TU_ASSERT(usbd_edpt_open(rhport, endpoint_descriptor)); - - if (tu_edpt_dir(endpoint_descriptor->bEndpointAddress) == TUSB_DIR_IN) - endpoint_in = endpoint_descriptor->bEndpointAddress; - else - endpoint_out = endpoint_descriptor->bEndpointAddress; - - ++found_endpoints; - } - - current_descriptor = tu_desc_next(current_descriptor); - } - return driver_length; -} - -static bool xinput_device_control_request(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) -{ - (void)rhport; - (void)stage; - (void)request; - - return true; -} - -static bool xinput_control_complete(uint8_t rhport, tusb_control_request_t const *request) -{ - (void)rhport; - (void)request; - - return true; -} - -static bool xinput_xfer_callback(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void)rhport; - (void)result; - (void)xferred_bytes; - - if (ep_addr == endpoint_out) - usbd_edpt_xfer(0, endpoint_out, xinput_out_buffer, XINPUT_OUT_SIZE); - - return true; -} - -const usbd_class_driver_t xinput_driver = - { -#if CFG_TUSB_DEBUG >= 2 - .name = "XINPUT", -#endif - .init = xinput_init, - .reset = xinput_reset, - .open = xinput_open, - .control_xfer_cb = xinput_device_control_request, - .xfer_cb = xinput_xfer_callback, - .sof = NULL}; diff --git a/lib/TinyUSB_Gamepad/src/xinput_driver.h b/lib/TinyUSB_Gamepad/src/xinput_driver.h deleted file mode 100644 index 03be6114f..000000000 --- a/lib/TinyUSB_Gamepad/src/xinput_driver.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com) - */ - -#pragma once - -#include -#include "tusb.h" -#include "device/usbd_pvt.h" - -#include "gamepad/descriptors/XInputDescriptors.h" - -#define XINPUT_OUT_SIZE 32 - -typedef enum -{ - XINPUT_PLED_OFF = 0x00, // All off - XINPUT_PLED_BLINKALL = 0x01, // All blinking - XINPUT_PLED_FLASH1 = 0x02, // 1 flashes, then on - XINPUT_PLED_FLASH2 = 0x03, // 2 flashes, then on - XINPUT_PLED_FLASH3 = 0x04, // 3 flashes, then on - XINPUT_PLED_FLASH4 = 0x05, // 4 flashes, then on - XINPUT_PLED_ON1 = 0x06, // 1 on - XINPUT_PLED_ON2 = 0x07, // 2 on - XINPUT_PLED_ON3 = 0x08, // 3 on - XINPUT_PLED_ON4 = 0x09, // 4 on - XINPUT_PLED_ROTATE = 0x0A, // Rotating (e.g. 1-2-4-3) - XINPUT_PLED_BLINK = 0x0B, // Blinking* - XINPUT_PLED_SLOWBLINK = 0x0C, // Slow blinking* - XINPUT_PLED_ALTERNATE = 0x0D, // Alternating (e.g. 1+4-2+3), then back to previous* -} XInputPLEDPattern; - -// USB endpoint state vars -extern uint8_t endpoint_in; -extern uint8_t endpoint_out; -extern uint8_t xinput_out_buffer[XINPUT_OUT_SIZE]; -extern const usbd_class_driver_t xinput_driver; - -void receive_xinput_report(void); -bool send_xinput_report(void *report, uint8_t report_size); - -#pragma once diff --git a/src/addons/board_led.cpp b/src/addons/board_led.cpp index cb6470f24..5c428413a 100644 --- a/src/addons/board_led.cpp +++ b/src/addons/board_led.cpp @@ -1,8 +1,9 @@ #include "addons/board_led.h" -#include "usb_driver.h" // Required to check USB state -#include "ps4_driver.h" +#include "drivers/shared/ps4data.h" +#include "usbdriver.h" #include "helper.h" #include "config.pb.h" +#include "drivermanager.h" bool BoardLedAddon::available() { const OnBoardLedOptions& options = Storage::getInstance().getAddonOptions().onBoardLedOptions; @@ -23,7 +24,7 @@ void BoardLedAddon::setup() { void BoardLedAddon::process() { bool state = 0; Gamepad * processedGamepad; - uint16_t joystickMid = GetJoystickMidValue(Storage::getInstance().getGamepadOptions().inputMode); + uint16_t joystickMid = DriverManager::getInstance().getDriver()->GetJoystickMidValue(); switch (onBoardLedMode) { case OnBoardLedMode::ON_BOARD_LED_MODE_INPUT_TEST: // Blinks on input processedGamepad = Storage::getInstance().GetProcessedGamepad(); diff --git a/src/addons/buzzerspeaker.cpp b/src/addons/buzzerspeaker.cpp index 7afd688ed..913ccd962 100644 --- a/src/addons/buzzerspeaker.cpp +++ b/src/addons/buzzerspeaker.cpp @@ -2,8 +2,8 @@ #include "addons/buzzerspeaker.h" #include "songs.h" #include "storagemanager.h" +#include "usbdriver.h" #include "math.h" -#include "usb_driver.h" #include "helper.h" #include "config.pb.h" diff --git a/src/addons/dualdirectional.cpp b/src/addons/dualdirectional.cpp index dc45ceea0..3210c0ef4 100644 --- a/src/addons/dualdirectional.cpp +++ b/src/addons/dualdirectional.cpp @@ -1,5 +1,4 @@ #include "addons/dualdirectional.h" -#include "GamepadOptions.h" #include "storagemanager.h" #include "helper.h" #include "config.pb.h" @@ -224,16 +223,14 @@ void DualDirectionalInput::process() } void DualDirectionalInput::OverrideGamepad(Gamepad * gamepad, DpadMode mode, uint8_t dpad) { - uint8_t input_mode = gamepad->getOptions().inputMode; - switch (mode) { case DPAD_MODE_LEFT_ANALOG: - gamepad->state.lx = dpadToAnalogX(dpad, input_mode); - gamepad->state.ly = dpadToAnalogY(dpad, input_mode); + gamepad->state.lx = dpadToAnalogX(dpad); + gamepad->state.ly = dpadToAnalogY(dpad); break; case DPAD_MODE_RIGHT_ANALOG: - gamepad->state.rx = dpadToAnalogX(dpad, input_mode); - gamepad->state.ry = dpadToAnalogY(dpad, input_mode); + gamepad->state.rx = dpadToAnalogX(dpad); + gamepad->state.ry = dpadToAnalogY(dpad); break; case DPAD_MODE_DIGITAL: gamepad->state.dpad = dpad; diff --git a/src/addons/i2cdisplay.cpp b/src/addons/i2cdisplay.cpp index baf683d2e..bdcbf467c 100644 --- a/src/addons/i2cdisplay.cpp +++ b/src/addons/i2cdisplay.cpp @@ -9,10 +9,11 @@ #include "storagemanager.h" #include "pico/stdlib.h" #include "bitmaps.h" -#include "ps4_driver.h" +#include "drivers/shared/ps4data.h" +#include "usbdriver.h" #include "version.h" #include "config.pb.h" -#include "usb_driver.h" +#include "class/hid/hid.h" bool I2CDisplayAddon::available() { const DisplayOptions& options = Storage::getInstance().getDisplayOptions(); @@ -249,7 +250,7 @@ void I2CDisplayAddon::process() { I2CDisplayAddon::DisplayMode I2CDisplayAddon::getDisplayMode() { if (configMode) { - gamepad->read(); + //gamepad->read(); // ?? uint16_t buttonState = gamepad->state.buttons; if (prevButtonState && !buttonState) { // has button been pressed (held and released)? switch (prevButtonState) { diff --git a/src/addons/inputhistory.cpp b/src/addons/inputhistory.cpp index 7261a5215..9a8bbd5f7 100644 --- a/src/addons/inputhistory.cpp +++ b/src/addons/inputhistory.cpp @@ -2,7 +2,6 @@ #include "addons/inputhistory.h" #include "storagemanager.h" #include "math.h" -#include "usb_driver.h" #include "helper.h" #include "config.pb.h" diff --git a/src/addons/keyboard_host.cpp b/src/addons/keyboard_host.cpp index 67fe5e27d..1cbdf4f33 100644 --- a/src/addons/keyboard_host.cpp +++ b/src/addons/keyboard_host.cpp @@ -1,10 +1,12 @@ #include "addons/keyboard_host.h" #include "storagemanager.h" +#include "drivermanager.h" #include "usbhostmanager.h" #include "peripheralmanager.h" +#include "class/hid/hid_host.h" bool KeyboardHostAddon::available() { - const KeyboardHostOptions& keyboardHostOptions = Storage::getInstance().getAddonOptions().keyboardHostOptions; + const KeyboardHostOptions& keyboardHostOptions = Storage::getInstance().getAddonOptions().keyboardHostOptions; return keyboardHostOptions.enabled && PeripheralManager::getInstance().isUSBEnabled(0); } @@ -105,7 +107,7 @@ uint8_t KeyboardHostAddon::getKeycodeFromModifier(uint8_t modifier) { // convert hid keycode to ascii and print via usb device CDC (ignore non-printable) void KeyboardHostAddon::process_kbd_report(uint8_t dev_addr, hid_keyboard_report_t const *report) { - uint16_t joystickMid = GetJoystickMidValue(Storage::getInstance().getGamepadOptions().inputMode); + uint16_t joystickMid = DriverManager::getInstance().getDriver()->GetJoystickMidValue(); _keyboard_host_state.dpad = 0; _keyboard_host_state.buttons = 0; @@ -121,8 +123,6 @@ void KeyboardHostAddon::process_kbd_report(uint8_t dev_addr, hid_keyboard_report uint8_t keycode = (i < 6) ? report->keycode[i] : getKeycodeFromModifier(report->modifier); if ( keycode ) { - const GamepadOptions& gamepadOptions = Storage::getInstance().getGamepadOptions(); - _keyboard_host_state.dpad |= ((keycode == _keyboard_host_mapDpadUp.key) ? _keyboard_host_mapDpadUp.buttonMask : _keyboard_host_state.dpad) | ((keycode == _keyboard_host_mapDpadDown.key) ? _keyboard_host_mapDpadDown.buttonMask : _keyboard_host_state.dpad) diff --git a/src/addons/neopicoleds.cpp b/src/addons/neopicoleds.cpp index 457fa00d8..76ad1cd22 100644 --- a/src/addons/neopicoleds.cpp +++ b/src/addons/neopicoleds.cpp @@ -12,8 +12,7 @@ #include "addons/neopicoleds.h" #include "addons/pleds.h" #include "themes.h" -#include "usb_driver.h" - +#include "usbdriver.h" #include "enums.h" #include "helper.h" @@ -40,6 +39,25 @@ static std::vector EMPTY_VECTOR; uint32_t rgbPLEDValues[4]; +// Move to Proto Enums +typedef enum +{ + XINPUT_PLED_OFF = 0x00, // All off + XINPUT_PLED_BLINKALL = 0x01, // All blinking + XINPUT_PLED_FLASH1 = 0x02, // 1 flashes, then on + XINPUT_PLED_FLASH2 = 0x03, // 2 flashes, then on + XINPUT_PLED_FLASH3 = 0x04, // 3 flashes, then on + XINPUT_PLED_FLASH4 = 0x05, // 4 flashes, then on + XINPUT_PLED_ON1 = 0x06, // 1 on + XINPUT_PLED_ON2 = 0x07, // 2 on + XINPUT_PLED_ON3 = 0x08, // 3 on + XINPUT_PLED_ON4 = 0x09, // 4 on + XINPUT_PLED_ROTATE = 0x0A, // Rotating (e.g. 1-2-4-3) + XINPUT_PLED_BLINK = 0x0B, // Blinking* + XINPUT_PLED_SLOWBLINK = 0x0C, // Slow blinking* + XINPUT_PLED_ALTERNATE = 0x0D, // Alternating (e.g. 1+4-2+3), then back to previous* +} XInputPLEDPattern; + // TODO: Make this a helper function // Animation Helper for Player LEDs PLEDAnimationState getXInputAnimationNEOPICO(uint8_t *data) diff --git a/src/addons/playerleds.cpp b/src/addons/playerleds.cpp index 852c535fa..5dc04ea92 100644 --- a/src/addons/playerleds.cpp +++ b/src/addons/playerleds.cpp @@ -8,13 +8,31 @@ #include "pico/stdlib.h" #include "hardware/pwm.h" #include "GamepadEnums.h" -#include "xinput_driver.h" -#include "usb_driver.h" // GP2040 Includes #include "addons/pleds.h" #include "helper.h" #include "storagemanager.h" +#include "usbdriver.h" + +// Move to Proto Enums +typedef enum +{ + XINPUT_PLED_OFF = 0x00, // All off + XINPUT_PLED_BLINKALL = 0x01, // All blinking + XINPUT_PLED_FLASH1 = 0x02, // 1 flashes, then on + XINPUT_PLED_FLASH2 = 0x03, // 2 flashes, then on + XINPUT_PLED_FLASH3 = 0x04, // 3 flashes, then on + XINPUT_PLED_FLASH4 = 0x05, // 4 flashes, then on + XINPUT_PLED_ON1 = 0x06, // 1 on + XINPUT_PLED_ON2 = 0x07, // 2 on + XINPUT_PLED_ON3 = 0x08, // 3 on + XINPUT_PLED_ON4 = 0x09, // 4 on + XINPUT_PLED_ROTATE = 0x0A, // Rotating (e.g. 1-2-4-3) + XINPUT_PLED_BLINK = 0x0B, // Blinking* + XINPUT_PLED_SLOWBLINK = 0x0C, // Slow blinking* + XINPUT_PLED_ALTERNATE = 0x0D, // Alternating (e.g. 1+4-2+3), then back to previous* +} XInputPLEDPattern; // TODO: make this a helper function // Animation Helper for Player LEDs diff --git a/src/addons/playernum.cpp b/src/addons/playernum.cpp index 2f3f8faa4..6db4abf14 100644 --- a/src/addons/playernum.cpp +++ b/src/addons/playernum.cpp @@ -3,6 +3,26 @@ #include "system.h" #include "helper.h" #include "config.pb.h" +#include "device/usbd.h" + +// Move to Proto Enums +typedef enum +{ + XINPUT_PLED_OFF = 0x00, // All off + XINPUT_PLED_BLINKALL = 0x01, // All blinking + XINPUT_PLED_FLASH1 = 0x02, // 1 flashes, then on + XINPUT_PLED_FLASH2 = 0x03, // 2 flashes, then on + XINPUT_PLED_FLASH3 = 0x04, // 3 flashes, then on + XINPUT_PLED_FLASH4 = 0x05, // 4 flashes, then on + XINPUT_PLED_ON1 = 0x06, // 1 on + XINPUT_PLED_ON2 = 0x07, // 2 on + XINPUT_PLED_ON3 = 0x08, // 3 on + XINPUT_PLED_ON4 = 0x09, // 4 on + XINPUT_PLED_ROTATE = 0x0A, // Rotating (e.g. 1-2-4-3) + XINPUT_PLED_BLINK = 0x0B, // Blinking* + XINPUT_PLED_SLOWBLINK = 0x0C, // Slow blinking* + XINPUT_PLED_ALTERNATE = 0x0D, // Alternating (e.g. 1+4-2+3), then back to previous* +} XInputPLEDPattern; bool PlayerNumAddon::available() { return Storage::getInstance().getAddonOptions().playerNumberOptions.enabled; diff --git a/src/addons/ps4mode.cpp b/src/addons/ps4mode.cpp index a524cbc22..91d55d280 100644 --- a/src/addons/ps4mode.cpp +++ b/src/addons/ps4mode.cpp @@ -7,7 +7,7 @@ #include "helper.h" #include "config.pb.h" -#include "ps4_driver.h" +#include "drivers/shared/ps4data.h" #include "mbedtls/error.h" #include "mbedtls/rsa.h" diff --git a/src/addons/pspassthrough.cpp b/src/addons/pspassthrough.cpp index 4ca01a3ea..a75ca01c5 100644 --- a/src/addons/pspassthrough.cpp +++ b/src/addons/pspassthrough.cpp @@ -3,6 +3,9 @@ #include "usbhostmanager.h" #include "peripheralmanager.h" +#include "class/hid/hid.h" +#include "class/hid/hid_host.h" + #include "CRC32.h" // Data passed between PS Passthrough and TinyUSB Host callbacks diff --git a/src/addons/snes_input.cpp b/src/addons/snes_input.cpp index 49abca09d..1bc76a080 100644 --- a/src/addons/snes_input.cpp +++ b/src/addons/snes_input.cpp @@ -1,4 +1,5 @@ #include "addons/snes_input.h" +#include "drivermanager.h" #include "storagemanager.h" #include "hardware/gpio.h" #include "helper.h" @@ -83,7 +84,7 @@ void SNESpadInput::process() { if (nextTimer < getMillis()) { snes->poll(); - uint16_t joystickMid = GetJoystickMidValue(Storage::getInstance().getGamepadOptions().inputMode); + uint16_t joystickMid = DriverManager::getInstance().getDriver()->GetJoystickMidValue(); leftX = joystickMid; leftY = joystickMid; diff --git a/src/addons/tilt.cpp b/src/addons/tilt.cpp index f312e6563..75514b068 100644 --- a/src/addons/tilt.cpp +++ b/src/addons/tilt.cpp @@ -1,4 +1,5 @@ #include "addons/tilt.h" +#include "drivermanager.h" #include "storagemanager.h" #include "helper.h" #include "config.pb.h" @@ -158,20 +159,20 @@ void TiltInput::process() //Since this is an auxiliary function for appeals and such, //pressing Tilt1 and Tilt2 at the same time will cause the light analog stick to correspond to each of the DPad methods. void TiltInput::OverrideGamepad(Gamepad* gamepad, uint8_t dpad1, uint8_t dpad2) { - bool pinTilt1Pressed = (pinTilt1 != (uint8_t)-1) ? !gpio_get(pinTilt1) : false; - bool pinTilt2Pressed = (pinTilt2 != (uint8_t)-1) ? !gpio_get(pinTilt2) : false; + bool pinTilt1Pressed = (pinTilt1 != (uint8_t)-1) ? !gpio_get(pinTilt1) : false; + bool pinTilt2Pressed = (pinTilt2 != (uint8_t)-1) ? !gpio_get(pinTilt2) : false; - // Scales input from 0-100% of maximum input - double scaledTilt1FactorLeftX = 1.0 - (tilt1FactorLeftX / 100.0); - double scaledTilt1FactorLeftY = 1.0 - (tilt1FactorLeftY / 100.0); - double scaledTilt1FactorRightX = 1.0 - (tilt1FactorRightX / 100.0); - double scaledTilt1FactorRightY = 1.0 - (tilt1FactorRightY / 100.0); - double scaledTilt2FactorLeftX = 1.0 - (tilt2FactorLeftX / 100.0); - double scaledTilt2FactorLeftY = 1.0 - (tilt2FactorLeftY / 100.0); - double scaledTilt2FactorRightX = 1.0 - (tilt2FactorRightX / 100.0); - double scaledTilt2FactorRightY = 1.0 - (tilt2FactorRightY / 100.0); + // Scales input from 0-100% of maximum input + double scaledTilt1FactorLeftX = 1.0 - (tilt1FactorLeftX / 100.0); + double scaledTilt1FactorLeftY = 1.0 - (tilt1FactorLeftY / 100.0); + double scaledTilt1FactorRightX = 1.0 - (tilt1FactorRightX / 100.0); + double scaledTilt1FactorRightY = 1.0 - (tilt1FactorRightY / 100.0); + double scaledTilt2FactorLeftX = 1.0 - (tilt2FactorLeftX / 100.0); + double scaledTilt2FactorLeftY = 1.0 - (tilt2FactorLeftY / 100.0); + double scaledTilt2FactorRightX = 1.0 - (tilt2FactorRightX / 100.0); + double scaledTilt2FactorRightY = 1.0 - (tilt2FactorRightY / 100.0); - uint8_t input_mode = gamepad->getOptions().inputMode; + uint16_t midValue = DriverManager::getInstance().getDriver()->GetJoystickMidValue(); if (pinTilt1Pressed && pinTilt2Pressed) { // inputs act as dpad @@ -179,23 +180,23 @@ void TiltInput::OverrideGamepad(Gamepad* gamepad, uint8_t dpad1, uint8_t dpad2) } else { // analog input mode if (pinTilt1Pressed) { - gamepad->state.lx = dpadToAnalogX(dpad1, input_mode) + (GetJoystickMidValue(input_mode) - dpadToAnalogX(dpad1, input_mode)) * scaledTilt1FactorLeftX; - gamepad->state.ly = dpadToAnalogY(dpad1, input_mode) + (GetJoystickMidValue(input_mode) - dpadToAnalogY(dpad1, input_mode)) * scaledTilt1FactorLeftY; + gamepad->state.lx = dpadToAnalogX(dpad1) + (midValue - dpadToAnalogX(dpad1)) * scaledTilt1FactorLeftX; + gamepad->state.ly = dpadToAnalogY(dpad1) + (midValue - dpadToAnalogY(dpad1)) * scaledTilt1FactorLeftY; - gamepad->state.rx = dpadToAnalogX(dpad2, input_mode) + (GetJoystickMidValue(input_mode) - dpadToAnalogX(dpad2, input_mode)) * scaledTilt1FactorRightX; - gamepad->state.ry = dpadToAnalogY(dpad2, input_mode) + (GetJoystickMidValue(input_mode) - dpadToAnalogY(dpad2, input_mode)) * scaledTilt1FactorRightY; + gamepad->state.rx = dpadToAnalogX(dpad2) + (midValue - dpadToAnalogX(dpad2)) * scaledTilt1FactorRightX; + gamepad->state.ry = dpadToAnalogY(dpad2) + (midValue - dpadToAnalogY(dpad2)) * scaledTilt1FactorRightY; } else if (pinTilt2Pressed) { - gamepad->state.lx = dpadToAnalogX(dpad1, input_mode) + (GetJoystickMidValue(input_mode) - dpadToAnalogX(dpad1, input_mode)) * scaledTilt2FactorLeftX; - gamepad->state.ly = dpadToAnalogY(dpad1, input_mode) + (GetJoystickMidValue(input_mode) - dpadToAnalogY(dpad1, input_mode)) * scaledTilt2FactorLeftY; + gamepad->state.lx = dpadToAnalogX(dpad1) + (midValue - dpadToAnalogX(dpad1)) * scaledTilt2FactorLeftX; + gamepad->state.ly = dpadToAnalogY(dpad1) + (midValue - dpadToAnalogY(dpad1)) * scaledTilt2FactorLeftY; - gamepad->state.rx = dpadToAnalogX(dpad2, input_mode) + (GetJoystickMidValue(input_mode) - dpadToAnalogX(dpad2, input_mode)) * scaledTilt2FactorRightX; - gamepad->state.ry = dpadToAnalogY(dpad2, input_mode) + (GetJoystickMidValue(input_mode) - dpadToAnalogY(dpad2, input_mode)) * scaledTilt2FactorRightY; + gamepad->state.rx = dpadToAnalogX(dpad2) + (midValue - dpadToAnalogX(dpad2)) * scaledTilt2FactorRightX; + gamepad->state.ry = dpadToAnalogY(dpad2) + (midValue - dpadToAnalogY(dpad2)) * scaledTilt2FactorRightY; } else { - gamepad->state.lx = dpadToAnalogX(dpad1, input_mode); - gamepad->state.ly = dpadToAnalogY(dpad1, input_mode); + gamepad->state.lx = dpadToAnalogX(dpad1); + gamepad->state.ly = dpadToAnalogY(dpad1); - gamepad->state.rx = dpadToAnalogX(dpad2, input_mode); - gamepad->state.ry = dpadToAnalogY(dpad2, input_mode); + gamepad->state.rx = dpadToAnalogX(dpad2); + gamepad->state.ry = dpadToAnalogY(dpad2); } } } diff --git a/src/addons/wiiext.cpp b/src/addons/wiiext.cpp index 28593050a..4a21acd92 100644 --- a/src/addons/wiiext.cpp +++ b/src/addons/wiiext.cpp @@ -1,4 +1,5 @@ #include "addons/wiiext.h" +#include "drivermanager.h" #include "storagemanager.h" #include "hardware/gpio.h" #include "helper.h" @@ -96,7 +97,7 @@ uint16_t WiiExtensionInput::bounds(uint16_t x, uint16_t out_min, uint16_t out_ma void WiiExtensionInput::update() { if (wii->extensionType != WII_EXTENSION_NONE) { - uint16_t joystickMid = GetJoystickMidValue(Storage::getInstance().getGamepadOptions().inputMode); + uint16_t joystickMid = DriverManager::getInstance().getDriver()->GetJoystickMidValue(); currentConfig = &extensionConfigs[wii->extensionType]; //for (const auto& [extensionButton, value] : currentConfig->buttonMap) { @@ -335,7 +336,7 @@ void WiiExtensionInput::updateAnalogState() { Gamepad * gamepad = Storage::getInstance().GetGamepad(); gamepad->hasAnalogTriggers = isAnalogTriggers; - uint16_t joystickMid = GetJoystickMidValue(Storage::getInstance().getGamepadOptions().inputMode); + uint16_t joystickMid = DriverManager::getInstance().getDriver()->GetJoystickMidValue(); uint16_t axisType; uint16_t analogInput; diff --git a/src/addons/xbonepassthrough.cpp b/src/addons/xbonepassthrough.cpp index 47c58bb8a..3c45873cc 100644 --- a/src/addons/xbonepassthrough.cpp +++ b/src/addons/xbonepassthrough.cpp @@ -3,9 +3,10 @@ #include "usbhostmanager.h" #include "peripheralmanager.h" -#include "xbone_driver.h" -#include "xgip_protocol.h" -#include "xinput_host.h" +#include "drivers/xbone/XBOneDescriptors.h" +#include "drivers/shared/xgip_protocol.h" +#include "drivers/shared/xinput_host.h" +#include "drivers/shared/xbonedata.h" #define XBONE_EXTENSION_DEBUG true diff --git a/src/config_legacy.cpp b/src/config_legacy.cpp index 25ebaebdc..b317577c2 100644 --- a/src/config_legacy.cpp +++ b/src/config_legacy.cpp @@ -487,6 +487,8 @@ static bool isValidInputMode(ConfigLegacy::InputMode inputMode) case INPUT_MODE_KEYBOARD: case INPUT_MODE_PS4: return true; + default: + break; } return false; } diff --git a/src/config_utils.cpp b/src/config_utils.cpp index 6678b0e3b..ac84a1d79 100644 --- a/src/config_utils.cpp +++ b/src/config_utils.cpp @@ -115,6 +115,13 @@ #ifndef DEFAULT_LOCK_HOTKEYS #define DEFAULT_LOCK_HOTKEYS false #endif +#ifndef DEFAULT_PS4CONTROLLER_TYPE + #define DEFAULT_PS4CONTROLLER_TYPE PS4_CONTROLLER +#endif + +#ifndef DEFAULT_PS4_REPORTHACK + #define DEFAULT_PS4_REPORTHACK false +#endif #ifndef GPIO_PIN_00 #define GPIO_PIN_00 GpioAction::NONE diff --git a/src/drivermanager.cpp b/src/drivermanager.cpp new file mode 100644 index 000000000..9be42b3e4 --- /dev/null +++ b/src/drivermanager.cpp @@ -0,0 +1,71 @@ +#include "drivermanager.h" + +#include "drivers/net/NetDriver.h" +#include "drivers/astro/AstroDriver.h" +#include "drivers/egret/EgretDriver.h" +#include "drivers/hid/HIDDriver.h" +#include "drivers/keyboard/KeyboardDriver.h" +#include "drivers/mdmini/MDMiniDriver.h" +#include "drivers/neogeo/NeoGeoDriver.h" +#include "drivers/pcengine/PCEngineDriver.h" +#include "drivers/psclassic/PSClassicDriver.h" +#include "drivers/ps4/PS4Driver.h" +#include "drivers/switch/SwitchDriver.h" +#include "drivers/xbone/XBOneDriver.h" +#include "drivers/xboxog/XboxOriginalDriver.h" +#include "drivers/xinput/XInputDriver.h" + +void DriverManager::setup(InputMode mode) { + switch (mode) { + case INPUT_MODE_CONFIG: + driver = new NetDriver(); + break; + case INPUT_MODE_ASTRO: + driver = new AstroDriver(); + break; + case INPUT_MODE_EGRET: + driver = new EgretDriver(); + break; + case INPUT_MODE_HID: + driver = new HIDDriver(); + break; + case INPUT_MODE_KEYBOARD: + driver = new KeyboardDriver(); + break; + case INPUT_MODE_MDMINI: + driver = new MDMiniDriver(); + break; + case INPUT_MODE_NEOGEO: + driver = new NeoGeoDriver(); + break; + case INPUT_MODE_PSCLASSIC: + driver = new PSClassicDriver(); + break; + case INPUT_MODE_PCEMINI: + driver = new PCEngineDriver(); + break; + case INPUT_MODE_PS4: + driver = new PS4Driver(); + break; + case INPUT_MODE_SWITCH: + driver = new SwitchDriver(); + break; + case INPUT_MODE_XBONE: + driver = new XBOneDriver(); + break; + case INPUT_MODE_XBOXORIGINAL: + driver = new XboxOriginalDriver(); + break; + case INPUT_MODE_XINPUT: + driver = new XInputDriver(); + break; + default: + return; + } + + // Initialize our chosen driver + driver->initialize(); + + // Start the TinyUSB Device functionality + tud_init(TUD_OPT_RHPORT); +} diff --git a/src/drivers/astro/AstroDriver.cpp b/src/drivers/astro/AstroDriver.cpp new file mode 100644 index 000000000..338f52514 --- /dev/null +++ b/src/drivers/astro/AstroDriver.cpp @@ -0,0 +1,109 @@ +#include "drivers/astro/AstroDriver.h" +#include "drivers/shared/driverhelper.h" + +void AstroDriver::initialize() { + astroReport = { + .id = 1, + .notuse1 = 0x7f, + .notuse2 = 0x7f, + .lx = 0x7f, + .ly = 0x7f, + .buttons = 0xf, + .notuse3 = 0, + }; + + class_driver = { + #if CFG_TUSB_DEBUG >= 2 + .name = "ASTRO", + #endif + .init = hidd_init, + .reset = hidd_reset, + .open = hidd_open, + .control_xfer_cb = hidd_control_xfer_cb, + .xfer_cb = hidd_xfer_cb, + .sof = NULL + }; +} + +void AstroDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { + astroReport.lx = 0x7f; + astroReport.ly = 0x7f; + + switch (gamepad->state.dpad & GAMEPAD_MASK_DPAD) + { + case GAMEPAD_MASK_UP: astroReport.lx = ASTRO_JOYSTICK_MID; astroReport.ly = ASTRO_JOYSTICK_MIN; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: astroReport.lx = ASTRO_JOYSTICK_MAX; astroReport.ly = ASTRO_JOYSTICK_MIN; break; + case GAMEPAD_MASK_RIGHT: astroReport.lx = ASTRO_JOYSTICK_MAX; astroReport.ly = ASTRO_JOYSTICK_MID; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: astroReport.lx = ASTRO_JOYSTICK_MAX; astroReport.ly = ASTRO_JOYSTICK_MAX; break; + case GAMEPAD_MASK_DOWN: astroReport.lx = ASTRO_JOYSTICK_MID; astroReport.ly = ASTRO_JOYSTICK_MAX; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: astroReport.lx = ASTRO_JOYSTICK_MIN; astroReport.ly = ASTRO_JOYSTICK_MAX; break; + case GAMEPAD_MASK_LEFT: astroReport.lx = ASTRO_JOYSTICK_MIN; astroReport.ly = ASTRO_JOYSTICK_MID; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: astroReport.lx = ASTRO_JOYSTICK_MIN; astroReport.ly = ASTRO_JOYSTICK_MIN; break; + default: astroReport.lx = ASTRO_JOYSTICK_MID; astroReport.ly = ASTRO_JOYSTICK_MID; break; + } + + + astroReport.buttons = 0x0F + | (gamepad->pressedB1() ? ASTRO_MASK_A : 0) + | (gamepad->pressedB2() ? ASTRO_MASK_B : 0) + | (gamepad->pressedB3() ? ASTRO_MASK_D : 0) + | (gamepad->pressedB4() ? ASTRO_MASK_E : 0) + | (gamepad->pressedR1() ? ASTRO_MASK_F : 0) + | (gamepad->pressedR2() ? ASTRO_MASK_C : 0) + | (gamepad->pressedS1() ? ASTRO_MASK_CREDIT : 0) + | (gamepad->pressedS2() ? ASTRO_MASK_START : 0) + ; + + // Wake up TinyUSB device + if (tud_suspended()) + tud_remote_wakeup(); + + void * report = &astroReport; + uint16_t report_size = sizeof(astroReport); + if (memcmp(last_report, report, report_size) != 0) + { + // HID ready + report sent, copy previous report + if (tud_hid_ready() && tud_hid_report(0, report, report_size) == true ) { + memcpy(last_report, report, report_size); + } + } +} + +// tud_hid_get_report_cb +uint16_t AstroDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { + memcpy(buffer, &astroReport, sizeof(AstroReport)); + return sizeof(AstroReport); +} + +// Only PS4 does anything with set report +void AstroDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {} + +// Only XboxOG and Xbox One use vendor control xfer cb +bool AstroDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + return false; +} + +const uint16_t * AstroDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) { + const char *value = (const char *)astro_string_descriptors[index]; + return getStringDescriptor(value, index); // getStringDescriptor returns a static array +} + +const uint8_t * AstroDriver::get_descriptor_device_cb() { + return astro_device_descriptor; +} + +const uint8_t * AstroDriver::get_hid_descriptor_report_cb(uint8_t itf) { + return astro_report_descriptor; +} + +const uint8_t * AstroDriver::get_descriptor_configuration_cb(uint8_t index) { + return astro_configuration_descriptor; +} + +const uint8_t * AstroDriver::get_descriptor_device_qualifier_cb() { + return nullptr; +} + +uint16_t AstroDriver::GetJoystickMidValue() { + return GAMEPAD_JOYSTICK_MID; +} diff --git a/src/drivers/egret/EgretDriver.cpp b/src/drivers/egret/EgretDriver.cpp new file mode 100644 index 000000000..0e44af047 --- /dev/null +++ b/src/drivers/egret/EgretDriver.cpp @@ -0,0 +1,102 @@ +#include "drivers/egret/EgretDriver.h" +#include "drivers/shared/driverhelper.h" + +void EgretDriver::initialize() { + egretReport = { + .buttons = 0, + .lx = EGRET_JOYSTICK_MID, + .ly = EGRET_JOYSTICK_MID, + }; + + class_driver = { + #if CFG_TUSB_DEBUG >= 2 + .name = "EGRET", + #endif + .init = hidd_init, + .reset = hidd_reset, + .open = hidd_open, + .control_xfer_cb = hidd_control_xfer_cb, + .xfer_cb = hidd_xfer_cb, + .sof = NULL + }; +} + +void EgretDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { + switch (gamepad->state.dpad & GAMEPAD_MASK_DPAD) + { + case GAMEPAD_MASK_UP: egretReport.lx = EGRET_JOYSTICK_MID; egretReport.ly = EGRET_JOYSTICK_MIN; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: egretReport.lx = EGRET_JOYSTICK_MAX; egretReport.ly = EGRET_JOYSTICK_MIN; break; + case GAMEPAD_MASK_RIGHT: egretReport.lx = EGRET_JOYSTICK_MAX; egretReport.ly = EGRET_JOYSTICK_MID; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: egretReport.lx = EGRET_JOYSTICK_MAX; egretReport.ly = EGRET_JOYSTICK_MAX; break; + case GAMEPAD_MASK_DOWN: egretReport.lx = EGRET_JOYSTICK_MID; egretReport.ly = EGRET_JOYSTICK_MAX; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: egretReport.lx = EGRET_JOYSTICK_MIN; egretReport.ly = EGRET_JOYSTICK_MAX; break; + case GAMEPAD_MASK_LEFT: egretReport.lx = EGRET_JOYSTICK_MIN; egretReport.ly = EGRET_JOYSTICK_MID; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: egretReport.lx = EGRET_JOYSTICK_MIN; egretReport.ly = EGRET_JOYSTICK_MIN; break; + default: egretReport.lx = EGRET_JOYSTICK_MID; egretReport.ly = EGRET_JOYSTICK_MID; break; + } + + egretReport.buttons = 0 + | (gamepad->pressedB1() ? EGRET_MASK_A : 0) + | (gamepad->pressedB2() ? EGRET_MASK_B : 0) + | (gamepad->pressedB3() ? EGRET_MASK_D : 0) + | (gamepad->pressedB4() ? EGRET_MASK_E : 0) + | (gamepad->pressedR1() ? EGRET_MASK_F : 0) + | (gamepad->pressedR2() ? EGRET_MASK_C : 0) + | (gamepad->pressedS1() ? EGRET_MASK_CREDIT : 0) + | (gamepad->pressedS2() ? EGRET_MASK_START : 0) + | (gamepad->pressedA1() ? EGRET_MASK_MENU : 0) + ; + + // Wake up TinyUSB device + if (tud_suspended()) + tud_remote_wakeup(); + + void * report = &egretReport; + uint16_t report_size = sizeof(egretReport); + if (memcmp(last_report, report, report_size) != 0) + { + // HID ready + report sent, copy previous report + if (tud_hid_ready() && tud_hid_report(0, report, report_size) == true ) { + memcpy(last_report, report, report_size); + } + } +} + +// tud_hid_get_report_cb +uint16_t EgretDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { + memcpy(buffer, &egretReport, sizeof(EgretReport)); + return sizeof(EgretReport); +} + +// Only PS4 does anything with set report +void EgretDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {} + +// Only XboxOG and Xbox One use vendor control xfer cb +bool EgretDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + return false; +} + +const uint16_t * EgretDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) { + const char *value = (const char *)egret_string_descriptors[index]; + return getStringDescriptor(value, index); // getStringDescriptor returns a static array +} + +const uint8_t * EgretDriver::get_descriptor_device_cb() { + return egret_device_descriptor; +} + +const uint8_t * EgretDriver::get_hid_descriptor_report_cb(uint8_t itf) { + return egret_report_descriptor; +} + +const uint8_t * EgretDriver::get_descriptor_configuration_cb(uint8_t index) { + return egret_configuration_descriptor; +} + +const uint8_t * EgretDriver::get_descriptor_device_qualifier_cb() { + return nullptr; +} + +uint16_t EgretDriver::GetJoystickMidValue() { + return GAMEPAD_JOYSTICK_MID; +} diff --git a/src/drivers/hid/HIDDriver.cpp b/src/drivers/hid/HIDDriver.cpp new file mode 100644 index 000000000..c4878dd74 --- /dev/null +++ b/src/drivers/hid/HIDDriver.cpp @@ -0,0 +1,149 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#include "drivers/hid/HIDDriver.h" +#include "drivers/hid/HIDDescriptors.h" +#include "drivers/shared/driverhelper.h" + +// Magic byte sequence to enable PS button on PS3 +static const uint8_t ps3_magic_init_bytes[8] = {0x21, 0x26, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00}; + +static bool hid_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + if ( request->bmRequestType == 0xA1 && + request->bRequest == HID_REQ_CONTROL_GET_REPORT && + request->wValue == 0x0300 ) { + return tud_control_xfer(rhport, request, (void *) ps3_magic_init_bytes, sizeof(ps3_magic_init_bytes)); + } else { + return hidd_control_xfer_cb(rhport, stage, request); + } +} + +void HIDDriver::initialize() { + hidReport = { + .square_btn = 0, .cross_btn = 0, .circle_btn = 0, .triangle_btn = 0, + .l1_btn = 0, .r1_btn = 0, .l2_btn = 0, .r2_btn = 0, + .select_btn = 0, .start_btn = 0, .l3_btn = 0, .r3_btn = 0, .ps_btn = 0, .tp_btn = 0, + .direction = 0x08, + .l_x_axis = HID_JOYSTICK_MID, + .l_y_axis = HID_JOYSTICK_MID, + .r_x_axis = HID_JOYSTICK_MID, + .r_y_axis = HID_JOYSTICK_MID, + .right_axis = 0x00, .left_axis = 0x00, .up_axis = 0x00, .down_axis = 0x00, + .triangle_axis = 0x00, .circle_axis = 0x00, .cross_axis = 0x00, .square_axis = 0x00, + .l1_axis = 0x00, .r1_axis = 0x00, .l2_axis = 0x00, .r2_axis = 0x00 + }; + + class_driver = { + #if CFG_TUSB_DEBUG >= 2 + .name = "HID", + #endif + .init = hidd_init, + .reset = hidd_reset, + .open = hidd_open, + .control_xfer_cb = hid_control_xfer_cb, + .xfer_cb = hidd_xfer_cb, + .sof = NULL + }; +} + +// Generate HID report from gamepad and send to TUSB Device +void HIDDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { + switch (gamepad->state.dpad & GAMEPAD_MASK_DPAD) + { + case GAMEPAD_MASK_UP: hidReport.direction = HID_HAT_UP; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: hidReport.direction = HID_HAT_UPRIGHT; break; + case GAMEPAD_MASK_RIGHT: hidReport.direction = HID_HAT_RIGHT; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: hidReport.direction = HID_HAT_DOWNRIGHT; break; + case GAMEPAD_MASK_DOWN: hidReport.direction = HID_HAT_DOWN; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: hidReport.direction = HID_HAT_DOWNLEFT; break; + case GAMEPAD_MASK_LEFT: hidReport.direction = HID_HAT_LEFT; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: hidReport.direction = HID_HAT_UPLEFT; break; + default: hidReport.direction = HID_HAT_NOTHING; break; + } + + hidReport.cross_btn = gamepad->pressedB1(); + hidReport.circle_btn = gamepad->pressedB2(); + hidReport.square_btn = gamepad->pressedB3(); + hidReport.triangle_btn = gamepad->pressedB4(); + hidReport.l1_btn = gamepad->pressedL1(); + hidReport.r1_btn = gamepad->pressedR1(); + hidReport.l2_btn = gamepad->pressedL2(); + hidReport.r2_btn = gamepad->pressedR2(); + hidReport.select_btn = gamepad->pressedS1(); + hidReport.start_btn = gamepad->pressedS2(); + hidReport.l3_btn = gamepad->pressedL3(); + hidReport.r3_btn = gamepad->pressedR3(); + hidReport.ps_btn = gamepad->pressedA1(); + hidReport.tp_btn = gamepad->pressedA2(); + + hidReport.l_x_axis = static_cast(gamepad->state.lx >> 8); + hidReport.l_y_axis = static_cast(gamepad->state.ly >> 8); + hidReport.r_x_axis = static_cast(gamepad->state.rx >> 8); + hidReport.r_y_axis = static_cast(gamepad->state.ry >> 8); + + if (gamepad->hasAnalogTriggers) + { + hidReport.l2_axis = gamepad->state.lt; + hidReport.r2_axis = gamepad->state.rt; + } else { + hidReport.l2_axis = gamepad->pressedL2() ? 0xFF : 0; + hidReport.r2_axis = gamepad->pressedR2() ? 0xFF : 0; + } + + + // Wake up TinyUSB device + if (tud_suspended()) + tud_remote_wakeup(); + + void * report = &hidReport; + uint16_t report_size = sizeof(hidReport); + if (memcmp(last_report, report, report_size) != 0) + { + // HID ready + report sent, copy previous report + if (tud_hid_ready() && tud_hid_report(0, report, report_size) == true ) { + memcpy(last_report, report, report_size); + } + } +} + +// tud_hid_get_report_cb +uint16_t HIDDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { + memcpy(buffer, &hidReport, sizeof(HIDReport)); + return sizeof(HIDReport); +} + +// Only PS4 does anything with set report +void HIDDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {} + +// Only XboxOG and Xbox One use vendor control xfer cb +bool HIDDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + return false; +} + +const uint16_t * HIDDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) { + const char *value = (const char *)hid_string_descriptors[index]; + return getStringDescriptor(value, index); // getStringDescriptor returns a static array +} + +const uint8_t * HIDDriver::get_descriptor_device_cb() { + return hid_device_descriptor; +} + +const uint8_t * HIDDriver::get_hid_descriptor_report_cb(uint8_t itf) { + return hid_report_descriptor; +} + +const uint8_t * HIDDriver::get_descriptor_configuration_cb(uint8_t index) { + return hid_configuration_descriptor; +} + +const uint8_t * HIDDriver::get_descriptor_device_qualifier_cb() { + return nullptr; +} + +uint16_t HIDDriver::GetJoystickMidValue() { + return HID_JOYSTICK_MID << 8; +} diff --git a/src/drivers/keyboard/KeyboardDriver.cpp b/src/drivers/keyboard/KeyboardDriver.cpp new file mode 100644 index 000000000..4d3a7991f --- /dev/null +++ b/src/drivers/keyboard/KeyboardDriver.cpp @@ -0,0 +1,162 @@ +#include "drivers/keyboard/KeyboardDriver.h" +#include "storagemanager.h" +#include "drivers/shared/driverhelper.h" +#include "drivers/hid/HIDDescriptors.h" + +void KeyboardDriver::initialize() { + keyboardReport = { + .keycode = { 0 }, + .multimedia = 0 + }; + + class_driver = { + #if CFG_TUSB_DEBUG >= 2 + .name = "KEYBOARD", + #endif + .init = hidd_init, + .reset = hidd_reset, + .open = hidd_open, + .control_xfer_cb = hidd_control_xfer_cb, + .xfer_cb = hidd_xfer_cb, + .sof = NULL + }; +} + +uint8_t KeyboardDriver::getModifier(uint8_t code) { + switch (code) { + case HID_KEY_CONTROL_LEFT : return KEYBOARD_MODIFIER_LEFTCTRL ; + case HID_KEY_SHIFT_LEFT : return KEYBOARD_MODIFIER_LEFTSHIFT ; + case HID_KEY_ALT_LEFT : return KEYBOARD_MODIFIER_LEFTALT ; + case HID_KEY_GUI_LEFT : return KEYBOARD_MODIFIER_LEFTGUI ; + case HID_KEY_CONTROL_RIGHT: return KEYBOARD_MODIFIER_RIGHTCTRL ; + case HID_KEY_SHIFT_RIGHT : return KEYBOARD_MODIFIER_RIGHTSHIFT; + case HID_KEY_ALT_RIGHT : return KEYBOARD_MODIFIER_RIGHTALT ; + case HID_KEY_GUI_RIGHT : return KEYBOARD_MODIFIER_RIGHTGUI ; + } + + return 0; +} + +uint8_t KeyboardDriver::getMultimedia(uint8_t code) { + switch (code) { + case KEYBOARD_MULTIMEDIA_NEXT_TRACK : return 0x01; + case KEYBOARD_MULTIMEDIA_PREV_TRACK : return 0x02; + case KEYBOARD_MULTIMEDIA_STOP : return 0x04; + case KEYBOARD_MULTIMEDIA_PLAY_PAUSE : return 0x08; + case KEYBOARD_MULTIMEDIA_MUTE : return 0x10; + case KEYBOARD_MULTIMEDIA_VOLUME_UP : return 0x20; + case KEYBOARD_MULTIMEDIA_VOLUME_DOWN: return 0x40; + } + return 0; +} + + +void KeyboardDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { + const KeyboardMapping& keyboardMapping = Storage::getInstance().getKeyboardMapping(); + releaseAllKeys(); + if(gamepad->pressedUp()) { pressKey(keyboardMapping.keyDpadUp); } + if(gamepad->pressedDown()) { pressKey(keyboardMapping.keyDpadDown); } + if(gamepad->pressedLeft()) { pressKey(keyboardMapping.keyDpadLeft); } + if(gamepad->pressedRight()) { pressKey(keyboardMapping.keyDpadRight); } + if(gamepad->pressedB1()) { pressKey(keyboardMapping.keyButtonB1); } + if(gamepad->pressedB2()) { pressKey(keyboardMapping.keyButtonB2); } + if(gamepad->pressedB3()) { pressKey(keyboardMapping.keyButtonB3); } + if(gamepad->pressedB4()) { pressKey(keyboardMapping.keyButtonB4); } + if(gamepad->pressedL1()) { pressKey(keyboardMapping.keyButtonL1); } + if(gamepad->pressedR1()) { pressKey(keyboardMapping.keyButtonR1); } + if(gamepad->pressedL2()) { pressKey(keyboardMapping.keyButtonL2); } + if(gamepad->pressedR2()) { pressKey(keyboardMapping.keyButtonR2); } + if(gamepad->pressedS1()) { pressKey(keyboardMapping.keyButtonS1); } + if(gamepad->pressedS2()) { pressKey(keyboardMapping.keyButtonS2); } + if(gamepad->pressedL3()) { pressKey(keyboardMapping.keyButtonL3); } + if(gamepad->pressedR3()) { pressKey(keyboardMapping.keyButtonR3); } + if(gamepad->pressedA1()) { pressKey(keyboardMapping.keyButtonA1); } + if(gamepad->pressedA2()) { pressKey(keyboardMapping.keyButtonA2); } + + // Wake up TinyUSB device + if (tud_suspended()) + tud_remote_wakeup(); + + void *keyboard_report_payload; + uint16_t keyboard_report_size; + if ( keyboardReport.reportId == KEYBOARD_KEY_REPORT_ID ) { + keyboard_report_payload = (void *)keyboardReport.keycode; + keyboard_report_size = sizeof(KeyboardReport::keycode); + + } else { + keyboard_report_payload = (void *)&keyboardReport.multimedia; + keyboard_report_size = sizeof(KeyboardReport::multimedia); + } + + // If we had a keycode but now have a multimedia key OR report is different + if (keyboard_report_size != last_report_size || + memcmp(last_report, &keyboardReport, last_report_size) != 0) { + if (tud_hid_ready()) { + if ( tud_hid_report(keyboardReport.reportId, keyboard_report_payload, keyboard_report_size) ) { + memcpy(last_report, keyboard_report_payload, keyboard_report_size); + last_report_size = keyboard_report_size; + } + } + } +} + +void KeyboardDriver::pressKey(uint8_t code) { + if (code > HID_KEY_GUI_RIGHT) { + keyboardReport.reportId = KEYBOARD_MULTIMEDIA_REPORT_ID; + keyboardReport.multimedia = getMultimedia(code); + } else { + keyboardReport.reportId = KEYBOARD_KEY_REPORT_ID; + keyboardReport.keycode[code / 8] |= 1 << (code % 8); + } +} + +void KeyboardDriver::releaseAllKeys(void) { + for (uint8_t i = 0; i < (sizeof(keyboardReport.keycode) / sizeof(keyboardReport.keycode[0])); i++) { + keyboardReport.keycode[i] = 0; + } + keyboardReport.multimedia = 0; +} + +// tud_hid_get_report_cb +uint16_t KeyboardDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { + if ( report_id == KEYBOARD_KEY_REPORT_ID ) { + memcpy(buffer, (void*) keyboardReport.keycode, sizeof(KeyboardReport::keycode)); + return sizeof(KeyboardReport::keycode); + } else { + memcpy(buffer, (void*) &keyboardReport.multimedia, sizeof(KeyboardReport::multimedia)); + return sizeof(KeyboardReport::multimedia); + } +} + +// Only PS4 does anything with set report +void KeyboardDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {} + +// Only XboxOG and Xbox One use vendor control xfer cb +bool KeyboardDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + return false; +} + +const uint16_t * KeyboardDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) { + const char *value = (const char *)keyboard_string_descriptors[index]; + return getStringDescriptor(value, index); // getStringDescriptor returns a static array +} + +const uint8_t * KeyboardDriver::get_descriptor_device_cb() { + return keyboard_device_descriptor; +} + +const uint8_t * KeyboardDriver::get_hid_descriptor_report_cb(uint8_t itf) { + return keyboard_report_descriptor; +} + +const uint8_t * KeyboardDriver::get_descriptor_configuration_cb(uint8_t index) { + return keyboard_configuration_descriptor; +} + +const uint8_t * KeyboardDriver::get_descriptor_device_qualifier_cb() { + return nullptr; +} + +uint16_t KeyboardDriver::GetJoystickMidValue() { + return HID_JOYSTICK_MID << 8; +} diff --git a/src/drivers/mdmini/MDMiniDriver.cpp b/src/drivers/mdmini/MDMiniDriver.cpp new file mode 100644 index 000000000..0537490e6 --- /dev/null +++ b/src/drivers/mdmini/MDMiniDriver.cpp @@ -0,0 +1,100 @@ +#include "drivers/mdmini/MDMiniDriver.h" +#include "drivers/shared/driverhelper.h" + +void MDMiniDriver::initialize() { + mdminiReport = { + .id = 0x01, + .notuse1 = 0x7f, + .notuse2 = 0x7f, + .lx = 0x7f, + .ly = 0x7f, + .buttons = 0x0f, + .notuse3 = 0x00, + }; + + class_driver = { + #if CFG_TUSB_DEBUG >= 2 + .name = "MDMINI", + #endif + .init = hidd_init, + .reset = hidd_reset, + .open = hidd_open, + .control_xfer_cb = hidd_control_xfer_cb, + .xfer_cb = hidd_xfer_cb, + .sof = NULL + }; +} + +void MDMiniDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { + mdminiReport.lx = 0x7f; + mdminiReport.ly = 0x7f; + + if (gamepad->pressedLeft()) { mdminiReport.lx = MDMINI_MASK_LEFT; } + if (gamepad->pressedRight()) { mdminiReport.lx = MDMINI_MASK_RIGHT; } + if (gamepad->pressedUp()) { mdminiReport.ly = MDMINI_MASK_UP; } + if (gamepad->pressedDown()) { mdminiReport.ly = MDMINI_MASK_DOWN; } + + mdminiReport.buttons = 0x0F + | (gamepad->pressedB1() ? MDMINI_MASK_A : 0) + | (gamepad->pressedB2() ? MDMINI_MASK_B : 0) + | (gamepad->pressedB3() ? MDMINI_MASK_X : 0) + | (gamepad->pressedB4() ? MDMINI_MASK_Y : 0) + | (gamepad->pressedR1() ? MDMINI_MASK_Z : 0) + | (gamepad->pressedR2() ? MDMINI_MASK_C : 0) + | (gamepad->pressedS2() ? MDMINI_MASK_START : 0) + | (gamepad->pressedS1() ? MDMINI_MASK_MODE : 0) + ; + + // Wake up TinyUSB device + if (tud_suspended()) + tud_remote_wakeup(); + + void * report = &mdminiReport; + uint16_t report_size = sizeof(mdminiReport); + if (memcmp(last_report, report, report_size) != 0) + { + // HID ready + report sent, copy previous report + if (tud_hid_ready() && tud_hid_report(0, report, report_size) == true ) { + memcpy(last_report, report, report_size); + } + } +} + +// tud_hid_get_report_cb +uint16_t MDMiniDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { + memcpy(buffer, &mdminiReport, sizeof(MDMiniReport)); + return sizeof(MDMiniReport); +} + +// Only PS4 does anything with set report +void MDMiniDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {} + +// Only XboxOG and Xbox One use vendor control xfer cb +bool MDMiniDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + return false; +} + +const uint16_t * MDMiniDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) { + const char *value = (const char *)mdmini_string_descriptors[index]; + return getStringDescriptor(value, index); // getStringDescriptor returns a static array +} + +const uint8_t * MDMiniDriver::get_descriptor_device_cb() { + return mdmini_device_descriptor; +} + +const uint8_t * MDMiniDriver::get_hid_descriptor_report_cb(uint8_t itf) { + return mdmini_report_descriptor; +} + +const uint8_t * MDMiniDriver::get_descriptor_configuration_cb(uint8_t index) { + return mdmini_configuration_descriptor; +} + +const uint8_t * MDMiniDriver::get_descriptor_device_qualifier_cb() { + return nullptr; +} + +uint16_t MDMiniDriver::GetJoystickMidValue() { + return GAMEPAD_JOYSTICK_MID; +} diff --git a/src/drivers/neogeo/NeoGeoDriver.cpp b/src/drivers/neogeo/NeoGeoDriver.cpp new file mode 100644 index 000000000..e6fe2393f --- /dev/null +++ b/src/drivers/neogeo/NeoGeoDriver.cpp @@ -0,0 +1,116 @@ +#include "drivers/neogeo/NeoGeoDriver.h" +#include "drivers/shared/driverhelper.h" + +void NeoGeoDriver::initialize() { + neogeoReport = { + .buttons = 0, + .hat = 0xf, + .const0 = 0x80, + .const1 = 0x80, + .const2 = 0x80, + .const3 = 0x80, + .const4 = 0, + .const5 = 0, + .const6 = 0, + .const7 = 0, + .const8 = 0, + .const9 = 0, + .const10 = 0, + .const11 = 0, + .const12 = 0, + .const13 = 0, + .const14 = 0, + .const15 = 0, + .const16 = 0, + .const17 = 0, + }; + + class_driver = { + #if CFG_TUSB_DEBUG >= 2 + .name = "NEOGEO", + #endif + .init = hidd_init, + .reset = hidd_reset, + .open = hidd_open, + .control_xfer_cb = hidd_control_xfer_cb, + .xfer_cb = hidd_xfer_cb, + .sof = NULL + }; +} + +void NeoGeoDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { + switch (gamepad->state.dpad & GAMEPAD_MASK_DPAD) + { + case GAMEPAD_MASK_UP: neogeoReport.hat = NEOGEO_HAT_UP; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: neogeoReport.hat = NEOGEO_HAT_UPRIGHT; break; + case GAMEPAD_MASK_RIGHT: neogeoReport.hat = NEOGEO_HAT_RIGHT; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: neogeoReport.hat = NEOGEO_HAT_DOWNRIGHT; break; + case GAMEPAD_MASK_DOWN: neogeoReport.hat = NEOGEO_HAT_DOWN; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: neogeoReport.hat = NEOGEO_HAT_DOWNLEFT; break; + case GAMEPAD_MASK_LEFT: neogeoReport.hat = NEOGEO_HAT_LEFT; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: neogeoReport.hat = NEOGEO_HAT_UPLEFT; break; + default: neogeoReport.hat = NEOGEO_HAT_NOTHING; break; + } + + neogeoReport.buttons = 0x0 + | (gamepad->pressedB3() ? NEOGEO_MASK_A : 0) + | (gamepad->pressedB1() ? NEOGEO_MASK_B : 0) + | (gamepad->pressedB4() ? NEOGEO_MASK_C : 0) + | (gamepad->pressedB2() ? NEOGEO_MASK_D : 0) + | (gamepad->pressedS1() ? NEOGEO_MASK_SELECT : 0) + | (gamepad->pressedS2() ? NEOGEO_MASK_START : 0) + ; + + // Wake up TinyUSB device + if (tud_suspended()) + tud_remote_wakeup(); + + void * report = &neogeoReport; + uint16_t report_size = sizeof(neogeoReport); + if (memcmp(last_report, report, report_size) != 0) + { + // HID ready + report sent, copy previous report + if (tud_hid_ready() && tud_hid_report(0, report, report_size) == true ) { + memcpy(last_report, report, report_size); + } + } +} + +// tud_hid_get_report_cb +uint16_t NeoGeoDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { + memcpy(buffer, &neogeoReport, sizeof(NeogeoReport)); + return sizeof(NeogeoReport); +} + +// Only PS4 does anything with set report +void NeoGeoDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {} + +// Only XboxOG and Xbox One use vendor control xfer cb +bool NeoGeoDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + return false; +} + +const uint16_t * NeoGeoDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) { + const char *value = (const char *)neogeo_string_descriptors[index]; + return getStringDescriptor(value, index); // getStringDescriptor returns a static array +} + +const uint8_t * NeoGeoDriver::get_descriptor_device_cb() { + return neogeo_device_descriptor; +} + +const uint8_t * NeoGeoDriver::get_hid_descriptor_report_cb(uint8_t itf) { + return neogeo_report_descriptor; +} + +const uint8_t * NeoGeoDriver::get_descriptor_configuration_cb(uint8_t index) { + return neogeo_configuration_descriptor; +} + +const uint8_t * NeoGeoDriver::get_descriptor_device_qualifier_cb() { + return nullptr; +} + +uint16_t NeoGeoDriver::GetJoystickMidValue() { + return NEOGEO_JOYSTICK_MID << 8; +} diff --git a/lib/TinyUSB_Gamepad/src/webserver_descriptors.h b/src/drivers/net/NetDriver.cpp similarity index 62% rename from lib/TinyUSB_Gamepad/src/webserver_descriptors.h rename to src/drivers/net/NetDriver.cpp index e5958e930..c154fc320 100644 --- a/lib/TinyUSB_Gamepad/src/webserver_descriptors.h +++ b/src/drivers/net/NetDriver.cpp @@ -1,29 +1,7 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ +#include "drivers/net/NetDriver.h" +#include "drivers/shared/driverhelper.h" +#include "class/net/net_device.h" -#include "tusb.h" /* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug. * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC. @@ -64,6 +42,86 @@ enum CONFIG_ID_COUNT }; +void NetDriver::initialize() { + class_driver = { + #if CFG_TUSB_DEBUG >= 2 + .name = "NET", + #endif + .init = netd_init, + .reset = netd_reset, + .open = netd_open, + .control_xfer_cb = netd_control_xfer_cb, + .xfer_cb = netd_xfer_cb, + .sof = NULL, + }; +} + +void NetDriver::process(Gamepad * gamepad, uint8_t * outBuffer) {} + +// tud_hid_get_report_cb +uint16_t NetDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { + return 0; +} + +// Only PS4 does anything with set report +void NetDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {} + +// Only XboxOG and Xbox One use vendor control xfer cb +bool NetDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + return false; +} + +static char const* string_desc_arr [] = +{ + [STRID_LANGID] = (const char[]) { 0x09, 0x04 }, // supported language is English (0x0409) + [STRID_MANUFACTURER] = "TinyUSB", // Manufacturer + [STRID_PRODUCT] = "TinyUSB Device", // Product + [STRID_SERIAL] = "123456", // Serial + [STRID_INTERFACE] = "TinyUSB Network Interface" // Interface Description + + // STRID_MAC index is handled separately +}; + +static uint16_t _desc_str[32]; + +const uint16_t * NetDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) { + (void) langid; + unsigned int chr_count = 0; + if (STRID_LANGID == index) { + memcpy(&_desc_str[1], string_desc_arr[STRID_LANGID], 2); + chr_count = 1; + } + else if (STRID_MAC == index) { + // Convert MAC address into UTF-16 + for (unsigned i=0; i> 4) & 0xf]; + _desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 0) & 0xf]; + } + } else { + // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. + // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors + + if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL; + const char* str = string_desc_arr[index]; + + // Cap at max char + chr_count = (uint8_t) strlen(str); + if ( chr_count > (TU_ARRAY_SIZE(_desc_str) - 1)) chr_count = TU_ARRAY_SIZE(_desc_str) - 1; + + // Convert ASCII string into UTF-16 + for (unsigned int i=0; i> 4) & 0xf]; - _desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 0) & 0xf]; - } - } - else - { - // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. - // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors - - if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL; - - const char* str = string_desc_arr[index]; - - // Cap at max char - chr_count = (uint8_t) strlen(str); - if ( chr_count > (TU_ARRAY_SIZE(_desc_str) - 1)) chr_count = TU_ARRAY_SIZE(_desc_str) - 1; - - // Convert ASCII string into UTF-16 - for (unsigned int i=0; i= 2 + .name = "PCENGINE", + #endif + .init = hidd_init, + .reset = hidd_reset, + .open = hidd_open, + .control_xfer_cb = hidd_control_xfer_cb, + .xfer_cb = hidd_xfer_cb, + .sof = NULL + }; +} + +void PCEngineDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { + switch (gamepad->state.dpad & GAMEPAD_MASK_DPAD) + { + case GAMEPAD_MASK_UP: pcengineReport.hat = PCENGINE_HAT_UP; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: pcengineReport.hat = PCENGINE_HAT_UPRIGHT; break; + case GAMEPAD_MASK_RIGHT: pcengineReport.hat = PCENGINE_HAT_RIGHT; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: pcengineReport.hat = PCENGINE_HAT_DOWNRIGHT; break; + case GAMEPAD_MASK_DOWN: pcengineReport.hat = PCENGINE_HAT_DOWN; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: pcengineReport.hat = PCENGINE_HAT_DOWNLEFT; break; + case GAMEPAD_MASK_LEFT: pcengineReport.hat = PCENGINE_HAT_LEFT; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: pcengineReport.hat = PCENGINE_HAT_UPLEFT; break; + default: pcengineReport.hat = PCENGINE_HAT_NOTHING; break; + } + + pcengineReport.buttons = 0x0 + | (gamepad->pressedB1() ? PCENGINE_MASK_1 : 0) + | (gamepad->pressedB2() ? PCENGINE_MASK_2 : 0) + | (gamepad->pressedS1() ? PCENGINE_MASK_SELECT : 0) + | (gamepad->pressedS2() ? PCENGINE_MASK_RUN : 0) + ; + + // Wake up TinyUSB device + if (tud_suspended()) + tud_remote_wakeup(); + + void * report = &pcengineReport; + uint16_t report_size = sizeof(pcengineReport); + if (memcmp(last_report, report, report_size) != 0) + { + // HID ready + report sent, copy previous report + if (tud_hid_ready() && tud_hid_report(0, report, report_size) == true ) { + memcpy(last_report, report, report_size); + } + } +} + +// tud_hid_get_report_cb +uint16_t PCEngineDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { + memcpy(buffer, &pcengineReport, sizeof(PCEngineReport)); + return sizeof(PCEngineReport); +} + +// Only PS4 does anything with set report +void PCEngineDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {} + +// Only XboxOG and Xbox One use vendor control xfer cb +bool PCEngineDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + return false; +} + +const uint16_t * PCEngineDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) { + const char *value = (const char *)pcengine_string_descriptors[index]; + return getStringDescriptor(value, index); // getStringDescriptor returns a static array +} + +const uint8_t * PCEngineDriver::get_descriptor_device_cb() { + return pcengine_device_descriptor; +} + +const uint8_t * PCEngineDriver::get_hid_descriptor_report_cb(uint8_t itf) { + return pcengine_report_descriptor; +} + +const uint8_t * PCEngineDriver::get_descriptor_configuration_cb(uint8_t index) { + return pcengine_configuration_descriptor; +} + +const uint8_t * PCEngineDriver::get_descriptor_device_qualifier_cb() { + return nullptr; +} + +uint16_t PCEngineDriver::GetJoystickMidValue() { + return GAMEPAD_JOYSTICK_MID; +} diff --git a/src/drivers/ps4/PS4Driver.cpp b/src/drivers/ps4/PS4Driver.cpp new file mode 100644 index 000000000..a66a506ab --- /dev/null +++ b/src/drivers/ps4/PS4Driver.cpp @@ -0,0 +1,312 @@ +#include "drivers/ps4/PS4Driver.h" +#include "drivers/shared/ps4data.h" +#include "drivers/shared/driverhelper.h" +#include "storagemanager.h" +#include "CRC32.h" +#include "mbedtls/error.h" +#include "mbedtls/rsa.h" +#include "mbedtls/sha256.h" +#include +#include "class/hid/hid.h" + +// force a report to be sent every X ms +#define PS4_KEEPALIVE_TIMER 1000 + +void PS4Driver::initialize() { + //touchpadData = { + // .p1 = 0x00, + // .p2 = 0x00 + //}; + + ps4Report = { + .report_id = 0x01, + .left_stick_x = PS4_JOYSTICK_MID, + .left_stick_y = PS4_JOYSTICK_MID, + .right_stick_x = PS4_JOYSTICK_MID, + .right_stick_y = PS4_JOYSTICK_MID, + .dpad = 0x08, + .button_west = 0, .button_south = 0, .button_east = 0, .button_north = 0, + .button_l1 = 0, .button_r1 = 0, .button_l2 = 0, .button_r2 = 0, + .button_select = 0, .button_start = 0, .button_l3 = 0, .button_r3 = 0, .button_home = 0, + .padding = 0, + .mystery = { }, + .touchpad_data = touchpadData, + .mystery_2 = { } + }; + + class_driver = { + #if CFG_TUSB_DEBUG >= 2 + .name = "PS4", + #endif + .init = hidd_init, + .reset = hidd_reset, + .open = hidd_open, + .control_xfer_cb = hidd_control_xfer_cb, + .xfer_cb = hidd_xfer_cb, + .sof = NULL + }; + + // setup PS5 compatibility + GamepadOptions& gamepadOptions = Storage::getInstance().getGamepadOptions(); + PS4Data::getInstance().ps4ControllerType = gamepadOptions.ps4ControllerType; + last_report_counter = 0; + last_axis_counter = 0; + cur_nonce_id = 1; + keep_alive_timer = to_ms_since_boot(get_absolute_time()); + send_nonce_part = 0; +} + +void PS4Driver::process(Gamepad * gamepad, uint8_t * outBuffer) { + const GamepadOptions & options = gamepad->getOptions(); + switch (gamepad->state.dpad & GAMEPAD_MASK_DPAD) + { + case GAMEPAD_MASK_UP: ps4Report.dpad = PS4_HAT_UP; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: ps4Report.dpad = PS4_HAT_UPRIGHT; break; + case GAMEPAD_MASK_RIGHT: ps4Report.dpad = PS4_HAT_RIGHT; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: ps4Report.dpad = PS4_HAT_DOWNRIGHT; break; + case GAMEPAD_MASK_DOWN: ps4Report.dpad = PS4_HAT_DOWN; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: ps4Report.dpad = PS4_HAT_DOWNLEFT; break; + case GAMEPAD_MASK_LEFT: ps4Report.dpad = PS4_HAT_LEFT; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: ps4Report.dpad = PS4_HAT_UPLEFT; break; + default: ps4Report.dpad = PS4_HAT_NOTHING; break; + } + + ps4Report.button_south = gamepad->pressedB1(); + ps4Report.button_east = gamepad->pressedB2(); + ps4Report.button_west = gamepad->pressedB3(); + ps4Report.button_north = gamepad->pressedB4(); + ps4Report.button_l1 = gamepad->pressedL1(); + ps4Report.button_r1 = gamepad->pressedR1(); + ps4Report.button_l2 = gamepad->pressedL2(); + ps4Report.button_r2 = gamepad->pressedR2(); + ps4Report.button_select = options.switchTpShareForDs4 ? gamepad->pressedA2() : gamepad->pressedS1(); + ps4Report.button_start = gamepad->pressedS2(); + ps4Report.button_l3 = gamepad->pressedL3(); + ps4Report.button_r3 = gamepad->pressedR3(); + ps4Report.button_home = gamepad->pressedA1(); + ps4Report.button_touchpad = options.switchTpShareForDs4 ? gamepad->pressedS1() : gamepad->pressedA2(); + + ps4Report.left_stick_x = static_cast(gamepad->state.lx >> 8); + ps4Report.left_stick_y = static_cast(gamepad->state.ly >> 8); + ps4Report.right_stick_x = static_cast(gamepad->state.rx >> 8); + ps4Report.right_stick_y = static_cast(gamepad->state.ry >> 8); + + if (gamepad->hasAnalogTriggers) + { + ps4Report.left_trigger = gamepad->state.lt; + ps4Report.right_trigger = gamepad->state.rt; + } else { + ps4Report.left_trigger = gamepad->pressedL2() ? 0xFF : 0; + ps4Report.right_trigger = gamepad->pressedR2() ? 0xFF : 0; + } + + // set touchpad to nothing + touchpadData.p1.unpressed = 1; + touchpadData.p2.unpressed = 1; + ps4Report.touchpad_data = touchpadData; + + // some games apparently can miss reports, or they rely on official behavior of getting frequent + // updates. we normally only send a report when the value changes; if we increment the counters + // every time we generate the report (every GP2040::run loop), we apparently overburden + // TinyUSB and introduce roughly 1ms of latency. but we want to loop often and report on every + // true update in order to achieve our tight <1ms report timing when we *do* have a different + // report to send. + // the "PS4 Hack" disables the counters so that we only report on changes, but this + // means we never report the same data twice, and games that expected it would get stuck + // inputs. the below code is a compromise: keep the tight report timing, but occasionally change + // the report counter and axis timing values in order to force a changed report --- this should + // eliminate the need for the PS4 Hack, but it's kept here at the moment for A/B testing purposes + if ( !options.ps4ReportHack ) { + uint32_t now = to_ms_since_boot(get_absolute_time()); + if ((now - keep_alive_timer) > PS4_KEEPALIVE_TIMER) { + last_report_counter = (last_report_counter+1) & 0x3F; + ps4Report.report_counter = last_report_counter; // report counter is 6 bits + ps4Report.axis_timing = now; // axis counter is 16 bits + keep_alive_timer = now; + } + } + + // Wake up TinyUSB device + if (tud_suspended()) + tud_remote_wakeup(); + + void * report = &ps4Report; + uint16_t report_size = sizeof(ps4Report); + if (memcmp(last_report, report, report_size) != 0) + { + // HID ready + report sent, copy previous report + if (tud_hid_ready() && tud_hid_report(0, report, report_size) == true ) { + memcpy(last_report, report, report_size); + } + } +} + +// 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, + 0xff, 0x7f, 0x0d, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// Nonce Page Size: 0x38 (56) +// Response Page Size: 0x38 (56) +static constexpr uint8_t output_0xf3[] = { 0x0, 0x38, 0x38, 0, 0, 0, 0 }; + +// tud_hid_get_report_cb +uint16_t PS4Driver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { + if ( report_type != HID_REPORT_TYPE_FEATURE ) { + memcpy(buffer, &ps4Report, sizeof(ps4Report)); + return sizeof(ps4Report); + } + + uint8_t data[64] = {}; + uint32_t crc32; + //ps4_out_buffer[0] = report_id; + switch(report_id) { + // Controller Definition Report + case PS4AuthReport::PS4_DEFINITION: + if (reqlen != sizeof(output_0x03)) { + return -1; + } + memcpy(buffer, output_0x03, reqlen); + buffer[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: + // We send 56 byte chunks back to the PS4, we've already calculated these + data[0] = 0xF1; + data[1] = cur_nonce_id; // nonce_id + data[2] = send_nonce_part; // next_part + data[3] = 0; + + // 56 byte chunks + memcpy(&data[4], &PS4Data::getInstance().ps4_auth_buffer[send_nonce_part*56], 56); + + // calculate the CRC32 of the buffer and write it back + crc32 = CRC32::calculate(data, 60); + memcpy(&data[60], &crc32, sizeof(uint32_t)); + memcpy(buffer, &data[1], 63); // move data over to buffer + if ( (++send_nonce_part) == 19 ) { + PS4Data::getInstance().ps4State = PS4State::no_nonce; + PS4Data::getInstance().authsent = true; + send_nonce_part = 0; + } + return 63; + // Are we ready to sign? + case PS4AuthReport::PS4_GET_SIGNING_STATE: + data[0] = 0xF2; + data[1] = cur_nonce_id; + data[2] = PS4Data::getInstance().ps4State == PS4State::signed_nonce_ready ? 0 : 16; // 0 means auth is ready, 16 means we're still signing + memset(&data[3], 0, 9); + crc32 = CRC32::calculate(data, 12); + memcpy(&data[12], &crc32, sizeof(uint32_t)); + memcpy(buffer, &data[1], 15); // move data over to buffer + return 15; + case PS4AuthReport::PS4_RESET_AUTH: // Reset the Authentication + if (reqlen != sizeof(output_0xf3)) { + return -1; + } + memcpy(buffer, output_0xf3, reqlen); + PS4Data::getInstance().ps4State = PS4State::no_nonce; + return reqlen; + default: + break; + }; + return -1; +} + +// Only PS4 does anything with set report +void PS4Driver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) { + if ( report_type != HID_REPORT_TYPE_FEATURE ) + return; + + uint8_t nonce_id; + uint8_t nonce_page; + uint32_t crc32; + uint8_t sendBuffer[64]; + uint8_t nonce[56]; // max nonce data + uint16_t noncelen; + uint16_t buflen; + + if (report_id == PS4AuthReport::PS4_SET_AUTH_PAYLOAD) { + if (bufsize != 63 ) { + return; + } + + // Setup CRC32 buffer + sendBuffer[0] = report_id; + memcpy(&sendBuffer[1], buffer, bufsize); + buflen = bufsize + 1; + + nonce_id = buffer[0]; + nonce_page = buffer[1]; + // data[2] is zero padding + + crc32 = CRC32::calculate(sendBuffer, buflen-sizeof(uint32_t)); + if ( crc32 != *((unsigned int*)&sendBuffer[buflen-sizeof(uint32_t)])) { + return; // CRC32 failed on set report + } + + // 256 byte nonce, with 56 byte packets leaves 24 extra bytes on the last packet? + 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; + // from 4 to 64 - 4 + } + + memcpy(nonce, &sendBuffer[4], noncelen); + save_nonce(nonce_id, nonce_page, nonce, noncelen); + } +} + +void PS4Driver::save_nonce(uint8_t nonce_id, uint8_t nonce_page, uint8_t * buffer, uint16_t buflen) { + if ( nonce_page != 0 && nonce_id != cur_nonce_id ) { + PS4Data::getInstance().ps4State = PS4State::no_nonce; + return; // setting nonce with mismatched id + } + + memcpy(&PS4Data::getInstance().nonce_buffer[nonce_page*56], buffer, buflen); + if ( nonce_page == 4 ) { + PS4Data::getInstance().ps4State = PS4State::nonce_ready; + } else if ( nonce_page == 0 ) { + cur_nonce_id = nonce_id; + PS4Data::getInstance().ps4State = PS4State::receiving_nonce; + } +} + +// Only XboxOG and Xbox One use vendor control xfer cb +bool PS4Driver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + return false; +} + +const uint16_t * PS4Driver::get_descriptor_string_cb(uint8_t index, uint16_t langid) { + const char *value = (const char *)ps4_string_descriptors[index]; + return getStringDescriptor(value, index); // getStringDescriptor returns a static array +} + +const uint8_t * PS4Driver::get_descriptor_device_cb() { + return ps4_device_descriptor; +} + +const uint8_t * PS4Driver::get_hid_descriptor_report_cb(uint8_t itf) { + return ps4_report_descriptor; +} + +const uint8_t * PS4Driver::get_descriptor_configuration_cb(uint8_t index) { + return ps4_configuration_descriptor; +} + +const uint8_t * PS4Driver::get_descriptor_device_qualifier_cb() { + return nullptr; +} + +uint16_t PS4Driver::GetJoystickMidValue() { + return PS4_JOYSTICK_MID << 8; +} diff --git a/src/drivers/psclassic/PSClassicDriver.cpp b/src/drivers/psclassic/PSClassicDriver.cpp new file mode 100644 index 000000000..aa6baea46 --- /dev/null +++ b/src/drivers/psclassic/PSClassicDriver.cpp @@ -0,0 +1,102 @@ +#include "drivers/psclassic/PSClassicDriver.h" +#include "drivers/shared/driverhelper.h" + +void PSClassicDriver::initialize() { + psClassicReport = { + .buttons = 0x0014 + }; + + class_driver = { + #if CFG_TUSB_DEBUG >= 2 + .name = "PSCLASSIC", + #endif + .init = hidd_init, + .reset = hidd_reset, + .open = hidd_open, + .control_xfer_cb = hidd_control_xfer_cb, + .xfer_cb = hidd_xfer_cb, + .sof = NULL + }; +} + +void PSClassicDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { + psClassicReport.buttons = PSCLASSIC_MASK_CENTER; + + switch (gamepad->state.dpad & GAMEPAD_MASK_DPAD) + { + case GAMEPAD_MASK_UP: psClassicReport.buttons = PSCLASSIC_MASK_UP; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: psClassicReport.buttons = PSCLASSIC_MASK_UP_RIGHT; break; + case GAMEPAD_MASK_RIGHT: psClassicReport.buttons = PSCLASSIC_MASK_RIGHT; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: psClassicReport.buttons = PSCLASSIC_MASK_DOWN_RIGHT; break; + case GAMEPAD_MASK_DOWN: psClassicReport.buttons = PSCLASSIC_MASK_DOWN; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: psClassicReport.buttons = PSCLASSIC_MASK_DOWN_LEFT; break; + case GAMEPAD_MASK_LEFT: psClassicReport.buttons = PSCLASSIC_MASK_LEFT; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: psClassicReport.buttons = PSCLASSIC_MASK_UP_LEFT; break; + default: psClassicReport.buttons = PSCLASSIC_MASK_CENTER; break; + } + + psClassicReport.buttons |= + (gamepad->pressedS2() ? PSCLASSIC_MASK_SELECT : 0) + | (gamepad->pressedS1() ? PSCLASSIC_MASK_START : 0) + | (gamepad->pressedB1() ? PSCLASSIC_MASK_CROSS : 0) + | (gamepad->pressedB2() ? PSCLASSIC_MASK_CIRCLE : 0) + | (gamepad->pressedB3() ? PSCLASSIC_MASK_SQUARE : 0) + | (gamepad->pressedB4() ? PSCLASSIC_MASK_TRIANGLE : 0) + | (gamepad->pressedL1() ? PSCLASSIC_MASK_L1 : 0) + | (gamepad->pressedR1() ? PSCLASSIC_MASK_R1 : 0) + | (gamepad->pressedL2() ? PSCLASSIC_MASK_L2 : 0) + | (gamepad->pressedR2() ? PSCLASSIC_MASK_R2 : 0) + ; + + // Wake up TinyUSB device + if (tud_suspended()) + tud_remote_wakeup(); + + void * report = &psClassicReport; + uint16_t report_size = sizeof(psClassicReport); + if (memcmp(last_report, report, report_size) != 0) { + // HID ready + report sent, copy previous report + if (tud_hid_ready() && tud_hid_report(0, report, report_size) == true ) { + memcpy(last_report, report, report_size); + } + } +} + +// tud_hid_get_report_cb +uint16_t PSClassicDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { + memcpy(buffer, &psClassicReport, sizeof(PSClassicReport)); + return sizeof(PSClassicReport); +} + +// Only PS4 does anything with set report +void PSClassicDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {} + +// Only XboxOG and Xbox One use vendor control xfer cb +bool PSClassicDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + return false; +} + +const uint16_t * PSClassicDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) { + const char *value = (const char *)psclassic_string_descriptors[index]; + return getStringDescriptor(value, index); // getStringDescriptor returns a static array +} + +const uint8_t * PSClassicDriver::get_descriptor_device_cb() { + return psclassic_device_descriptor; +} + +const uint8_t * PSClassicDriver::get_hid_descriptor_report_cb(uint8_t itf) { + return psclassic_report_descriptor; +} + +const uint8_t * PSClassicDriver::get_descriptor_configuration_cb(uint8_t index) { + return psclassic_configuration_descriptor; +} + +const uint8_t * PSClassicDriver::get_descriptor_device_qualifier_cb() { + return nullptr; +} + +uint16_t PSClassicDriver::GetJoystickMidValue() { + return GAMEPAD_JOYSTICK_MID; +} diff --git a/lib/TinyUSB_Gamepad/src/xgip_protocol.cpp b/src/drivers/shared/xgip_protocol.cpp similarity index 99% rename from lib/TinyUSB_Gamepad/src/xgip_protocol.cpp rename to src/drivers/shared/xgip_protocol.cpp index 68a155eba..4f205f897 100644 --- a/lib/TinyUSB_Gamepad/src/xgip_protocol.cpp +++ b/src/drivers/shared/xgip_protocol.cpp @@ -23,8 +23,8 @@ * */ -#include "xgip_protocol.h" -#include "gamepad/descriptors/XBOneDescriptors.h" +#include "drivers/xbone/XBOneDescriptors.h" +#include "drivers/shared/xgip_protocol.h" // Default Constructor XGIPProtocol::XGIPProtocol() { diff --git a/lib/TinyUSB_Gamepad/src/xinput_host.cpp b/src/drivers/shared/xinput_host.cpp similarity index 99% rename from lib/TinyUSB_Gamepad/src/xinput_host.cpp rename to src/drivers/shared/xinput_host.cpp index 8dc2e7049..b06f7ca3e 100644 --- a/lib/TinyUSB_Gamepad/src/xinput_host.cpp +++ b/src/drivers/shared/xinput_host.cpp @@ -31,7 +31,7 @@ #include "host/usbh.h" #include "host/usbh_pvt.h" -#include "xinput_host.h" +#include "drivers/shared/xinput_host.h" //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF diff --git a/src/drivers/switch/SwitchDriver.cpp b/src/drivers/switch/SwitchDriver.cpp new file mode 100644 index 000000000..8a50e6c34 --- /dev/null +++ b/src/drivers/switch/SwitchDriver.cpp @@ -0,0 +1,115 @@ +#include "drivers/switch/SwitchDriver.h" +#include "drivers/shared/driverhelper.h" + +void SwitchDriver::initialize() { + switchReport = { + .buttons = 0, + .hat = SWITCH_HAT_NOTHING, + .lx = SWITCH_JOYSTICK_MID, + .ly = SWITCH_JOYSTICK_MID, + .rx = SWITCH_JOYSTICK_MID, + .ry = SWITCH_JOYSTICK_MID, + .vendor = 0, + }; + + class_driver = { + #if CFG_TUSB_DEBUG >= 2 + .name = "SWITCH", + #endif + .init = hidd_init, + .reset = hidd_reset, + .open = hidd_open, + .control_xfer_cb = hidd_control_xfer_cb, + .xfer_cb = hidd_xfer_cb, + .sof = NULL + }; +} + +void SwitchDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { + switch (gamepad->state.dpad & GAMEPAD_MASK_DPAD) + { + case GAMEPAD_MASK_UP: switchReport.hat = SWITCH_HAT_UP; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: switchReport.hat = SWITCH_HAT_UPRIGHT; break; + case GAMEPAD_MASK_RIGHT: switchReport.hat = SWITCH_HAT_RIGHT; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: switchReport.hat = SWITCH_HAT_DOWNRIGHT; break; + case GAMEPAD_MASK_DOWN: switchReport.hat = SWITCH_HAT_DOWN; break; + case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: switchReport.hat = SWITCH_HAT_DOWNLEFT; break; + case GAMEPAD_MASK_LEFT: switchReport.hat = SWITCH_HAT_LEFT; break; + case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: switchReport.hat = SWITCH_HAT_UPLEFT; break; + default: switchReport.hat = SWITCH_HAT_NOTHING; break; + } + + switchReport.buttons = 0 + | (gamepad->pressedB1() ? SWITCH_MASK_B : 0) + | (gamepad->pressedB2() ? SWITCH_MASK_A : 0) + | (gamepad->pressedB3() ? SWITCH_MASK_Y : 0) + | (gamepad->pressedB4() ? SWITCH_MASK_X : 0) + | (gamepad->pressedL1() ? SWITCH_MASK_L : 0) + | (gamepad->pressedR1() ? SWITCH_MASK_R : 0) + | (gamepad->pressedL2() ? SWITCH_MASK_ZL : 0) + | (gamepad->pressedR2() ? SWITCH_MASK_ZR : 0) + | (gamepad->pressedS1() ? SWITCH_MASK_MINUS : 0) + | (gamepad->pressedS2() ? SWITCH_MASK_PLUS : 0) + | (gamepad->pressedL3() ? SWITCH_MASK_L3 : 0) + | (gamepad->pressedR3() ? SWITCH_MASK_R3 : 0) + | (gamepad->pressedA1() ? SWITCH_MASK_HOME : 0) + | (gamepad->pressedA2() ? SWITCH_MASK_CAPTURE : 0) + ; + + switchReport.lx = static_cast(gamepad->state.lx >> 8); + switchReport.ly = static_cast(gamepad->state.ly >> 8); + switchReport.rx = static_cast(gamepad->state.rx >> 8); + switchReport.ry = static_cast(gamepad->state.ry >> 8); + + // Wake up TinyUSB device + if (tud_suspended()) + tud_remote_wakeup(); + + void * report = &switchReport; + uint16_t report_size = sizeof(switchReport); + if (memcmp(last_report, report, report_size) != 0) { + // HID ready + report sent, copy previous report + if (tud_hid_ready() && tud_hid_report(0, report, report_size) == true ) { + memcpy(last_report, report, report_size); + } + } +} + +// tud_hid_get_report_cb +uint16_t SwitchDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { + memcpy(buffer, &switchReport, sizeof(SwitchReport)); + return sizeof(SwitchReport); +} + +// Only PS4 does anything with set report +void SwitchDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {} + +// Only XboxOG and Xbox One use vendor control xfer cb +bool SwitchDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + return false; +} + +const uint16_t * SwitchDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) { + const char *value = (const char *)switch_string_descriptors[index]; + return getStringDescriptor(value, index); // getStringDescriptor returns a static array +} + +const uint8_t * SwitchDriver::get_descriptor_device_cb() { + return switch_device_descriptor; +} + +const uint8_t * SwitchDriver::get_hid_descriptor_report_cb(uint8_t itf) { + return switch_report_descriptor; +} + +const uint8_t * SwitchDriver::get_descriptor_configuration_cb(uint8_t index) { + return switch_configuration_descriptor; +} + +const uint8_t * SwitchDriver::get_descriptor_device_qualifier_cb() { + return nullptr; +} + +uint16_t SwitchDriver::GetJoystickMidValue() { + return SWITCH_JOYSTICK_MID << 8; +} diff --git a/lib/TinyUSB_Gamepad/src/xbone_driver.cpp b/src/drivers/xbone/XBOneDriver.cpp similarity index 59% rename from lib/TinyUSB_Gamepad/src/xbone_driver.cpp rename to src/drivers/xbone/XBOneDriver.cpp index 19a862590..15ae1f546 100644 --- a/lib/TinyUSB_Gamepad/src/xbone_driver.cpp +++ b/src/drivers/xbone/XBOneDriver.cpp @@ -1,18 +1,8 @@ -/* - * SPDX-License-Identifier: MIT - * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) - */ +#include "drivers/xbone/XBOneDriver.h" +#include "drivers/shared/driverhelper.h" +#include "drivers/shared/xbonedata.h" -#include "xbone_driver.h" -#include "gamepad/descriptors/XBOneDescriptors.h" - -#include "system.h" - -#define ENDPOINT_SIZE 64 - -#define CFG_TUD_XBONE 8 -#define CFG_TUD_XINPUT_TX_BUFSIZE 64 -#define CFG_TUD_XINPUT_RX_BUFSIZE 64 +#define XBONE_KEEPALIVE_TIMER 15000 #define USB_SETUP_DEVICE_TO_HOST 0x80 #define USB_SETUP_HOST_TO_DEVICE 0x00 @@ -29,44 +19,10 @@ #define DESC_EXTENDED_PROPERTIES_DESCRIPTOR 0x0005 #define REQ_GET_XGIP_HEADER 0x90 -static bool waiting_ack=false; -static uint32_t waiting_ack_timeout=0; -uint8_t xbone_out_buffer[XBONE_OUT_SIZE] = {}; -static uint32_t timer_wait_for_announce = 0; -static uint32_t xbox_one_powered_on = false; - // Sent report queue every 15 milliseconds static uint32_t lastReportQueueSent = 0; #define REPORT_QUEUE_INTERVAL 15 -// Report Queue for big report sizes from dongle -#include -typedef struct { - uint8_t report[XBONE_ENDPOINT_SIZE]; - uint16_t len; -} report_queue_t; - -static std::queue report_queue; - -#define XGIP_ACK_WAIT_TIMEOUT 2000 - -typedef struct { - uint8_t itf_num; - uint8_t ep_in; - uint8_t ep_out; // optional Out endpoint - CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_XINPUT_TX_BUFSIZE]; - CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_XINPUT_RX_BUFSIZE]; -} xboned_interface_t; - -CFG_TUSB_MEM_SECTION static xboned_interface_t _xboned_itf[CFG_TUD_XBONE]; -static inline uint8_t get_index_by_itfnum(uint8_t itf_num) { - for (uint8_t i = 0; i < CFG_TUD_XBONE; i++) { - if (itf_num == _xboned_itf[i].itf_num) return i; - } - - return 0xFF; -} - typedef enum { IDLE_STATE = 0, READY_ANNOUNCE, @@ -77,8 +33,14 @@ typedef enum { static XboxOneDriverState xboneDriverState; -static XGIPProtocol outgoingXGIP; -static XGIPProtocol incomingXGIP; +static uint8_t xb1_guide_on[] = { 0x01, 0x5b }; +static uint8_t xb1_guide_off[] = { 0x00, 0x5b }; + +static uint8_t xboneIdle[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + // Check if Auth is completed (start is 0x01, 0x01, and invalid is 0x01, 0x07) const uint8_t authReady[] = {0x01, 0x00}; @@ -119,6 +81,39 @@ const uint8_t xboxOneDescriptor[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static bool waiting_ack = false; +static uint32_t waiting_ack_timeout=0; +static uint32_t timer_wait_for_announce; +static bool xbox_one_powered_on; + +// Report Queue for big report sizes from dongle +#include +typedef struct { + uint8_t report[XBONE_ENDPOINT_SIZE]; + uint16_t len; +} report_queue_t; + +static std::queue report_queue; + +#define XGIP_ACK_WAIT_TIMEOUT 2000 + +#define CFG_TUD_XBONE 8 +#define CFG_TUD_XINPUT_TX_BUFSIZE 64 +#define CFG_TUD_XINPUT_RX_BUFSIZE 64 + +typedef struct { + uint8_t itf_num; + uint8_t ep_in; + uint8_t ep_out; // optional Out endpoint + CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_XINPUT_TX_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_XINPUT_RX_BUFSIZE]; +} xboned_interface_t; + +CFG_TUSB_MEM_SECTION static xboned_interface_t _xboned_itf[CFG_TUD_XBONE]; + +static XGIPProtocol outgoingXGIP; +static XGIPProtocol incomingXGIP; + // Windows requires a Descriptor Single for Xbox One typedef struct { uint32_t TotalLength; @@ -145,18 +140,6 @@ const OS_COMPATIBLE_ID_DESCRIPTOR_SINGLE DevCompatIDsOne = { Reserved3 : {0} }; -void queue_xbone_report(void *report, uint16_t report_size) { - report_queue_t item; - memcpy(item.report, report, report_size); - item.len = report_size; - report_queue.push(item); -} - -void set_ack_wait() { - waiting_ack = true; - waiting_ack_timeout = to_ms_since_boot(get_absolute_time()); // 2 second time-out -} - static void xbone_reset(uint8_t rhport) { (void)rhport; timer_wait_for_announce = to_ms_since_boot(get_absolute_time()); @@ -174,6 +157,7 @@ static void xbone_init(void) { xbone_reset(TUD_OPT_RHPORT); } + static uint16_t xbone_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { uint16_t drv_len = 0; if (TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass) { @@ -216,14 +200,11 @@ static uint16_t xbone_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc return drv_len; } -static bool xbone_device_control_request(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { - return true; -} - -static bool xbone_control_complete(uint8_t rhport, tusb_control_request_t const *request) { - (void)rhport; - (void)request; - return true; +static void queue_xbone_report(void *report, uint16_t report_size) { + report_queue_t item; + memcpy(item.report, report, report_size); + item.len = report_size; + report_queue.push(item); } bool xbone_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, @@ -276,33 +257,171 @@ bool xbone_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, return true; } -// DevCompatIDsOne sends back XGIP10 data when requested by Windows -bool xbone_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, - tusb_control_request_t const *request) { - uint8_t buf[255]; +void XBOneDriver::initialize() { + xboneReport = { + .sync = 0, + .guide = 0, + .start = 0, + .back = 0, + .a = 0, + .b = 0, + .x = 0, + .y = 0, + .dpadUp = 0, + .dpadDown = 0, + .dpadLeft = 0, + .dpadRight = 0, + .leftShoulder = 0, + .rightShoulder = 0, + .leftThumbClick = 0, + .rightThumbClick = 0, + .leftTrigger = 0, + .rightTrigger = 0, + .leftStickX = GAMEPAD_JOYSTICK_MID, + .leftStickY = GAMEPAD_JOYSTICK_MID, + .rightStickX = GAMEPAD_JOYSTICK_MID, + .rightStickY = GAMEPAD_JOYSTICK_MID, + .reserved = {} + }; + class_driver = { +#if CFG_TUSB_DEBUG >= 2 + .name = "XBONE", +#endif + .init = xbone_init, + .reset = xbone_reset, + .open = xbone_open, + .control_xfer_cb = tud_vendor_control_xfer_cb, + .xfer_cb = xbone_xfer_cb, + .sof = NULL + }; + + keep_alive_timer = to_ms_since_boot(get_absolute_time()); + keep_alive_sequence = 1; // sequence starts at 1? + virtual_keycode_sequence = 0; + xb1_guide_pressed = false; + last_report_counter = 0; +} + +void XBOneDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { + uint16_t xboneReportSize = 0; - // nothing to with DATA & ACK stage - if (stage != CONTROL_STAGE_SETUP) - return true; + // Perform update + this->update(); - if (request->bmRequestType_bit.direction == TUSB_DIR_IN) { // This is where we should be - uint16_t len = request->wLength; - if ( request->bmRequestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_VENDOR) && request->bRequest == REQ_GET_OS_FEATURE_DESCRIPTOR && - request->wIndex == DESC_EXTENDED_COMPATIBLE_ID_DESCRIPTOR) { - memcpy(buf, &DevCompatIDsOne, len); + // No input until auth is ready + if ( XboxOneData::getInstance().getAuthCompleted() == false ) { + GIP_HEADER((&xboneReport), GIP_INPUT_REPORT, false, last_report_counter); + memcpy((void*)&((uint8_t*)&xboneReport)[4], xboneIdle, sizeof(xboneIdle)); + xboneReportSize = sizeof(XboxOneGamepad_Data_t); + send_xbone_usb((uint8_t*)&xboneReport, xboneReportSize); + return; + } + + uint32_t now = to_ms_since_boot(get_absolute_time()); + // Send Keep-Alive every 15 seconds (keep_alive_timer updates if send is successful) + if ( (now - keep_alive_timer) > XBONE_KEEPALIVE_TIMER) { + memset(&xboneReport.Header, 0, sizeof(GipHeader_t)); + GIP_HEADER((&xboneReport), GIP_KEEPALIVE, 1, keep_alive_sequence); + xboneReport.Header.length = 4; + static uint8_t keepAlive[] = { 0x80, 0x00, 0x00, 0x00 }; + memcpy(&((uint8_t*)&xboneReport)[4], &keepAlive, sizeof(keepAlive)); + xboneReportSize = sizeof(GipHeader_t) + sizeof(keepAlive); + // If successful, update our keep alive timer/sequence + if ( send_xbone_usb((uint8_t*)&xboneReport, xboneReportSize) == true ) { + keep_alive_timer = to_ms_since_boot(get_absolute_time()); + keep_alive_sequence++; // will rollover + if ( keep_alive_sequence == 0 ) + keep_alive_sequence = 1; + } + return; + } + + // Virtual Keycode for Guide Button + if ( gamepad->pressedA1() || xb1_guide_pressed == true ) { + // In a change-state + if ( (gamepad->pressedA1() && xb1_guide_pressed == false) || + (!gamepad->pressedA1() && xb1_guide_pressed == true)) { + virtual_keycode_sequence++; // will rollover + if ( virtual_keycode_sequence == 0 ) + virtual_keycode_sequence = 1; + GIP_HEADER((&xboneReport), GIP_VIRTUAL_KEYCODE, 1, virtual_keycode_sequence); + xboneReport.Header.length = sizeof(xb1_guide_on); + if ( gamepad->pressedA1() ) { + xb1_guide_pressed = true; + memcpy(&((uint8_t*)&xboneReport)[4], &xb1_guide_on, sizeof(xb1_guide_on)); + } else { + xb1_guide_pressed = false; + memcpy(&((uint8_t*)&xboneReport)[4], &xb1_guide_off, sizeof(xb1_guide_off)); + } + } + xboneReportSize = sizeof(GipHeader_t) + sizeof(xb1_guide_on); + send_xbone_usb((uint8_t*)&xboneReport, xboneReportSize); + return; + } + + // Only change xbox one input report if we have different inputs! + XboxOneGamepad_Data_t newInputReport; + + // This is due to our tusb_driver.cpp checking memcmp(last_report, report, size) + memset(&newInputReport, 0, sizeof(XboxOneGamepad_Data_t)); + GIP_HEADER((&newInputReport), GIP_INPUT_REPORT, false, last_report_counter); + + newInputReport.a = gamepad->pressedB1(); + newInputReport.b = gamepad->pressedB2(); + newInputReport.x = gamepad->pressedB3(); + newInputReport.y = gamepad->pressedB4(); + newInputReport.leftShoulder = gamepad->pressedL1(); + newInputReport.rightShoulder = gamepad->pressedR1(); + newInputReport.leftThumbClick = gamepad->pressedL3(); + newInputReport.rightThumbClick = gamepad->pressedR3(); + newInputReport.start = gamepad->pressedS2(); + newInputReport.back = gamepad->pressedS1(); + newInputReport.guide = 0; // always 0 + newInputReport.sync = 0; + newInputReport.dpadUp = gamepad->pressedUp(); + newInputReport.dpadDown = gamepad->pressedDown(); + newInputReport.dpadLeft = gamepad->pressedLeft(); + newInputReport.dpadRight = gamepad->pressedRight(); + + newInputReport.leftStickX = static_cast(gamepad->state.lx) + INT16_MIN; + newInputReport.leftStickY = static_cast(~gamepad->state.ly) + INT16_MIN; + newInputReport.rightStickX = static_cast(gamepad->state.rx) + INT16_MIN; + newInputReport.rightStickY = static_cast(~gamepad->state.ry) + INT16_MIN; + + if (gamepad->hasAnalogTriggers) + { + newInputReport.leftTrigger = gamepad->pressedL2() ? 0x03FF : gamepad->state.lt; + newInputReport.rightTrigger = gamepad->pressedR2() ? 0x03FF : gamepad->state.rt; + } + else + { + newInputReport.leftTrigger = gamepad->pressedL2() ? 0x03FF : 0; + newInputReport.rightTrigger = gamepad->pressedR2() ? 0x03FF : 0; + } + + // We changed inputs since generating our last report, increment last report counter (but don't update until success) + if ( memcmp(&last_report[4], &((uint8_t*)&newInputReport)[4], sizeof(XboxOneGamepad_Data_t)-4) != 0 ) { + xboneReportSize = sizeof(XboxOneGamepad_Data_t); + memcpy(&xboneReport, &newInputReport, xboneReportSize); + xboneReport.Header.sequence = last_report_counter + 1; + if ( xboneReport.Header.sequence == 0 ) + xboneReport.Header.sequence = 1; + + // Successfully sent report, actually increment last report counter! + if ( send_xbone_usb((uint8_t*)&xboneReport, xboneReportSize) == true ) { + if ( memcmp(&last_report[4], &((uint8_t*)&xboneReport)[4], xboneReportSize-4) != 0) { + last_report_counter++; + if (last_report_counter == 0) + last_report_counter = 1; + memcpy(last_report, &xboneReport, xboneReportSize); + } } - tud_control_xfer(rhport, request, (void*)buf, len); - } else { - tud_control_xfer(rhport, request, (void*)buf, request->wLength); } - return true; } -// Send a packet to our Xbox One driver end-point -bool send_xbone_report(void *report, uint16_t report_size) { - uint8_t itf = 0; +bool XBOneDriver::send_xbone_usb(uint8_t const *report, uint16_t report_size) { + uint8_t itf = 0; xboned_interface_t *p_xbone = _xboned_itf; - bool ret = false; for (;; itf++, p_xbone++) { if (itf >= TU_ARRAY_SIZE(_xboned_itf)) { return false; @@ -314,34 +433,83 @@ bool send_xbone_report(void *report, uint16_t report_size) { (p_xbone->ep_in != 0) && (!usbd_edpt_busy(TUD_OPT_RHPORT, p_xbone->ep_in))) // Is the IN endpoint available? { usbd_edpt_claim(0, p_xbone->ep_in); // Take control of IN endpoint - ret = usbd_edpt_xfer(0, p_xbone->ep_in, (uint8_t *)report, report_size); // Send report buffer + usbd_edpt_xfer(0, p_xbone->ep_in, (uint8_t *)report, report_size); // Send report buffer usbd_edpt_release(0, p_xbone->ep_in); // Release control of IN endpoint + + // we successfully sent the report + return true; } + return false; +} - return ret; +// tud_hid_get_report_cb +uint16_t XBOneDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { + memcpy(buffer, &xboneReport, sizeof(xboneReport)); + return sizeof(xboneReport); } -const usbd_class_driver_t xbone_driver = - { -#if CFG_TUSB_DEBUG >= 2 - .name = "XBONE", -#endif - .init = xbone_init, - .reset = xbone_reset, - .open = xbone_open, - .control_xfer_cb = tud_vendor_control_xfer_cb, - .xfer_cb = xbone_xfer_cb, - .sof = NULL}; +// Only PS4 does anything with set report +void XBOneDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {} + +// Only XboxOG and Xbox One use vendor control xfer cb +bool XBOneDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + uint8_t buf[255]; + + // nothing to with DATA & ACK stage + if (stage != CONTROL_STAGE_SETUP) + return true; + + if (request->bmRequestType_bit.direction == TUSB_DIR_IN) { // This is where we should be + uint16_t len = request->wLength; + if ( request->bmRequestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_RECIPIENT_DEVICE | USB_SETUP_TYPE_VENDOR) && request->bRequest == REQ_GET_OS_FEATURE_DESCRIPTOR && + request->wIndex == DESC_EXTENDED_COMPATIBLE_ID_DESCRIPTOR) { + memcpy(buf, &DevCompatIDsOne, len); + } + tud_control_xfer(rhport, request, (void*)buf, len); + } else { + tud_control_xfer(rhport, request, (void*)buf, request->wLength); + } + return true; +} + +const uint16_t * XBOneDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) { + const char *value = (const char *)xbone_string_descriptors[index]; + return getStringDescriptor(value, index); // getStringDescriptor returns a static array +} + +const uint8_t * XBOneDriver::get_descriptor_device_cb() { + return xbone_device_descriptor; +} + +const uint8_t * XBOneDriver::get_hid_descriptor_report_cb(uint8_t itf) { + return nullptr; +} + +const uint8_t * XBOneDriver::get_descriptor_configuration_cb(uint8_t index) { + return xbone_configuration_descriptor; +} + +const uint8_t * XBOneDriver::get_descriptor_device_qualifier_cb() { + return xbone_device_qualifier; +} -// Update our Xbox One driver as things need to happen under-the-hood -void xbone_driver_update() { +void XBOneDriver::set_ack_wait() { + waiting_ack = true; + waiting_ack_timeout = to_ms_since_boot(get_absolute_time()); // 2 second time-out +} + +void XBOneDriver::update() { uint32_t now = to_ms_since_boot(get_absolute_time()); if ( !report_queue.empty() ) { if ( (now - lastReportQueueSent) > REPORT_QUEUE_INTERVAL ) { - if ( send_xbone_report(report_queue.front().report, report_queue.front().len) ) { - report_queue.pop(); + report_queue_t & report_front = report_queue.front(); + uint16_t xboneReportSize = report_front.len; + if ( send_xbone_usb(report_front.report, xboneReportSize) ) { lastReportQueueSent = now; + // Set last report queue sent to our report sent by the queue + memcpy(last_report, &report_front.report, xboneReportSize); + report_queue.pop(); } else { sleep_ms(REPORT_QUEUE_INTERVAL); } @@ -399,3 +567,7 @@ void xbone_driver_update() { break; }; } + +uint16_t XBOneDriver::GetJoystickMidValue() { + return GAMEPAD_JOYSTICK_MID; +} diff --git a/src/drivers/xboxog/XboxOriginalDriver.cpp b/src/drivers/xboxog/XboxOriginalDriver.cpp new file mode 100644 index 000000000..853d9b02e --- /dev/null +++ b/src/drivers/xboxog/XboxOriginalDriver.cpp @@ -0,0 +1,110 @@ +#include "drivers/xboxog/XboxOriginalDriver.h" +#include "drivers/xboxog/xid/xid.h" +#include "drivers/shared/driverhelper.h" + +void XboxOriginalDriver::initialize() { + xboxOriginalReport = { + .dButtons = 0, + .A = 0, + .B = 0, + .X = 0, + .Y = 0, + .BLACK = 0, + .WHITE = 0, + .L = 0, + .R = 0, + .leftStickX = 0, + .leftStickY = 0, + .rightStickX = 0, + .rightStickY = 0, + }; + + // Copy XID driver to local class driver + memcpy(&class_driver, xid_get_driver(), sizeof(usbd_class_driver_t)); +} + +void XboxOriginalDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { + // digital buttons + xboxOriginalReport.dButtons = 0 + | (gamepad->pressedUp() ? XID_DUP : 0) + | (gamepad->pressedDown() ? XID_DDOWN : 0) + | (gamepad->pressedLeft() ? XID_DLEFT : 0) + | (gamepad->pressedRight() ? XID_DRIGHT : 0) + | (gamepad->pressedS2() ? XID_START : 0) + | (gamepad->pressedS1() ? XID_BACK : 0) + | (gamepad->pressedL3() ? XID_LS : 0) + | (gamepad->pressedR3() ? XID_RS : 0) + ; + + // analog buttons - convert to digital + xboxOriginalReport.A = (gamepad->pressedB1() ? 0xFF : 0); + xboxOriginalReport.B = (gamepad->pressedB2() ? 0xFF : 0); + xboxOriginalReport.X = (gamepad->pressedB3() ? 0xFF : 0); + xboxOriginalReport.Y = (gamepad->pressedB4() ? 0xFF : 0); + xboxOriginalReport.BLACK = (gamepad->pressedL1() ? 0xFF : 0); + xboxOriginalReport.WHITE = (gamepad->pressedR1() ? 0xFF : 0); + + // analog triggers + if (gamepad->hasAnalogTriggers) { + xboxOriginalReport.L = gamepad->pressedL2() ? 0xFF : gamepad->state.lt; + xboxOriginalReport.R = gamepad->pressedR2() ? 0xFF : gamepad->state.rt; + } else { + xboxOriginalReport.L = gamepad->pressedL2() ? 0xFF : 0; + xboxOriginalReport.R = gamepad->pressedR2() ? 0xFF : 0; + } + + // analog sticks + xboxOriginalReport.leftStickX = static_cast(gamepad->state.lx) + INT16_MIN; + xboxOriginalReport.leftStickY = static_cast(~gamepad->state.ly) + INT16_MIN; + xboxOriginalReport.rightStickX = static_cast(gamepad->state.rx) + INT16_MIN; + xboxOriginalReport.rightStickY = static_cast(~gamepad->state.ry) + INT16_MIN; + + if (tud_suspended()) + tud_remote_wakeup(); + + uint8_t xIndex = xid_get_index_by_type(0, XID_TYPE_GAMECONTROLLER); + if (memcmp(last_report, &xboxOriginalReport, sizeof(XboxOriginalReport)) != 0) { + if ( xid_send_report(xIndex, &xboxOriginalReport, sizeof(XboxOriginalReport)) == true ) { + memcpy(last_report, &xboxOriginalReport, sizeof(XboxOriginalReport)); + } + } +} + +// tud_hid_get_report_cb +uint16_t XboxOriginalDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { + memcpy(buffer, &xboxOriginalReport, sizeof(XboxOriginalReport)); + return sizeof(XboxOriginalReport); +} + +// Only PS4 does anything with set report +void XboxOriginalDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {} + +// Only XboxOG and Xbox One use vendor control xfer cb +bool XboxOriginalDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + return class_driver.control_xfer_cb(rhport, stage, request); +} + +const uint16_t * XboxOriginalDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) { + const char *value = (const char *)xboxoriginal_string_descriptors[index]; + return getStringDescriptor(value, index); // getStringDescriptor returns a static array +} + +const uint8_t * XboxOriginalDriver::get_descriptor_device_cb() { + return xboxoriginal_device_descriptor; +} + +const uint8_t * XboxOriginalDriver::get_hid_descriptor_report_cb(uint8_t itf) { + return nullptr; +} + +const uint8_t * XboxOriginalDriver::get_descriptor_configuration_cb(uint8_t index) { + return xboxoriginal_configuration_descriptor; +} + +const uint8_t * XboxOriginalDriver::get_descriptor_device_qualifier_cb() { + return nullptr; +} + +uint16_t XboxOriginalDriver::GetJoystickMidValue() { + return GAMEPAD_JOYSTICK_MID; +} diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/xid.c b/src/drivers/xboxog/xid/xid.c similarity index 99% rename from lib/TinyUSB_Gamepad/src/xid_driver/xid.c rename to src/drivers/xboxog/xid/xid.c index f26c9861f..86312ff77 100644 --- a/lib/TinyUSB_Gamepad/src/xid_driver/xid.c +++ b/src/drivers/xboxog/xid/xid.c @@ -1,4 +1,4 @@ -#include "xid.h" +#include "drivers/xboxog/xid/xid.h" bool duke_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, xid_interface_t *p_xid); bool steelbattalion_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, xid_interface_t *p_xid); diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/xid_driver.c b/src/drivers/xboxog/xid/xid_driver.c similarity index 57% rename from lib/TinyUSB_Gamepad/src/xid_driver/xid_driver.c rename to src/drivers/xboxog/xid/xid_driver.c index 4cdd4c34d..3d4531e95 100644 --- a/lib/TinyUSB_Gamepad/src/xid_driver/xid_driver.c +++ b/src/drivers/xboxog/xid/xid_driver.c @@ -1,4 +1,4 @@ -#include "xid.h" +#include "drivers/xboxog/xid/xid.h" uint8_t *xremote_get_rom() { diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/xid_gamepad.c b/src/drivers/xboxog/xid/xid_gamepad.c similarity index 96% rename from lib/TinyUSB_Gamepad/src/xid_driver/xid_gamepad.c rename to src/drivers/xboxog/xid/xid_gamepad.c index 10e27f908..0f63e1012 100644 --- a/lib/TinyUSB_Gamepad/src/xid_driver/xid_gamepad.c +++ b/src/drivers/xboxog/xid/xid_gamepad.c @@ -1,4 +1,4 @@ -#include "xid_driver.h" +#include "drivers/xboxog/xid/xid_driver.h" bool duke_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, xid_interface_t *p_xid) { diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/xid_remote.c b/src/drivers/xboxog/xid/xid_remote.c similarity index 97% rename from lib/TinyUSB_Gamepad/src/xid_driver/xid_remote.c rename to src/drivers/xboxog/xid/xid_remote.c index dafbaa0d1..646d6ebdb 100644 --- a/lib/TinyUSB_Gamepad/src/xid_driver/xid_remote.c +++ b/src/drivers/xboxog/xid/xid_remote.c @@ -1,4 +1,4 @@ -#include "xid_driver.h" +#include "drivers/xboxog/xid/xid_driver.h" uint8_t *xremote_get_rom(); diff --git a/lib/TinyUSB_Gamepad/src/xid_driver/xid_steelbattalion.c b/src/drivers/xboxog/xid/xid_steelbattalion.c similarity index 96% rename from lib/TinyUSB_Gamepad/src/xid_driver/xid_steelbattalion.c rename to src/drivers/xboxog/xid/xid_steelbattalion.c index 8cea0286a..5c92ec415 100644 --- a/lib/TinyUSB_Gamepad/src/xid_driver/xid_steelbattalion.c +++ b/src/drivers/xboxog/xid/xid_steelbattalion.c @@ -1,4 +1,4 @@ -#include "xid_driver.h" +#include "drivers/xboxog/xid/xid_driver.h" bool steelbattalion_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, xid_interface_t *p_xid) { diff --git a/src/drivers/xinput/XInputDriver.cpp b/src/drivers/xinput/XInputDriver.cpp new file mode 100644 index 000000000..cb0e730fd --- /dev/null +++ b/src/drivers/xinput/XInputDriver.cpp @@ -0,0 +1,206 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info) + */ + +#include "drivers/xinput/XInputDriver.h" +#include "drivers/shared/driverhelper.h" + +#define XINPUT_OUT_SIZE 32 + +uint8_t endpoint_in = 0; +uint8_t endpoint_out = 0; +uint8_t xinput_out_buffer[XINPUT_OUT_SIZE] = {}; + +static void xinput_init(void) +{ +} + +static void xinput_reset(uint8_t rhport) +{ + (void)rhport; +} + +static uint16_t xinput_open(uint8_t rhport, tusb_desc_interface_t const *itf_descriptor, uint16_t max_length) +{ + uint16_t driver_length = sizeof(tusb_desc_interface_t) + (itf_descriptor->bNumEndpoints * sizeof(tusb_desc_endpoint_t)) + 16; + + TU_VERIFY(max_length >= driver_length, 0); + + uint8_t const *current_descriptor = tu_desc_next(itf_descriptor); + uint8_t found_endpoints = 0; + while ((found_endpoints < itf_descriptor->bNumEndpoints) && (driver_length <= max_length)) + { + tusb_desc_endpoint_t const *endpoint_descriptor = (tusb_desc_endpoint_t const *)current_descriptor; + if (TUSB_DESC_ENDPOINT == tu_desc_type(endpoint_descriptor)) + { + TU_ASSERT(usbd_edpt_open(rhport, endpoint_descriptor)); + + if (tu_edpt_dir(endpoint_descriptor->bEndpointAddress) == TUSB_DIR_IN) + endpoint_in = endpoint_descriptor->bEndpointAddress; + else + endpoint_out = endpoint_descriptor->bEndpointAddress; + + ++found_endpoints; + } + + current_descriptor = tu_desc_next(current_descriptor); + } + return driver_length; +} + +static bool xinput_device_control_request(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) +{ + (void)rhport; + (void)stage; + (void)request; + + return true; +} + +static bool xinput_control_complete(uint8_t rhport, tusb_control_request_t const *request) +{ + (void)rhport; + (void)request; + + return true; +} + +static bool xinput_xfer_callback(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void)rhport; + (void)result; + (void)xferred_bytes; + + if (ep_addr == endpoint_out) + usbd_edpt_xfer(0, endpoint_out, xinput_out_buffer, XINPUT_OUT_SIZE); + + return true; +} + +void XInputDriver::initialize() { + xinputReport = { + .report_id = 0, + .report_size = XINPUT_ENDPOINT_SIZE, + .buttons1 = 0, + .buttons2 = 0, + .lt = 0, + .rt = 0, + .lx = GAMEPAD_JOYSTICK_MID, + .ly = GAMEPAD_JOYSTICK_MID, + .rx = GAMEPAD_JOYSTICK_MID, + .ry = GAMEPAD_JOYSTICK_MID, + ._reserved = { }, + }; + + class_driver = { + #if CFG_TUSB_DEBUG >= 2 + .name = "XINPUT", + #endif + .init = xinput_init, + .reset = xinput_reset, + .open = xinput_open, + .control_xfer_cb = xinput_device_control_request, + .xfer_cb = xinput_xfer_callback, + .sof = NULL + }; +} + +void XInputDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { + xinputReport.buttons1 = 0 + | (gamepad->pressedUp() ? XBOX_MASK_UP : 0) + | (gamepad->pressedDown() ? XBOX_MASK_DOWN : 0) + | (gamepad->pressedLeft() ? XBOX_MASK_LEFT : 0) + | (gamepad->pressedRight() ? XBOX_MASK_RIGHT : 0) + | (gamepad->pressedS2() ? XBOX_MASK_START : 0) + | (gamepad->pressedS1() ? XBOX_MASK_BACK : 0) + | (gamepad->pressedL3() ? XBOX_MASK_LS : 0) + | (gamepad->pressedR3() ? XBOX_MASK_RS : 0) + ; + + xinputReport.buttons2 = 0 + | (gamepad->pressedL1() ? XBOX_MASK_LB : 0) + | (gamepad->pressedR1() ? XBOX_MASK_RB : 0) + | (gamepad->pressedA1() ? XBOX_MASK_HOME : 0) + | (gamepad->pressedB1() ? XBOX_MASK_A : 0) + | (gamepad->pressedB2() ? XBOX_MASK_B : 0) + | (gamepad->pressedB3() ? XBOX_MASK_X : 0) + | (gamepad->pressedB4() ? XBOX_MASK_Y : 0) + ; + + xinputReport.lx = static_cast(gamepad->state.lx) + INT16_MIN; + xinputReport.ly = static_cast(~gamepad->state.ly) + INT16_MIN; + xinputReport.rx = static_cast(gamepad->state.rx) + INT16_MIN; + xinputReport.ry = static_cast(~gamepad->state.ry) + INT16_MIN; + + if (gamepad->hasAnalogTriggers) + { + xinputReport.lt = gamepad->pressedL2() ? 0xFF : gamepad->state.lt; + xinputReport.rt = gamepad->pressedR2() ? 0xFF : gamepad->state.rt; + } + else + { + xinputReport.lt = gamepad->pressedL2() ? 0xFF : 0; + xinputReport.rt = gamepad->pressedR2() ? 0xFF : 0; + } + + // compare against previous report and send new + if ( memcmp(last_report, &xinputReport, sizeof(XInputReport)) != 0) { + if ( tud_ready() && // Is the device ready? + (endpoint_in != 0) && (!usbd_edpt_busy(0, endpoint_in)) ) // Is the IN endpoint available? + { + usbd_edpt_claim(0, endpoint_in); // Take control of IN endpoint + usbd_edpt_xfer(0, endpoint_in, (uint8_t *)&xinputReport, sizeof(XInputReport)); // Send report buffer + usbd_edpt_release(0, endpoint_in); // Release control of IN endpoint + memcpy(last_report, &xinputReport, sizeof(XInputReport)); // save if we sent it + } + } + + // check for player LEDs + if (tud_ready() && + (endpoint_out != 0) && (!usbd_edpt_busy(0, endpoint_out))) + { + usbd_edpt_claim(0, endpoint_out); // Take control of OUT endpoint + usbd_edpt_xfer(0, endpoint_out, outBuffer, XINPUT_OUT_SIZE); // Retrieve report buffer + usbd_edpt_release(0, endpoint_out); // Release control of OUT endpoint + } +} + +// tud_hid_get_report_cb +uint16_t XInputDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { + memcpy(buffer, &xinputReport, sizeof(XInputReport)); + return sizeof(XInputReport); +} + +// Only PS4 does anything with set report +void XInputDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {} + +// Only XboxOG and Xbox One use vendor control xfer cb +bool XInputDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + return false; +} + +const uint16_t * XInputDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) { + const char *value = (const char *)xinput_string_descriptors[index]; + return getStringDescriptor(value, index); // getStringDescriptor returns a static array +} + +const uint8_t * XInputDriver::get_descriptor_device_cb() { + return xinput_device_descriptor; +} + +const uint8_t * XInputDriver::get_hid_descriptor_report_cb(uint8_t itf) { + return nullptr; +} + +const uint8_t * XInputDriver::get_descriptor_configuration_cb(uint8_t index) { + return xinput_configuration_descriptor; +} + +const uint8_t * XInputDriver::get_descriptor_device_qualifier_cb() { + return nullptr; +} + +uint16_t XInputDriver::GetJoystickMidValue() { + return GAMEPAD_JOYSTICK_MID; +} diff --git a/src/gamepad.cpp b/src/gamepad.cpp index 9249e167c..4cfbb0817 100644 --- a/src/gamepad.cpp +++ b/src/gamepad.cpp @@ -12,15 +12,10 @@ #include "FlashPROM.h" #include "CRC32.h" +#include "drivermanager.h" #include "storagemanager.h" #include "system.h" -// PS5 compatibility -#include "ps4_driver.h" - -// Xbox One compatibility -#include "xbone_driver.h" - // MUST BE DEFINED for mpgs uint32_t getMillis() { return to_ms_since_boot(get_absolute_time()); @@ -30,194 +25,6 @@ uint64_t getMicro() { return to_us_since_boot(get_absolute_time()); } - -static HIDReport hidReport -{ - .square_btn = 0, .cross_btn = 0, .circle_btn = 0, .triangle_btn = 0, - .l1_btn = 0, .r1_btn = 0, .l2_btn = 0, .r2_btn = 0, - .select_btn = 0, .start_btn = 0, .l3_btn = 0, .r3_btn = 0, .ps_btn = 0, .tp_btn = 0, - .direction = 0x08, - .l_x_axis = HID_JOYSTICK_MID, - .l_y_axis = HID_JOYSTICK_MID, - .r_x_axis = HID_JOYSTICK_MID, - .r_y_axis = HID_JOYSTICK_MID, - .right_axis = 0x00, .left_axis = 0x00, .up_axis = 0x00, .down_axis = 0x00, - .triangle_axis = 0x00, .circle_axis = 0x00, .cross_axis = 0x00, .square_axis = 0x00, - .l1_axis = 0x00, .r1_axis = 0x00, .l2_axis = 0x00, .r2_axis = 0x00 -}; - -// force a report to be sent every X ms -#define PS4_KEEPALIVE_TIMER 1000 - -static PS4Report ps4Report -{ - .report_id = 0x01, - .left_stick_x = PS4_JOYSTICK_MID, - .left_stick_y = PS4_JOYSTICK_MID, - .right_stick_x = PS4_JOYSTICK_MID, - .right_stick_y = PS4_JOYSTICK_MID, - .dpad = 0x08, - .button_west = 0, .button_south = 0, .button_east = 0, .button_north = 0, - .button_l1 = 0, .button_r1 = 0, .button_l2 = 0, .button_r2 = 0, - .button_select = 0, .button_start = 0, .button_l3 = 0, .button_r3 = 0, .button_home = 0, - .padding = 0, - .mystery = { }, - .touchpad_data = TouchpadData(), - .mystery_2 = { } -}; - -static SwitchReport switchReport -{ - .buttons = 0, - .hat = SWITCH_HAT_NOTHING, - .lx = SWITCH_JOYSTICK_MID, - .ly = SWITCH_JOYSTICK_MID, - .rx = SWITCH_JOYSTICK_MID, - .ry = SWITCH_JOYSTICK_MID, - .vendor = 0, -}; - -static XInputReport xinputReport -{ - .report_id = 0, - .report_size = XINPUT_ENDPOINT_SIZE, - .buttons1 = 0, - .buttons2 = 0, - .lt = 0, - .rt = 0, - .lx = GAMEPAD_JOYSTICK_MID, - .ly = GAMEPAD_JOYSTICK_MID, - .rx = GAMEPAD_JOYSTICK_MID, - .ry = GAMEPAD_JOYSTICK_MID, - ._reserved = { }, -}; - -static NeogeoReport neogeoReport -{ - .buttons = 0, - .hat = 0xf, - .const0 = 0x80, - .const1 = 0x80, - .const2 = 0x80, - .const3 = 0x80, - .const4 = 0, - .const5 = 0, - .const6 = 0, - .const7 = 0, - .const8 = 0, - .const9 = 0, - .const10 = 0, - .const11 = 0, - .const12 = 0, - .const13 = 0, - .const14 = 0, - .const15 = 0, - .const16 = 0, - .const17 = 0, -}; - -static MDMiniReport mdminiReport -{ - .id = 0x01, - .notuse1 = 0x7f, - .notuse2 = 0x7f, - .lx = 0x7f, - .ly = 0x7f, - .buttons = 0x0f, - .notuse3 = 0x00, -}; - -static PCEngineReport pcengineReport -{ - .buttons = 0, - .hat = 0xf, - .const0 = 0x80, - .const1 = 0x80, - .const2 = 0x80, - .const3 = 0x80, - .const4 = 0, -}; - -static AstroReport astroReport -{ - .id = 1, - .notuse1 = 0x7f, - .notuse2 = 0x7f, - .lx = 0x7f, - .ly = 0x7f, - .buttons = 0xf, - .notuse3 = 0, -}; - -static EgretReport egretReport -{ - .buttons = 0, - .lx = EGRET_JOYSTICK_MID, - .ly = EGRET_JOYSTICK_MID, -}; - -static PSClassicReport psClassicReport -{ - .buttons = 0x0014 -}; - -static XboxOriginalReport xboxOriginalReport -{ - .dButtons = 0, - .A = 0, - .B = 0, - .X = 0, - .Y = 0, - .BLACK = 0, - .WHITE = 0, - .L = 0, - .R = 0, - .leftStickX = 0, - .leftStickY = 0, - .rightStickX = 0, - .rightStickY = 0, -}; - -#define XBONE_KEEPALIVE_TIMER 15000 - -static XboxOneGamepad_Data_t xboneReport -{ - .sync = 0, - .guide = 0, - .start = 0, - .back = 0, - .a = 0, - .b = 0, - .x = 0, - .y = 0, - .dpadUp = 0, - .dpadDown = 0, - .dpadLeft = 0, - .dpadRight = 0, - .leftShoulder = 0, - .rightShoulder = 0, - .leftThumbClick = 0, - .rightThumbClick = 0, - .leftTrigger = 0, - .rightTrigger = 0, - .leftStickX = GAMEPAD_JOYSTICK_MID, - .leftStickY = GAMEPAD_JOYSTICK_MID, - .rightStickX = GAMEPAD_JOYSTICK_MID, - .rightStickY = GAMEPAD_JOYSTICK_MID, - .reserved = {} -}; - -static uint16_t xboneReportSize; - -// Xbox One & PS4/PS5 Timing -static TouchpadData touchpadData; - -static KeyboardReport keyboardReport -{ - .keycode = { 0 }, - .multimedia = 0 -}; - Gamepad::Gamepad() : debouncer() , options(Storage::getInstance().getGamepadOptions()) @@ -228,7 +35,6 @@ void Gamepad::setup() { // Configure pin mapping GpioAction* pinMappings = Storage::getInstance().getProfilePinMappings(); - const GamepadOptions& gamepadOptions = Storage::getInstance().getGamepadOptions(); mapDpadUp = new GamepadButtonMapping(GAMEPAD_MASK_UP); mapDpadDown = new GamepadButtonMapping(GAMEPAD_MASK_DOWN); @@ -282,17 +88,7 @@ void Gamepad::setup() } } - // setup PS5 compatibility - PS4Data::getInstance().ps4ControllerType = gamepadOptions.ps4ControllerType; - last_report_counter = 0; - last_axis_counter = 0; - - // Xbox One/PS4 Keep-Alive - keep_alive_timer = to_ms_since_boot(get_absolute_time()); - keep_alive_sequence = 1; - virtual_keycode_sequence = 0; - xb1_guide_pressed = false; - xboneReportSize = sizeof(XboxOneGamepad_Data_t); + lastAction = HOTKEY_NONE; } /** @@ -327,8 +123,12 @@ void Gamepad::reinit() void Gamepad::process() { memcpy(&rawState, &state, sizeof(GamepadState)); + // Get the midpoint value for the current mode - uint16_t joystickMid = GetJoystickMidValue(options.inputMode); + uint16_t joystickMid = GAMEPAD_JOYSTICK_MID; + if ( DriverManager::getInstance().getDriver() != nullptr ) { + joystickMid = DriverManager::getInstance().getDriver()->GetJoystickMidValue(); + } // NOTE: Inverted X/Y-axis must run before SOCD and Dpad processing if (options.invertXAxis) { @@ -365,8 +165,8 @@ void Gamepad::process() state.rx = joystickMid; state.ry = joystickMid; } - state.lx = dpadToAnalogX(state.dpad, options.inputMode); - state.ly = dpadToAnalogY(state.dpad, options.inputMode); + state.lx = dpadToAnalogX(state.dpad); + state.ly = dpadToAnalogY(state.dpad); state.dpad = 0; break; @@ -375,8 +175,8 @@ void Gamepad::process() state.lx = joystickMid; state.ly = joystickMid; } - state.rx = dpadToAnalogX(state.dpad, options.inputMode); - state.ry = dpadToAnalogY(state.dpad, options.inputMode); + state.rx = dpadToAnalogX(state.dpad); + state.ry = dpadToAnalogY(state.dpad); state.dpad = 0; break; @@ -397,8 +197,12 @@ void Gamepad::read() { // Need to invert since we're using pullups Mask_t values = ~gpio_get_all(); + // Get the midpoint value for the current mode - uint16_t joystickMid = GetJoystickMidValue(options.inputMode); + uint16_t joystickMid = GAMEPAD_JOYSTICK_MID; + if ( DriverManager::getInstance().getDriver() != nullptr ) { + joystickMid = DriverManager::getInstance().getDriver()->GetJoystickMidValue(); + } state.aux = 0 | (values & mapButtonFn->pinMask) ? mapButtonFn->buttonMask : 0; @@ -436,7 +240,8 @@ void Gamepad::read() } void Gamepad::debounce() { - debouncer.debounce(&state); + if (Storage::getInstance().getGamepadOptions().debounceDelay > 0) + debouncer.debounce(&state); } void Gamepad::save() @@ -446,11 +251,11 @@ void Gamepad::save() void Gamepad::hotkey() { - if (options.lockHotkeys) return; - + if (options.lockHotkeys) + return; + GamepadHotkey action = HOTKEY_NONE; - - if (pressedHotkey(hotkeyOptions.hotkey01)) action = selectHotkey(hotkeyOptions.hotkey01); + if (pressedHotkey(hotkeyOptions.hotkey01)) action = selectHotkey(hotkeyOptions.hotkey01); else if (pressedHotkey(hotkeyOptions.hotkey02)) action = selectHotkey(hotkeyOptions.hotkey02); else if (pressedHotkey(hotkeyOptions.hotkey03)) action = selectHotkey(hotkeyOptions.hotkey03); else if (pressedHotkey(hotkeyOptions.hotkey04)) action = selectHotkey(hotkeyOptions.hotkey04); @@ -466,57 +271,117 @@ void Gamepad::hotkey() else if (pressedHotkey(hotkeyOptions.hotkey14)) action = selectHotkey(hotkeyOptions.hotkey14); else if (pressedHotkey(hotkeyOptions.hotkey15)) action = selectHotkey(hotkeyOptions.hotkey15); else if (pressedHotkey(hotkeyOptions.hotkey16)) action = selectHotkey(hotkeyOptions.hotkey16); - else lastAction = HOTKEY_NONE; - processHotkeyIfNewAction(action); + if ( lastAction != action ) { + processHotkeyAction(action); + lastAction = action; + } } /** * @brief Take a hotkey action if it hasn't already been taken, modifying state/options appropriately. */ -void Gamepad::processHotkeyIfNewAction(GamepadHotkey action) -{ +void Gamepad::processHotkeyAction(GamepadHotkey action) { bool reqSave = false; switch (action) { - case HOTKEY_NONE : return; - case HOTKEY_DPAD_DIGITAL : options.dpadMode = DPAD_MODE_DIGITAL; reqSave = true; break; - case HOTKEY_DPAD_LEFT_ANALOG : options.dpadMode = DPAD_MODE_LEFT_ANALOG; reqSave = true; break; - case HOTKEY_DPAD_RIGHT_ANALOG : options.dpadMode = DPAD_MODE_RIGHT_ANALOG; reqSave = true; break; - case HOTKEY_HOME_BUTTON : state.buttons |= GAMEPAD_MASK_A1; break; - case HOTKEY_L3_BUTTON : state.buttons |= GAMEPAD_MASK_L3; break; - case HOTKEY_R3_BUTTON : state.buttons |= GAMEPAD_MASK_R3; break; - case HOTKEY_B1_BUTTON : state.buttons |= GAMEPAD_MASK_B1; break; - case HOTKEY_B2_BUTTON : state.buttons |= GAMEPAD_MASK_B2; break; - case HOTKEY_B3_BUTTON : state.buttons |= GAMEPAD_MASK_B3; break; - case HOTKEY_B4_BUTTON : state.buttons |= GAMEPAD_MASK_B4; break; - case HOTKEY_L1_BUTTON : state.buttons |= GAMEPAD_MASK_L1; break; - case HOTKEY_R1_BUTTON : state.buttons |= GAMEPAD_MASK_R1; break; - case HOTKEY_L2_BUTTON : state.buttons |= GAMEPAD_MASK_L2; break; - case HOTKEY_R2_BUTTON : state.buttons |= GAMEPAD_MASK_R2; break; - case HOTKEY_S1_BUTTON : state.buttons |= GAMEPAD_MASK_S1; break; - case HOTKEY_S2_BUTTON : state.buttons |= GAMEPAD_MASK_S2; break; - case HOTKEY_A1_BUTTON : state.buttons |= GAMEPAD_MASK_A1; break; - case HOTKEY_A2_BUTTON : state.buttons |= GAMEPAD_MASK_A2; break; - case HOTKEY_SOCD_UP_PRIORITY : options.socdMode = SOCD_MODE_UP_PRIORITY; reqSave = true; break; - case HOTKEY_SOCD_NEUTRAL : options.socdMode = SOCD_MODE_NEUTRAL; reqSave = true; break; - case HOTKEY_SOCD_LAST_INPUT : options.socdMode = SOCD_MODE_SECOND_INPUT_PRIORITY; reqSave = true; break; - case HOTKEY_SOCD_FIRST_INPUT : options.socdMode = SOCD_MODE_FIRST_INPUT_PRIORITY; reqSave = true;break; - case HOTKEY_SOCD_BYPASS : options.socdMode = SOCD_MODE_BYPASS; reqSave = true; break; - case HOTKEY_REBOOT_DEFAULT : System::reboot(System::BootMode::DEFAULT); break; - case HOTKEY_CAPTURE_BUTTON : state.buttons |= GAMEPAD_MASK_A2; break; - case HOTKEY_TOUCHPAD_BUTTON : state.buttons |= GAMEPAD_MASK_A2; break; - case HOTKEY_INVERT_X_AXIS : + case HOTKEY_DPAD_DIGITAL: + options.dpadMode = DPAD_MODE_DIGITAL; + reqSave = true; + break; + case HOTKEY_DPAD_LEFT_ANALOG: + options.dpadMode = DPAD_MODE_LEFT_ANALOG; + reqSave = true; + break; + case HOTKEY_DPAD_RIGHT_ANALOG: + options.dpadMode = DPAD_MODE_RIGHT_ANALOG; + reqSave = true; + break; + case HOTKEY_HOME_BUTTON: + state.buttons |= GAMEPAD_MASK_A1; + break; + case HOTKEY_L3_BUTTON: + state.buttons |= GAMEPAD_MASK_L3; + break; + case HOTKEY_R3_BUTTON: + state.buttons |= GAMEPAD_MASK_R3; + break; + case HOTKEY_B1_BUTTON: + state.buttons |= GAMEPAD_MASK_B1; + break; + case HOTKEY_B2_BUTTON: + state.buttons |= GAMEPAD_MASK_B2; + break; + case HOTKEY_B3_BUTTON: + state.buttons |= GAMEPAD_MASK_B3; + break; + case HOTKEY_B4_BUTTON: + state.buttons |= GAMEPAD_MASK_B4; + break; + case HOTKEY_L1_BUTTON: + state.buttons |= GAMEPAD_MASK_L1; + break; + case HOTKEY_R1_BUTTON: + state.buttons |= GAMEPAD_MASK_R1; + break; + case HOTKEY_L2_BUTTON: + state.buttons |= GAMEPAD_MASK_L2; + break; + case HOTKEY_R2_BUTTON: + state.buttons |= GAMEPAD_MASK_R2; + break; + case HOTKEY_S1_BUTTON: + state.buttons |= GAMEPAD_MASK_S1; + break; + case HOTKEY_S2_BUTTON: + state.buttons |= GAMEPAD_MASK_S2; + break; + case HOTKEY_A1_BUTTON: + state.buttons |= GAMEPAD_MASK_A1; + break; + case HOTKEY_A2_BUTTON: + state.buttons |= GAMEPAD_MASK_A2; + break; + case HOTKEY_SOCD_UP_PRIORITY: + options.socdMode = SOCD_MODE_UP_PRIORITY; + reqSave = true; + break; + case HOTKEY_SOCD_NEUTRAL: + options.socdMode = SOCD_MODE_NEUTRAL; + reqSave = true; + break; + case HOTKEY_SOCD_LAST_INPUT: + options.socdMode = SOCD_MODE_SECOND_INPUT_PRIORITY; + reqSave = true; + break; + case HOTKEY_SOCD_FIRST_INPUT: + options.socdMode = SOCD_MODE_FIRST_INPUT_PRIORITY; + reqSave = true; + break; + case HOTKEY_SOCD_BYPASS: + options.socdMode = SOCD_MODE_BYPASS; + reqSave = true; + break; + case HOTKEY_REBOOT_DEFAULT: + System::reboot(System::BootMode::DEFAULT); + break; + case HOTKEY_CAPTURE_BUTTON: + state.buttons |= GAMEPAD_MASK_A2; + break; + case HOTKEY_TOUCHPAD_BUTTON: + state.buttons |= GAMEPAD_MASK_A2; + break; + case HOTKEY_INVERT_X_AXIS: if (action != lastAction) { options.invertXAxis = !options.invertXAxis; reqSave = true; } break; - case HOTKEY_INVERT_Y_AXIS : + case HOTKEY_INVERT_Y_AXIS: if (action != lastAction) { options.invertYAxis = !options.invertYAxis; reqSave = true; } break; - case HOTKEY_TOGGLE_4_WAY_MODE : + case HOTKEY_TOGGLE_4_WAY_MODE: if (action != lastAction) { options.fourWayMode = !options.fourWayMode; reqSave = true; @@ -557,719 +422,12 @@ void Gamepad::processHotkeyIfNewAction(GamepadHotkey action) reqSave = true; } break; + default: // Unknown action + return; } // only save if we did something different (except NONE because NONE doesn't get here) - if (action != lastAction && reqSave) { + if (reqSave) { save(); } - - lastAction = action; -} - - -void * Gamepad::getReport() -{ - switch (options.inputMode) - { - case INPUT_MODE_XINPUT: - return getXInputReport(); - - case INPUT_MODE_SWITCH: - return getSwitchReport(); - - case INPUT_MODE_PS4: - return getPS4Report(); - - case INPUT_MODE_XBONE: - return getXBOneReport(); - - case INPUT_MODE_KEYBOARD: - return getKeyboardReport(); - - case INPUT_MODE_NEOGEO: - return getNeogeoReport(); - - case INPUT_MODE_MDMINI: - return getMDMiniReport(); - - case INPUT_MODE_PCEMINI: - return getPCEngineReport(); - - case INPUT_MODE_EGRET: - return getEgretReport(); - - case INPUT_MODE_ASTRO: - return getAstroReport(); - - case INPUT_MODE_PSCLASSIC: - return getPSClassicReport(); - - case INPUT_MODE_XBOXORIGINAL: - return getXboxOriginalReport(); - - default: - return getHIDReport(); - } -} - - -uint16_t Gamepad::getReportSize() -{ - switch (options.inputMode) - { - case INPUT_MODE_XINPUT: - return sizeof(XInputReport); - - case INPUT_MODE_SWITCH: - return sizeof(SwitchReport); - - case INPUT_MODE_PS4: - return sizeof(PS4Report); - - case INPUT_MODE_XBONE: - return xboneReportSize; - - case INPUT_MODE_KEYBOARD: - return sizeof(KeyboardReport); - - case INPUT_MODE_NEOGEO: - return sizeof(NeogeoReport); - - case INPUT_MODE_MDMINI: - return sizeof(MDMiniReport); - - case INPUT_MODE_PCEMINI: - return sizeof(PCEngineReport); - - case INPUT_MODE_EGRET: - return sizeof(EgretReport); - - case INPUT_MODE_ASTRO: - return sizeof(AstroReport); - - case INPUT_MODE_PSCLASSIC: - return sizeof(PSClassicReport); - - case INPUT_MODE_XBOXORIGINAL: - return sizeof(XboxOriginalReport); - - default: - return sizeof(HIDReport); - } -} - -HIDReport *Gamepad::getHIDReport() -{ - switch (state.dpad & GAMEPAD_MASK_DPAD) - { - case GAMEPAD_MASK_UP: hidReport.direction = HID_HAT_UP; break; - case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: hidReport.direction = HID_HAT_UPRIGHT; break; - case GAMEPAD_MASK_RIGHT: hidReport.direction = HID_HAT_RIGHT; break; - case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: hidReport.direction = HID_HAT_DOWNRIGHT; break; - case GAMEPAD_MASK_DOWN: hidReport.direction = HID_HAT_DOWN; break; - case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: hidReport.direction = HID_HAT_DOWNLEFT; break; - case GAMEPAD_MASK_LEFT: hidReport.direction = HID_HAT_LEFT; break; - case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: hidReport.direction = HID_HAT_UPLEFT; break; - default: hidReport.direction = HID_HAT_NOTHING; break; - } - - hidReport.cross_btn = pressedB1(); - hidReport.circle_btn = pressedB2(); - hidReport.square_btn = pressedB3(); - hidReport.triangle_btn = pressedB4(); - hidReport.l1_btn = pressedL1(); - hidReport.r1_btn = pressedR1(); - hidReport.l2_btn = pressedL2(); - hidReport.r2_btn = pressedR2(); - hidReport.select_btn = pressedS1(); - hidReport.start_btn = pressedS2(); - hidReport.l3_btn = pressedL3(); - hidReport.r3_btn = pressedR3(); - hidReport.ps_btn = pressedA1(); - hidReport.tp_btn = pressedA2(); - - hidReport.l_x_axis = static_cast(state.lx >> 8); - hidReport.l_y_axis = static_cast(state.ly >> 8); - hidReport.r_x_axis = static_cast(state.rx >> 8); - hidReport.r_y_axis = static_cast(state.ry >> 8); - - return &hidReport; -} - - -SwitchReport *Gamepad::getSwitchReport() -{ - switch (state.dpad & GAMEPAD_MASK_DPAD) - { - case GAMEPAD_MASK_UP: switchReport.hat = SWITCH_HAT_UP; break; - case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: switchReport.hat = SWITCH_HAT_UPRIGHT; break; - case GAMEPAD_MASK_RIGHT: switchReport.hat = SWITCH_HAT_RIGHT; break; - case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: switchReport.hat = SWITCH_HAT_DOWNRIGHT; break; - case GAMEPAD_MASK_DOWN: switchReport.hat = SWITCH_HAT_DOWN; break; - case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: switchReport.hat = SWITCH_HAT_DOWNLEFT; break; - case GAMEPAD_MASK_LEFT: switchReport.hat = SWITCH_HAT_LEFT; break; - case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: switchReport.hat = SWITCH_HAT_UPLEFT; break; - default: switchReport.hat = SWITCH_HAT_NOTHING; break; - } - - switchReport.buttons = 0 - | (pressedB1() ? SWITCH_MASK_B : 0) - | (pressedB2() ? SWITCH_MASK_A : 0) - | (pressedB3() ? SWITCH_MASK_Y : 0) - | (pressedB4() ? SWITCH_MASK_X : 0) - | (pressedL1() ? SWITCH_MASK_L : 0) - | (pressedR1() ? SWITCH_MASK_R : 0) - | (pressedL2() ? SWITCH_MASK_ZL : 0) - | (pressedR2() ? SWITCH_MASK_ZR : 0) - | (pressedS1() ? SWITCH_MASK_MINUS : 0) - | (pressedS2() ? SWITCH_MASK_PLUS : 0) - | (pressedL3() ? SWITCH_MASK_L3 : 0) - | (pressedR3() ? SWITCH_MASK_R3 : 0) - | (pressedA1() ? SWITCH_MASK_HOME : 0) - | (pressedA2() ? SWITCH_MASK_CAPTURE : 0) - ; - - switchReport.lx = static_cast(state.lx >> 8); - switchReport.ly = static_cast(state.ly >> 8); - switchReport.rx = static_cast(state.rx >> 8); - switchReport.ry = static_cast(state.ry >> 8); - - return &switchReport; -} - - -XInputReport *Gamepad::getXInputReport() -{ - xinputReport.buttons1 = 0 - | (pressedUp() ? XBOX_MASK_UP : 0) - | (pressedDown() ? XBOX_MASK_DOWN : 0) - | (pressedLeft() ? XBOX_MASK_LEFT : 0) - | (pressedRight() ? XBOX_MASK_RIGHT : 0) - | (pressedS2() ? XBOX_MASK_START : 0) - | (pressedS1() ? XBOX_MASK_BACK : 0) - | (pressedL3() ? XBOX_MASK_LS : 0) - | (pressedR3() ? XBOX_MASK_RS : 0) - ; - - xinputReport.buttons2 = 0 - | (pressedL1() ? XBOX_MASK_LB : 0) - | (pressedR1() ? XBOX_MASK_RB : 0) - | (pressedA1() ? XBOX_MASK_HOME : 0) - | (pressedB1() ? XBOX_MASK_A : 0) - | (pressedB2() ? XBOX_MASK_B : 0) - | (pressedB3() ? XBOX_MASK_X : 0) - | (pressedB4() ? XBOX_MASK_Y : 0) - ; - - xinputReport.lx = static_cast(state.lx) + INT16_MIN; - xinputReport.ly = static_cast(~state.ly) + INT16_MIN; - xinputReport.rx = static_cast(state.rx) + INT16_MIN; - xinputReport.ry = static_cast(~state.ry) + INT16_MIN; - - if (hasAnalogTriggers) - { - xinputReport.lt = pressedL2() ? 0xFF : state.lt; - xinputReport.rt = pressedR2() ? 0xFF : state.rt; - } - else - { - xinputReport.lt = pressedL2() ? 0xFF : 0; - xinputReport.rt = pressedR2() ? 0xFF : 0; - } - - return &xinputReport; -} - -static uint8_t xb1_guide_on[] = { 0x01, 0x5b }; -static uint8_t xb1_guide_off[] = { 0x00, 0x5b }; -static uint8_t xboneIdle[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -// On Send report Success -void Gamepad::sendReportSuccess() { - switch( (options.inputMode) ) { - case INPUT_MODE_XBONE: - if ( xboneReport.Header.command == GIP_KEEPALIVE) { - keep_alive_timer = to_ms_since_boot(get_absolute_time()); - keep_alive_sequence++; // will rollover - if ( keep_alive_sequence == 0 ) - keep_alive_sequence = 1; - } else if ( xboneReport.Header.command == GIP_INPUT_REPORT ) { - // Successfully sent report, actually increment last report counter! - if ( memcmp(&last_report[4], &((uint8_t*)&xboneReport)[4], xboneReportSize-4) != 0) { - last_report_counter++; - if (last_report_counter == 0) - last_report_counter = 1; - memcpy(last_report, &xboneReport, xboneReportSize); - } - } - break; - default: - break; - }; -} - -XboxOneGamepad_Data_t *Gamepad::getXBOneReport() -{ - // No input until auth is ready - if ( XboxOneData::getInstance().getAuthCompleted() == false ) { - GIP_HEADER((&xboneReport), GIP_INPUT_REPORT, false, last_report_counter); - memcpy((void*)&((uint8_t*)&xboneReport)[4], xboneIdle, sizeof(xboneIdle)); - xboneReportSize = sizeof(XboxOneGamepad_Data_t); - return &xboneReport; - } - - uint32_t now = to_ms_since_boot(get_absolute_time()); - // Send Keep-Alive every 15 seconds (keep_alive_timer updates if send is successful) - if ( (now - keep_alive_timer) > XBONE_KEEPALIVE_TIMER) { - memset(&xboneReport.Header, 0, sizeof(GipHeader_t)); - GIP_HEADER((&xboneReport), GIP_KEEPALIVE, 1, keep_alive_sequence); - xboneReport.Header.length = 4; - static uint8_t keepAlive[] = { 0x80, 0x00, 0x00, 0x00 }; - memcpy(&((uint8_t*)&xboneReport)[4], &keepAlive, sizeof(keepAlive)); - xboneReportSize = sizeof(GipHeader_t) + sizeof(keepAlive); - return &xboneReport; - } - - // Virtual Keycode for Guide Button - if ( pressedA1() || xb1_guide_pressed == true ) { - // In a change-state - if ( (pressedA1() && xb1_guide_pressed == false) || - (!pressedA1() && xb1_guide_pressed == true)) { - virtual_keycode_sequence++; // will rollover - if ( virtual_keycode_sequence == 0 ) - virtual_keycode_sequence = 1; - GIP_HEADER((&xboneReport), GIP_VIRTUAL_KEYCODE, 1, virtual_keycode_sequence); - xboneReport.Header.length = sizeof(xb1_guide_on); - if ( pressedA1() ) { - xb1_guide_pressed = true; - memcpy(&((uint8_t*)&xboneReport)[4], &xb1_guide_on, sizeof(xb1_guide_on)); - } else { - xb1_guide_pressed = false; - memcpy(&((uint8_t*)&xboneReport)[4], &xb1_guide_off, sizeof(xb1_guide_off)); - } - } - xboneReportSize = sizeof(GipHeader_t) + sizeof(xb1_guide_on); - return &xboneReport; - } - - // Only change xbox one input report if we have different inputs! - XboxOneGamepad_Data_t newInputReport; - - // This is due to our tusb_driver.cpp checking memcmp(last_report, report, size) - memset(&newInputReport, 0, sizeof(XboxOneGamepad_Data_t)); - GIP_HEADER((&newInputReport), GIP_INPUT_REPORT, false, last_report_counter); - - newInputReport.a = pressedB1(); - newInputReport.b = pressedB2(); - newInputReport.x = pressedB3(); - newInputReport.y = pressedB4(); - newInputReport.leftShoulder = pressedL1(); - newInputReport.rightShoulder = pressedR1(); - newInputReport.leftThumbClick = pressedL3(); - newInputReport.rightThumbClick = pressedR3(); - newInputReport.start = pressedS2(); - newInputReport.back = pressedS1(); - newInputReport.guide = 0; // always 0 - newInputReport.sync = 0; - newInputReport.dpadUp = pressedUp(); - newInputReport.dpadDown = pressedDown(); - newInputReport.dpadLeft = pressedLeft(); - newInputReport.dpadRight = pressedRight(); - - newInputReport.leftStickX = static_cast(state.lx) + INT16_MIN; - newInputReport.leftStickY = static_cast(~state.ly) + INT16_MIN; - newInputReport.rightStickX = static_cast(state.rx) + INT16_MIN; - newInputReport.rightStickY = static_cast(~state.ry) + INT16_MIN; - - if (hasAnalogTriggers) - { - newInputReport.leftTrigger = pressedL2() ? 0x03FF : state.lt; - newInputReport.rightTrigger = pressedR2() ? 0x03FF : state.rt; - } - else - { - newInputReport.leftTrigger = pressedL2() ? 0x03FF : 0; - newInputReport.rightTrigger = pressedR2() ? 0x03FF : 0; - } - - // We changed inputs since generating our last report, increment last report counter (but don't update until success) - if ( memcmp(&last_report[4], &((uint8_t*)&newInputReport)[4], sizeof(XboxOneGamepad_Data_t)-4) != 0 ) { - xboneReportSize = sizeof(XboxOneGamepad_Data_t); - memcpy(&xboneReport, &newInputReport, xboneReportSize); - xboneReport.Header.sequence = last_report_counter + 1; - if ( xboneReport.Header.sequence == 0 ) - xboneReport.Header.sequence = 1; - } - - return &xboneReport; -} - - -PS4Report *Gamepad::getPS4Report() -{ - switch (state.dpad & GAMEPAD_MASK_DPAD) - { - case GAMEPAD_MASK_UP: ps4Report.dpad = PS4_HAT_UP; break; - case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: ps4Report.dpad = PS4_HAT_UPRIGHT; break; - case GAMEPAD_MASK_RIGHT: ps4Report.dpad = PS4_HAT_RIGHT; break; - case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: ps4Report.dpad = PS4_HAT_DOWNRIGHT; break; - case GAMEPAD_MASK_DOWN: ps4Report.dpad = PS4_HAT_DOWN; break; - case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: ps4Report.dpad = PS4_HAT_DOWNLEFT; break; - case GAMEPAD_MASK_LEFT: ps4Report.dpad = PS4_HAT_LEFT; break; - case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: ps4Report.dpad = PS4_HAT_UPLEFT; break; - default: ps4Report.dpad = PS4_HAT_NOTHING; break; - } - - ps4Report.button_south = pressedB1(); - ps4Report.button_east = pressedB2(); - ps4Report.button_west = pressedB3(); - ps4Report.button_north = pressedB4(); - ps4Report.button_l1 = pressedL1(); - ps4Report.button_r1 = pressedR1(); - ps4Report.button_l2 = pressedL2(); - ps4Report.button_r2 = pressedR2(); - ps4Report.button_select = options.switchTpShareForDs4 ? pressedA2() : pressedS1(); - ps4Report.button_start = pressedS2(); - ps4Report.button_l3 = pressedL3(); - ps4Report.button_r3 = pressedR3(); - ps4Report.button_home = pressedA1(); - ps4Report.button_touchpad = options.switchTpShareForDs4 ? pressedS1() : pressedA2(); - - ps4Report.left_stick_x = static_cast(state.lx >> 8); - ps4Report.left_stick_y = static_cast(state.ly >> 8); - ps4Report.right_stick_x = static_cast(state.rx >> 8); - ps4Report.right_stick_y = static_cast(state.ry >> 8); - - if (hasAnalogTriggers) - { - ps4Report.left_trigger = state.lt; - ps4Report.right_trigger = state.rt; - } - else - { - ps4Report.left_trigger = pressedL2() ? 0xFF : 0; - ps4Report.right_trigger = pressedR2() ? 0xFF : 0; - } - - // set touchpad to nothing - touchpadData.p1.unpressed = 1; - touchpadData.p2.unpressed = 1; - ps4Report.touchpad_data = touchpadData; - - // some games apparently can miss reports, or they rely on official behavior of getting frequent - // updates. we normally only send a report when the value changes; if we increment the counters - // every time we generate the report (every GP2040::run loop), we apparently overburden - // TinyUSB and introduce roughly 1ms of latency. but we want to loop often and report on every - // true update in order to achieve our tight <1ms report timing when we *do* have a different - // report to send. - // the "PS4 Hack" disables the counters so that we only report on changes, but this - // means we never report the same data twice, and games that expected it would get stuck - // inputs. the below code is a compromise: keep the tight report timing, but occasionally change - // the report counter and axis timing values in order to force a changed report --- this should - // eliminate the need for the PS4 Hack, but it's kept here at the moment for A/B testing purposes - if ( !options.ps4ReportHack ) { - uint32_t now = to_ms_since_boot(get_absolute_time()); - if ((now - keep_alive_timer) > PS4_KEEPALIVE_TIMER) { - last_report_counter = (last_report_counter+1) & 0x3F; - ps4Report.report_counter = last_report_counter; // report counter is 6 bits - ps4Report.axis_timing = now; // axis counter is 16 bits - keep_alive_timer = now; - } - } - - return &ps4Report; -} - -uint8_t Gamepad::getModifier(uint8_t code) { - switch (code) { - case HID_KEY_CONTROL_LEFT : return KEYBOARD_MODIFIER_LEFTCTRL ; - case HID_KEY_SHIFT_LEFT : return KEYBOARD_MODIFIER_LEFTSHIFT ; - case HID_KEY_ALT_LEFT : return KEYBOARD_MODIFIER_LEFTALT ; - case HID_KEY_GUI_LEFT : return KEYBOARD_MODIFIER_LEFTGUI ; - case HID_KEY_CONTROL_RIGHT: return KEYBOARD_MODIFIER_RIGHTCTRL ; - case HID_KEY_SHIFT_RIGHT : return KEYBOARD_MODIFIER_RIGHTSHIFT; - case HID_KEY_ALT_RIGHT : return KEYBOARD_MODIFIER_RIGHTALT ; - case HID_KEY_GUI_RIGHT : return KEYBOARD_MODIFIER_RIGHTGUI ; - } - - return 0; -} - -uint8_t Gamepad::getMultimedia(uint8_t code) { - switch (code) { - case KEYBOARD_MULTIMEDIA_NEXT_TRACK : return 0x01; - case KEYBOARD_MULTIMEDIA_PREV_TRACK : return 0x02; - case KEYBOARD_MULTIMEDIA_STOP : return 0x04; - case KEYBOARD_MULTIMEDIA_PLAY_PAUSE : return 0x08; - case KEYBOARD_MULTIMEDIA_MUTE : return 0x10; - case KEYBOARD_MULTIMEDIA_VOLUME_UP : return 0x20; - case KEYBOARD_MULTIMEDIA_VOLUME_DOWN: return 0x40; - } - return 0; -} - -void Gamepad::pressKey(uint8_t code) { - if (code > HID_KEY_GUI_RIGHT) { - keyboardReport.reportId = KEYBOARD_MULTIMEDIA_REPORT_ID; - keyboardReport.multimedia = getMultimedia(code); - } else { - keyboardReport.reportId = KEYBOARD_KEY_REPORT_ID; - keyboardReport.keycode[code / 8] |= 1 << (code % 8); - } -} - -void Gamepad::releaseAllKeys(void) { - for (uint8_t i = 0; i < (sizeof(keyboardReport.keycode) / sizeof(keyboardReport.keycode[0])); i++) { - keyboardReport.keycode[i] = 0; - } - keyboardReport.multimedia = 0; -} - -KeyboardReport *Gamepad::getKeyboardReport() -{ - const KeyboardMapping& keyboardMapping = Storage::getInstance().getKeyboardMapping(); - releaseAllKeys(); - if(pressedUp()) { pressKey(keyboardMapping.keyDpadUp); } - if(pressedDown()) { pressKey(keyboardMapping.keyDpadDown); } - if(pressedLeft()) { pressKey(keyboardMapping.keyDpadLeft); } - if(pressedRight()) { pressKey(keyboardMapping.keyDpadRight); } - if(pressedB1()) { pressKey(keyboardMapping.keyButtonB1); } - if(pressedB2()) { pressKey(keyboardMapping.keyButtonB2); } - if(pressedB3()) { pressKey(keyboardMapping.keyButtonB3); } - if(pressedB4()) { pressKey(keyboardMapping.keyButtonB4); } - if(pressedL1()) { pressKey(keyboardMapping.keyButtonL1); } - if(pressedR1()) { pressKey(keyboardMapping.keyButtonR1); } - if(pressedL2()) { pressKey(keyboardMapping.keyButtonL2); } - if(pressedR2()) { pressKey(keyboardMapping.keyButtonR2); } - if(pressedS1()) { pressKey(keyboardMapping.keyButtonS1); } - if(pressedS2()) { pressKey(keyboardMapping.keyButtonS2); } - if(pressedL3()) { pressKey(keyboardMapping.keyButtonL3); } - if(pressedR3()) { pressKey(keyboardMapping.keyButtonR3); } - if(pressedA1()) { pressKey(keyboardMapping.keyButtonA1); } - if(pressedA2()) { pressKey(keyboardMapping.keyButtonA2); } - return &keyboardReport; -} - -PCEngineReport *Gamepad::getPCEngineReport() -{ - - switch (state.dpad & GAMEPAD_MASK_DPAD) - { - case GAMEPAD_MASK_UP: pcengineReport.hat = PCENGINE_HAT_UP; break; - case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: pcengineReport.hat = PCENGINE_HAT_UPRIGHT; break; - case GAMEPAD_MASK_RIGHT: pcengineReport.hat = PCENGINE_HAT_RIGHT; break; - case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: pcengineReport.hat = PCENGINE_HAT_DOWNRIGHT; break; - case GAMEPAD_MASK_DOWN: pcengineReport.hat = PCENGINE_HAT_DOWN; break; - case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: pcengineReport.hat = PCENGINE_HAT_DOWNLEFT; break; - case GAMEPAD_MASK_LEFT: pcengineReport.hat = PCENGINE_HAT_LEFT; break; - case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: pcengineReport.hat = PCENGINE_HAT_UPLEFT; break; - default: pcengineReport.hat = PCENGINE_HAT_NOTHING; break; - } - - pcengineReport.buttons = 0x0 - | (pressedB1() ? PCENGINE_MASK_1 : 0) - | (pressedB2() ? PCENGINE_MASK_2 : 0) - | (pressedS1() ? PCENGINE_MASK_SELECT : 0) - | (pressedS2() ? PCENGINE_MASK_RUN : 0) - ; - - return &pcengineReport; -} - -NeogeoReport *Gamepad::getNeogeoReport() -{ - - switch (state.dpad & GAMEPAD_MASK_DPAD) - { - case GAMEPAD_MASK_UP: neogeoReport.hat = NEOGEO_HAT_UP; break; - case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: neogeoReport.hat = NEOGEO_HAT_UPRIGHT; break; - case GAMEPAD_MASK_RIGHT: neogeoReport.hat = NEOGEO_HAT_RIGHT; break; - case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: neogeoReport.hat = NEOGEO_HAT_DOWNRIGHT; break; - case GAMEPAD_MASK_DOWN: neogeoReport.hat = NEOGEO_HAT_DOWN; break; - case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: neogeoReport.hat = NEOGEO_HAT_DOWNLEFT; break; - case GAMEPAD_MASK_LEFT: neogeoReport.hat = NEOGEO_HAT_LEFT; break; - case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: neogeoReport.hat = NEOGEO_HAT_UPLEFT; break; - default: neogeoReport.hat = NEOGEO_HAT_NOTHING; break; - } - - neogeoReport.buttons = 0x0 - | (pressedB3() ? NEOGEO_MASK_A : 0) - | (pressedB1() ? NEOGEO_MASK_B : 0) - | (pressedB4() ? NEOGEO_MASK_C : 0) - | (pressedB2() ? NEOGEO_MASK_D : 0) - | (pressedS1() ? NEOGEO_MASK_SELECT : 0) - | (pressedS2() ? NEOGEO_MASK_START : 0) - ; - - return &neogeoReport; -} - - -MDMiniReport *Gamepad::getMDMiniReport() -{ - mdminiReport.lx = 0x7f; - mdminiReport.ly = 0x7f; - - if (pressedLeft()) { mdminiReport.lx = MDMINI_MASK_LEFT; } - if (pressedRight()) { mdminiReport.lx = MDMINI_MASK_RIGHT; } - - if (pressedUp()) { mdminiReport.ly = MDMINI_MASK_UP; } - if (pressedDown()) { mdminiReport.ly = MDMINI_MASK_DOWN; } - - mdminiReport.buttons = 0x0F - | (pressedB1() ? MDMINI_MASK_A : 0) - | (pressedB2() ? MDMINI_MASK_B : 0) - | (pressedB3() ? MDMINI_MASK_X : 0) - | (pressedB4() ? MDMINI_MASK_Y : 0) - | (pressedR1() ? MDMINI_MASK_Z : 0) - | (pressedR2() ? MDMINI_MASK_C : 0) - | (pressedS2() ? MDMINI_MASK_START : 0) - | (pressedS1() ? MDMINI_MASK_MODE : 0) - ; - - return &mdminiReport; -} - -AstroReport *Gamepad::getAstroReport() -{ - astroReport.lx = 0x7f; - astroReport.ly = 0x7f; - - switch (state.dpad & GAMEPAD_MASK_DPAD) - { - case GAMEPAD_MASK_UP: astroReport.lx = ASTRO_JOYSTICK_MID; astroReport.ly = ASTRO_JOYSTICK_MIN; break; - case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: astroReport.lx = ASTRO_JOYSTICK_MAX; astroReport.ly = ASTRO_JOYSTICK_MIN; break; - case GAMEPAD_MASK_RIGHT: astroReport.lx = ASTRO_JOYSTICK_MAX; astroReport.ly = ASTRO_JOYSTICK_MID; break; - case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: astroReport.lx = ASTRO_JOYSTICK_MAX; astroReport.ly = ASTRO_JOYSTICK_MAX; break; - case GAMEPAD_MASK_DOWN: astroReport.lx = ASTRO_JOYSTICK_MID; astroReport.ly = ASTRO_JOYSTICK_MAX; break; - case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: astroReport.lx = ASTRO_JOYSTICK_MIN; astroReport.ly = ASTRO_JOYSTICK_MAX; break; - case GAMEPAD_MASK_LEFT: astroReport.lx = ASTRO_JOYSTICK_MIN; astroReport.ly = ASTRO_JOYSTICK_MID; break; - case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: astroReport.lx = ASTRO_JOYSTICK_MIN; astroReport.ly = ASTRO_JOYSTICK_MIN; break; - default: astroReport.lx = ASTRO_JOYSTICK_MID; astroReport.ly = ASTRO_JOYSTICK_MID; break; - } - - - astroReport.buttons = 0x0F - | (pressedB1() ? ASTRO_MASK_A : 0) - | (pressedB2() ? ASTRO_MASK_B : 0) - | (pressedB3() ? ASTRO_MASK_D : 0) - | (pressedB4() ? ASTRO_MASK_E : 0) - | (pressedR1() ? ASTRO_MASK_F : 0) - | (pressedR2() ? ASTRO_MASK_C : 0) - | (pressedS1() ? ASTRO_MASK_CREDIT : 0) - | (pressedS2() ? ASTRO_MASK_START : 0) - ; - - return &astroReport; -} - -EgretReport *Gamepad::getEgretReport() -{ - switch (state.dpad & GAMEPAD_MASK_DPAD) - { - case GAMEPAD_MASK_UP: egretReport.lx = EGRET_JOYSTICK_MID; egretReport.ly = EGRET_JOYSTICK_MIN; break; - case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: egretReport.lx = EGRET_JOYSTICK_MAX; egretReport.ly = EGRET_JOYSTICK_MIN; break; - case GAMEPAD_MASK_RIGHT: egretReport.lx = EGRET_JOYSTICK_MAX; egretReport.ly = EGRET_JOYSTICK_MID; break; - case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: egretReport.lx = EGRET_JOYSTICK_MAX; egretReport.ly = EGRET_JOYSTICK_MAX; break; - case GAMEPAD_MASK_DOWN: egretReport.lx = EGRET_JOYSTICK_MID; egretReport.ly = EGRET_JOYSTICK_MAX; break; - case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: egretReport.lx = EGRET_JOYSTICK_MIN; egretReport.ly = EGRET_JOYSTICK_MAX; break; - case GAMEPAD_MASK_LEFT: egretReport.lx = EGRET_JOYSTICK_MIN; egretReport.ly = EGRET_JOYSTICK_MID; break; - case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: egretReport.lx = EGRET_JOYSTICK_MIN; egretReport.ly = EGRET_JOYSTICK_MIN; break; - default: egretReport.lx = EGRET_JOYSTICK_MID; egretReport.ly = EGRET_JOYSTICK_MID; break; - } - - - egretReport.buttons = 0 - | (pressedB1() ? EGRET_MASK_A : 0) - | (pressedB2() ? EGRET_MASK_B : 0) - | (pressedB3() ? EGRET_MASK_D : 0) - | (pressedB4() ? EGRET_MASK_E : 0) - | (pressedR1() ? EGRET_MASK_F : 0) - | (pressedR2() ? EGRET_MASK_C : 0) - | (pressedS1() ? EGRET_MASK_CREDIT : 0) - | (pressedS2() ? EGRET_MASK_START : 0) - | (pressedA1() ? EGRET_MASK_MENU : 0) - ; - - return &egretReport; -} - -PSClassicReport *Gamepad::getPSClassicReport() -{ - psClassicReport.buttons = PSCLASSIC_MASK_CENTER; - - switch (state.dpad & GAMEPAD_MASK_DPAD) - { - case GAMEPAD_MASK_UP: psClassicReport.buttons = PSCLASSIC_MASK_UP; break; - case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: psClassicReport.buttons = PSCLASSIC_MASK_UP_RIGHT; break; - case GAMEPAD_MASK_RIGHT: psClassicReport.buttons = PSCLASSIC_MASK_RIGHT; break; - case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: psClassicReport.buttons = PSCLASSIC_MASK_DOWN_RIGHT; break; - case GAMEPAD_MASK_DOWN: psClassicReport.buttons = PSCLASSIC_MASK_DOWN; break; - case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: psClassicReport.buttons = PSCLASSIC_MASK_DOWN_LEFT; break; - case GAMEPAD_MASK_LEFT: psClassicReport.buttons = PSCLASSIC_MASK_LEFT; break; - case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: psClassicReport.buttons = PSCLASSIC_MASK_UP_LEFT; break; - default: psClassicReport.buttons = PSCLASSIC_MASK_CENTER; break; - } - - psClassicReport.buttons |= - (pressedS2() ? PSCLASSIC_MASK_SELECT : 0) - | (pressedS1() ? PSCLASSIC_MASK_START : 0) - | (pressedB1() ? PSCLASSIC_MASK_CROSS : 0) - | (pressedB2() ? PSCLASSIC_MASK_CIRCLE : 0) - | (pressedB3() ? PSCLASSIC_MASK_SQUARE : 0) - | (pressedB4() ? PSCLASSIC_MASK_TRIANGLE : 0) - | (pressedL1() ? PSCLASSIC_MASK_L1 : 0) - | (pressedR1() ? PSCLASSIC_MASK_R1 : 0) - | (pressedL2() ? PSCLASSIC_MASK_L2 : 0) - | (pressedR2() ? PSCLASSIC_MASK_R2 : 0) - ; - - return &psClassicReport; -} - -XboxOriginalReport *Gamepad::getXboxOriginalReport() -{ - // digital buttons - xboxOriginalReport.dButtons = 0 - | (pressedUp() ? XID_DUP : 0) - | (pressedDown() ? XID_DDOWN : 0) - | (pressedLeft() ? XID_DLEFT : 0) - | (pressedRight() ? XID_DRIGHT : 0) - | (pressedS2() ? XID_START : 0) - | (pressedS1() ? XID_BACK : 0) - | (pressedL3() ? XID_LS : 0) - | (pressedR3() ? XID_RS : 0) - ; - - // analog buttons - convert to digital - xboxOriginalReport.A = (pressedB1() ? 0xFF : 0); - xboxOriginalReport.B = (pressedB2() ? 0xFF : 0); - xboxOriginalReport.X = (pressedB3() ? 0xFF : 0); - xboxOriginalReport.Y = (pressedB4() ? 0xFF : 0); - xboxOriginalReport.BLACK = (pressedL1() ? 0xFF : 0); - xboxOriginalReport.WHITE = (pressedR1() ? 0xFF : 0); - - // analog triggers - if (hasAnalogTriggers) - { - xboxOriginalReport.L = pressedL2() ? 0xFF : state.lt; - xboxOriginalReport.R = pressedR2() ? 0xFF : state.rt; - } - else - { - xboxOriginalReport.L = pressedL2() ? 0xFF : 0; - xboxOriginalReport.R = pressedR2() ? 0xFF : 0; - } - - // analog sticks - xboxOriginalReport.leftStickX = static_cast(state.lx) + INT16_MIN; - xboxOriginalReport.leftStickY = static_cast(~state.ly) + INT16_MIN; - xboxOriginalReport.rightStickX = static_cast(state.rx) + INT16_MIN; - xboxOriginalReport.rightStickY = static_cast(~state.ry) + INT16_MIN; - - return &xboxOriginalReport; } diff --git a/src/gamepad/GamepadDescriptors.cpp b/src/gamepad/GamepadDescriptors.cpp deleted file mode 100644 index 0b4120a76..000000000 --- a/src/gamepad/GamepadDescriptors.cpp +++ /dev/null @@ -1,289 +0,0 @@ -#include "GamepadDescriptors.h" - -// This is never used -static uint16_t getConfigurationDescriptor(const uint8_t *buffer, InputMode mode) -{ - switch (mode) - { - case INPUT_MODE_XINPUT: - buffer = xinput_configuration_descriptor; - return sizeof(xinput_configuration_descriptor); - - case INPUT_MODE_SWITCH: - buffer = switch_configuration_descriptor; - return sizeof(switch_configuration_descriptor); - - case INPUT_MODE_KEYBOARD: - buffer = keyboard_configuration_descriptor; - return sizeof(keyboard_configuration_descriptor); - - case INPUT_MODE_PS4: - buffer = ps4_configuration_descriptor; - return sizeof(ps4_configuration_descriptor); - - case INPUT_MODE_NEOGEO: - buffer = neogeo_configuration_descriptor; - return sizeof(neogeo_configuration_descriptor); - - case INPUT_MODE_MDMINI: - buffer = mdmini_configuration_descriptor; - return sizeof(mdmini_configuration_descriptor); - - case INPUT_MODE_PCEMINI: - buffer = pcengine_configuration_descriptor; - return sizeof(pcengine_configuration_descriptor); - - case INPUT_MODE_EGRET: - buffer = egret_configuration_descriptor; - return sizeof(egret_configuration_descriptor); - - case INPUT_MODE_ASTRO: - buffer = astro_configuration_descriptor; - return sizeof(astro_configuration_descriptor); - - case INPUT_MODE_PSCLASSIC: - buffer = psclassic_configuration_descriptor; - return sizeof(psclassic_configuration_descriptor); - - case INPUT_MODE_XBOXORIGINAL: - buffer = xboxoriginal_configuration_descriptor; - return sizeof(xboxoriginal_configuration_descriptor); - - case INPUT_MODE_XBONE: - buffer = xbone_configuration_descriptor; - return sizeof(xbone_configuration_descriptor); - - - default: - buffer = hid_configuration_descriptor; - return sizeof(hid_configuration_descriptor); - } -} - -static uint16_t getDeviceDescriptor(const uint8_t *buffer, InputMode mode) -{ - switch (mode) - { - case INPUT_MODE_XINPUT: - buffer = xinput_device_descriptor; - return sizeof(xinput_device_descriptor); - - case INPUT_MODE_SWITCH: - buffer = switch_device_descriptor; - return sizeof(switch_device_descriptor); - - case INPUT_MODE_KEYBOARD: - buffer = keyboard_device_descriptor; - return sizeof(keyboard_device_descriptor); - - case INPUT_MODE_PS4: - buffer = ps4_device_descriptor; - return sizeof(ps4_device_descriptor); - - case INPUT_MODE_NEOGEO: - buffer = neogeo_device_descriptor; - return sizeof(neogeo_device_descriptor); - - case INPUT_MODE_MDMINI: - buffer = mdmini_device_descriptor; - return sizeof(mdmini_device_descriptor); - - case INPUT_MODE_PCEMINI: - buffer = pcengine_device_descriptor; - return sizeof(pcengine_device_descriptor); - - case INPUT_MODE_EGRET: - buffer = egret_device_descriptor; - return sizeof(egret_device_descriptor); - - case INPUT_MODE_ASTRO: - buffer = astro_device_descriptor; - return sizeof(astro_device_descriptor); - - case INPUT_MODE_PSCLASSIC: - buffer = psclassic_device_descriptor; - return sizeof(psclassic_device_descriptor); - - case INPUT_MODE_XBOXORIGINAL: - buffer = xboxoriginal_device_descriptor; - return sizeof(xboxoriginal_device_descriptor); - - default: - buffer = hid_device_descriptor; - return sizeof(hid_device_descriptor); - } -} - -static uint16_t getHIDDescriptor(const uint8_t *buffer, InputMode mode) -{ - switch (mode) - { - case INPUT_MODE_SWITCH: - buffer = switch_hid_descriptor; - return sizeof(switch_hid_descriptor); - - case INPUT_MODE_KEYBOARD: - buffer = keyboard_hid_descriptor; - return sizeof(keyboard_hid_descriptor); - - case INPUT_MODE_NEOGEO: - buffer = neogeo_hid_descriptor; - return sizeof(neogeo_hid_descriptor); - - case INPUT_MODE_MDMINI: - buffer = mdmini_hid_descriptor; - return sizeof(mdmini_hid_descriptor); - - case INPUT_MODE_PCEMINI: - buffer = pcengine_hid_descriptor; - return sizeof(pcengine_hid_descriptor); - - case INPUT_MODE_EGRET: - buffer = egret_hid_descriptor; - return sizeof(egret_hid_descriptor); - - case INPUT_MODE_ASTRO: - buffer = astro_hid_descriptor; - return sizeof(astro_hid_descriptor); - - case INPUT_MODE_PSCLASSIC: - buffer = psclassic_hid_descriptor; - return sizeof(psclassic_hid_descriptor); - - default: - buffer = hid_hid_descriptor; - return sizeof(hid_hid_descriptor); - } -} - -static uint16_t getHIDReport(const uint8_t *buffer, InputMode mode) -{ - switch (mode) - { - case INPUT_MODE_SWITCH: - buffer = switch_report_descriptor; - return sizeof(switch_report_descriptor); - - case INPUT_MODE_KEYBOARD: - buffer = keyboard_report_descriptor; - return sizeof(keyboard_report_descriptor); - - case INPUT_MODE_NEOGEO: - buffer = neogeo_report_descriptor; - return sizeof(neogeo_report_descriptor); - - case INPUT_MODE_MDMINI: - buffer = mdmini_report_descriptor; - return sizeof(mdmini_report_descriptor); - - case INPUT_MODE_PCEMINI: - buffer = pcengine_report_descriptor; - return sizeof(pcengine_report_descriptor); - - case INPUT_MODE_EGRET: - buffer = egret_report_descriptor; - return sizeof(egret_report_descriptor); - - case INPUT_MODE_ASTRO: - buffer = astro_report_descriptor; - return sizeof(astro_report_descriptor); - - case INPUT_MODE_PSCLASSIC: - buffer = psclassic_report_descriptor; - return sizeof(psclassic_report_descriptor); - - default: - buffer = hid_report_descriptor; - return sizeof(hid_report_descriptor); - } -} - -static uint16_t getStringDescriptor(const uint16_t *buffer, InputMode mode, uint8_t index) -{ - static uint8_t descriptorStringBuffer[64]; // Max 64 bytes - - const char *value; - uint16_t size; - uint8_t charCount; - - switch (mode) - { - case INPUT_MODE_XINPUT: - value = (const char *)xinput_string_descriptors[index]; - size = sizeof(xinput_string_descriptors[index]); - break; - - case INPUT_MODE_SWITCH: - value = (const char *)switch_string_descriptors[index]; - size = sizeof(switch_string_descriptors[index]); - break; - - case INPUT_MODE_KEYBOARD: - value = (const char *)keyboard_string_descriptors[index]; - size = sizeof(keyboard_string_descriptors[index]); - break; - - case INPUT_MODE_PS4: - value = (const char *)ps4_string_descriptors[index]; - size = sizeof(ps4_string_descriptors[index]); - break; - - case INPUT_MODE_NEOGEO: - value = (const char *)neogeo_string_descriptors[index]; - size = sizeof(neogeo_string_descriptors[index]); - break; - - case INPUT_MODE_MDMINI: - value = (const char *)mdmini_string_descriptors[index]; - size = sizeof(mdmini_string_descriptors[index]); - break; - - case INPUT_MODE_PCEMINI: - value = (const char *)pcengine_string_descriptors[index]; - size = sizeof(pcengine_string_descriptors[index]); - break; - - case INPUT_MODE_EGRET: - value = (const char *)egret_string_descriptors[index]; - size = sizeof(egret_string_descriptors[index]); - break; - - case INPUT_MODE_ASTRO: - value = (const char *)astro_string_descriptors[index]; - size = sizeof(astro_string_descriptors[index]); - break; - - case INPUT_MODE_PSCLASSIC: - value = (const char *)psclassic_string_descriptors[index]; - size = sizeof(psclassic_string_descriptors[index]); - break; - - case INPUT_MODE_XBOXORIGINAL: - value = (const char *)xboxoriginal_string_descriptors[index]; - size = sizeof(xboxoriginal_string_descriptors[index]); - break; - - default: - value = (const char *)hid_string_descriptors[index]; - size = sizeof(hid_string_descriptors[index]); - break; - } - - // Cap at max char - charCount = strlen(value); - if (charCount > 31) - charCount = 31; - - for (uint8_t i = 0; i < charCount; i++) - descriptorStringBuffer[1 + i] = value[i]; - - - // first byte is length (including header), second byte is string type - descriptorStringBuffer[0] = (2 * charCount + 2); - descriptorStringBuffer[1] = 0x03; - - // Cast temp buffer to final result - buffer = (uint16_t *)descriptorStringBuffer; - - return size; -} diff --git a/src/gamepad/GamepadState.cpp b/src/gamepad/GamepadState.cpp new file mode 100644 index 000000000..da2f6a412 --- /dev/null +++ b/src/gamepad/GamepadState.cpp @@ -0,0 +1,162 @@ +#include "GamepadState.h" +#include "drivermanager.h" + +// Convert the horizontal GamepadState dpad axis value into an analog value +uint16_t dpadToAnalogX(uint8_t dpad) +{ + switch (dpad & (GAMEPAD_MASK_LEFT | GAMEPAD_MASK_RIGHT)) + { + case GAMEPAD_MASK_LEFT: + return GAMEPAD_JOYSTICK_MIN; + + case GAMEPAD_MASK_RIGHT: + return GAMEPAD_JOYSTICK_MAX; + + default: + return DriverManager::getInstance().getDriver()->GetJoystickMidValue(); + } +} + +// Convert the vertical GamepadState dpad axis value into an analog value +uint16_t dpadToAnalogY(uint8_t dpad) +{ + switch (dpad & (GAMEPAD_MASK_UP | GAMEPAD_MASK_DOWN)) + { + case GAMEPAD_MASK_UP: + return GAMEPAD_JOYSTICK_MIN; + + case GAMEPAD_MASK_DOWN: + return GAMEPAD_JOYSTICK_MAX; + + default: + return DriverManager::getInstance().getDriver()->GetJoystickMidValue(); + } +} + +uint8_t getMaskFromDirection(DpadDirection direction) +{ + return dpadMasks[direction-1]; +} + +uint8_t updateDpad(uint8_t dpad, DpadDirection direction) +{ + static bool inList[] = {false, false, false, false, false}; // correspond to DpadDirection: none, up, down, left, right + static list dpadList; + + if(dpad & getMaskFromDirection(direction)) + { + if(!inList[direction]) + { + dpadList.push_back(direction); + inList[direction] = true; + } + } + else + { + if(inList[direction]) + { + dpadList.remove(direction); + inList[direction] = false; + } + } + + if(dpadList.empty()) { + return 0; + } + else { + return getMaskFromDirection(dpadList.back()); + } +} + +/** + * @brief Filter diagonals out of the dpad, making the device work as a 4-way lever. + * + * The most recent cardinal direction wins. + * + * @param dpad The GameState.dpad value. + * @return uint8_t The new dpad value. + */ +uint8_t filterToFourWayMode(uint8_t dpad) +{ + updateDpad(dpad, DIRECTION_UP); + updateDpad(dpad, DIRECTION_DOWN); + updateDpad(dpad, DIRECTION_LEFT); + return updateDpad(dpad, DIRECTION_RIGHT); +} + +/** + * @brief Run SOCD cleaning against a D-pad value. + * + * @param mode The SOCD cleaning mode. + * @param dpad The GamepadState.dpad value. + * @return uint8_t The clean D-pad value. + */ +uint8_t runSOCDCleaner(SOCDMode mode, uint8_t dpad) +{ + if (mode == SOCD_MODE_BYPASS) { + return dpad; + } + + static DpadDirection lastUD = DIRECTION_NONE; + static DpadDirection lastLR = DIRECTION_NONE; + uint8_t newDpad = 0; + + switch (dpad & (GAMEPAD_MASK_UP | GAMEPAD_MASK_DOWN)) + { + case (GAMEPAD_MASK_UP | GAMEPAD_MASK_DOWN): + if (mode == SOCD_MODE_UP_PRIORITY) + { + newDpad |= GAMEPAD_MASK_UP; + lastUD = DIRECTION_UP; + } + else if (mode == SOCD_MODE_SECOND_INPUT_PRIORITY && lastUD != DIRECTION_NONE) + newDpad |= (lastUD == DIRECTION_UP) ? GAMEPAD_MASK_DOWN : GAMEPAD_MASK_UP; + else if (mode == SOCD_MODE_FIRST_INPUT_PRIORITY && lastUD != DIRECTION_NONE) + newDpad |= (lastUD == DIRECTION_UP) ? GAMEPAD_MASK_UP : GAMEPAD_MASK_DOWN; + else + lastUD = DIRECTION_NONE; + break; + + case GAMEPAD_MASK_UP: + newDpad |= GAMEPAD_MASK_UP; + lastUD = DIRECTION_UP; + break; + + case GAMEPAD_MASK_DOWN: + newDpad |= GAMEPAD_MASK_DOWN; + lastUD = DIRECTION_DOWN; + break; + + default: + lastUD = DIRECTION_NONE; + break; + } + + switch (dpad & (GAMEPAD_MASK_LEFT | GAMEPAD_MASK_RIGHT)) + { + case (GAMEPAD_MASK_LEFT | GAMEPAD_MASK_RIGHT): + if (mode == SOCD_MODE_SECOND_INPUT_PRIORITY && lastLR != DIRECTION_NONE) + newDpad |= (lastLR == DIRECTION_LEFT) ? GAMEPAD_MASK_RIGHT : GAMEPAD_MASK_LEFT; + else if (mode == SOCD_MODE_FIRST_INPUT_PRIORITY && lastLR != DIRECTION_NONE) + newDpad |= (lastLR == DIRECTION_LEFT) ? GAMEPAD_MASK_LEFT : GAMEPAD_MASK_RIGHT; + else + lastLR = DIRECTION_NONE; + break; + + case GAMEPAD_MASK_LEFT: + newDpad |= GAMEPAD_MASK_LEFT; + lastLR = DIRECTION_LEFT; + break; + + case GAMEPAD_MASK_RIGHT: + newDpad |= GAMEPAD_MASK_RIGHT; + lastLR = DIRECTION_RIGHT; + break; + + default: + lastLR = DIRECTION_NONE; + break; + } + + return newDpad; +} diff --git a/src/gp2040.cpp b/src/gp2040.cpp index 54a86f4b6..f01192ba7 100644 --- a/src/gp2040.cpp +++ b/src/gp2040.cpp @@ -10,7 +10,8 @@ #include "addonmanager.h" #include "usbhostmanager.h" -#include "addons/analog.h" // Inputs for Core0 +// Inputs for Core0 +#include "addons/analog.h" #include "addons/bootsel_button.h" #include "addons/focus_mode.h" #include "addons/dualdirectional.h" @@ -32,9 +33,10 @@ #include "hardware/adc.h" // TinyUSB -#include "usb_driver.h" #include "tusb.h" +// USB Input Class Drivers +#include "drivermanager.h" static const uint32_t REBOOT_HOTKEY_ACTIVATION_TIME_MS = 50; static const uint32_t REBOOT_HOTKEY_HOLD_TIME_MS = 4000; @@ -98,77 +100,70 @@ void GP2040::setup() { addons.LoadAddon(new TiltInput(), CORE0_INPUT); addons.LoadAddon(new InputMacro(), CORE0_INPUT); - + InputMode inputMode = gamepad->getOptions().inputMode; const BootAction bootAction = getBootAction(); - switch (bootAction) { case BootAction::ENTER_WEBCONFIG_MODE: - { - Storage::getInstance().SetConfigMode(true); - initialize_driver(INPUT_MODE_CONFIG); - ConfigManager::getInstance().setup(CONFIG_TYPE_WEB); - break; - } - + // Move this to the Net driver initialize + Storage::getInstance().SetConfigMode(true); + //initialize_driver(INPUT_MODE_CONFIG); + DriverManager::getInstance().setup(INPUT_MODE_CONFIG); + ConfigManager::getInstance().setup(CONFIG_TYPE_WEB); + return; case BootAction::ENTER_USB_MODE: - { - reset_usb_boot(0, 0); - break; - } - - case BootAction::SET_INPUT_MODE_HID: + reset_usb_boot(0, 0); + return; + case BootAction::SET_INPUT_MODE_HID: // HID drivers + inputMode = INPUT_MODE_HID; + break; case BootAction::SET_INPUT_MODE_SWITCH: - case BootAction::SET_INPUT_MODE_XINPUT: - case BootAction::SET_INPUT_MODE_PS4: - case BootAction::SET_INPUT_MODE_XBONE: + inputMode = INPUT_MODE_SWITCH; + break; case BootAction::SET_INPUT_MODE_KEYBOARD: + inputMode = INPUT_MODE_KEYBOARD; + break; case BootAction::SET_INPUT_MODE_NEOGEO: + inputMode = INPUT_MODE_NEOGEO; + break; case BootAction::SET_INPUT_MODE_MDMINI: + inputMode = INPUT_MODE_MDMINI; + break; case BootAction::SET_INPUT_MODE_PCEMINI: + inputMode = INPUT_MODE_PCEMINI; + break; case BootAction::SET_INPUT_MODE_EGRET: + inputMode = INPUT_MODE_EGRET; + break; case BootAction::SET_INPUT_MODE_ASTRO: + inputMode = INPUT_MODE_ASTRO; + break; case BootAction::SET_INPUT_MODE_PSCLASSIC: - case BootAction::SET_INPUT_MODE_XBOXORIGINAL: + inputMode = INPUT_MODE_PSCLASSIC; + break; + case BootAction::SET_INPUT_MODE_XINPUT: // X-Input Driver + inputMode = INPUT_MODE_SWITCH; + break; + case BootAction::SET_INPUT_MODE_PS4: // PS4 / PS5 Driver + inputMode = INPUT_MODE_PS4; + break; + case BootAction::SET_INPUT_MODE_XBONE: // Xbox One Driver + inputMode = INPUT_MODE_XBONE; + break; + case BootAction::SET_INPUT_MODE_XBOXORIGINAL: // Xbox OG Driver + inputMode = INPUT_MODE_XBOXORIGINAL; + break; case BootAction::NONE: - { - InputMode inputMode = gamepad->getOptions().inputMode; - if (bootAction == BootAction::SET_INPUT_MODE_HID) { - inputMode = INPUT_MODE_HID; - } else if (bootAction == BootAction::SET_INPUT_MODE_SWITCH) { - inputMode = INPUT_MODE_SWITCH; - } else if (bootAction == BootAction::SET_INPUT_MODE_XINPUT) { - inputMode = INPUT_MODE_XINPUT; - } else if (bootAction == BootAction::SET_INPUT_MODE_PS4) { - inputMode = INPUT_MODE_PS4; - } else if (bootAction == BootAction::SET_INPUT_MODE_XBONE) { - inputMode = INPUT_MODE_XBONE; - } else if (bootAction == BootAction::SET_INPUT_MODE_KEYBOARD) { - inputMode = INPUT_MODE_KEYBOARD; - } else if (bootAction == BootAction::SET_INPUT_MODE_NEOGEO) { - inputMode = INPUT_MODE_NEOGEO; - } else if (bootAction == BootAction::SET_INPUT_MODE_MDMINI) { - inputMode = INPUT_MODE_MDMINI; - } else if (bootAction == BootAction::SET_INPUT_MODE_PCEMINI) { - inputMode = INPUT_MODE_PCEMINI; - } else if (bootAction == BootAction::SET_INPUT_MODE_EGRET) { - inputMode = INPUT_MODE_EGRET; - } else if (bootAction == BootAction::SET_INPUT_MODE_ASTRO) { - inputMode = INPUT_MODE_ASTRO; - } else if (bootAction == BootAction::SET_INPUT_MODE_PSCLASSIC) { - inputMode = INPUT_MODE_PSCLASSIC; - } else if (bootAction == BootAction::SET_INPUT_MODE_XBOXORIGINAL) { - inputMode = INPUT_MODE_XBOXORIGINAL; - } + default: + break; + } - if (inputMode != gamepad->getOptions().inputMode) { - // Save the changed input mode - gamepad->setInputMode(inputMode); - gamepad->save(); - } + // Setup USB Driver + DriverManager::getInstance().setup(inputMode); - initialize_driver(inputMode); - break; - } + // Save the changed input mode + if (inputMode != gamepad->getOptions().inputMode) { + gamepad->setInputMode(inputMode); + gamepad->save(); } } @@ -205,55 +200,34 @@ void GP2040::deinitializeStandardGpio() { } void GP2040::run() { + GPDriver * inputDriver = DriverManager::getInstance().getDriver(); Gamepad * gamepad = Storage::getInstance().GetGamepad(); Gamepad * processedGamepad = Storage::getInstance().GetProcessedGamepad(); bool configMode = Storage::getInstance().GetConfigMode(); uint8_t * featureData = Storage::getInstance().GetFeatureData(); memset(featureData, 0, 32); // X-Input is the only feature data currently supported while (1) { // LOOP - // check if we should reinitialize the gamepad - if (gamepad->userRequestedReinit) { - // deinitialize the ordinary (non-reserved, non-addon) GPIO pins, since - // we are moving off of them and onto potentially different pin assignments - // we currently don't support ASSIGNED_TO_ADDON pins being reinitialized, - // but if they were to be, that'd be the addon's duty, not ours - this->deinitializeStandardGpio(); - - // now we can load the latest configured profile, which will map the - // new set of GPIOs to use... - Storage::getInstance().setFunctionalPinMappings(); - - // ...and initialize the pins again - this->initializeStandardGpio(); - - // now we can tell the gamepad that the new mappings are in place - // and ready to use, and the pins are ready, so it should reinitialize itself - gamepad->reinit(); - // ...and addons on this core, if they implemented reinit (just things - // with simple GPIO pin usage, at time of writing) - addons.ReinitializeAddons(ADDON_PROCESS::CORE0_INPUT); - - // and we're done - gamepad->userRequestedReinit = false; - } + this->getReinitGamepad(gamepad); + // Do any queued saves in StorageManager Storage::getInstance().performEnqueuedSaves(); + + // Read Gamepad + gamepad->read(); + // Config Loop (Web-Config does not require gamepad) if (configMode == true) { + ConfigManager::getInstance().loop(); - gamepad->read(); rebootHotkeys.process(gamepad, configMode); continue; } + // Process USB Host on Core0 USBHostManager::getInstance().process(); - // Gamepad Features - gamepad->read(); // gpio pin reads - // Debounce if set - if (Storage::getInstance().getGamepadOptions().debounceDelay) - gamepad->debounce(); + gamepad->debounce(); // Pre-Process add-ons for MPGS addons.PreprocessAddons(ADDON_PROCESS::CORE0_INPUT); @@ -269,17 +243,9 @@ void GP2040::run() { // Copy Processed Gamepad for Core1 (race condition otherwise) memcpy(&processedGamepad->state, &gamepad->state, sizeof(GamepadState)); - // Update input driver - update_input_driver(); - - // USB FEATURES : Send/Get USB Features (including Player LEDs on X-Input) - if ( send_report(gamepad->getReport(), gamepad->getReportSize()) ) { - gamepad->sendReportSuccess(); - } + // Process Input Driver + inputDriver->process(gamepad, featureData); - // GET USB REPORT (If Endpoint Available) - receive_report(featureData); - // Process USB Report Addons addons.ProcessAddons(ADDON_PROCESS::CORE0_USBREPORT); @@ -287,6 +253,34 @@ void GP2040::run() { } } +void GP2040::getReinitGamepad(Gamepad * gamepad) { + // check if we should reinitialize the gamepad + if (gamepad->userRequestedReinit) { + // deinitialize the ordinary (non-reserved, non-addon) GPIO pins, since + // we are moving off of them and onto potentially different pin assignments + // we currently don't support ASSIGNED_TO_ADDON pins being reinitialized, + // but if they were to be, that'd be the addon's duty, not ours + this->deinitializeStandardGpio(); + + // now we can load the latest configured profile, which will map the + // new set of GPIOs to use... + Storage::getInstance().setFunctionalPinMappings(); + + // ...and initialize the pins again + this->initializeStandardGpio(); + + // now we can tell the gamepad that the new mappings are in place + // and ready to use, and the pins are ready, so it should reinitialize itself + gamepad->reinit(); + // ...and addons on this core, if they implemented reinit (just things + // with simple GPIO pin usage, at time of writing) + addons.ReinitializeAddons(ADDON_PROCESS::CORE0_INPUT); + + // and we're done + gamepad->userRequestedReinit = false; + } +} + GP2040::BootAction GP2040::getBootAction() { switch (System::takeBootMode()) { case System::BootMode::GAMEPAD: return BootAction::NONE; diff --git a/src/peripheralmanager.cpp b/src/peripheralmanager.cpp index 2fe5f8592..1c4663cba 100644 --- a/src/peripheralmanager.cpp +++ b/src/peripheralmanager.cpp @@ -22,18 +22,21 @@ PeripheralI2C* PeripheralManager::getI2C(uint8_t block) { if (block < NUM_I2CS) { return ((block == 0) ? &blockI2C0 : &blockI2C1); } + return nullptr; } PeripheralSPI* PeripheralManager::getSPI(uint8_t block) { if (block < NUM_SPIS) { return ((block == 0) ? &blockSPI0 : &blockSPI1); } + return nullptr; } PeripheralUSB* PeripheralManager::getUSB(uint8_t block) { if (block < NUM_USBS) { return ((block == 0) ? &blockUSB0 : &blockUSB0); } + return nullptr; } bool PeripheralManager::isI2CEnabled(uint8_t block) { diff --git a/src/usbdriver.cpp b/src/usbdriver.cpp new file mode 100644 index 000000000..6ac32e69f --- /dev/null +++ b/src/usbdriver.cpp @@ -0,0 +1,101 @@ +/* + * SPDX-License-Identifier: MIT + * SPDX-FileCopyrightText: Copyright (c) 2024 Open Stick Community (gp2040-ce.info) + */ + +#ifndef _USBDRIVER_CPP_ +#define _USBDRIVER_CPP_ + +#include "tusb.h" +#include "drivermanager.h" + +static bool usb_mounted; +static bool usb_suspended; + +bool get_usb_mounted(void) { + return usb_mounted; +} + +bool get_usb_suspended(void) { + return usb_suspended; +} + +const usbd_class_driver_t *usbd_app_driver_get_cb(uint8_t *driver_count) { + *driver_count = 1; + return DriverManager::getInstance().getDriver()->get_class_driver(); +} + +uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { + return DriverManager::getInstance().getDriver()->get_report(report_id, report_type, buffer, reqlen); +} + +// Invoked when received SET_REPORT control request or +// received data on OUT endpoint ( Report ID = 0, Type = 0 ) +void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) { + DriverManager::getInstance().getDriver()->set_report(report_id, report_type, buffer, bufsize); + tud_hid_report(report_id, buffer, bufsize); // echo back anything we received from host +} + +// Invoked when device is mounted +void tud_mount_cb(void) +{ + usb_mounted = true; +} + +// Invoked when device is unmounted +void tud_umount_cb(void) +{ + usb_mounted = false; +} + +// Invoked when usb bus is suspended +// remote_wakeup_en : if host allow us to perform remote wakeup +// Within 7ms, device must draw an average of current less than 2.5 mA from bus +void tud_suspend_cb(bool remote_wakeup_en) { + (void)remote_wakeup_en; + usb_suspended = true; +} + +// Invoked when usb bus is resumed +void tud_resume_cb(void) { + usb_suspended = false; +} + +// Vendor Controlled XFER occured +bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, + tusb_control_request_t const *request) { + return DriverManager::getInstance().getDriver()->vendor_control_xfer_cb(rhport, stage, request); +} + + +// Invoked when received GET STRING DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { + return DriverManager::getInstance().getDriver()->get_descriptor_string_cb(index, langid); +} + +// Invoked when received GET DEVICE DESCRIPTOR +// Application return pointer to descriptor +uint8_t const *tud_descriptor_device_cb() { + return DriverManager::getInstance().getDriver()->get_descriptor_device_cb(); +} + +// Invoked when received GET HID REPORT DESCRIPTOR +// Application return pointer to descriptor +// Descriptor contents must exist long enough for transfer to complete +uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf) { + return DriverManager::getInstance().getDriver()->get_hid_descriptor_report_cb(itf); +} + +// Invoked when received GET CONFIGURATION DESCRIPTOR +// Application return pointer to descriptor +// Descriptor contents must exist long enough for transfer to complete +uint8_t const *tud_descriptor_configuration_cb(uint8_t index) { + return DriverManager::getInstance().getDriver()->get_descriptor_configuration_cb(index); +} + +uint8_t const* tud_descriptor_device_qualifier_cb() { + return DriverManager::getInstance().getDriver()->get_descriptor_device_qualifier_cb(); +} + +#endif \ No newline at end of file diff --git a/src/usbhostmanager.cpp b/src/usbhostmanager.cpp index 8c5312d8c..b058a0c63 100644 --- a/src/usbhostmanager.cpp +++ b/src/usbhostmanager.cpp @@ -8,7 +8,7 @@ #include "host/usbh.h" #include "host/usbh_pvt.h" -#include "xinput_host.h" +#include "drivers/shared/xinput_host.h" void USBHostManager::start() { // This will happen after Gamepad has initialized