Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88a84fe6f2 | ||
|
|
91906866a8 | ||
|
|
22cabd06dc | ||
|
|
bf52296e60 | ||
|
|
9bdc0dbb33 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,5 +3,4 @@ build
|
||||
release
|
||||
generated
|
||||
tools
|
||||
.ignore
|
||||
src/usbh/tusb_hid/experiment
|
||||
.ignore
|
||||
@@ -40,6 +40,7 @@ file(GLOB_RECURSE SOURCES
|
||||
"src/usbd/shared/*"
|
||||
"src/usbd/switch/*"
|
||||
"src/usbd/xboxog/*"
|
||||
"src/usbd/dinput/*"
|
||||
"src/usbd/xinput/*")
|
||||
|
||||
# Firmware
|
||||
@@ -59,7 +60,8 @@ add_compile_definitions(FEATHER_RP2040)
|
||||
|
||||
#------- USB host data +/- will be GPIO 0/1 ---------------------------------------#
|
||||
|
||||
# add_compile_definitions(HOST_DEBUG) # CDC device, include utilities/log.h and use log() as you would printf()
|
||||
#------- CDC MODE --------#
|
||||
# add_compile_definitions(HOST_DEBUG) # makes RP2040 a CDC device, include "utilities/log.h" and use log() as you would printf()
|
||||
|
||||
|
||||
target_link_libraries(${NAME}
|
||||
@@ -79,6 +81,7 @@ target_link_libraries(${NAME}
|
||||
tinyusb_host
|
||||
tinyusb_pico_pio_usb
|
||||
CRC32
|
||||
hid_parser
|
||||
cmsis_core
|
||||
)
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ Firmware for the RP2040, setup for the [Adafruit Feather USB Host board](https:/
|
||||
|
||||
### Wireless adapters
|
||||
- Xbox 360 PC adapter (Microsoft or clones, syncs 1 controller)
|
||||
- 8Bitdo v1 and v2 Bluetooth adapters (set to XInput mode)
|
||||
- 8Bitdo v1 and v2 Bluetooth adapters
|
||||
- Most wireless adapters that present themselves as Switch/XInput/PlayStation controllers should work
|
||||
|
||||
Note: There are some third party controllers that can change their VID/PID, these might not work correctly.
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "usbh/tusb_hid/ps3.h"
|
||||
#include "usbh/tusb_hid/ps4.h"
|
||||
#include "usbh/tusb_hid/ps5.h"
|
||||
// #include "usbh/tusb_hid/ps3.h"
|
||||
// #include "usbh/tusb_hid/ps4.h"
|
||||
// #include "usbh/tusb_hid/ps5.h"
|
||||
#include "usbh/tusb_xinput/xinput_host.h"
|
||||
|
||||
struct GamepadState{
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
|
||||
#define HID_ENDPOINT_SIZE 64
|
||||
|
||||
// Mac OS-X and Linux automatically load the correct drivers. On
|
||||
// Windows, even though the driver is supplied by Microsoft, an
|
||||
// INF file is needed to load the driver. These numbers need to
|
||||
// match the INF file.
|
||||
// #define VENDOR_ID 0x10C4
|
||||
// #define PRODUCT_ID 0x82C0
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* Endpoint Buffer Configuration
|
||||
@@ -29,6 +36,21 @@
|
||||
#define DINPUT_HAT_UPLEFT 0x07
|
||||
#define DINPUT_HAT_NOTHING 0x08
|
||||
|
||||
#define DINPUT_MASK_SQUARE (1U << 0)
|
||||
#define DINPUT_MASK_CROSS (1U << 1)
|
||||
#define DINPUT_MASK_CIRCLE (1U << 2)
|
||||
#define DINPUT_MASK_TRIANGLE (1U << 3)
|
||||
#define DINPUT_MASK_L1 (1U << 4)
|
||||
#define DINPUT_MASK_R1 (1U << 5)
|
||||
#define DINPUT_MASK_L2 (1U << 6)
|
||||
#define DINPUT_MASK_R2 (1U << 7)
|
||||
#define DINPUT_MASK_SELECT (1U << 8)
|
||||
#define DINPUT_MASK_START (1U << 9)
|
||||
#define DINPUT_MASK_L3 (1U << 10)
|
||||
#define DINPUT_MASK_R3 (1U << 11)
|
||||
#define DINPUT_MASK_PS (1U << 12)
|
||||
#define DINPUT_MASK_TP (1U << 13)
|
||||
|
||||
#define DINPUT_JOYSTICK_MIN 0x00
|
||||
#define DINPUT_JOYSTICK_MID 0x80
|
||||
#define DINPUT_JOYSTICK_MAX 0xFF
|
||||
@@ -96,29 +118,29 @@ typedef struct __attribute((packed, aligned(1)))
|
||||
uint8_t r2_axis;
|
||||
} DInputReport;
|
||||
|
||||
// struct DInputLed {
|
||||
// uint8_t time_enabled; /* the total time the led is active (0xff means forever) */
|
||||
// uint8_t duty_length; /* how long a cycle is in deciseconds (0 means "really fast") */
|
||||
// uint8_t enabled;
|
||||
// uint8_t duty_off; /* % of duty_length the led is off (0xff means 100%) */
|
||||
// uint8_t duty_on; /* % of duty_length the led is on (0xff mean 100%) */
|
||||
// } __attribute__((packed));
|
||||
struct DInputLed {
|
||||
uint8_t time_enabled; /* the total time the led is active (0xff means forever) */
|
||||
uint8_t duty_length; /* how long a cycle is in deciseconds (0 means "really fast") */
|
||||
uint8_t enabled;
|
||||
uint8_t duty_off; /* % of duty_length the led is off (0xff means 100%) */
|
||||
uint8_t duty_on; /* % of duty_length the led is on (0xff mean 100%) */
|
||||
} __attribute__((packed));
|
||||
|
||||
// struct DInputRumble {
|
||||
// uint8_t padding;
|
||||
// uint8_t right_duration; /* Right motor duration (0xff means forever) */
|
||||
// uint8_t right_motor_on; /* Right (small) motor on/off, only supports values of 0 or 1 (off/on) */
|
||||
// uint8_t left_duration; /* Left motor duration (0xff means forever) */
|
||||
// uint8_t left_motor_force; /* left (large) motor, supports force values from 0 to 255 */
|
||||
// } __attribute__((packed));
|
||||
struct DInputRumble {
|
||||
uint8_t padding;
|
||||
uint8_t right_duration; /* Right motor duration (0xff means forever) */
|
||||
uint8_t right_motor_on; /* Right (small) motor on/off, only supports values of 0 or 1 (off/on) */
|
||||
uint8_t left_duration; /* Left motor duration (0xff means forever) */
|
||||
uint8_t left_motor_force; /* left (large) motor, supports force values from 0 to 255 */
|
||||
} __attribute__((packed));
|
||||
|
||||
// struct DInputOutReport {
|
||||
// struct DInputRumble rumble;
|
||||
// uint8_t padding[4];
|
||||
// uint8_t leds_bitmap; /* bitmap of enabled LEDs: LED_1 = 0x02, LED_2 = 0x04, ... */
|
||||
// struct DInputLed led[4]; /* LEDx at (4 - x) */
|
||||
// struct DInputLed _reserved; /* LED5, not actually soldered */
|
||||
// } __attribute__((packed));
|
||||
struct DInputOutReport {
|
||||
struct DInputRumble rumble;
|
||||
uint8_t padding[4];
|
||||
uint8_t leds_bitmap; /* bitmap of enabled LEDs: LED_1 = 0x02, LED_2 = 0x04, ... */
|
||||
struct DInputLed led[4]; /* LEDx at (4 - x) */
|
||||
struct DInputLed _reserved; /* LED5, not actually soldered */
|
||||
} __attribute__((packed));
|
||||
|
||||
static const uint8_t dinput_string_language[] = { 0x09, 0x04 };
|
||||
static const uint8_t dinput_string_manufacturer[] = "SHANWAN";
|
||||
|
||||
@@ -213,13 +213,13 @@ static const uint8_t hid_report_descriptor[] =
|
||||
|
||||
static const uint8_t hid_hid_descriptor[] =
|
||||
{
|
||||
0x09, // bLength
|
||||
0x21, // bDescriptorType (HID)
|
||||
0x11, 0x01, // bcdHID 1.11
|
||||
0x00, // bCountryCode
|
||||
0x01, // bNumDescriptors
|
||||
0x22, // bDescriptorType[0] (HID)
|
||||
sizeof(hid_report_descriptor), 0x00, // wDescriptorLength[0] 90
|
||||
0x09, // bLength
|
||||
0x21, // bDescriptorType (HID)
|
||||
0x11, 0x01, // bcdHID 1.11
|
||||
0x00, // bCountryCode
|
||||
0x01, // bNumDescriptors
|
||||
0x22, // bDescriptorType[0] (HID)
|
||||
sizeof(hid_report_descriptor), 0x00, // wDescriptorLength[0] 90
|
||||
};
|
||||
|
||||
#define CONFIG1_DESC_SIZE (9+9+9+7)
|
||||
|
||||
@@ -105,7 +105,7 @@ typedef struct __attribute((packed, aligned(1)))
|
||||
int16_t acceler_z;
|
||||
|
||||
int16_t velocity_z;
|
||||
} Dualshock3Report;
|
||||
} DualShock3Report;
|
||||
|
||||
struct sixaxis_led {
|
||||
uint8_t time_enabled; /* the total time the led is active (0xff means forever) */
|
||||
|
||||
@@ -5,12 +5,6 @@
|
||||
#include "tusb.h"
|
||||
#include "bsp/board_api.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.
|
||||
*
|
||||
* Auto ProductID layout's Bitmap:
|
||||
* [MSB] HID | MSC | CDC [LSB]
|
||||
*/
|
||||
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
|
||||
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
|
||||
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
|
||||
@@ -24,8 +18,6 @@ tusb_desc_device_t const usbserial_device_descriptor =
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = USB_BCD,
|
||||
|
||||
// Use Interface Association Descriptor (IAD) for CDC
|
||||
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
@@ -72,7 +64,6 @@ enum {
|
||||
STRID_SERIAL,
|
||||
};
|
||||
|
||||
// array of pointer to string descriptors
|
||||
char const *string_desc_arr[] =
|
||||
{
|
||||
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
|
||||
|
||||
@@ -1,60 +1,41 @@
|
||||
#include <pico/stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/multicore.h"
|
||||
#include "hardware/flash.h"
|
||||
|
||||
#include "tusb.h"
|
||||
#include "hardware/sync.h"
|
||||
|
||||
#include "input_mode.h"
|
||||
|
||||
#define AIRCR_REG (*((volatile uint32_t *)(0xE000ED0C))) // Address of the AIRCR register
|
||||
#define AIRCR_SYSRESETREQ (1 << 2) // Position of SYSRESETREQ bit in AIRCR
|
||||
#define AIRCR_VECTKEY (0x5FA << 16) // VECTKEY value
|
||||
#define AIRCR_Register (*((volatile uint32_t*)(PPB_BASE + 0x0ED0C)))
|
||||
|
||||
#define FLASH_TARGET_OFFSET (256 * 1024)
|
||||
#define FLASH_SIZE_BYTES (2 * 1024 * 1024)
|
||||
#define EEPROM_SIZE 1
|
||||
#define EEPROM_FLASH_TARGET_OFFSET (2 * 1024 * 1024 - EEPROM_SIZE)
|
||||
|
||||
void system_reset() {
|
||||
AIRCR_REG = AIRCR_VECTKEY | AIRCR_SYSRESETREQ;
|
||||
while(1);
|
||||
}
|
||||
|
||||
bool store_input_mode(enum InputMode new_mode)
|
||||
void store_input_mode(enum InputMode mode)
|
||||
{
|
||||
int buf[FLASH_PAGE_SIZE/sizeof(int)];
|
||||
memset(buf, 0xFF, FLASH_PAGE_SIZE);
|
||||
int saved_mode = new_mode; // changed to uint8?
|
||||
uint8_t data = (uint8_t)mode;
|
||||
|
||||
buf[0] = saved_mode;
|
||||
uint32_t flash_offset = EEPROM_FLASH_TARGET_OFFSET % FLASH_SECTOR_SIZE;
|
||||
uint32_t flash_sector_base = EEPROM_FLASH_TARGET_OFFSET - flash_offset;
|
||||
|
||||
uint32_t saved_interrupts = save_and_disable_interrupts();
|
||||
uint8_t new_sector_content[FLASH_SECTOR_SIZE];
|
||||
|
||||
flash_range_erase((FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE), FLASH_SECTOR_SIZE);
|
||||
flash_range_program((FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE), (uint8_t *)buf, FLASH_PAGE_SIZE);
|
||||
memcpy(new_sector_content, (const void *)(XIP_BASE + flash_sector_base), FLASH_SECTOR_SIZE);
|
||||
|
||||
restore_interrupts(saved_interrupts);
|
||||
new_sector_content[flash_offset] = data;
|
||||
|
||||
return true;
|
||||
|
||||
// const uint8_t *flash_target_contents = (const uint8_t *)(XIP_BASE + FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE);
|
||||
|
||||
// if ((uint8_t)saved_mode != *flash_target_contents)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// return true;
|
||||
flash_range_erase(flash_sector_base, FLASH_SECTOR_SIZE);
|
||||
flash_range_program(flash_sector_base, new_sector_content, FLASH_SECTOR_SIZE);
|
||||
}
|
||||
|
||||
bool change_input_mode(Gamepad previous_gamepad)
|
||||
void change_input_mode(Gamepad previous_gamepad)
|
||||
{
|
||||
if (!previous_gamepad.state.start)
|
||||
{
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
InputMode new_mode;
|
||||
|
||||
if (previous_gamepad.state.up)
|
||||
@@ -77,26 +58,21 @@ bool change_input_mode(Gamepad previous_gamepad)
|
||||
{
|
||||
new_mode = INPUT_MODE_PSCLASSIC;
|
||||
}
|
||||
|
||||
bool mode_stored = false;
|
||||
|
||||
if (new_mode)
|
||||
// else if (previous_gamepad.state.b)
|
||||
// {
|
||||
// new_mode = INPUT_MODE_USBSERIAL;
|
||||
// }
|
||||
else
|
||||
{
|
||||
// tinyusb needs to be kaput in order to write to the flash
|
||||
// just hangs otherwise
|
||||
|
||||
tud_disconnect();
|
||||
sleep_ms(300);
|
||||
multicore_reset_core1(); // stop tusb host
|
||||
|
||||
if (store_input_mode(new_mode))
|
||||
{
|
||||
system_reset(); // reset rp2040
|
||||
mode_stored = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
return mode_stored;
|
||||
store_input_mode(new_mode);
|
||||
sleep_ms(200);
|
||||
|
||||
// restart the rp2040
|
||||
AIRCR_Register = 0x5FA0004;
|
||||
sleep_ms(200);
|
||||
}
|
||||
|
||||
enum InputMode get_input_mode()
|
||||
@@ -105,11 +81,12 @@ enum InputMode get_input_mode()
|
||||
return INPUT_MODE_USBSERIAL;
|
||||
#endif
|
||||
|
||||
const uint8_t *stored_value = (const uint8_t *)(XIP_BASE + FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE);
|
||||
const uint8_t* flash_addr = (const uint8_t*)(XIP_BASE + EEPROM_FLASH_TARGET_OFFSET);
|
||||
uint8_t stored_value = *flash_addr;
|
||||
|
||||
if (*stored_value >= INPUT_MODE_XINPUT && *stored_value <= INPUT_MODE_XBOXORIGINAL)
|
||||
if (stored_value >= INPUT_MODE_XINPUT && stored_value <= INPUT_MODE_XBOXORIGINAL)
|
||||
{
|
||||
return(enum InputMode)*stored_value;
|
||||
return(enum InputMode)stored_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -9,17 +9,18 @@ extern "C" {
|
||||
|
||||
enum InputMode
|
||||
{
|
||||
INPUT_MODE_XINPUT = 0x01,
|
||||
INPUT_MODE_SWITCH = 0x02,
|
||||
INPUT_MODE_HID = 0x03,
|
||||
INPUT_MODE_PSCLASSIC = 0x04,
|
||||
INPUT_MODE_XBOXORIGINAL = 0x05,
|
||||
INPUT_MODE_USBSERIAL = 0x06,
|
||||
INPUT_MODE_XINPUT,
|
||||
INPUT_MODE_SWITCH,
|
||||
INPUT_MODE_HID,
|
||||
// INPUT_MODE_KEYBOARD,
|
||||
INPUT_MODE_PSCLASSIC,
|
||||
INPUT_MODE_XBOXORIGINAL,
|
||||
INPUT_MODE_USBSERIAL,
|
||||
// INPUT_MODE_CONFIG,
|
||||
};
|
||||
|
||||
enum InputMode get_input_mode();
|
||||
bool change_input_mode(Gamepad previous_gamepad_state);
|
||||
void change_input_mode(Gamepad previous_gamepad_state);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "usbd/drivermanager.h"
|
||||
#include "usbd/gpdriver.h"
|
||||
|
||||
#include "Gamepad.h"
|
||||
#include "input_mode.h"
|
||||
|
||||
Gamepad gamepad;
|
||||
@@ -44,7 +43,7 @@ int main(void)
|
||||
GPDriver* driver = driverManager.getDriver();
|
||||
driver->process(&gamepad, outBuffer);
|
||||
|
||||
if (absolute_time_diff_us(last_time_gamepad_checked, get_absolute_time()) >= 500000)
|
||||
if (absolute_time_diff_us(last_time_gamepad_checked, get_absolute_time()) >= 200000)
|
||||
{
|
||||
// check if digital buttons have changed (first 16 bytes of gamepad.state)
|
||||
if (memcmp(&gamepad.state, &previous_gamepad.state, 16) != 0)
|
||||
@@ -55,10 +54,8 @@ int main(void)
|
||||
// haven't changed for 3 seconds
|
||||
else if (absolute_time_diff_us(last_time_gamepad_changed, get_absolute_time()) >= 3000000)
|
||||
{
|
||||
if (!change_input_mode(previous_gamepad))
|
||||
{
|
||||
last_time_gamepad_changed = get_absolute_time();
|
||||
}
|
||||
change_input_mode(previous_gamepad);
|
||||
last_time_gamepad_changed = get_absolute_time();
|
||||
}
|
||||
|
||||
last_time_gamepad_checked = get_absolute_time();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// #include "net/NetDriver.h"
|
||||
// #include "keyboard/KeyboardDriver.h"
|
||||
|
||||
// #include "usbd/dinput/DInputDriver.h"
|
||||
#include "usbd/hid/HIDDriver.h"
|
||||
#include "usbd/psclassic/PSClassicDriver.h"
|
||||
#include "usbd/switch/SwitchDriver.h"
|
||||
@@ -23,6 +24,9 @@ void DriverManager::setup(InputMode mode)
|
||||
case INPUT_MODE_HID:
|
||||
driver = new HIDDriver();
|
||||
break;
|
||||
// case INPUT_MODE_HID:
|
||||
// driver = new DInputDriver();
|
||||
// break;
|
||||
case INPUT_MODE_PSCLASSIC:
|
||||
driver = new PSClassicDriver();
|
||||
break;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "usbd/hid/HIDDriver.h"
|
||||
#include "descriptors/HIDDescriptors.h"
|
||||
#include "descriptors/PS3Descriptors.h"
|
||||
#include "usbd/shared/driverhelper.h"
|
||||
|
||||
// Magic byte sequence to enable PS button on PS3
|
||||
@@ -127,11 +128,13 @@ void HIDDriver::process(Gamepad * gamepad, uint8_t * outBuffer)
|
||||
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);
|
||||
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) {}
|
||||
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)
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
|
||||
#include "usbh/tusb_host_manager.h" // global enum host_mode
|
||||
|
||||
// TODO: make a host driver class for all this
|
||||
// TODO: make a class for all this
|
||||
|
||||
Mouse* mouse = nullptr;
|
||||
N64USB* n64usb = nullptr;
|
||||
PSClassic* psclassic = nullptr;
|
||||
Dualshock3* dualshock3 = nullptr;
|
||||
@@ -21,7 +22,7 @@ Dualsense* dualsense = nullptr;
|
||||
SwitchPro* switch_pro = nullptr;
|
||||
SwitchWired* switch_wired = nullptr;
|
||||
|
||||
static bool gamepad_mounted;
|
||||
static bool gamepad_mounted = false;
|
||||
static uint8_t gamepad_dev_addr = 0;
|
||||
static uint8_t gamepad_instance = 0;
|
||||
|
||||
@@ -81,6 +82,11 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
|
||||
n64usb = new N64USB();
|
||||
n64usb->init(dev_addr, instance);
|
||||
}
|
||||
else if (host_mode == HOST_MODE_HID_MOUSE && !mouse)
|
||||
{
|
||||
mouse = new Mouse();
|
||||
mouse->init(dev_addr, instance);
|
||||
}
|
||||
|
||||
if (!tuh_hid_receive_report(dev_addr, instance))
|
||||
{
|
||||
@@ -129,6 +135,11 @@ void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
|
||||
delete dualsense;
|
||||
dualsense = nullptr;
|
||||
}
|
||||
if (mouse)
|
||||
{
|
||||
delete mouse;
|
||||
mouse = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,6 +169,9 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons
|
||||
case HOST_MODE_HID_N64USB:
|
||||
n64usb->process_report(report, len);
|
||||
break;
|
||||
case HOST_MODE_HID_MOUSE:
|
||||
mouse->process_report(report, len);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !tuh_hid_receive_report(dev_addr, instance) )
|
||||
@@ -166,6 +180,7 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons
|
||||
}
|
||||
}
|
||||
|
||||
// send rumble data
|
||||
bool send_fb_data_to_hid_gamepad()
|
||||
{
|
||||
if (!gamepad_mounted)
|
||||
@@ -200,6 +215,9 @@ bool send_fb_data_to_hid_gamepad()
|
||||
case HOST_MODE_HID_N64USB:
|
||||
rumble_sent = n64usb->send_fb_data();
|
||||
break;
|
||||
case HOST_MODE_HID_MOUSE:
|
||||
rumble_sent = mouse->send_fb_data();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef _HID_HOST_APP_H_
|
||||
#define _HID_HOST_APP_H_
|
||||
|
||||
#include "usbh/tusb_hid/mouse.h"
|
||||
#include "usbh/tusb_hid/n64usb.h"
|
||||
#include "usbh/tusb_hid/psclassic.h"
|
||||
#include "usbh/tusb_hid/ps3.h"
|
||||
|
||||
76
src/usbh/tusb_hid/mouse.cpp
Normal file
76
src/usbh/tusb_hid/mouse.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
#include <stdint.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "tusb.h"
|
||||
|
||||
#include "usbh/tusb_hid/mouse.h"
|
||||
|
||||
#include "utilities/scaling.h"
|
||||
|
||||
#include "Gamepad.h"
|
||||
|
||||
void Mouse::init(uint8_t dev_addr, uint8_t instance)
|
||||
{
|
||||
mouse.dev_addr = dev_addr;
|
||||
mouse.instance = instance;
|
||||
}
|
||||
|
||||
int16_t Mouse::scale_and_clamp_axes(int32_t value)
|
||||
{
|
||||
// minimum % of int16 +/- joystick value allowed
|
||||
float minimum_percentage = 0.10; // 5%
|
||||
int32_t scaled_value = 0;
|
||||
|
||||
if (value > 0)
|
||||
{
|
||||
scaled_value = (INT16_MAX * minimum_percentage) + ((1 - minimum_percentage) * value);
|
||||
}
|
||||
else if (value < 0)
|
||||
{
|
||||
scaled_value = (INT16_MIN * minimum_percentage) + ((1 - minimum_percentage) * value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (scaled_value >= INT16_MAX) return INT16_MAX;
|
||||
else if (scaled_value <= INT16_MIN) return INT16_MIN;
|
||||
|
||||
return (int16_t)scaled_value;
|
||||
}
|
||||
|
||||
void Mouse::update_gamepad(const hid_mouse_report_t* mouse_report)
|
||||
{
|
||||
// gamepad.reset_state();
|
||||
|
||||
gamepad.state.rt = (mouse_report->buttons & MOUSE_BUTTON_LEFT ) ? 0xFF : 0x00;
|
||||
gamepad.state.lt = (mouse_report->buttons & MOUSE_BUTTON_RIGHT) ? 0xFF : 0x00;
|
||||
|
||||
// for testing
|
||||
gamepad.state.x = (mouse_report->buttons & MOUSE_BUTTON_BACKWARD);
|
||||
gamepad.state.a = (mouse_report->buttons & MOUSE_BUTTON_FORWARD );
|
||||
|
||||
gamepad.state.y = (mouse_report->wheel != 0);
|
||||
|
||||
int32_t scaled_y = scale_int8_to_int16(mouse_report->y, true) * 2; // * 2 to make more responsive
|
||||
int32_t scaled_x = scale_int8_to_int16(mouse_report->x, false) * 2;
|
||||
|
||||
gamepad.state.ry = scale_and_clamp_axes(scaled_y);
|
||||
gamepad.state.rx = scale_and_clamp_axes(scaled_x);
|
||||
}
|
||||
|
||||
void Mouse::process_report(uint8_t const* report, uint16_t len)
|
||||
{
|
||||
static hid_mouse_report_t prev_report = { 0 };
|
||||
|
||||
hid_mouse_report_t mouse_report;
|
||||
memcpy(&mouse_report, report, sizeof(mouse_report));
|
||||
|
||||
if (memcmp(&mouse_report, &prev_report, sizeof(mouse_report)) != 0)
|
||||
update_gamepad(&mouse_report);
|
||||
}
|
||||
|
||||
bool Mouse::send_fb_data()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
31
src/usbh/tusb_hid/mouse.h
Normal file
31
src/usbh/tusb_hid/mouse.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef _MOUSE_H_
|
||||
#define _MOUSE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "class/hid/hid.h"
|
||||
#include "usbh/tusb_hid/shared.h"
|
||||
|
||||
struct MouseState
|
||||
{
|
||||
uint8_t dev_addr = {0};
|
||||
uint8_t instance = {0};
|
||||
};
|
||||
|
||||
class Mouse
|
||||
{
|
||||
public:
|
||||
void init(uint8_t dev_addr, uint8_t instance);
|
||||
void process_report(uint8_t const* report, uint16_t len);
|
||||
bool send_fb_data();
|
||||
|
||||
private:
|
||||
MouseState mouse;
|
||||
|
||||
int16_t scale_and_clamp_axes(int32_t value);
|
||||
void update_gamepad(const hid_mouse_report_t* mouse_report);
|
||||
};
|
||||
|
||||
#endif // _MOUSE_H_
|
||||
@@ -6,15 +6,14 @@
|
||||
#include "class/hid/hid_host.h"
|
||||
|
||||
#include "utilities/scaling.h"
|
||||
#include "Gamepad.h"
|
||||
|
||||
#include "usbh/tusb_hid/ps3.h"
|
||||
#include "Gamepad.h"
|
||||
|
||||
#include "utilities/log.h"
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* this only works for DInput currently, no DS3 */
|
||||
/* -------------------------------------------- */
|
||||
/* ---------------------------- */
|
||||
/* this does not work currently */
|
||||
/* ---------------------------- */
|
||||
|
||||
void Dualshock3::init(uint8_t dev_addr, uint8_t instance)
|
||||
{
|
||||
@@ -25,13 +24,15 @@ void Dualshock3::init(uint8_t dev_addr, uint8_t instance)
|
||||
tuh_vid_pid_get(dualshock3.dev_addr, &vid, &pid);
|
||||
if (vid == 0x054C && pid == 0x0268) dualshock3.sixaxis = true;
|
||||
|
||||
// tuh_hid_set_protocol(dualshock3.dev_addr, dualshock3.instance, HID_PROTOCOL_REPORT);
|
||||
// sleep_ms(200);
|
||||
if (enable_reports())
|
||||
{
|
||||
// log("reports enabled, addr: %02X inst: %02X", dev_addr, instance);
|
||||
log("reports enabled, addr: %02X inst: %02X", dev_addr, instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
// log("report enable failed");
|
||||
log("reports enable failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +68,13 @@ bool Dualshock3::enable_reports()
|
||||
return dualshock3.report_enabled;
|
||||
}
|
||||
|
||||
// void Dualshock3::reset_state()
|
||||
// {
|
||||
// dualshock3.report_enabled = false;
|
||||
// dualshock3.dev_addr = 0;
|
||||
// dualshock3.instance = 0;
|
||||
// }
|
||||
|
||||
void Dualshock3::update_gamepad_dinput(const DInputReport* dinput_report)
|
||||
{
|
||||
gamepad.reset_state();
|
||||
@@ -127,7 +135,7 @@ void Dualshock3::update_gamepad_dinput(const DInputReport* dinput_report)
|
||||
gamepad.state.ry = scale_uint8_to_int16(dinput_report->r_y_axis, true);
|
||||
}
|
||||
|
||||
void Dualshock3::update_gamepad(const Dualshock3Report* ds3_data)
|
||||
void Dualshock3::update_gamepad(const DualShock3Report* ds3_data)
|
||||
{
|
||||
gamepad.reset_state();
|
||||
|
||||
@@ -165,12 +173,12 @@ void Dualshock3::process_report(uint8_t const* report, uint16_t len)
|
||||
// if (report[0] != 0x01) return;
|
||||
|
||||
// print hex values
|
||||
// char hex_buffer[len * 3];
|
||||
// for (int i = 0; i < len; i++)
|
||||
// {
|
||||
// sprintf(hex_buffer + (i * 3), "%02X ", report[i]); // Convert byte to hexadecimal string
|
||||
// }
|
||||
// log(hex_buffer);
|
||||
char hex_buffer[len * 3];
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
sprintf(hex_buffer + (i * 3), "%02X ", report[i]); // Convert byte to hexadecimal string
|
||||
}
|
||||
log(hex_buffer);
|
||||
|
||||
if (!dualshock3.sixaxis)
|
||||
{
|
||||
@@ -182,8 +190,8 @@ void Dualshock3::process_report(uint8_t const* report, uint16_t len)
|
||||
}
|
||||
else
|
||||
{
|
||||
static Dualshock3Report prev_report = { 0 };
|
||||
Dualshock3Report ds3_report;
|
||||
static DualShock3Report prev_report = { 0 };
|
||||
DualShock3Report ds3_report;
|
||||
memcpy(&ds3_report, report, sizeof(ds3_report));
|
||||
update_gamepad(&ds3_report);
|
||||
prev_report = ds3_report;
|
||||
@@ -217,5 +225,8 @@ bool Dualshock3::send_fb_data()
|
||||
output_report.rumble.left_duration = UINT8_MAX / 2;
|
||||
output_report.rumble.left_motor_force = gamepadOut.out_state.lrumble;
|
||||
|
||||
return tuh_hid_send_report(dualshock3.dev_addr, dualshock3.instance, 0x1, &output_report, sizeof(output_report));
|
||||
bool rumble_sent = tuh_hid_send_report(dualshock3.dev_addr, dualshock3.instance, 1, &output_report, sizeof(output_report));
|
||||
|
||||
return rumble_sent;
|
||||
// return true;
|
||||
}
|
||||
@@ -6,14 +6,15 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "usbh/tusb_hid/shared.h"
|
||||
#include "descriptors/PS3Descriptors.h"
|
||||
#include "descriptors/DInputDescriptors.h"
|
||||
#include "descriptors/PS3Descriptors.h"
|
||||
|
||||
#define PS3_REPORT_BUFFER_SIZE 48
|
||||
|
||||
const usb_vid_pid_t ps3_devices[] =
|
||||
{
|
||||
{0x054C, 0x0268}, // Sony Batoh (Dualshock 3)
|
||||
{0x2563, 0x0575}, // Nuplay Armor 3
|
||||
// {0x045E, 0x028E}, // Voyee generic "P3", won't work, IDs are for a 360 controller (dumb)
|
||||
{0x044F, 0xB324}, // ThrustMaster Dual Trigger (PS3 mode)
|
||||
{0x0738, 0x8818}, // MadCatz Street Fighter IV Arcade FightStick
|
||||
@@ -40,8 +41,8 @@ class Dualshock3
|
||||
Dualshock3State dualshock3;
|
||||
|
||||
bool enable_reports();
|
||||
void reset_state();
|
||||
void update_gamepad(const Dualshock3Report* ds3_data);
|
||||
// void reset_state();
|
||||
void update_gamepad(const DualShock3Report* ds3_data);
|
||||
void update_gamepad_dinput(const DInputReport* dinput_report);
|
||||
};
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
#include "tusb_host.h"
|
||||
#include "tusb_host_manager.h"
|
||||
|
||||
// TODO figure out something to do with the leds
|
||||
// tuh_mounted is always true after unplugging a gamepad, idk what's up with that
|
||||
|
||||
#ifdef FEATHER_RP2040
|
||||
#define PIO_USB_DP_PIN 16 // DM = 17
|
||||
#define PIN_5V_EN 18
|
||||
@@ -59,10 +62,8 @@ void usbh_main()
|
||||
|
||||
if (current_time - fb_sent_time >= fb_interval)
|
||||
{
|
||||
if (send_fb_data_to_gamepad())
|
||||
{
|
||||
fb_sent_time = current_time;
|
||||
}
|
||||
send_fb_data_to_gamepad();
|
||||
fb_sent_time = current_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,9 @@
|
||||
|
||||
HostMode host_mode;
|
||||
|
||||
bool device_mounted;
|
||||
bool device_mounted = false;
|
||||
uint8_t device_daddr = 0;
|
||||
tusb_desc_interface_t config_descriptor;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -26,7 +27,7 @@ const DeviceTypeInfo device_types[] =
|
||||
{
|
||||
{ n64_devices, sizeof(n64_devices) / sizeof(usb_vid_pid_t), HOST_MODE_HID_N64USB },
|
||||
{ psc_devices, sizeof(psc_devices) / sizeof(usb_vid_pid_t), HOST_MODE_HID_PSCLASSIC },
|
||||
{ ps3_devices, sizeof(ps3_devices) / sizeof(usb_vid_pid_t), HOST_MODE_HID_PS3 },
|
||||
// { ps3_devices, sizeof(ps3_devices) / sizeof(usb_vid_pid_t), HOST_MODE_HID_PS3 },
|
||||
{ ps4_devices, sizeof(ps4_devices) / sizeof(usb_vid_pid_t), HOST_MODE_HID_PS4 },
|
||||
{ ps5_devices, sizeof(ps5_devices) / sizeof(usb_vid_pid_t), HOST_MODE_HID_PS5 },
|
||||
{ switch_wired_devices, sizeof(switch_wired_devices) / sizeof(usb_vid_pid_t), HOST_MODE_HID_SWITCH_WIRED },
|
||||
@@ -46,16 +47,31 @@ bool check_vid_pid(const usb_vid_pid_t* devices, size_t num_devices, HostMode ch
|
||||
return false;
|
||||
}
|
||||
|
||||
void config_descriptor_complete_cb(tuh_xfer_t* xfer)
|
||||
{
|
||||
if (xfer->result == XFER_RESULT_SUCCESS)
|
||||
{
|
||||
if ((config_descriptor.bInterfaceSubClass == 0x5D && config_descriptor.bInterfaceProtocol == 0x81) ||
|
||||
(config_descriptor.bInterfaceSubClass == 0x5D && config_descriptor.bInterfaceProtocol == 0x01) ||
|
||||
(config_descriptor.bInterfaceSubClass == 0x47 && config_descriptor.bInterfaceProtocol == 0xD0) ||
|
||||
(config_descriptor.bInterfaceSubClass == 0x42 && config_descriptor.bInterfaceClass == 0x58))
|
||||
{
|
||||
host_mode = HOST_MODE_XINPUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tuh_mount_cb(uint8_t daddr)
|
||||
{
|
||||
device_mounted = true;
|
||||
device_daddr = daddr;
|
||||
if (!device_mounted)
|
||||
{
|
||||
device_mounted = true;
|
||||
device_daddr = daddr;
|
||||
}
|
||||
|
||||
uint16_t vid, pid;
|
||||
tuh_vid_pid_get(daddr, &vid, &pid);
|
||||
|
||||
host_mode = HOST_MODE_XINPUT;
|
||||
|
||||
// set host mode depending on VID/PID match
|
||||
const size_t num_device_types = sizeof(device_types) / sizeof(DeviceTypeInfo);
|
||||
|
||||
@@ -68,12 +84,15 @@ void tuh_mount_cb(uint8_t daddr)
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
// if (!tuh_descriptor_get_configuration(daddr, 0, &config_descriptor, sizeof(config_descriptor), config_descriptor_complete_cb, 0))
|
||||
// {
|
||||
host_mode = HOST_MODE_HID_MOUSE; // idk
|
||||
// }
|
||||
}
|
||||
|
||||
void tuh_umount_cb(uint8_t daddr)
|
||||
{
|
||||
if (device_mounted)
|
||||
if (device_mounted && device_daddr == daddr)
|
||||
{
|
||||
device_mounted = false;
|
||||
}
|
||||
@@ -92,20 +111,18 @@ usbh_class_driver_t const* usbh_app_driver_get_cb(uint8_t* driver_count)
|
||||
}
|
||||
}
|
||||
|
||||
bool send_fb_data_to_gamepad()
|
||||
void send_fb_data_to_gamepad()
|
||||
{
|
||||
if (!device_mounted)
|
||||
return true;
|
||||
|
||||
if (host_mode == HOST_MODE_XINPUT)
|
||||
if (device_mounted)
|
||||
{
|
||||
return send_fb_data_to_xinput_gamepad();
|
||||
if (host_mode == HOST_MODE_XINPUT)
|
||||
{
|
||||
send_fb_data_to_xinput_gamepad();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (send_fb_data_to_hid_gamepad())
|
||||
gamepadOut.rumble_hid_reset(); // needed so rumble doesn't get stuck on
|
||||
}
|
||||
}
|
||||
else if (send_fb_data_to_hid_gamepad())
|
||||
{
|
||||
gamepadOut.rumble_hid_reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -10,11 +10,12 @@ typedef enum
|
||||
HOST_MODE_HID_PS3,
|
||||
HOST_MODE_HID_PS4,
|
||||
HOST_MODE_HID_PS5,
|
||||
HOST_MODE_HID_N64USB
|
||||
HOST_MODE_HID_N64USB,
|
||||
HOST_MODE_HID_MOUSE
|
||||
} HostMode;
|
||||
|
||||
extern HostMode host_mode;
|
||||
|
||||
bool send_fb_data_to_gamepad();
|
||||
void send_fb_data_to_gamepad();
|
||||
|
||||
#endif // _TUSB_HOST_MANAGER_H_
|
||||
@@ -44,5 +44,28 @@ int16_t scale_uint8_to_int16(uint8_t value, bool invert)
|
||||
scaled_value = INT16_MAX;
|
||||
}
|
||||
|
||||
return (int16_t)scaled_value;
|
||||
}
|
||||
|
||||
int16_t scale_int8_to_int16(int8_t value, bool invert)
|
||||
{
|
||||
const uint16_t multiplier = 257;
|
||||
|
||||
int32_t scaled_value = (int32_t)value * multiplier;
|
||||
|
||||
if (invert)
|
||||
{
|
||||
scaled_value = -scaled_value;
|
||||
}
|
||||
|
||||
if (scaled_value < INT16_MIN)
|
||||
{
|
||||
scaled_value = INT16_MIN;
|
||||
}
|
||||
else if (scaled_value > INT16_MAX)
|
||||
{
|
||||
scaled_value = INT16_MAX;
|
||||
}
|
||||
|
||||
return (int16_t)scaled_value;
|
||||
}
|
||||
@@ -7,5 +7,6 @@
|
||||
|
||||
uint8_t scale_int16_to_uint8(int16_t value, bool invert);
|
||||
int16_t scale_uint8_to_int16(uint8_t value, bool invert);
|
||||
int16_t scale_int8_to_int16(int8_t value, bool invert);
|
||||
|
||||
#endif // _SCALING_H_
|
||||
@@ -1,3 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#define FW_VERSION "0.3.0"
|
||||
#define FW_VERSION "0.2.0"
|
||||
|
||||
Reference in New Issue
Block a user