GP2040-CE Input Driver system rehaul (#830)
* Does not compile yet but this adds a TON of new code for each input driver mode, and separates all of the individual modes out of the gamepad instance. Still tons of work to be done. * Everything moved around, it compiles! * Fixed string buffer, XInput was missing from driver manager setup list, added conditionals for joystick mid as we can do a GPIO read before input mode is decided... tud_init() added to driver setup to make everything work * Small fixes for keyboard and xbox one * Moving drivers above drivermanager * Fixed naming for "Neogeo" to "NeoGeo" * Upper, lower * Bug with hotkey & hotkey saving was messing up the UP direction * Missed PS Classic in the driver manager list * Changed from 3 functions down to 1, no reason to have the extra * Fixed one get_report in Xbox Original driver, small code clean-up on xbox one * Replacing some tabs w/ spaces Small change to xbone driver to remove unused variable and set last report to 0 in initialize * Update AstroDriver.h
This commit is contained in:
@@ -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}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "usbaddon.h"
|
||||
#include "gamepad.h"
|
||||
#include "class/hid/hid.h"
|
||||
|
||||
#ifndef KEYBOARD_HOST_ENABLED
|
||||
#define KEYBOARD_HOST_ENABLED 0
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "usbaddon.h"
|
||||
|
||||
#include "xgip_protocol.h"
|
||||
#include "drivers/shared/xgip_protocol.h"
|
||||
|
||||
#ifndef XBONEPASSTHROUGH_ENABLED
|
||||
#define XBONEPASSTHROUGH_ENABLED 0
|
||||
|
||||
24
headers/drivermanager.h
Normal file
24
headers/drivermanager.h
Normal file
@@ -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
|
||||
30
headers/drivers/astro/AstroDriver.h
Normal file
30
headers/drivers/astro/AstroDriver.h
Normal file
@@ -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_
|
||||
30
headers/drivers/egret/EgretDriver.h
Normal file
30
headers/drivers/egret/EgretDriver.h
Normal file
@@ -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_
|
||||
30
headers/drivers/hid/HIDDriver.h
Normal file
30
headers/drivers/hid/HIDDriver.h
Normal file
@@ -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_
|
||||
35
headers/drivers/keyboard/KeyboardDriver.h
Normal file
35
headers/drivers/keyboard/KeyboardDriver.h
Normal file
@@ -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_
|
||||
30
headers/drivers/mdmini/MDMiniDriver.h
Normal file
30
headers/drivers/mdmini/MDMiniDriver.h
Normal file
@@ -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_
|
||||
30
headers/drivers/neogeo/NeoGeoDriver.h
Normal file
30
headers/drivers/neogeo/NeoGeoDriver.h
Normal file
@@ -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_
|
||||
27
headers/drivers/net/NetDriver.h
Normal file
27
headers/drivers/net/NetDriver.h
Normal file
@@ -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_
|
||||
30
headers/drivers/pcengine/PCEngineDriver.h
Normal file
30
headers/drivers/pcengine/PCEngineDriver.h
Normal file
@@ -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_
|
||||
38
headers/drivers/ps4/PS4Driver.h
Normal file
38
headers/drivers/ps4/PS4Driver.h
Normal file
@@ -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_
|
||||
30
headers/drivers/psclassic/PSClassicDriver.h
Normal file
30
headers/drivers/psclassic/PSClassicDriver.h
Normal file
@@ -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_
|
||||
26
headers/drivers/shared/driverhelper.h
Normal file
26
headers/drivers/shared/driverhelper.h
Normal file
@@ -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_
|
||||
@@ -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 @@ private:
|
||||
ps4ControllerType = PS4ControllerType::PS4_CONTROLLER;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _PS4_DATA_H_
|
||||
@@ -1,33 +1,5 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#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 @@ private:
|
||||
uint16_t authLen;
|
||||
uint8_t authType;
|
||||
};
|
||||
|
||||
#endif // _XBONE_DATA_H_
|
||||
@@ -51,11 +51,31 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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();
|
||||
30
headers/drivers/switch/SwitchDriver.h
Normal file
30
headers/drivers/switch/SwitchDriver.h
Normal file
@@ -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_
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <pico/unique_id.h>
|
||||
#include <cstring>
|
||||
|
||||
#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;
|
||||
39
headers/drivers/xbone/XBOneDriver.h
Normal file
39
headers/drivers/xbone/XBOneDriver.h
Normal file
@@ -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_
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "xid_driver.h"
|
||||
#include "drivers/xboxog/xid/xid_driver.h"
|
||||
|
||||
#define XboxOriginalReport USB_XboxGamepad_InReport_t
|
||||
|
||||
30
headers/drivers/xboxog/XboxOriginalDriver.h
Normal file
30
headers/drivers/xboxog/XboxOriginalDriver.h
Normal file
@@ -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_
|
||||
@@ -9,9 +9,9 @@ extern "C"
|
||||
#include <stdint.h>
|
||||
#include <tusb.h>
|
||||
#include <device/usbd_pvt.h>
|
||||
#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
|
||||
@@ -9,7 +9,7 @@ extern "C"
|
||||
#include <stdint.h>
|
||||
#include <tusb.h>
|
||||
#include <device/usbd_pvt.h>
|
||||
#include "xid.h"
|
||||
#include "drivers/xboxog/xid/xid.h"
|
||||
|
||||
static const tusb_desc_device_t XID_DESC_DEVICE =
|
||||
{
|
||||
@@ -7,7 +7,7 @@ extern "C"
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include "tusb.h"
|
||||
#include <tusb.h>
|
||||
|
||||
#define XID_XREMOTE_ROM_CLASS 0x59
|
||||
|
||||
30
headers/drivers/xinput/XInputDriver.h
Normal file
30
headers/drivers/xinput/XInputDriver.h
Normal file
@@ -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
|
||||
@@ -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 @@ public:
|
||||
*/
|
||||
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 @@ public:
|
||||
/**
|
||||
* @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 @@ public:
|
||||
|
||||
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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string.h>
|
||||
#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);
|
||||
}
|
||||
@@ -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<DpadDirection> 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);
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "gamepad.h"
|
||||
#include "addonmanager.h"
|
||||
#include "peripheralmanager.h"
|
||||
#include "gpdriver.h"
|
||||
|
||||
#include "pico/types.h"
|
||||
|
||||
@@ -58,6 +59,7 @@ private:
|
||||
SET_INPUT_MODE_XBOXORIGINAL
|
||||
};
|
||||
BootAction getBootAction();
|
||||
void getReinitGamepad(Gamepad * gamepad);
|
||||
|
||||
// GPIO manipulation for setup and profile reinit
|
||||
void initializeStandardGpio();
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info)
|
||||
*/
|
||||
|
||||
#ifndef _GPCONFIG_H_
|
||||
#define _GPCONFIG_H_
|
||||
|
||||
|
||||
42
headers/gpdriver.h
Normal file
42
headers/gpdriver.h
Normal file
@@ -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
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <stdint.h>
|
||||
#include "AnimationStation.hpp"
|
||||
#include "PlayerLEDs.h"
|
||||
#include "xinput_driver.h"
|
||||
|
||||
// GP2040-CE Board Config (64 character limit)
|
||||
#ifndef GP2040_BOARDCONFIG
|
||||
|
||||
7
headers/usbdriver.h
Normal file
7
headers/usbdriver.h
Normal file
@@ -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_
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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};
|
||||
@@ -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);
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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);
|
||||
@@ -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 <random>
|
||||
|
||||
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};
|
||||
@@ -1,288 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com)
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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 <wchar.h>
|
||||
#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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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};
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#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
|
||||
@@ -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();
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<uint8_t> 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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -487,6 +487,8 @@ static bool isValidInputMode(ConfigLegacy::InputMode inputMode)
|
||||
case INPUT_MODE_KEYBOARD:
|
||||
case INPUT_MODE_PS4:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
71
src/drivermanager.cpp
Normal file
71
src/drivermanager.cpp
Normal file
@@ -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);
|
||||
}
|
||||
109
src/drivers/astro/AstroDriver.cpp
Normal file
109
src/drivers/astro/AstroDriver.cpp
Normal file
@@ -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;
|
||||
}
|
||||
102
src/drivers/egret/EgretDriver.cpp
Normal file
102
src/drivers/egret/EgretDriver.cpp
Normal file
@@ -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;
|
||||
}
|
||||
149
src/drivers/hid/HIDDriver.cpp
Normal file
149
src/drivers/hid/HIDDriver.cpp
Normal file
@@ -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<uint8_t>(gamepad->state.lx >> 8);
|
||||
hidReport.l_y_axis = static_cast<uint8_t>(gamepad->state.ly >> 8);
|
||||
hidReport.r_x_axis = static_cast<uint8_t>(gamepad->state.rx >> 8);
|
||||
hidReport.r_y_axis = static_cast<uint8_t>(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;
|
||||
}
|
||||
162
src/drivers/keyboard/KeyboardDriver.cpp
Normal file
162
src/drivers/keyboard/KeyboardDriver.cpp
Normal file
@@ -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;
|
||||
}
|
||||
100
src/drivers/mdmini/MDMiniDriver.cpp
Normal file
100
src/drivers/mdmini/MDMiniDriver.cpp
Normal file
@@ -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;
|
||||
}
|
||||
116
src/drivers/neogeo/NeoGeoDriver.cpp
Normal file
116
src/drivers/neogeo/NeoGeoDriver.cpp
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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<sizeof(tud_network_mac_address); i++)
|
||||
{
|
||||
_desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[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<chr_count; i++)
|
||||
{
|
||||
_desc_str[1+i] = str[i];
|
||||
}
|
||||
}
|
||||
|
||||
// first byte is length (including header), second byte is string type
|
||||
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8 ) | (2*chr_count + 2));
|
||||
|
||||
return _desc_str;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Device Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
@@ -91,13 +149,15 @@ tusb_desc_device_t const desc_device =
|
||||
.bNumConfigurations = CONFIG_ID_COUNT // multiple configurations
|
||||
};
|
||||
|
||||
// Invoked when received GET DEVICE DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
uint8_t const * web_tud_descriptor_device_cb(void)
|
||||
{
|
||||
return (uint8_t const *) &desc_device;
|
||||
const uint8_t * NetDriver::get_descriptor_device_cb() {
|
||||
return (uint8_t const *) &desc_device;
|
||||
}
|
||||
|
||||
const uint8_t * NetDriver::get_hid_descriptor_report_cb(uint8_t itf) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Configuration Descriptor
|
||||
//--------------------------------------------------------------------+
|
||||
@@ -172,77 +232,14 @@ static uint8_t const * const configuration_arr[2] =
|
||||
#endif
|
||||
};
|
||||
|
||||
// Invoked when received GET CONFIGURATION DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
// Descriptor contents must exist long enough for transfer to complete
|
||||
uint8_t const * web_tud_descriptor_configuration_cb(uint8_t index)
|
||||
{
|
||||
return (index < CONFIG_ID_COUNT) ? configuration_arr[index] : NULL;
|
||||
const uint8_t * NetDriver::get_descriptor_configuration_cb(uint8_t index) {
|
||||
return (index < CONFIG_ID_COUNT) ? configuration_arr[index] : NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// String Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
const uint8_t * NetDriver::get_descriptor_device_qualifier_cb() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// array of pointer to string descriptors
|
||||
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];
|
||||
|
||||
// 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* web_tud_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<sizeof(tud_network_mac_address); i++)
|
||||
{
|
||||
_desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[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<chr_count; i++)
|
||||
{
|
||||
_desc_str[1+i] = str[i];
|
||||
}
|
||||
}
|
||||
|
||||
// first byte is length (including header), second byte is string type
|
||||
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8 ) | (2*chr_count + 2));
|
||||
|
||||
return _desc_str;
|
||||
}
|
||||
uint16_t NetDriver::GetJoystickMidValue() {
|
||||
return GAMEPAD_JOYSTICK_MID;
|
||||
}
|
||||
101
src/drivers/pcengine/PCEngineDriver.cpp
Normal file
101
src/drivers/pcengine/PCEngineDriver.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
#include "drivers/pcengine/PCEngineDriver.h"
|
||||
#include "drivers/shared/driverhelper.h"
|
||||
|
||||
void PCEngineDriver::initialize() {
|
||||
pcengineReport = {
|
||||
.buttons = 0,
|
||||
.hat = 0xf,
|
||||
.const0 = 0x80,
|
||||
.const1 = 0x80,
|
||||
.const2 = 0x80,
|
||||
.const3 = 0x80,
|
||||
.const4 = 0,
|
||||
};
|
||||
|
||||
class_driver = {
|
||||
#if CFG_TUSB_DEBUG >= 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;
|
||||
}
|
||||
312
src/drivers/ps4/PS4Driver.cpp
Normal file
312
src/drivers/ps4/PS4Driver.cpp
Normal file
@@ -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 <random>
|
||||
#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<uint8_t>(gamepad->state.lx >> 8);
|
||||
ps4Report.left_stick_y = static_cast<uint8_t>(gamepad->state.ly >> 8);
|
||||
ps4Report.right_stick_x = static_cast<uint8_t>(gamepad->state.rx >> 8);
|
||||
ps4Report.right_stick_y = static_cast<uint8_t>(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;
|
||||
}
|
||||
102
src/drivers/psclassic/PSClassicDriver.cpp
Normal file
102
src/drivers/psclassic/PSClassicDriver.cpp
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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() {
|
||||
@@ -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
|
||||
115
src/drivers/switch/SwitchDriver.cpp
Normal file
115
src/drivers/switch/SwitchDriver.cpp
Normal file
@@ -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<uint8_t>(gamepad->state.lx >> 8);
|
||||
switchReport.ly = static_cast<uint8_t>(gamepad->state.ly >> 8);
|
||||
switchReport.rx = static_cast<uint8_t>(gamepad->state.rx >> 8);
|
||||
switchReport.ry = static_cast<uint8_t>(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;
|
||||
}
|
||||
@@ -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 <queue>
|
||||
typedef struct {
|
||||
uint8_t report[XBONE_ENDPOINT_SIZE];
|
||||
uint16_t len;
|
||||
} report_queue_t;
|
||||
|
||||
static std::queue<report_queue_t> 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 <queue>
|
||||
typedef struct {
|
||||
uint8_t report[XBONE_ENDPOINT_SIZE];
|
||||
uint16_t len;
|
||||
} report_queue_t;
|
||||
|
||||
static std::queue<report_queue_t> 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,10 +257,203 @@ 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;
|
||||
|
||||
// Perform update
|
||||
this->update();
|
||||
|
||||
// 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<int16_t>(gamepad->state.lx) + INT16_MIN;
|
||||
newInputReport.leftStickY = static_cast<int16_t>(~gamepad->state.ly) + INT16_MIN;
|
||||
newInputReport.rightStickX = static_cast<int16_t>(gamepad->state.rx) + INT16_MIN;
|
||||
newInputReport.rightStickY = static_cast<int16_t>(~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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool XBOneDriver::send_xbone_usb(uint8_t const *report, uint16_t report_size) {
|
||||
uint8_t itf = 0;
|
||||
xboned_interface_t *p_xbone = _xboned_itf;
|
||||
for (;; itf++, p_xbone++) {
|
||||
if (itf >= TU_ARRAY_SIZE(_xboned_itf)) {
|
||||
return false;
|
||||
}
|
||||
if (p_xbone->ep_in)
|
||||
break;
|
||||
}
|
||||
if ( tud_ready() && // Is the device ready?
|
||||
(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
|
||||
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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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)
|
||||
@@ -298,50 +472,44 @@ bool xbone_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage,
|
||||
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;
|
||||
xboned_interface_t *p_xbone = _xboned_itf;
|
||||
bool ret = false;
|
||||
for (;; itf++, p_xbone++) {
|
||||
if (itf >= TU_ARRAY_SIZE(_xboned_itf)) {
|
||||
return false;
|
||||
}
|
||||
if (p_xbone->ep_in)
|
||||
break;
|
||||
}
|
||||
if ( tud_ready() && // Is the device ready?
|
||||
(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_release(0, p_xbone->ep_in); // Release control of IN endpoint
|
||||
}
|
||||
|
||||
return ret;
|
||||
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 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};
|
||||
const uint8_t * XBOneDriver::get_descriptor_device_cb() {
|
||||
return xbone_device_descriptor;
|
||||
}
|
||||
|
||||
// Update our Xbox One driver as things need to happen under-the-hood
|
||||
void xbone_driver_update() {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user