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:
Luke A
2024-02-07 12:14:06 -05:00
committed by GitHub
parent 7f95aee1f4
commit 43358ed8f0
114 changed files with 3384 additions and 3134 deletions

View File

@@ -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}

View File

@@ -3,6 +3,7 @@
#include "usbaddon.h"
#include "gamepad.h"
#include "class/hid/hid.h"
#ifndef KEYBOARD_HOST_ENABLED
#define KEYBOARD_HOST_ENABLED 0

View File

@@ -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

View File

@@ -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
View 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

View 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_

View 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_

View 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_

View 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_

View 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_

View 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_

View 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_

View 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_

View 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_

View 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_

View 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_

View File

@@ -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_

View File

@@ -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_

View File

@@ -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();

View 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_

View File

@@ -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;

View 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_

View File

@@ -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

View 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_

View File

@@ -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

View File

@@ -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 =
{

View File

@@ -7,7 +7,7 @@ extern "C"
#endif
#include <stdint.h>
#include "tusb.h"
#include <tusb.h>
#define XID_XREMOTE_ROM_CLASS 0x59

View 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

View File

@@ -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;

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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();

View File

@@ -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
View 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

View File

@@ -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
View 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_

View File

@@ -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

View File

@@ -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)

View File

@@ -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
)

View File

@@ -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"
}

View File

@@ -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};

View File

@@ -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);

View File

@@ -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,
};

View File

@@ -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);

View File

@@ -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};

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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();

View File

@@ -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};

View File

@@ -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

View File

@@ -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();

View File

@@ -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"

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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"

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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;

View File

@@ -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"

View File

@@ -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

View File

@@ -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;

View File

@@ -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);
}
}
}

View File

@@ -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;

View File

@@ -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

View File

@@ -487,6 +487,8 @@ static bool isValidInputMode(ConfigLegacy::InputMode inputMode)
case INPUT_MODE_KEYBOARD:
case INPUT_MODE_PS4:
return true;
default:
break;
}
return false;
}

View File

@@ -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
View 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);
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View File

@@ -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;
}

View 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;
}

View 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;
}

View 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;
}

View File

@@ -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() {

View File

@@ -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

View 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;
}

View File

@@ -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