5 Commits

Author SHA1 Message Date
wiredopposite
88a84fe6f2 input mode selection 2024-03-11 14:18:55 -06:00
wiredopposite
91906866a8 mouse testing 2024-03-10 10:15:33 -06:00
wiredopposite
22cabd06dc fixed button combo polling 2024-03-10 09:40:02 -06:00
wiredopposite
bf52296e60 add input mode switching 2024-03-09 23:06:25 -07:00
wiredopposite
9bdc0dbb33 add input mode switching 2024-03-09 23:03:25 -07:00
25 changed files with 345 additions and 167 deletions

3
.gitignore vendored
View File

@@ -3,5 +3,4 @@ build
release
generated
tools
.ignore
src/usbh/tusb_hid/experiment
.ignore

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,3 @@
#pragma once
#define FW_VERSION "0.3.0"
#define FW_VERSION "0.2.0"