v1.0.0-alpha

This commit is contained in:
wiredopposite
2024-12-13 18:58:18 -07:00
parent da14684b90
commit f863f84976
79 changed files with 4396 additions and 2991 deletions

3
.gitignore vendored
View File

@@ -7,4 +7,7 @@ Firmware/ESP32/build
Firmware/ESP32/components/btstack
Firmware/ESP32/sdkconfig.old
Firmware/external/pico-sdk
Firmware/external/picotool
Tools/dvd-dongle-rom.bin

3
.gitmodules vendored
View File

@@ -4,9 +4,6 @@
[submodule "Firmware/external/tinyusb"]
path = Firmware/external/tinyusb
url = https://github.com/hathach/tinyusb.git
[submodule "Firmware/external/Pico-PIO-USB"]
path = Firmware/external/Pico-PIO-USB
url = https://github.com/sekigon-gonnoc/Pico-PIO-USB.git
[submodule "Tools/dump-dvd-kit"]
path = Tools/dump-dvd-kit
url = https://github.com/XboxDev/dump-dvd-kit.git

View File

@@ -21,12 +21,15 @@
namespace bluepad32 {
// I2CDriver i2c_driver;
static constexpr uint32_t FEEDBACK_TIME_MS = 200;
static constexpr uint32_t LED_TIME_MS = 500;
struct Device
{
std::atomic<bool> connected{false};
std::atomic<bool> new_report_in{false};
std::atomic<ReportIn> report_in{ReportIn()};
std::atomic<ReportOut> report_out{ReportOut()};
};
@@ -50,6 +53,13 @@ static inline void send_feedback_cb(btstack_timer_source *ts)
{
continue;
}
// ReportOut report_out;
// report_out.index = i;
// i2c_driver.i2c_read_blocking(i2c_driver.MULTI_SLAVE ? i + 1 : 1, reinterpret_cast<uint8_t*>(&report_out), sizeof(ReportOut));
// if (!report_out.rumble_l && !report_out.rumble_r)
// {
// continue;
// }
bp_device->report_parser.play_dual_rumble(bp_device, 0, FEEDBACK_TIME_MS, report_out.rumble_l, report_out.rumble_r);
}
@@ -92,7 +102,7 @@ static void init_complete_cb(void)
// // Based on runtime condition, you can delete or list the stored BT keys.
// if (1)
// {
// uni_bt_del_keys_unsafe();
uni_bt_del_keys_unsafe();
// }
// else
// {
@@ -187,16 +197,16 @@ static void controller_data_cb(uni_hid_device_t* device, uni_controller_t* contr
case DPAD_RIGHT:
report_in.dpad = Gamepad::DPad::RIGHT;
break;
case DPAD_UP | DPAD_RIGHT:
case (DPAD_UP | DPAD_RIGHT):
report_in.dpad = Gamepad::DPad::UP_RIGHT;
break;
case DPAD_DOWN | DPAD_RIGHT:
case (DPAD_DOWN | DPAD_RIGHT):
report_in.dpad = Gamepad::DPad::DOWN_RIGHT;
break;
case DPAD_DOWN | DPAD_LEFT:
case (DPAD_DOWN | DPAD_LEFT):
report_in.dpad = Gamepad::DPad::DOWN_LEFT;
break;
case DPAD_UP | DPAD_LEFT:
case (DPAD_UP | DPAD_LEFT):
report_in.dpad = Gamepad::DPad::UP_LEFT;
break;
default:
@@ -225,6 +235,8 @@ static void controller_data_cb(uni_hid_device_t* device, uni_controller_t* contr
report_in.joystick_ry = static_cast<int16_t>(uni_gp->axis_ry);
devices_[idx].report_in.store(report_in);
devices_[idx].new_report_in.store(true);
// i2c_driver.i2c_write_blocking(i2c_driver.MULTI_SLAVE ? idx + 1 : 1, reinterpret_cast<const uint8_t*>(&report_in), sizeof(ReportIn));
std::memcpy(uni_gp, &prev_uni_gp[idx], sizeof(uni_gamepad_t));
}
@@ -256,6 +268,7 @@ uni_platform* get_driver()
ReportIn get_report_in(uint8_t index)
{
devices_[index].new_report_in.store(false);
return devices_[index].report_in.load();
}
@@ -280,6 +293,8 @@ void run_task()
board_api::init_pins();
// i2c_driver.initialize_i2c();
btstack_init();
uni_platform_set_custom(get_driver());
@@ -302,7 +317,6 @@ void run_task()
btstack_run_loop_execute();
}
//Thread safe
bool any_connected()
{
for (auto& device : devices_)
@@ -320,4 +334,9 @@ bool connected(uint8_t index)
return devices_[index].connected.load();
}
bool new_report_in(uint8_t index)
{
return devices_[index].new_report_in.load();
}
} // namespace bluepad32

View File

@@ -12,6 +12,7 @@ namespace bluepad32
void run_task();
bool connected(uint8_t index);
bool any_connected();
bool new_report_in(uint8_t index);
ReportIn get_report_in(uint8_t index);
void set_report_out(const ReportOut& report);
}

View File

@@ -41,13 +41,16 @@ void I2CDriver::run_task()
continue;
}
report_in = bluepad32::get_report_in(i);
if (i2c_write_blocking(MULTI_SLAVE ? (i + 1) : 0x01, reinterpret_cast<const uint8_t*>(&report_in), sizeof(ReportIn)) != ESP_OK)
if (bluepad32::new_report_in(i))
{
continue;
report_in = bluepad32::get_report_in(i);
if (i2c_write_blocking(MULTI_SLAVE ? (i + 1) : 0x01, reinterpret_cast<const uint8_t*>(&report_in), sizeof(ReportIn)) != ESP_OK)
{
continue;
}
}
vTaskDelay(1);
// vTaskDelay(1);
if (i2c_read_blocking(MULTI_SLAVE ? (i + 1) : 0x01, reinterpret_cast<uint8_t*>(&report_out), sizeof(ReportOut)) != ESP_OK)
{

View File

@@ -12,21 +12,17 @@
class I2CDriver
{
public:
I2CDriver() = default;
~I2CDriver() { i2c_driver_delete(I2C_NUM_0); }
void run_task();
private:
static constexpr bool MULTI_SLAVE =
#if CONFIG_MULTI_SLAVE_MODE == 0
false;
#else
true;
#endif
// std::array<ReportIn, CONFIG_BLUEPAD32_MAX_DEVICES> report_in_buffer_{};
// std::array<std::atomic<bool>, CONFIG_BLUEPAD32_MAX_DEVICES> new_report_in_{false};
// std::array<ReportOut, CONFIG_BLUEPAD32_MAX_DEVICES> report_out_buffer_{};
I2CDriver() = default;
~I2CDriver() { i2c_driver_delete(I2C_NUM_0); }
void run_task();
void initialize_i2c();
@@ -61,6 +57,19 @@ private:
i2c_cmd_link_delete(cmd);
return ret;
}
private:
// static constexpr bool MULTI_SLAVE =
// #if CONFIG_MULTI_SLAVE_MODE == 0
// false;
// #else
// true;
// #endif
// std::array<ReportIn, CONFIG_BLUEPAD32_MAX_DEVICES> report_in_buffer_{};
// std::array<std::atomic<bool>, CONFIG_BLUEPAD32_MAX_DEVICES> new_report_in_{false};
// std::array<ReportOut, CONFIG_BLUEPAD32_MAX_DEVICES> report_out_buffer_{};
};
#endif // _I2C_DRIVER_H_

View File

@@ -10,6 +10,7 @@
void app_main(void)
{
// run_bluepad32();
xTaskCreatePinnedToCore(
run_bluepad32,
"bp32",

View File

@@ -1982,10 +1982,10 @@ CONFIG_BLUEPAD32_PLATFORM_CUSTOM=y
CONFIG_BLUEPAD32_MAX_DEVICES=1
CONFIG_BLUEPAD32_GAP_SECURITY=y
# CONFIG_BLUEPAD32_LOG_LEVEL_NONE is not set
# CONFIG_BLUEPAD32_LOG_LEVEL_ERROR is not set
CONFIG_BLUEPAD32_LOG_LEVEL_ERROR=y
# CONFIG_BLUEPAD32_LOG_LEVEL_INFO is not set
CONFIG_BLUEPAD32_LOG_LEVEL_DEBUG=y
CONFIG_BLUEPAD32_LOG_LEVEL=3
# CONFIG_BLUEPAD32_LOG_LEVEL_DEBUG is not set
CONFIG_BLUEPAD32_LOG_LEVEL=1
# CONFIG_BLUEPAD32_USB_CONSOLE_ENABLE is not set
CONFIG_BLUEPAD32_ENABLE_BLE_BY_DEFAULT=y
CONFIG_BLUEPAD32_MAX_ALLOWLIST=4

View File

@@ -116,5 +116,15 @@
"flash.h": "c",
"uart_bridge.h": "c",
"usbh.h": "c"
}
},
"cmake.buildEnvironment": {
"PICO_SDK_PATH": "C:/Programming/pico-sdk"
},
"cmake.environment": {
"PICO_SDK_PATH": "C:/Programming/pico-sdk"
},
"cmake.configureArgs": [
"-DOGXM_BOARD=EXTERNAL_4CH",
"-DMAX_GAMEPADS=4"
]
}

View File

@@ -3,8 +3,8 @@ cmake_minimum_required(VERSION 3.13)
set(FW_NAME "OGX-Mini")
set(FW_VERSION "v1.0.0-alpha")
set(CMAKE_C_COMPILER ${C_COMPILER})
set(CMAKE_CXX_COMPILER ${CXX_COMPILER})
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
@@ -21,8 +21,8 @@ get_pico_sdk(${EXTERNAL_DIR})
include(${PICO_SDK_PATH}/pico_sdk_init.cmake)
message("PICO_SDK_VERSION_STRING: ${PICO_SDK_VERSION_STRING}")
if (PICO_SDK_VERSION_STRING VERSION_LESS "1.4.0")
message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")
if (PICO_SDK_VERSION_STRING VERSION_LESS "2.1.0")
message(FATAL_ERROR "Raspberry Pi Pico SDK version 2.1.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")
endif()
project(${FW_NAME} C CXX ASM)
@@ -41,6 +41,8 @@ set(SOURCES_BOARD
${SRC}/OGXMini/OGXMini_PicoW.cpp
${SRC}/OGXMini/OGXMini_ESP32.cpp
${SRC}/TaskQueue/TaskQueue.cpp
${SRC}/Board/board_api.cpp
${SRC}/UserSettings/UserSettings.cpp
@@ -134,21 +136,21 @@ if(EN_USB_HOST)
list(APPEND SOURCES_BOARD
${SRC}/USBHost/tuh_callbacks.cpp
${SRC}/USBHost/HostDriver/DInput/DInput.cpp
${SRC}/USBHost/HostDriver/PSClassic/PSClassic.cpp
${SRC}/USBHost/HostDriver/SwitchWired/SwitchWired.cpp
${SRC}/USBHost/HostDriver/SwitchPro/SwitchPro.cpp
${SRC}/USBHost/HostDriver/PS5/PS5.cpp
${SRC}/USBHost/HostDriver/PS4/PS4.cpp
${SRC}/USBHost/HostDriver/PS3/PS3.cpp
# ${SRC}/USBHost/HostDriver/DInput/DInput.cpp
# ${SRC}/USBHost/HostDriver/PSClassic/PSClassic.cpp
# ${SRC}/USBHost/HostDriver/SwitchWired/SwitchWired.cpp
# ${SRC}/USBHost/HostDriver/SwitchPro/SwitchPro.cpp
# ${SRC}/USBHost/HostDriver/PS5/PS5.cpp
# ${SRC}/USBHost/HostDriver/PS4/PS4.cpp
# ${SRC}/USBHost/HostDriver/PS3/PS3.cpp
# ${SRC}/USBHost/HostDriver/N64/N64.cpp
# ${SRC}/USBHost/HostDriver/HIDGeneric/HIDGeneric.cpp
${SRC}/USBHost/HostDriver/XInput/XboxOG.cpp
${SRC}/USBHost/HostDriver/XInput/XboxOne.cpp
${SRC}/USBHost/HostDriver/XInput/Xbox360.cpp
${SRC}/USBHost/HostDriver/XInput/Xbox360W.cpp
${SRC}/USBHost/HostDriver/N64/N64.cpp
${SRC}/USBHost/HostDriver/XInput/tuh_xinput/tuh_xinput.cpp
${SRC}/USBHost/HostDriver/HIDGeneric/HIDGeneric.cpp
${SRC}/USBHost/HostDriver/tuh_uni/tuh_uni.cpp
${SRC}/USBHost/HIDParser/HIDJoystick.cpp
${SRC}/USBHost/HIDParser/HIDReportDescriptor.cpp
@@ -196,7 +198,8 @@ if(EN_4CH)
add_compile_definitions(CONFIG_EN_4CH=1)
message(STATUS "4CH enabled.")
list(APPEND SOURCES_BOARD
${SRC}/I2CDriver/i2c_driver_4ch.cpp
${SRC}/I2CDriver/4Channel/I2CMaster.cpp
${SRC}/I2CDriver/4Channel/I2CSlave.cpp
)
list(APPEND LIBS_BOARD
hardware_i2c
@@ -235,27 +238,34 @@ if(EXISTS ${SRC}/USBDevice/DeviceDriver/XboxOG/tud_xid/tud_xid_xremote_rom.h)
endif()
if(NOT EN_BLUETOOTH)
add_compile_definitions(PICO_BOOT_STAGE2_CHOOSE_GENERIC_03H=1 PICO_XOSC_STARTUP_DELAY_MULTIPLIER=64)
# add_compile_definitions(PICO_BOOT_STAGE2_CHOOSE_GENERIC_03H=1 PICO_XOSC_STARTUP_DELAY_MULTIPLIER=64)
add_compile_definitions(PICO_XOSC_STARTUP_DELAY_MULTIPLIER=64)
endif()
pico_sdk_init()
# pico_enable_stdio_usb(${FW_NAME} 0)
add_executable(${FW_NAME} ${SOURCES_BOARD})
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
pico_enable_stdio_uart(${FW_NAME} 1)
add_compile_definitions(CFG_TUSB_DEBUG=2)
add_compile_definitions(LOG=2)
target_compile_options(${FW_NAME} PRIVATE
-Wall # Enable most warnings
-Wextra # Enable extra warnings
-Wconversion # Warn on type conversion issues
-Wsign-conversion # Warn on sign conversion issues
# -Werror # Treat warnings as errors
)
# target_compile_options(${FW_NAME} PRIVATE
# -Wall # Enable most warnings
# -Wextra # Enable extra warnings
# -Wconversion # Warn on type conversion issues
# -Wsign-conversion # Warn on sign conversion issues
# # -Werror # Treat warnings as errors
# )
add_link_options(
-Wl,--gc-sections
)
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
add_compile_definitions(CFG_TUSB_DEBUG=0)
add_compile_options(
-O2 # Optimize for speed
-O3 # Optimize for speed
-mcpu=cortex-m0plus # Target ARM Cortex-M0+
-mthumb # Use Thumb instruction set
-ffunction-sections # Place each function in its own section

View File

@@ -19,28 +19,26 @@ static_assert((CONFIG_BLUEPAD32_MAX_DEVICES == MAX_GAMEPADS), "Mismatch between
namespace bluepad32 {
static constexpr uint32_t FEEDBACK_TIME_MS = 200;
static constexpr uint32_t FEEDBACK_TIME_MS = 250;
static constexpr uint32_t LED_CHECK_TIME_MS = 500;
struct Device
struct BTDevice
{
bool connected{false};
Gamepad* gamepad{nullptr};
};
std::array<Device, MAX_GAMEPADS> devices_;
BTDevice bt_devices_[MAX_GAMEPADS];
btstack_timer_source_t led_timer_;
bool led_timer_set_{false};
//This solves a null function pointer issue with bluepad32, device->report_parser.play_dual_rumble() becomes null before the disconnect callback
//This solves a function pointer/crash issue with bluepad32
void set_rumble(uni_hid_device_t* bp_device, uint16_t length, uint8_t rumble_l, uint8_t rumble_r)
{
if (!bp_device || !bp_device->report_parser.play_dual_rumble)
{
return;
}
switch (bp_device->controller_type)
{
case CONTROLLER_TYPE_XBoxOneController:
uni_hid_parser_xboxone_play_dual_rumble(bp_device, 0, length, rumble_l, rumble_r);
uni_hid_parser_xboxone_play_dual_rumble(bp_device, 0, length + 10, rumble_l, rumble_r);
break;
case CONTROLLER_TYPE_AndroidController:
if (bp_device->vendor_id == UNI_HID_PARSER_STADIA_VID && bp_device->product_id == UNI_HID_PARSER_STADIA_PID)
@@ -77,20 +75,18 @@ static void send_feedback_cb(btstack_timer_source *ts)
{
uni_hid_device_t* bp_device = nullptr;
for (uint8_t i = 0; i < devices_.size(); ++i)
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
{
if (!devices_[i].connected ||
if (!bt_devices_[i].connected ||
!(bp_device = uni_hid_device_get_instance_for_idx(i)))
{
continue;
}
uint8_t rumble_l = devices_[i].gamepad->get_rumble_l().uint8();
uint8_t rumble_r = devices_[i].gamepad->get_rumble_r().uint8();
if (rumble_l > 0 || rumble_r > 0)
Gamepad::PadOut gp_out = bt_devices_[i].gamepad->get_pad_out();
if (gp_out.rumble_l > 0 || gp_out.rumble_r > 0)
{
// bp_device->report_parser.play_dual_rumble(bp_device, 0, static_cast<uint16_t>(FEEDBACK_TIME_MS), rumble_l, rumble_r);
set_rumble(bp_device, static_cast<uint16_t>(FEEDBACK_TIME_MS), rumble_l, rumble_r);
set_rumble(bp_device, static_cast<uint16_t>(FEEDBACK_TIME_MS), gp_out.rumble_l, gp_out.rumble_r);
}
}
@@ -151,9 +147,14 @@ static void device_disconnected_cb(uni_hid_device_t* device)
{
return;
}
devices_[idx].connected = false;
devices_[idx].gamepad->reset_pad();
if (!led_timer_set_)
{
led_timer_set_ = true;
led_timer_.process = check_led_cb;
led_timer_.context = nullptr;
btstack_run_loop_set_timer(&led_timer_, LED_CHECK_TIME_MS);
btstack_run_loop_add_timer(&led_timer_);
}
}
static uni_error_t device_ready_cb(uni_hid_device_t* device)
@@ -164,7 +165,13 @@ static uni_error_t device_ready_cb(uni_hid_device_t* device)
return UNI_ERROR_SUCCESS;
}
devices_[idx].connected = true;
bt_devices_[idx].connected = true;
if (led_timer_set_)
{
led_timer_set_ = false;
btstack_run_loop_remove_timer(&led_timer_);
board_api::set_led(true);
}
return UNI_ERROR_SUCCESS;
}
@@ -185,66 +192,60 @@ static void controller_data_cb(uni_hid_device_t* device, uni_controller_t* contr
uni_gamepad_t *uni_gp = &controller->gamepad;
int idx = uni_hid_device_get_idx_for_instance(device);
if (idx >= MAX_GAMEPADS || idx < 0 || std::memcmp(uni_gp, &prev_uni_gp[idx], sizeof(uni_gamepad_t)) == 0)
{
return;
}
Gamepad* gamepad = devices_[idx].gamepad;
gamepad->reset_pad();
Gamepad* gamepad = bt_devices_[idx].gamepad;
Gamepad::PadIn gp_in;
switch (uni_gp->dpad)
{
case DPAD_UP:
gamepad->set_dpad_up();
gp_in.dpad = gamepad->MAP_DPAD_UP;
break;
case DPAD_DOWN:
gamepad->set_dpad_down();
gp_in.dpad = gamepad->MAP_DPAD_DOWN;
break;
case DPAD_LEFT:
gamepad->set_dpad_left();
gp_in.dpad = gamepad->MAP_DPAD_LEFT;
break;
case DPAD_RIGHT:
gamepad->set_dpad_right();
gp_in.dpad = gamepad->MAP_DPAD_RIGHT;
break;
case DPAD_UP | DPAD_RIGHT:
gamepad->set_dpad_up_right();
gp_in.dpad = gamepad->MAP_DPAD_UP_RIGHT;
break;
case DPAD_DOWN | DPAD_RIGHT:
gamepad->set_dpad_down_right();
gp_in.dpad = gamepad->MAP_DPAD_DOWN_RIGHT;
break;
case DPAD_DOWN | DPAD_LEFT:
gamepad->set_dpad_down_left();
gp_in.dpad = gamepad->MAP_DPAD_DOWN_LEFT;
break;
case DPAD_UP | DPAD_LEFT:
gamepad->set_dpad_up_left();
gp_in.dpad = gamepad->MAP_DPAD_UP_LEFT;
break;
default:
break;
}
if (uni_gp->buttons & BUTTON_A) gamepad->set_button_a();
if (uni_gp->buttons & BUTTON_B) gamepad->set_button_b();
if (uni_gp->buttons & BUTTON_X) gamepad->set_button_x();
if (uni_gp->buttons & BUTTON_Y) gamepad->set_button_y();
if (uni_gp->buttons & BUTTON_SHOULDER_L) gamepad->set_button_lb();
if (uni_gp->buttons & BUTTON_SHOULDER_R) gamepad->set_button_rb();
if (uni_gp->buttons & BUTTON_THUMB_L) gamepad->set_button_l3();
if (uni_gp->buttons & BUTTON_THUMB_R) gamepad->set_button_r3();
if (uni_gp->misc_buttons & MISC_BUTTON_BACK) gamepad->set_button_back();
if (uni_gp->misc_buttons & MISC_BUTTON_START) gamepad->set_button_start();
if (uni_gp->misc_buttons & MISC_BUTTON_SYSTEM) gamepad->set_button_sys();
if (uni_gp->misc_buttons & MISC_BUTTON_CAPTURE) gamepad->set_button_misc();
if (uni_gp->buttons & BUTTON_A) gp_in.buttons |= gamepad->MAP_BUTTON_A;
if (uni_gp->buttons & BUTTON_B) gp_in.buttons |= gamepad->MAP_BUTTON_B;
if (uni_gp->buttons & BUTTON_X) gp_in.buttons |= gamepad->MAP_BUTTON_X;
if (uni_gp->buttons & BUTTON_Y) gp_in.buttons |= gamepad->MAP_BUTTON_Y;
if (uni_gp->buttons & BUTTON_SHOULDER_L) gp_in.buttons |= gamepad->MAP_BUTTON_LB;
if (uni_gp->buttons & BUTTON_SHOULDER_R) gp_in.buttons |= gamepad->MAP_BUTTON_RB;
if (uni_gp->buttons & BUTTON_THUMB_L) gp_in.buttons |= gamepad->MAP_BUTTON_L3;
if (uni_gp->buttons & BUTTON_THUMB_R) gp_in.buttons |= gamepad->MAP_BUTTON_R3;
if (uni_gp->misc_buttons & MISC_BUTTON_BACK) gp_in.buttons |= gamepad->MAP_BUTTON_BACK;
if (uni_gp->misc_buttons & MISC_BUTTON_START) gp_in.buttons |= gamepad->MAP_BUTTON_START;
if (uni_gp->misc_buttons & MISC_BUTTON_SYSTEM) gp_in.buttons |= gamepad->MAP_BUTTON_SYS;
gamepad->set_trigger_l_uint10(uni_gp->brake);
gamepad->set_trigger_r_uint10(uni_gp->throttle);
gp_in.trigger_l = Scale::uint10_to_uint8(uni_gp->brake);
gp_in.trigger_r = Scale::uint10_to_uint8(uni_gp->throttle);
gamepad->set_joystick_lx_int10(uni_gp->axis_x);
gamepad->set_joystick_ly_int10(uni_gp->axis_y);
gamepad->set_joystick_rx_int10(uni_gp->axis_rx);
gamepad->set_joystick_ry_int10(uni_gp->axis_ry);
gp_in.joystick_lx = Scale::int10_to_int16(uni_gp->axis_x);
gp_in.joystick_ly = Scale::int10_to_int16(uni_gp->axis_y);
gp_in.joystick_rx = Scale::int10_to_int16(uni_gp->axis_rx);
gp_in.joystick_ry = Scale::int10_to_int16(uni_gp->axis_ry);
std::memcpy(uni_gp, &prev_uni_gp[idx], sizeof(uni_gamepad_t));
gamepad->set_pad_in(gp_in);
}
const uni_property_t* get_property_cb(uni_property_idx_t idx)
@@ -272,11 +273,11 @@ uni_platform* get_driver()
//Public API
void run_task(std::array<Gamepad, MAX_GAMEPADS>& gamepads)
void run_task(Gamepad (&gamepads)[MAX_GAMEPADS])
{
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
{
devices_[i].gamepad = &gamepads[i];
bt_devices_[i].gamepad = &gamepads[i];
}
uni_platform_set_custom(get_driver());
@@ -288,11 +289,11 @@ void run_task(std::array<Gamepad, MAX_GAMEPADS>& gamepads)
btstack_run_loop_set_timer(&feedback_timer, FEEDBACK_TIME_MS);
btstack_run_loop_add_timer(&feedback_timer);
btstack_timer_source_t led_timer;
led_timer.process = check_led_cb;
led_timer.context = nullptr;
btstack_run_loop_set_timer(&led_timer, LED_CHECK_TIME_MS);
btstack_run_loop_add_timer(&led_timer);
led_timer_set_ = true;
led_timer_.process = check_led_cb;
led_timer_.context = nullptr;
btstack_run_loop_set_timer(&led_timer_, LED_CHECK_TIME_MS);
btstack_run_loop_add_timer(&led_timer_);
btstack_run_loop_execute();
}
@@ -302,14 +303,14 @@ std::array<bool, MAX_GAMEPADS> get_connected_map()
std::array<bool, MAX_GAMEPADS> mounted_map;
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
{
mounted_map[i] = devices_[i].connected;
mounted_map[i] = bt_devices_[i].connected;
}
return mounted_map;
}
bool any_connected()
{
for (auto& device : devices_)
for (auto& device : bt_devices_)
{
if (device.connected)
{

View File

@@ -13,8 +13,8 @@
namespace bluepad32
{
void run_task(std::array<Gamepad, MAX_GAMEPADS>& gamepads);
std::array<bool, MAX_GAMEPADS> get_connected_map();
void run_task(Gamepad (&gamepads)[MAX_GAMEPADS]);
// std::array<bool, MAX_GAMEPADS> get_connected_map();
bool any_connected();
} //namespace bluepad32

View File

@@ -1,3 +1,5 @@
/* This is too messy I'll clean it up at some point */
#include <pico/stdlib.h>
#include <pico/mutex.h>
#include <hardware/gpio.h>
@@ -49,8 +51,6 @@ void init_gpio()
gpio_put(RGB_PWR_PIN, 1);
#endif
set_led(false);
#elif defined(CONFIG_EN_BLUETOOTH)
//

View File

@@ -4,619 +4,283 @@
#include <cstdint>
#include <atomic>
#include <limits>
#include <array>
#include <cstring>
#include <pico/mutex.h>
#include "Scale.h"
#include "UserSettings/UserProfile.h"
namespace INT_16
{
static constexpr int16_t MIN = INT16_MIN;
static constexpr int16_t MID = 0;
static constexpr int16_t MAX = INT16_MAX;
}
namespace UINT_16
{
static constexpr uint16_t MIN = 0;
static constexpr uint16_t MID = 0x8000;
static constexpr uint16_t MAX = 0xFFFF;
}
namespace UINT_8
{
static constexpr uint8_t MAX = 0xFF;
static constexpr uint8_t MID = 0x80;
static constexpr uint8_t MIN = 0x00;
}
namespace INT_10
{
static constexpr int32_t MIN = -512;
static constexpr int32_t MAX = 511;
}
namespace UINT_10
{
static constexpr int32_t MAX = 1023;
}
class Gamepad
{
public:
struct DPad
//Defaults used by device to get buttons
static constexpr uint8_t DPAD_UP = 0x01;
static constexpr uint8_t DPAD_DOWN = 0x02;
static constexpr uint8_t DPAD_LEFT = 0x04;
static constexpr uint8_t DPAD_RIGHT = 0x08;
static constexpr uint8_t DPAD_UP_LEFT = DPAD_UP | DPAD_LEFT;
static constexpr uint8_t DPAD_UP_RIGHT = DPAD_UP | DPAD_RIGHT;
static constexpr uint8_t DPAD_DOWN_LEFT = DPAD_DOWN | DPAD_LEFT;
static constexpr uint8_t DPAD_DOWN_RIGHT = DPAD_DOWN | DPAD_RIGHT;
static constexpr uint8_t DPAD_NONE = 0x00;
static constexpr uint16_t BUTTON_A = 0x0001;
static constexpr uint16_t BUTTON_B = 0x0002;
static constexpr uint16_t BUTTON_X = 0x0004;
static constexpr uint16_t BUTTON_Y = 0x0008;
static constexpr uint16_t BUTTON_L3 = 0x0010;
static constexpr uint16_t BUTTON_R3 = 0x0020;
static constexpr uint16_t BUTTON_BACK = 0x0040;
static constexpr uint16_t BUTTON_START = 0x0080;
static constexpr uint16_t BUTTON_LB = 0x0100;
static constexpr uint16_t BUTTON_RB = 0x0200;
static constexpr uint16_t BUTTON_SYS = 0x0400;
static constexpr uint16_t BUTTON_MISC = 0x0800;
static constexpr uint8_t ANALOG_OFF_UP = 1;
static constexpr uint8_t ANALOG_OFF_DOWN = 2;
static constexpr uint8_t ANALOG_OFF_LEFT = 3;
static constexpr uint8_t ANALOG_OFF_RIGHT = 4;
static constexpr uint8_t ANALOG_OFF_A = 5;
static constexpr uint8_t ANALOG_OFF_B = 6;
static constexpr uint8_t ANALOG_OFF_X = 7;
static constexpr uint8_t ANALOG_OFF_Y = 8;
static constexpr uint8_t ANALOG_OFF_LB = 9;
static constexpr uint8_t ANALOG_OFF_RB = 10;
//Mappings used by host to set buttons
uint8_t MAP_DPAD_UP = DPAD_UP ;
uint8_t MAP_DPAD_DOWN = DPAD_DOWN ;
uint8_t MAP_DPAD_LEFT = DPAD_LEFT ;
uint8_t MAP_DPAD_RIGHT = DPAD_RIGHT ;
uint8_t MAP_DPAD_UP_LEFT = DPAD_UP_LEFT ;
uint8_t MAP_DPAD_UP_RIGHT = DPAD_UP_RIGHT ;
uint8_t MAP_DPAD_DOWN_LEFT = DPAD_DOWN_LEFT ;
uint8_t MAP_DPAD_DOWN_RIGHT = DPAD_DOWN_RIGHT;
uint8_t MAP_DPAD_NONE = DPAD_NONE ;
uint16_t MAP_BUTTON_A = BUTTON_A ;
uint16_t MAP_BUTTON_B = BUTTON_B ;
uint16_t MAP_BUTTON_X = BUTTON_X ;
uint16_t MAP_BUTTON_Y = BUTTON_Y ;
uint16_t MAP_BUTTON_L3 = BUTTON_L3 ;
uint16_t MAP_BUTTON_R3 = BUTTON_R3 ;
uint16_t MAP_BUTTON_BACK = BUTTON_BACK ;
uint16_t MAP_BUTTON_START = BUTTON_START;
uint16_t MAP_BUTTON_LB = BUTTON_LB ;
uint16_t MAP_BUTTON_RB = BUTTON_RB ;
uint16_t MAP_BUTTON_SYS = BUTTON_SYS ;
uint16_t MAP_BUTTON_MISC = BUTTON_MISC ;
uint8_t MAP_ANALOG_OFF_UP = ANALOG_OFF_UP ;
uint8_t MAP_ANALOG_OFF_DOWN = ANALOG_OFF_DOWN ;
uint8_t MAP_ANALOG_OFF_LEFT = ANALOG_OFF_LEFT ;
uint8_t MAP_ANALOG_OFF_RIGHT = ANALOG_OFF_RIGHT;
uint8_t MAP_ANALOG_OFF_A = ANALOG_OFF_A ;
uint8_t MAP_ANALOG_OFF_B = ANALOG_OFF_B ;
uint8_t MAP_ANALOG_OFF_X = ANALOG_OFF_X ;
uint8_t MAP_ANALOG_OFF_Y = ANALOG_OFF_Y ;
uint8_t MAP_ANALOG_OFF_LB = ANALOG_OFF_LB ;
uint8_t MAP_ANALOG_OFF_RB = ANALOG_OFF_RB ;
//
#pragma pack(push, 1)
struct PadIn
{
static constexpr uint8_t UP = 0x01;
static constexpr uint8_t DOWN = 0x02;
static constexpr uint8_t LEFT = 0x04;
static constexpr uint8_t RIGHT = 0x08;
static constexpr uint8_t UP_LEFT = UP | LEFT;
static constexpr uint8_t UP_RIGHT = UP | RIGHT;
static constexpr uint8_t DOWN_LEFT = DOWN | LEFT;
static constexpr uint8_t DOWN_RIGHT = DOWN | RIGHT;
static constexpr uint8_t NONE = 0x00;
uint8_t dpad;
uint16_t buttons;
uint8_t trigger_l;
uint8_t trigger_r;
int16_t joystick_lx;
int16_t joystick_ly;
int16_t joystick_rx;
int16_t joystick_ry;
uint8_t chatpad[3];
uint8_t analog[10];
PadIn()
{
std::memset(this, 0, sizeof(PadIn));
}
};
struct Button
struct PadOut
{
static constexpr uint16_t A = 0x0001;
static constexpr uint16_t B = 0x0002;
static constexpr uint16_t X = 0x0004;
static constexpr uint16_t Y = 0x0008;
static constexpr uint16_t L3 = 0x0010;
static constexpr uint16_t R3 = 0x0020;
static constexpr uint16_t BACK = 0x0040;
static constexpr uint16_t START = 0x0080;
static constexpr uint16_t LB = 0x0100;
static constexpr uint16_t RB = 0x0200;
static constexpr uint16_t SYS = 0x0400;
static constexpr uint16_t MISC = 0x0800;
};
uint8_t rumble_l;
uint8_t rumble_r;
using Chatpad = std::array<uint8_t, 3>;
PadOut()
{
std::memset(this, 0, sizeof(PadOut));
}
};
#pragma pack(pop)
Gamepad()
{
reset_pad();
reset_rumble();
setup_deadzones();
mutex_init(&pad_in_mutex_);
mutex_init(&pad_out_mutex_);
reset_pad_in();
reset_pad_out();
setup_deadzones(profile_);
};
~Gamepad() = default;
class Values //Store and scale values
{
public:
Values() : type_(Type::UINT8), uint8_(0) {};
~Values() = default;
inline int16_t int16(const bool invert = false) const
{
int16_t result = 0;
switch (type_.load())
{
case Type::INT16:
result = int16_.load();
break;
case Type::UINT16:
result = uint16_to_int16(uint16_.load());
break;
case Type::UINT8:
result = uint8_to_int16(uint8_.load());
break;
case Type::INT8:
result = int8_to_int16(int8_.load());
break;
default:
break;
}
return invert ? invert_joy(result) : result;
}
inline uint16_t uint16(const bool invert = false) const
{
uint16_t result = 0;
switch (type_.load())
{
case Type::UINT16:
result = uint16_.load();
break;
case Type::INT16:
result = int16_to_uint16(int16_.load());
break;
case Type::UINT8:
result = uint8_to_uint16(uint8_.load());
break;
case Type::INT8:
result = int8_to_uint16(int8_.load());
break;
}
return invert ? invert_joy(result) : result;
}
inline uint8_t uint8(const bool invert = false) const
{
uint8_t result = 0;
switch (type_.load())
{
case Type::UINT8:
result = uint8_.load();
break;
case Type::INT16:
result = int16_to_uint8(int16_.load());
break;
case Type::UINT16:
result = uint16_to_uint8(uint16_.load());
break;
case Type::INT8:
result = int8_to_uint8(int8_.load());
break;
}
return invert ? invert_joy(result) : result;
}
inline int8_t int8(bool invert = false) const
{
int8_t result = 0;
switch (type_.load())
{
case Type::INT8:
result = int8_.load();
break;
case Type::INT16:
result = int16_to_int8(int16_.load());
break;
case Type::UINT16:
result = uint16_to_int8(uint16_.load());
break;
case Type::UINT8:
result = uint8_to_int8(uint8_.load());
break;
}
return invert ? invert_joy(result) : result;
}
inline void set_value(int16_t value) { type_.store(Type::INT16); int16_.store(value); }
inline void set_value(uint16_t value) { type_.store(Type::UINT16); uint16_.store(value); }
inline void set_value(int8_t value) { type_.store(Type::INT8); int8_.store(value); }
inline void set_value(uint8_t value) { type_.store(Type::UINT8); uint8_.store(value); }
inline void reset_value() { type_ = Type::INT16; uint16_ = 0; };
static inline uint8_t invert_joy(uint8_t value)
{
return static_cast<uint8_t>(UINT_8::MAX - value);
}
static inline int8_t invert_joy(int8_t value)
{
return (value == std::numeric_limits<int8_t>::min()) ? std::numeric_limits<int8_t>::max() : -value;
}
static inline uint16_t invert_joy(uint16_t value)
{
return static_cast<uint16_t>(std::numeric_limits<uint16_t>::max() - value);
}
static inline int16_t invert_joy(int16_t value)
{
return (value == std::numeric_limits<int16_t>::min()) ? std::numeric_limits<int16_t>::max() : -value;
}
static inline uint8_t int16_to_uint8(int16_t value)
{
uint16_t shifted_value = static_cast<uint16_t>(value + UINT_16::MID);
return static_cast<uint8_t>(shifted_value >> 8);
}
static inline uint16_t int16_to_uint16(int16_t value)
{
return static_cast<uint16_t>(value + UINT_16::MID);
}
static inline int8_t int16_to_int8(int16_t value)
{
return static_cast<int8_t>((value + UINT_16::MID) >> 8);
}
static inline uint8_t uint16_to_uint8(uint16_t value)
{
return static_cast<uint8_t>(value >> 8);
}
static inline int16_t uint16_to_int16(uint16_t value)
{
return static_cast<int16_t>(value - UINT_16::MID);
}
static inline int8_t uint16_to_int8(uint16_t value)
{
return static_cast<int8_t>((value >> 8) - UINT_8::MID);
}
static inline int16_t uint8_to_int16(uint8_t value)
{
return static_cast<int16_t>((static_cast<int32_t>(value) << 8) - UINT_16::MID);
}
static inline uint16_t uint8_to_uint16(uint8_t value)
{
return static_cast<uint16_t>(value) << 8;
}
static inline int8_t uint8_to_int8(uint8_t value)
{
return static_cast<int8_t>(value - UINT_8::MID);
}
static inline int16_t int8_to_int16(int8_t value)
{
return static_cast<int16_t>(value) << 8;
}
static inline uint16_t int8_to_uint16(int8_t value)
{
return static_cast<uint16_t>((value + UINT_8::MID) << 8);
}
static inline uint8_t int8_to_uint8(int8_t value)
{
return static_cast<uint8_t>(value + UINT_8::MID);
}
static inline uint8_t int10_to_uint8(int32_t value)
{
value = value - INT_10::MIN;
if (value >= UINT_10::MAX)
{
return UINT_8::MAX;
}
else if (value <= 0)
{
return 0;
}
return static_cast<uint8_t>(value >> 2);
}
static inline int16_t int10_to_int16(int32_t value)
{
constexpr int32_t scale_factor = INT_16::MAX - INT_16::MIN;
constexpr int32_t range = INT_10::MAX - INT_10::MIN;
if (value >= INT_10::MAX)
{
return INT_16::MAX;
}
else if (value <= INT_10::MIN)
{
return INT_16::MIN;
}
int32_t scaled_value = (value - INT_10::MIN) * scale_factor;
return static_cast<int16_t>(scaled_value / range + INT_16::MIN);
}
static inline uint8_t uint10_to_uint8(int32_t value)
{
if (value > UINT_10::MAX)
{
value = UINT_10::MAX;
}
else if (value < 0)
{
value = 0;
}
return static_cast<uint8_t>(value >> 2);
}
private:
enum class Type { INT16, UINT16, INT8, UINT8 };
std::atomic<Type> type_;
union {
std::atomic<int16_t> int16_;
std::atomic<uint16_t> uint16_;
std::atomic<int8_t> int8_;
std::atomic<uint8_t> uint8_;
};
}; //Values
//Get
inline bool new_pad_in() const { return new_pad_in_.load(); }
inline bool new_pad_out() const { return new_pad_out_.load(); }
inline bool analog_enabled() const { return analog_enabled_.load(std::memory_order_relaxed); }
inline bool analog_enabled() const { return analog_enabled_; }
inline uint8_t get_dpad_buttons() const { return pad_state_.dpad; }
inline uint16_t get_buttons() const { return pad_state_.buttons; }
inline PadIn get_pad_in()
{
PadIn pad_in;
{
mutex_enter_blocking(&pad_in_mutex_);
pad_in = pad_in_;
new_pad_in_.store(false);
mutex_exit(&pad_in_mutex_);
}
return pad_in;
}
inline bool get_dpad_up() const { return (pad_state_.dpad & DPad::UP); }
inline bool get_dpad_down() const { return (pad_state_.dpad & DPad::DOWN); }
inline bool get_dpad_left() const { return (pad_state_.dpad & DPad::LEFT); }
inline bool get_dpad_right() const { return (pad_state_.dpad & DPad::RIGHT); }
inline bool get_button_a() const { return (pad_state_.buttons & Button::A); }
inline bool get_button_b() const { return (pad_state_.buttons & Button::B); }
inline bool get_button_x() const { return (pad_state_.buttons & Button::X); }
inline bool get_button_y() const { return (pad_state_.buttons & Button::Y); }
inline bool get_button_lb() const { return (pad_state_.buttons & Button::LB); }
inline bool get_button_rb() const { return (pad_state_.buttons & Button::RB); }
inline bool get_button_l3() const { return (pad_state_.buttons & Button::L3); }
inline bool get_button_r3() const { return (pad_state_.buttons & Button::R3); }
inline bool get_button_start() const { return (pad_state_.buttons & Button::START); }
inline bool get_button_back() const { return (pad_state_.buttons & Button::BACK); }
inline bool get_button_sys() const { return (pad_state_.buttons & Button::SYS); }
inline bool get_button_misc() const { return (pad_state_.buttons & Button::MISC); }
inline const Values& get_trigger_l() const { return pad_state_.triggers.l; }
inline const Values& get_trigger_r() const { return pad_state_.triggers.r; }
inline const Values& get_joystick_lx() const { return pad_state_.joysticks.lx; }
inline const Values& get_joystick_ly() const { return pad_state_.joysticks.ly; }
inline const Values& get_joystick_rx() const { return pad_state_.joysticks.rx; }
inline const Values& get_joystick_ry() const { return pad_state_.joysticks.ry; }
inline uint8_t get_analog_up() const { return pad_state_.analog_buttons.up; }
inline uint8_t get_analog_down() const { return pad_state_.analog_buttons.down; }
inline uint8_t get_analog_left() const { return pad_state_.analog_buttons.left; }
inline uint8_t get_analog_right() const { return pad_state_.analog_buttons.right; }
inline uint8_t get_analog_a() const { return pad_state_.analog_buttons.a; }
inline uint8_t get_analog_b() const { return pad_state_.analog_buttons.b; }
inline uint8_t get_analog_x() const { return pad_state_.analog_buttons.x; }
inline uint8_t get_analog_y() const { return pad_state_.analog_buttons.y; }
inline uint8_t get_analog_lb() const { return pad_state_.analog_buttons.lb; }
inline uint8_t get_analog_rb() const { return pad_state_.analog_buttons.rb; }
inline const Values& get_rumble_l() const { return rumble_state_.l; }
inline const Values& get_rumble_r() const { return rumble_state_.r; }
inline Chatpad get_chatpad() const
{
return
{
pad_state_.chatpad[0],
pad_state_.chatpad[1],
pad_state_.chatpad[2]
};
inline PadOut get_pad_out()
{
PadOut pad_out;
mutex_enter_blocking(&pad_out_mutex_);
pad_out = pad_out_;
new_pad_out_.store(false);
mutex_exit(&pad_out_mutex_);
return pad_out;
}
//Set
void set_analog_enabled(bool value) { analog_enabled_ = value; }
void set_analog_enabled(bool value)
{
analog_enabled_.store(value);
}
void set_profile(const UserProfile& user_profile)
{
profile_ = user_profile;
setup_deadzones();
setup_mappings(profile_);
setup_deadzones(profile_);
}
inline void set_dpad(uint8_t value) { pad_state_.dpad = value; }
inline void set_dpad_up() { pad_state_.dpad |= profile_.dpad_up; }
inline void set_dpad_down() { pad_state_.dpad |= profile_.dpad_down; }
inline void set_dpad_left() { pad_state_.dpad |= profile_.dpad_left; }
inline void set_dpad_right() { pad_state_.dpad |= profile_.dpad_right; }
inline void set_dpad_up_left() { pad_state_.dpad |= (profile_.dpad_up | profile_.dpad_left); }
inline void set_dpad_up_right() { pad_state_.dpad |= (profile_.dpad_up | profile_.dpad_right); }
inline void set_dpad_down_left() { pad_state_.dpad |= (profile_.dpad_down | profile_.dpad_left); }
inline void set_dpad_down_right() { pad_state_.dpad |= (profile_.dpad_down | profile_.dpad_right); }
inline void set_buttons(uint16_t value) { pad_state_.buttons = value; }
inline void set_button_a() { pad_state_.buttons |= profile_.button_a; }
inline void set_button_b() { pad_state_.buttons |= profile_.button_b; }
inline void set_button_x() { pad_state_.buttons |= profile_.button_x; }
inline void set_button_y() { pad_state_.buttons |= profile_.button_y; }
inline void set_button_lb() { pad_state_.buttons |= profile_.button_lb; }
inline void set_button_rb() { pad_state_.buttons |= profile_.button_rb; }
inline void set_button_l3() { pad_state_.buttons |= profile_.button_l3; }
inline void set_button_r3() { pad_state_.buttons |= profile_.button_r3; }
inline void set_button_start() { pad_state_.buttons |= profile_.button_start; }
inline void set_button_back() { pad_state_.buttons |= profile_.button_back; }
inline void set_button_sys() { pad_state_.buttons |= profile_.button_sys; }
inline void set_button_misc() { pad_state_.buttons |= profile_.button_misc; }
inline void set_analog_up(uint8_t value) { *analog_map_[profile_.analog_off_up] = value; }
inline void set_analog_down(uint8_t value) { *analog_map_[profile_.analog_off_down] = value; }
inline void set_analog_left(uint8_t value) { *analog_map_[profile_.analog_off_left] = value; }
inline void set_analog_right(uint8_t value) { *analog_map_[profile_.analog_off_right] = value; }
inline void set_analog_a(uint8_t value) { *analog_map_[profile_.analog_off_a] = value; }
inline void set_analog_b(uint8_t value) { *analog_map_[profile_.analog_off_b] = value; }
inline void set_analog_x(uint8_t value) { *analog_map_[profile_.analog_off_x] = value; }
inline void set_analog_y(uint8_t value) { *analog_map_[profile_.analog_off_y] = value; }
inline void set_analog_lb(uint8_t value) { *analog_map_[profile_.analog_off_lb] = value; }
inline void set_analog_rb(uint8_t value) { *analog_map_[profile_.analog_off_rb] = value; }
inline void set_trigger_l(const uint8_t value) { pad_state_.triggers.l.set_value((value > dz_trig_uint8_.l) ? value : UINT_8::MIN); }
inline void set_trigger_l(const uint16_t value) { pad_state_.triggers.l.set_value((value > dz_trig_uint16_.l) ? value : UINT_16::MIN); }
inline void set_trigger_r(const uint8_t value) { pad_state_.triggers.r.set_value((value > dz_trig_uint8_.r) ? value : UINT_8::MIN); }
inline void set_trigger_r(const uint16_t value) { pad_state_.triggers.r.set_value((value > dz_trig_uint16_.r) ? value : UINT_16::MIN); }
inline void set_joystick_lx(const int16_t value, const bool invert = false) { pad_state_.joysticks.lx.set_value((value < dz_joy_int16_.l_neg || value > dz_joy_int16_.l_pos) ? (invert ? Values::invert_joy(value) : value) : INT_16::MID); }
inline void set_joystick_lx(const uint8_t value, const bool invert = false) { pad_state_.joysticks.lx.set_value((value < dz_joy_uint8_.l_neg || value > dz_joy_uint8_.l_pos) ? (invert ? Values::invert_joy(value) : value) : UINT_8::MID); }
inline void set_joystick_ly(const int16_t value, const bool invert = false) { pad_state_.joysticks.ly.set_value((value < dz_joy_int16_.l_neg || value > dz_joy_int16_.l_pos) ? ((invert ^ profile_.invert_ly) ? Values::invert_joy(value) : value) : INT_16::MID); }
inline void set_joystick_ly(const uint8_t value, const bool invert = false) { pad_state_.joysticks.ly.set_value((value < dz_joy_uint8_.l_neg || value > dz_joy_uint8_.l_pos) ? ((invert ^ profile_.invert_ly) ? Values::invert_joy(value) : value) : UINT_8::MID); }
inline void set_joystick_rx(const int16_t value, const bool invert = false) { pad_state_.joysticks.rx.set_value((value < dz_joy_int16_.r_neg || value > dz_joy_int16_.r_pos) ? (invert ? Values::invert_joy(value) : value) : INT_16::MID); }
inline void set_joystick_rx(const uint8_t value, const bool invert = false) { pad_state_.joysticks.rx.set_value((value < dz_joy_uint8_.r_neg || value > dz_joy_uint8_.r_pos) ? (invert ? Values::invert_joy(value) : value) : UINT_8::MID); }
inline void set_joystick_ry(const int16_t value, const bool invert = false) { pad_state_.joysticks.ry.set_value((value < dz_joy_int16_.r_neg || value > dz_joy_int16_.r_pos) ? ((invert ^ profile_.invert_ry) ? Values::invert_joy(value) : value) : INT_16::MID); }
inline void set_joystick_ry(const uint8_t value, const bool invert = false) { pad_state_.joysticks.ry.set_value((value < dz_joy_uint8_.r_neg || value > dz_joy_uint8_.r_pos) ? ((invert ^ profile_.invert_ry) ? Values::invert_joy(value) : value) : UINT_8::MID); }
// 10 bit methods for weird stuff
inline void set_trigger_l_uint10(const int32_t value)
{
uint8_t new_value = Values::uint10_to_uint8(value);
pad_state_.triggers.l.set_value((new_value > dz_trig_uint8_.l) ? new_value : UINT_8::MIN);
}
inline void set_trigger_r_uint10(const int32_t value)
{
uint8_t new_value = Values::uint10_to_uint8(value);
pad_state_.triggers.r.set_value((new_value > dz_trig_uint8_.r) ? new_value : UINT_8::MIN);
}
inline void set_joystick_lx_int10(const int32_t value, const bool invert = false)
{
uint8_t new_value = Values::int10_to_uint8(value);
pad_state_.joysticks.lx.set_value((new_value < dz_joy_uint8_.l_neg || new_value > dz_joy_uint8_.l_pos) ? (invert ? Values::invert_joy(new_value) : new_value) : UINT_8::MID);
}
inline void set_joystick_ly_int10(const int32_t value, const bool invert = false)
{
uint8_t new_value = Values::int10_to_uint8(value);
pad_state_.joysticks.ly.set_value((new_value < dz_joy_uint8_.l_neg || new_value > dz_joy_uint8_.l_pos) ? ((invert ^ profile_.invert_ly) ? Values::invert_joy(new_value) : new_value) : UINT_8::MID);
}
inline void set_joystick_rx_int10(const int32_t value, const bool invert = false)
{
uint8_t new_value = Values::int10_to_uint8(value);
pad_state_.joysticks.rx.set_value((new_value < dz_joy_uint8_.r_neg || new_value > dz_joy_uint8_.r_pos) ? (invert ? Values::invert_joy(new_value) : new_value) : UINT_8::MID);
}
inline void set_joystick_ry_int10(const int32_t value, const bool invert = false)
{
uint8_t new_value = Values::int10_to_uint8(value);
pad_state_.joysticks.ry.set_value((new_value < dz_joy_uint8_.r_neg || new_value > dz_joy_uint8_.r_pos) ? ((invert ^ profile_.invert_ry) ? Values::invert_joy(new_value) : new_value) : UINT_8::MID);
}
// inline void set_joystick_lx_int10(const int32_t value, const bool invert = false)
// {
// int16_t new_value = Values::int10_to_int16(value);
// pad_state_.joysticks.lx.set_value((new_value < dz_joy_int16_.l_neg || new_value > dz_joy_int16_.l_pos) ? (invert ? Values::invert_joy(new_value) : new_value) : INT_16::MID);
// }
// inline void set_joystick_ly_int10(const int32_t value, const bool invert = false)
// {
// int16_t new_value = Values::int10_to_int16(value);
// pad_state_.joysticks.ly.set_value((new_value < dz_joy_int16_.l_neg || new_value > dz_joy_int16_.l_pos) ? ((invert ^ profile_.invert_ly) ? Values::invert_joy(new_value) : new_value) : INT_16::MID);
// }
// inline void set_joystick_rx_int10(const int32_t value, const bool invert = false)
// {
// int16_t new_value = Values::int10_to_int16(value);
// pad_state_.joysticks.rx.set_value((new_value < dz_joy_int16_.r_neg || new_value > dz_joy_int16_.r_pos) ? (invert ? Values::invert_joy(new_value) : new_value) : INT_16::MID);
// }
// inline void set_joystick_ry_int10(const int32_t value, const bool invert = false)
// {
// int16_t new_value = Values::int10_to_int16(value);
// pad_state_.joysticks.ry.set_value((new_value < dz_joy_int16_.r_neg || new_value > dz_joy_int16_.r_pos) ? ((invert ^ profile_.invert_ry) ? Values::invert_joy(new_value) : new_value) : INT_16::MID);
// }
inline void set_rumble_l(uint8_t value) { rumble_state_.l.set_value(value); }
inline void set_rumble_l(uint16_t value) { rumble_state_.l.set_value(value); }
inline void set_rumble_r(uint8_t value) { rumble_state_.r.set_value(value); }
inline void set_rumble_r(uint16_t value) { rumble_state_.r.set_value(value); }
inline void set_chatpad(const Chatpad& chatpad_array)
inline void set_pad_in(PadIn pad_in)
{
pad_state_.chatpad[0] = chatpad_array[0];
pad_state_.chatpad[1] = chatpad_array[1];
pad_state_.chatpad[2] = chatpad_array[2];
pad_in.trigger_l = (pad_in.trigger_l > dz_.trigger_l) ? pad_in.trigger_l : UINT_8::MIN;
pad_in.trigger_r = (pad_in.trigger_r > dz_.trigger_r) ? pad_in.trigger_r : UINT_8::MIN;
pad_in.joystick_lx = (pad_in.joystick_lx < dz_.joystick_l_neg || pad_in.joystick_lx > dz_.joystick_l_pos) ? pad_in.joystick_lx : INT_16::MID;
pad_in.joystick_ly = (pad_in.joystick_ly < dz_.joystick_l_neg || pad_in.joystick_ly > dz_.joystick_l_pos) ? pad_in.joystick_ly : INT_16::MID;
pad_in.joystick_rx = (pad_in.joystick_rx < dz_.joystick_r_neg || pad_in.joystick_rx > dz_.joystick_r_pos) ? pad_in.joystick_rx : INT_16::MID;
pad_in.joystick_ry = (pad_in.joystick_ry < dz_.joystick_r_neg || pad_in.joystick_ry > dz_.joystick_r_pos) ? pad_in.joystick_ry : INT_16::MID;
pad_in.joystick_ly = profile_.invert_ly ? Scale::invert_joy(pad_in.joystick_ly) : pad_in.joystick_ly;
pad_in.joystick_ry = profile_.invert_ry ? Scale::invert_joy(pad_in.joystick_ry) : pad_in.joystick_ry;
{
mutex_enter_blocking(&pad_in_mutex_);
pad_in_ = pad_in;
mutex_exit(&pad_in_mutex_);
}
new_pad_in_.store(true);
}
inline void reset_buttons() { pad_state_.dpad = 0; pad_state_.buttons = 0; }
inline void reset_pad()
inline void set_pad_out(PadOut pad_out)
{
mutex_enter_blocking(&pad_out_mutex_);
pad_out_ = pad_out;
mutex_exit(&pad_out_mutex_);
new_pad_out_.store(true);
}
inline void reset_pad_in()
{
pad_state_.dpad = 0;
pad_state_.buttons = 0;
pad_state_.triggers.l.set_value(UINT_8::MIN);
pad_state_.triggers.r.set_value(UINT_8::MIN);
pad_state_.joysticks.lx.set_value(UINT_8::MID);
pad_state_.joysticks.ly.set_value(UINT_8::MID);
pad_state_.joysticks.rx.set_value(UINT_8::MID);
pad_state_.joysticks.ry.set_value(UINT_8::MID);
std::memset(&pad_state_.analog_buttons, 0, sizeof(PadState::AnalogButtons));
std::memset(&pad_state_.chatpad, 0, sizeof(Chatpad));
mutex_enter_blocking(&pad_in_mutex_);
std::memset(&pad_in_, 0, sizeof(pad_in_));
mutex_exit(&pad_in_mutex_);
new_pad_in_.store(true);
}
inline void reset_rumble()
inline void reset_pad_out()
{
rumble_state_.l.set_value(UINT_8::MIN);
rumble_state_.l.set_value(UINT_8::MIN);
mutex_enter_blocking(&pad_out_mutex_);
std::memset(&pad_out_, 0, sizeof(pad_out_));
mutex_exit(&pad_out_mutex_);
new_pad_out_.store(true);
}
private:
struct PadState
{
uint8_t dpad{0};
uint16_t buttons{0};
mutex_t pad_in_mutex_;
mutex_t pad_out_mutex_;
struct Triggers
{
Values l;
Values r;
} triggers;
PadOut pad_out_;
PadIn pad_in_;
struct Joysticks
{
Values lx;
Values ly;
Values rx;
Values ry;
} joysticks;
std::atomic<bool> new_pad_in_{false};
std::atomic<bool> new_pad_out_{false};
std::atomic<bool> analog_enabled_{false};
struct AnalogButtons
{
uint8_t up{0};
uint8_t down{0};
uint8_t left{0};
uint8_t right{0};
uint8_t a{0};
uint8_t b{0};
uint8_t x{0};
uint8_t y{0};
uint8_t lb{0};
uint8_t rb{0};
} analog_buttons;
std::array<uint8_t, 3> chatpad = { 0, 0, 0 };
};
struct Rumble
{
Values l;
Values r;
};
bool analog_enabled_{false};
UserProfile profile_;
template<typename type>
struct DZTrigger
struct Deadzones
{
type l{0};
type r{0};
};
uint8_t trigger_l{0};
uint8_t trigger_r{0};
int16_t joystick_l_neg{0};
int16_t joystick_l_pos{0};
int16_t joystick_r_neg{0};
int16_t joystick_r_pos{0};
} dz_;
template<typename type>
struct DZJoystick
void setup_mappings(const UserProfile& profile)
{
type l_neg;
type l_pos;
type r_neg;
type r_pos;
MAP_DPAD_UP = profile.dpad_up;
MAP_DPAD_DOWN = profile.dpad_down;
MAP_DPAD_LEFT = profile.dpad_left;
MAP_DPAD_RIGHT = profile.dpad_right;
MAP_DPAD_UP_LEFT = profile.dpad_up | profile.dpad_left;
MAP_DPAD_UP_RIGHT = profile.dpad_up | profile.dpad_right;
MAP_DPAD_DOWN_LEFT = profile.dpad_down | profile.dpad_left;
MAP_DPAD_DOWN_RIGHT = profile.dpad_down | profile.dpad_right;
MAP_DPAD_NONE = 0;
DZJoystick()
{
if constexpr (std::is_same_v<type, uint8_t>) { l_neg = l_pos = r_neg = r_pos = UINT_8::MID; }
else if constexpr (std::is_same_v<type, int16_t>) { l_neg = l_pos = r_neg = r_pos = 0; }
}
};
MAP_BUTTON_A = profile.button_a;
MAP_BUTTON_B = profile.button_b;
MAP_BUTTON_X = profile.button_x;
MAP_BUTTON_Y = profile.button_y;
MAP_BUTTON_L3 = profile.button_l3;
MAP_BUTTON_R3 = profile.button_r3;
MAP_BUTTON_BACK = profile.button_back;
MAP_BUTTON_START = profile.button_start;
MAP_BUTTON_LB = profile.button_lb;
MAP_BUTTON_RB = profile.button_rb;
MAP_BUTTON_SYS = profile.button_sys;
MAP_BUTTON_MISC = profile.button_misc;
DZTrigger<uint8_t> dz_trig_uint8_;
DZTrigger<uint16_t> dz_trig_uint16_;
DZJoystick<int16_t> dz_joy_int16_;
DZJoystick<uint8_t> dz_joy_uint8_;
MAP_ANALOG_OFF_UP = profile.analog_off_up;
MAP_ANALOG_OFF_DOWN = profile.analog_off_down;
MAP_ANALOG_OFF_LEFT = profile.analog_off_left;
MAP_ANALOG_OFF_RIGHT = profile.analog_off_right;
MAP_ANALOG_OFF_A = profile.analog_off_a;
MAP_ANALOG_OFF_B = profile.analog_off_b;
MAP_ANALOG_OFF_X = profile.analog_off_x;
MAP_ANALOG_OFF_Y = profile.analog_off_y;
MAP_ANALOG_OFF_LB = profile.analog_off_lb;
MAP_ANALOG_OFF_RB = profile.analog_off_rb;
}
PadState pad_state_;
Rumble rumble_state_;
std::array<uint8_t*, sizeof(PadState::AnalogButtons)> analog_map_ =
void setup_deadzones(const UserProfile& profile) //Deadzones in the profile are 0-255 (0-100%)
{
&pad_state_.analog_buttons.up,
&pad_state_.analog_buttons.down,
&pad_state_.analog_buttons.left,
&pad_state_.analog_buttons.right,
&pad_state_.analog_buttons.a,
&pad_state_.analog_buttons.b,
&pad_state_.analog_buttons.x,
&pad_state_.analog_buttons.y,
&pad_state_.analog_buttons.lb,
&pad_state_.analog_buttons.rb
};
dz_.trigger_l = profile_.dz_trigger_l;
dz_.trigger_r = profile_.dz_trigger_r;
void setup_deadzones() //Deadzones in the profile are 0-255 (0-100%)
{
dz_trig_uint8_.l = profile_.dz_trigger_l;
dz_trig_uint8_.r = profile_.dz_trigger_r;
dz_trig_uint16_.l = Values::uint8_to_uint16(profile_.dz_trigger_l);
dz_trig_uint16_.r = Values::uint8_to_uint16(profile_.dz_trigger_r);
dz_joy_uint8_.l_neg = UINT_8::MID - (profile_.dz_joystick_l / 2);
dz_joy_uint8_.l_pos = UINT_8::MID + (profile_.dz_joystick_l / 2);
dz_joy_uint8_.r_neg = UINT_8::MID - (profile_.dz_joystick_r / 2);
dz_joy_uint8_.r_pos = UINT_8::MID + (profile_.dz_joystick_r / 2);
dz_joy_int16_.l_neg = Values::uint8_to_int16(dz_joy_uint8_.l_neg);
dz_joy_int16_.l_pos = Values::uint8_to_int16(dz_joy_uint8_.l_pos);
dz_joy_int16_.r_neg = Values::uint8_to_int16(dz_joy_uint8_.r_neg);
dz_joy_int16_.r_pos = Values::uint8_to_int16(dz_joy_uint8_.r_pos);
dz_.joystick_l_pos = Scale::uint8_to_int16(profile_.dz_joystick_l / 2);
dz_.joystick_l_neg = Scale::invert_joy(dz_.joystick_l_pos);
dz_.joystick_r_pos = Scale::uint8_to_int16(profile_.dz_joystick_r / 2);
dz_.joystick_r_neg = Scale::invert_joy(dz_.joystick_r_pos);
}
};

View File

@@ -0,0 +1,77 @@
#ifndef I2C_DRIVER_4CH_H
#define I2C_DRIVER_4CH_H
#include <cstdint>
#include <algorithm>
#include "board_config.h"
#include "Gamepad.h"
#include "USBHost/HostDriver/HostDriver.h"
class I2CDriver
{
public:
virtual ~I2CDriver() = default;
virtual void initialize(uint8_t address) = 0;
virtual void process(Gamepad (&gamepads)[MAX_GAMEPADS]) = 0;
virtual void notify_tuh_mounted(HostDriver::Type host_type = HostDriver::Type::UNKNOWN) = 0;
virtual void notify_tuh_unmounted(HostDriver::Type host_type = HostDriver::Type::UNKNOWN) = 0;
virtual void notify_xbox360w_connected(uint8_t idx) = 0;
virtual void notify_xbox360w_disconnected(uint8_t idx) = 0;
protected:
enum class PacketID : uint8_t { UNKNOWN = 0, PAD, STATUS, ENABLE, DISABLE };
enum class SlaveStatus : uint8_t { NC = 0, NOT_READY, READY, RESP_OK };
#pragma pack(push, 1)
struct PacketIn
{
uint8_t packet_len;
uint8_t packet_id;
Gamepad::PadIn pad_in;
PacketIn()
{
std::memset(this, 0, sizeof(PacketIn));
packet_len = sizeof(PacketIn);
packet_id = static_cast<uint8_t>(PacketID::PAD);
}
};
static_assert(sizeof(PacketIn) == 28, "I2CDriver::PacketIn is misaligned");
struct PacketOut
{
uint8_t packet_len;
uint8_t packet_id;
Gamepad::PadOut pad_out;
PacketOut()
{
std::memset(this, 0, sizeof(PacketOut));
packet_len = sizeof(PacketOut);
packet_id = static_cast<uint8_t>(PacketID::PAD);
}
};
static_assert(sizeof(PacketOut) == 4, "I2CDriver::PacketOut is misaligned");
struct PacketStatus
{
uint8_t packet_len;
uint8_t packet_id;
uint8_t status;
PacketStatus()
{
packet_len = sizeof(PacketStatus);
packet_id = static_cast<uint8_t>(PacketID::STATUS);
status = static_cast<uint8_t>(SlaveStatus::NC);
}
};
static_assert(sizeof(PacketStatus) == 3, "I2CDriver::PacketStatus is misaligned");
#pragma pack(pop)
static constexpr size_t MAX_PACKET_SIZE = std::max(sizeof(PacketStatus), std::max(sizeof(PacketIn), sizeof(PacketOut)));
};
#endif // I2C_DRIVER_4CH_H

View File

@@ -0,0 +1,91 @@
#ifndef I2C_4CH_MANAGER_H
#define I2C_4CH_MANAGER_H
#include <cstdint>
#include <memory>
#include <atomic>
#include "board_config.h"
#include "Gamepad.h"
#include "I2CDriver/4Channel/I2CMaster.h"
#include "I2CDriver/4Channel/I2CSlave.h"
#include "I2CDriver/4Channel/I2CDriver.h"
class I2CManager
{
public:
I2CManager(const I2CManager&) = delete;
I2CManager& operator=(const I2CManager&) = delete;
static I2CManager& get_instance()
{
static I2CManager instance;
return instance;
}
bool initialize_driver() //Gamepad idx 0 for slave to update on interrupt
{
uint8_t i2c_address = get_i2c_address();
if (i2c_address == 0xFF)
{
return false;
}
if (i2c_address < 1)
{
is_master_.store(true);
driver_ = std::make_unique<I2CMaster>();
}
else
{
driver_ = std::make_unique<I2CSlave>();
}
driver_->initialize(i2c_address);
return true;
}
I2CDriver* get_driver()
{
return driver_.get();
}
bool is_master()
{
return is_master_.load();
}
private:
I2CManager() {};
~I2CManager() {};
std::unique_ptr<I2CDriver> driver_{nullptr};
std::atomic<bool> is_master_{false};
uint8_t get_i2c_address()
{
gpio_init(SLAVE_ADDR_PIN_1);
gpio_init(SLAVE_ADDR_PIN_2);
gpio_pull_up(SLAVE_ADDR_PIN_1);
gpio_pull_up(SLAVE_ADDR_PIN_2);
if (gpio_get(SLAVE_ADDR_PIN_1) == 1 && gpio_get(SLAVE_ADDR_PIN_2) == 1)
{
return 0x00;
}
else if (gpio_get(SLAVE_ADDR_PIN_1) == 1 && gpio_get(SLAVE_ADDR_PIN_2) == 0)
{
return 0x01;
}
else if (gpio_get(SLAVE_ADDR_PIN_1) == 0 && gpio_get(SLAVE_ADDR_PIN_2) == 1)
{
return 0x02;
}
else if (gpio_get(SLAVE_ADDR_PIN_1) == 0 && gpio_get(SLAVE_ADDR_PIN_2) == 0)
{
return 0x03;
}
return 0xFF;
}
};
#endif // I2C_4CH_MANAGER_H

View File

@@ -0,0 +1,192 @@
#include <cstring>
#include "TaskQueue/TaskQueue.h"
#include "I2CDriver/4Channel/I2CMaster.h"
void I2CMaster::initialize(uint8_t address)
{
i2c_init(I2C_PORT, I2C_BAUDRATE);
gpio_init(I2C_SDA_PIN);
gpio_set_function(I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_pull_up(I2C_SDA_PIN);
gpio_init(I2C_SCL_PIN);
gpio_set_function(I2C_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(I2C_SCL_PIN);
for (uint8_t i = 0; i < NUM_SLAVES; ++i)
{
slaves_[i].address = address + i + 1;
}
tid_update_slave_ = TaskQueue::Core0::get_new_task_id();
TaskQueue::Core0::queue_delayed_task(tid_update_slave_, 1000, true, [this]
{
for (auto& slave : slaves_)
{
update_slave_status(slave);
sleep_us(10);
}
});
}
void I2CMaster::process(Gamepad (&gamepads)[MAX_GAMEPADS])
{
if (notify_deinit_.load())
{
notify_tud_deinit();
return;
}
for (uint8_t i = 0; i < NUM_SLAVES; ++i)
{
Slave& slave = slaves_[i];
if (!slave.enabled.load() || !slave_detected(slave.address))
{
continue;
}
if (slave.status == SlaveStatus::READY)
{
if (send_packet_in(slave, gamepads[i + 1]))
{
get_packet_out(slave, gamepads[i + 1]);
}
}
sleep_us(100);
}
}
void I2CMaster::notify_tuh_mounted(HostDriver::Type host_type)
{
if (host_type == HostDriver::Type::XBOX360W)
{
i2c_enabled_.store(true);
}
}
void I2CMaster::notify_tuh_unmounted(HostDriver::Type host_type)
{
i2c_enabled_.store(false);
notify_deinit_.store(true);
}
void I2CMaster::notify_xbox360w_connected(uint8_t idx)
{
if (idx < 1 || idx >= MAX_GAMEPADS)
{
return;
}
slaves_[idx - 1].enabled.store(true);
}
void I2CMaster::notify_xbox360w_disconnected(uint8_t idx)
{
if (idx < 1 || idx >= MAX_GAMEPADS)
{
return;
}
slaves_[idx - 1].enabled.store(false);
}
bool I2CMaster::slave_detected(uint8_t address)
{
uint8_t dummy_data = 0;
int result = i2c_write_timeout_us(I2C_PORT, address, &dummy_data, 0, false, 1000);
return (result >= 0);
}
void I2CMaster::update_slave_status(Slave& slave)
{
bool slave_enabled = slave.enabled.load();
if (!slave_detected(slave.address))
{
slave.status = SlaveStatus::NC;
return;
}
if (!update_slave_enabled(slave.address, slave_enabled))
{
slave.status = SlaveStatus::NOT_READY;
return;
}
if (slave_enabled)
{
PacketStatus status_packet = PacketStatus();
int count = 0;
status_packet.packet_id = static_cast<uint8_t>(PacketID::STATUS);
count = i2c_write_blocking(I2C_PORT, slave.address, reinterpret_cast<uint8_t*>(&status_packet), sizeof(PacketStatus), false);
if (count == sizeof(PacketStatus))
{
count = i2c_read_blocking(I2C_PORT, slave.address, reinterpret_cast<uint8_t*>(&status_packet), sizeof(PacketStatus), false);
slave.status = (count > 0) ? static_cast<SlaveStatus>(status_packet.status) : SlaveStatus::NOT_READY;
}
else
{
slave.status = SlaveStatus::NOT_READY;
}
}
else
{
slave.status = SlaveStatus::NOT_READY;
}
}
//Tell slave if it's enabled or not
bool I2CMaster::update_slave_enabled(uint8_t address, bool enabled)
{
PacketStatus status_packet;
status_packet.packet_id = enabled ? static_cast<uint8_t>(PacketID::ENABLE) : static_cast<uint8_t>(PacketID::DISABLE);
int count = i2c_write_blocking(I2C_PORT, address, reinterpret_cast<uint8_t*>(&status_packet), sizeof(PacketStatus), false);
if (count == sizeof(PacketStatus))
{
count = i2c_read_blocking(I2C_PORT, address, reinterpret_cast<uint8_t*>(&status_packet), sizeof(PacketStatus), false);
return (static_cast<SlaveStatus>(status_packet.status) == SlaveStatus::RESP_OK);
}
return false;
}
bool I2CMaster::send_packet_in(Slave& slave, Gamepad& gamepad)
{
static PacketIn packet_in = PacketIn();
Gamepad::PadIn pad_in = gamepad.get_pad_in();
packet_in.pad_in = pad_in;
int count = i2c_write_blocking(I2C_PORT, slave.address, reinterpret_cast<uint8_t*>(&packet_in), sizeof(packet_in), false);
// int count = i2c_write_timeout_us(I2C_PORT, slave.address, reinterpret_cast<uint8_t*>(&packet_in), sizeof(packet_in), false, 2000);
return (count == sizeof(PacketIn));
}
bool I2CMaster::get_packet_out(Slave& slave, Gamepad& gamepad)
{
static PacketOut packet_out = PacketOut();
int count = i2c_read_blocking(I2C_PORT, slave.address, reinterpret_cast<uint8_t*>(&packet_out), sizeof(PacketOut), false);
if (count != sizeof(PacketOut))
{
return false;
}
gamepad.set_pad_out(packet_out.pad_out);
return true;
}
void I2CMaster::notify_tud_deinit()
{
for (auto& slave : slaves_)
{
if (slave.status != SlaveStatus::NC && slave_detected(slave.address) && slave.enabled.load())
{
int retries = 0;
while (!update_slave_enabled(slave.address, false) && retries < 6)
{
sleep_ms(1);
++retries;
}
}
}
}

View File

@@ -0,0 +1,57 @@
#ifndef I2C_MASTER_4CH_H
#define I2C_MASTER_4CH_H
#include <cstdint>
#include <atomic>
#include <array>
#include <pico/time.h>
#include <hardware/gpio.h>
#include <hardware/i2c.h>
#include "board_config.h"
#include "Gamepad.h"
#include "I2CDriver/4Channel/I2CDriver.h"
class I2CMaster : public I2CDriver
{
public:
~I2CMaster() override;
void initialize(uint8_t address) override;
void process(Gamepad (&gamepads)[MAX_GAMEPADS]) override;
void notify_tuh_mounted(HostDriver::Type host_type) override;
void notify_tuh_unmounted(HostDriver::Type host_type) override;
void notify_xbox360w_connected(uint8_t idx) override;
void notify_xbox360w_disconnected(uint8_t idx) override;
private:
struct Slave
{
uint8_t address{0xFF};
SlaveStatus status{SlaveStatus::NC};
std::atomic<bool> enabled{false};
};
static constexpr size_t NUM_SLAVES = MAX_GAMEPADS - 1;
static_assert(NUM_SLAVES > 0, "I2CMaster::NUM_SLAVES must be greater than 0 to use I2C");
// repeating_timer_t update_slave_timer_;
uint32_t tid_update_slave_;
bool update_slave_status_{false};
std::atomic<bool> i2c_enabled_{false};
std::atomic<bool> notify_deinit_{false};
std::array<Slave, NUM_SLAVES> slaves_;
static bool slave_detected(uint8_t address);
static void update_slave_status(Slave& slave);
static bool update_slave_enabled(uint8_t address, bool enabled);
static bool update_slave_timer_cb(repeating_timer_t* rt);
bool send_packet_in(Slave& slave, Gamepad& gamepad);
bool get_packet_out(Slave& slave, Gamepad& gamepad);
void notify_tud_deinit();
};
#endif // I2C_MASTER_4CH_H

View File

@@ -0,0 +1,160 @@
#include <cstring>
#include <array>
#include "Board/board_api.h"
#include "OGXMini/OGXMini.h"
#include "I2CDriver/4Channel/I2CSlave.h"
I2CSlave* I2CSlave::this_instance_ = nullptr;
void I2CSlave::initialize(uint8_t address)
{
this_instance_ = this;
i2c_init(I2C_PORT, I2C_BAUDRATE);
gpio_init(I2C_SDA_PIN);
gpio_set_function(I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_pull_up(I2C_SDA_PIN);
gpio_init(I2C_SCL_PIN);
gpio_set_function(I2C_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(I2C_SCL_PIN);
i2c_slave_init(I2C_PORT, address, &slave_handler);
}
void I2CSlave::notify_tuh_mounted(HostDriver::Type host_type)
{
i2c_disabled_.store(true);
}
void I2CSlave::notify_tuh_unmounted(HostDriver::Type host_type)
{
i2c_disabled_.store(false);
}
void I2CSlave::process(Gamepad (&gamepads)[MAX_GAMEPADS])
{
if (i2c_disabled_.load())
{
return;
}
if (packet_in_.packet_id == static_cast<uint8_t>(PacketID::PAD))
{
gamepads[0].set_pad_in(packet_in_.pad_in);
if (gamepads[0].new_pad_out())
{
packet_out_.pad_out = gamepads[0].get_pad_out();
}
}
}
I2CSlave::PacketID I2CSlave::get_packet_id(uint8_t* buffer_in)
{
switch (static_cast<PacketID>(buffer_in[1]))
{
case PacketID::PAD:
if (buffer_in[0] == sizeof(PacketIn))
{
return PacketID::PAD;
}
break;
case PacketID::DISABLE:
if (buffer_in[0] == sizeof(PacketStatus))
{
return PacketID::DISABLE;
}
break;
case PacketID::ENABLE:
if (buffer_in[0] == sizeof(PacketStatus))
{
return PacketID::ENABLE;
}
break;
case PacketID::STATUS:
if (buffer_in[0] == sizeof(PacketStatus))
{
return PacketID::STATUS;
}
break;
default:
break;
}
return PacketID::UNKNOWN;
}
void I2CSlave::slave_handler(i2c_inst_t *i2c, i2c_slave_event_t event)
{
static int count = 0;
static std::array<uint8_t, MAX_PACKET_SIZE> buffer_in{0};
static std::array<uint8_t, MAX_PACKET_SIZE> buffer_out{0};
switch (event)
{
case I2C_SLAVE_RECEIVE: // master has written
if (count < MAX_PACKET_SIZE)
{
buffer_in.data()[count] = i2c_read_byte_raw(i2c);
++count;
}
// else // Something's wrong, reset
// {
// count = 0;
// buffer_in.fill(0);
// buffer_out.fill(0);
// }
break;
case I2C_SLAVE_FINISH: // master signalled Stop / Restart
// Each master write has an ID indicating the type of data to send back on the next read request
// Every write has an associated read
switch (get_packet_id(buffer_in.data()))
{
case PacketID::PAD:
this_instance_->packet_in_ = *reinterpret_cast<PacketIn*>(buffer_in.data());
*reinterpret_cast<PacketOut*>(buffer_out.data()) = this_instance_->packet_out_;
break;
case PacketID::STATUS:
buffer_out.data()[0] = sizeof(PacketStatus);
buffer_out.data()[1] = static_cast<uint8_t>(PacketID::STATUS);
// if something is mounted by tuh, signal to not send gamepad data
buffer_out.data()[2] = this_instance_->i2c_disabled_.load() ? static_cast<uint8_t>(SlaveStatus::NOT_READY) : static_cast<uint8_t>(SlaveStatus::READY);
break;
case PacketID::ENABLE:
buffer_out.data()[0] = sizeof(PacketStatus);
buffer_out.data()[1] = static_cast<uint8_t>(PacketID::STATUS);
buffer_out.data()[2] = static_cast<uint8_t>(SlaveStatus::RESP_OK);
if (!this_instance_->i2c_disabled_.load())
{
// If no TUH devices are mounted, signal to connect usb
OGXMini::update_tuh_status(true);
}
break;
case PacketID::DISABLE:
buffer_out.data()[0] = sizeof(PacketStatus);
buffer_out.data()[1] = static_cast<uint8_t>(PacketID::STATUS);
buffer_out.data()[2] = static_cast<uint8_t>(SlaveStatus::RESP_OK);
if (!this_instance_->i2c_disabled_.load())
{
// If no TUH devices are mounted, signal to disconnect usb reset the pico
OGXMini::update_tuh_status(false);
}
break;
default:
break;
}
count = 0;
break;
case I2C_SLAVE_REQUEST: // master requesting data
i2c_write_raw_blocking(i2c, buffer_out.data(), buffer_out.data()[0]);
buffer_in.fill(0);
break;
default:
break;
}
}

View File

@@ -0,0 +1,36 @@
#ifndef I2C_SLAVE_4CH_H
#define I2C_SLAVE_4CH_H
#include <cstdint>
#include <atomic>
#include <cstring>
#include <pico/time.h>
#include <hardware/gpio.h>
#include <hardware/i2c.h>
#include <pico/i2c_slave.h>
#include "board_config.h"
#include "Gamepad.h"
#include "I2CDriver/4Channel/I2CDriver.h"
class I2CSlave : public I2CDriver
{
public:
void initialize(uint8_t address) override;
void process(Gamepad (&gamepads)[MAX_GAMEPADS]) override;
void notify_tuh_mounted(HostDriver::Type host_type) override;
void notify_tuh_unmounted(HostDriver::Type host_type) override;
void notify_xbox360w_connected(uint8_t idx) override {};
void notify_xbox360w_disconnected(uint8_t idx) override {};
private:
static I2CSlave* this_instance_;
PacketIn packet_in_;
PacketOut packet_out_;
std::atomic<bool> i2c_disabled_;
static PacketID get_packet_id(uint8_t* buffer_in);
static void slave_handler(i2c_inst_t *i2c, i2c_slave_event_t event);
};
#endif // I2C_SLAVE_4CH_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,145 @@
#ifndef _I2C_DRIVER_H_
#define _I2C_DRIVER_H_
// #ifndef _I2C_DRIVER_H_
// #define _I2C_DRIVER_H_
#include <cstdint>
// #include <cstdint>
#include "Gamepad.h"
#include "USBHost/HostManager.h"
// #include "Gamepad.h"
// #include "USBHost/HostManager.h"
// /* Master will only write/read slave if an Xbox360 wireless controller is connected for its corresponding slave.
// Slaves will read/write from the bus only if they don't have a device mounted by tusb host.
// Could be made to work so that a USB hub could be connected to port 1 and host 4 controllers, maybe later.
// This is run on core0 with the device stack, but some values are checked and modified by core1 (atomic types). */
namespace i2c_driver_4ch
{
void initialize(std::array<Gamepad, MAX_GAMEPADS>& gamepads);
void process();
bool is_active();
// // /* Master will only write/read slave if an Xbox360 wireless controller is connected for its corresponding slave.
// // Slaves will read/write from the bus only if they don't have a device mounted by tusb host.
// // Could be made to work so that a USB hub could be connected to port 1 and host 4 controllers, maybe later.
// // This is run on core0 with the device stack, but some values are checked and modified by core1 (atomic types). */
// // namespace i2c
// // {
// // void initialize(Gamepad (&gamepads)[MAX_GAMEPADS]);
void notify_tud_deinit();
// // struct driver
// // {
// // void (*process)(){nullptr};
// // bool (*is_active)(){nullptr};
// // void (*notify_tud_deinit)(){nullptr};
// // void (*notify_tuh_mounted)(HostDriver::Type host_type){nullptr};
// // void (*notify_tuh_unmounted)(HostDriver::Type host_type){nullptr};
// // void (*notify_xbox360w_connected)(uint8_t idx){nullptr};
// // void (*notify_xbox360w_disconnected)(uint8_t idx){nullptr};
// // };
// // driver* get_driver();
void notify_tuh_mounted(HostDriver::Type host_type = HostDriver::Type::UNKNOWN);
void notify_tuh_unmounted(HostDriver::Type host_type = HostDriver::Type::UNKNOWN);
// // // void process();
// // // bool is_active();
void notify_xbox360w_connected(uint8_t idx);
void notify_xbox360w_disconnected(uint8_t idx);
}
// // // void notify_tud_deinit();
#endif // _I2C_DRIVER_H_
// // // void notify_tuh_mounted(HostDriver::Type host_type = HostDriver::Type::UNKNOWN);
// // // void notify_tuh_unmounted(HostDriver::Type host_type = HostDriver::Type::UNKNOWN);
// // // void notify_xbox360w_connected(uint8_t idx);
// // // void notify_xbox360w_disconnected(uint8_t idx);
// // }
// class I2CDriver4Ch
// {
// public:
// I2CDriver4Ch& get_instance()
// {
// static I2CDriver4Ch instance;
// return instance;
// }
// I2CDriver4Ch(const I2CDriver4Ch&) = delete;
// I2CDriver4Ch& operator=(const I2CDriver4Ch&) = delete;
// void initialize(Gamepad (&gamepads)[MAX_GAMEPADS]);
// private:
// I2CDriver4Ch() = default;
// ~I2CDriver4Ch() = default;
// I2CDriver4Ch(const I2CDriver4Ch&) = delete;
// I2CDriver4Ch& operator=(const I2CDriver4Ch&) = delete;
// enum class Mode { MASTER = 0, SLAVE };
// enum class ReportID : uint8_t { UNKNOWN = 0, PAD, STATUS, CONNECT, DISCONNECT };
// enum class SlaveStatus : uint8_t { NC = 0, NOT_READY, READY, RESP_OK };
// #pragma pack(push, 1)
// struct ReportIn
// {
// uint8_t report_len;
// uint8_t report_id;
// uint8_t pad_in[sizeof(Gamepad::PadIn) - sizeof(Gamepad::PadIn::analog)];
// ReportIn()
// {
// std::memset(this, 0, sizeof(ReportIn));
// report_len = sizeof(ReportIn);
// report_id = static_cast<uint8_t>(ReportID::PAD);
// }
// };
// static_assert(sizeof(ReportIn) == 18, "I2CDriver::ReportIn size mismatch");
// struct ReportOut
// {
// uint8_t report_len;
// uint8_t report_id;
// uint8_t pad_out[sizeof(Gamepad::PadOut)];
// ReportOut()
// {
// std::memset(this, 0, sizeof(ReportOut));
// report_len = sizeof(ReportOut);
// report_id = static_cast<uint8_t>(ReportID::PAD);
// }
// };
// static_assert(sizeof(ReportOut) == 4, "I2CDriver::ReportOut size mismatch");
// struct ReportStatus
// {
// uint8_t report_len;
// uint8_t report_id;
// uint8_t status;
// ReportStatus()
// {
// report_len = sizeof(ReportStatus);
// report_id = static_cast<uint8_t>(ReportID::STATUS);
// status = static_cast<uint8_t>(SlaveStatus::NC);
// }
// };
// static_assert(sizeof(ReportStatus) == 3, "I2CDriver::ReportStatus size mismatch");
// #pragma pack(pop)
// static constexpr size_t MAX_BUFFER_SIZE = std::max(sizeof(ReportStatus), std::max(sizeof(ReportIn), sizeof(ReportOut)));
// struct Master
// {
// std::atomic<bool> enabled{false};
// struct Slave
// {
// uint8_t address{0xFF};
// Gamepad* gamepad{nullptr};
// SlaveStatus status{SlaveStatus::NC};
// std::atomic<bool> enabled{false};
// uint32_t last_update{0};
// };
// std::array<Slave, MAX_GAMEPADS - 1> slaves;
// };
// struct Slave
// {
// uint8_t address{0xFF};
// Gamepad* gamepad{nullptr};
// std::atomic<bool> i2c_enabled{false};
// std::atomic<bool> tuh_enabled{false};
// };
// Slave slave_;
// static Gamepad* gamepads_[MAX_GAMEPADS];
// };
// #endif // _I2C_DRIVER_H_

View File

@@ -60,7 +60,6 @@ static constexpr size_t MAX_BUFFER_SIZE = std::max(sizeof(ReportOut), sizeof(Rep
static constexpr uint8_t I2C_ADDR = 0x01;
std::array<Gamepad*, MAX_GAMEPADS> gamepads_{nullptr};
// std::atomic<bool> pad_connected_ = false;
inline void process_in_report(ReportIn* report_in)
{
@@ -79,6 +78,7 @@ inline void process_in_report(ReportIn* report_in)
gamepad->set_joystick_ly_int10(static_cast<int32_t>(report_in->joystick_ly));
gamepad->set_joystick_rx_int10(static_cast<int32_t>(report_in->joystick_rx));
gamepad->set_joystick_ry_int10(static_cast<int32_t>(report_in->joystick_ry));
gamepad->set_new_report(true);
}
inline void fill_out_report(uint8_t index, ReportOut* report_out)
@@ -174,9 +174,4 @@ void initialize(std::array<Gamepad, MAX_GAMEPADS>& gamepad)
i2c_slave_init(I2C_PORT, I2C_ADDR, &slave_handler);
}
// bool pad_connected()
// {
// return pad_connected_.load();
// }
} // namespace i2c_driver_esp32

View File

@@ -8,20 +8,13 @@
namespace OGXMini
{
enum class TUDStatus { INIT, DEINIT, NOCHANGE };
struct GPCheckContext
{
bool driver_changed;
UserSettings& user_settings;
};
static constexpr int32_t FEEDBACK_DELAY_MS = 100;
static constexpr int32_t FEEDBACK_DELAY_MS = 150;
static constexpr int32_t TUD_CHECK_DELAY_MS = 500;
void run_program();
void update_tud_status(bool host_mounted);
// Callback to notify main loop of tuh mounted
void update_tuh_status(bool mounted) __attribute__((weak));
}
} // namespace OGXMini
#endif // _OGX_MINI_H_

View File

@@ -1,7 +1,6 @@
#include "board_config.h"
#if OGXM_BOARD == INTERNAL_4CH || OGXM_BOARD == EXTERNAL_4CH
#include <array>
#include <pico/multicore.h>
#include "tusb.h"
@@ -9,19 +8,37 @@
#include "pio_usb.h"
#include "USBDevice/DeviceManager.h"
#include "USBHost/HostManager.h"
#include "Board/board_api.h"
#include "OGXMini/OGXMini.h"
#include "I2CDriver/i2c_driver_4ch.h"
#include "I2CDriver/4Channel/I2CManager.h"
#include "Gamepad.h"
#include "TaskQueue/TaskQueue.h"
namespace OGXMini {
std::array<Gamepad, MAX_GAMEPADS> gamepads_;
Gamepad gamepads_[MAX_GAMEPADS];
bool feedback_cb(repeating_timer_t* rt)
//Called by tusb host or i2c driver so we know to connect or disconnect usb
void update_tud_status(bool host_mounted)
{
static_cast<HostManager*>(rt->user_data)->send_feedback();
return true;
board_api::set_led(host_mounted);
if (!host_mounted)
{
TaskQueue::Core0::queue_task([]()
{
tud_disconnect();
sleep_ms(300);
multicore_reset_core1();
sleep_ms(300);
board_api::reboot();
});
}
else if (!tud_inited())
{
tud_init(BOARD_TUD_RHPORT);
}
}
void core1_task()
@@ -34,46 +51,19 @@ void core1_task()
tuh_init(BOARD_TUH_RHPORT);
repeating_timer_t feedback_timer;
add_repeating_timer_ms(FEEDBACK_DELAY_MS, feedback_cb, &host_manager, &feedback_timer);
uint32_t tid_feedback = TaskQueue::Core1::get_new_task_id();
TaskQueue::Core1::queue_delayed_task(tid_feedback, FEEDBACK_DELAY_MS, true, [&host_manager]
{
host_manager.send_feedback();
});
while (true)
{
TaskQueue::Core1::process_tasks();
tuh_task();
sleep_us(100);
}
}
bool gp_check_cb(repeating_timer_t* rt)
{
GPCheckContext* gp_check_ctx = static_cast<GPCheckContext*>(rt->user_data);
gp_check_ctx->driver_changed = gp_check_ctx->user_settings.check_for_driver_change(gamepads_.front());
return true;
}
bool tud_status_cb(repeating_timer_t* rt)
{
TUDStatusContext* tud_status_ctx = static_cast<TUDStatusContext*>(rt->user_data);
bool host_mounted = HostManager::get_instance().mounted() || i2c_driver::is_active();
bool device_ininted = tud_inited();
board_api::set_led(host_mounted);
if (host_mounted && !device_ininted)
{
tud_status_ctx->status = TUDStatus::INIT;
}
else if (!host_mounted && device_ininted)
{
tud_status_ctx->status = TUDStatus::DEINIT;
}
else
{
tud_status_ctx->status = TUDStatus::NOCHANGE;
}
return true;
}
void run_program()
{
UserSettings user_settings;
@@ -81,6 +71,7 @@ void run_program()
board_init();
board_api::init_gpio();
board_api::set_led(false);
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
{
@@ -90,47 +81,40 @@ void run_program()
DeviceManager& device_manager = DeviceManager::get_instance();
device_manager.initialize_driver(user_settings.get_current_driver());
i2c_driver::initialize(gamepads_);
I2CManager& i2c_manager = I2CManager::get_instance();
i2c_manager.initialize_driver();
multicore_reset_core1();
multicore_launch_core1(core1_task);
GPCheckContext gp_check_ctx = { false, user_settings };
repeating_timer_t gp_check_timer;
add_repeating_timer_ms(UserSettings::GP_CHECK_DELAY_MS, gp_check_cb, &gp_check_ctx, &gp_check_timer);
TUDStatusContext tud_status_ctx = { TUDStatus::NOCHANGE, &HostManager::get_instance() };
repeating_timer_t tud_status_timer;
add_repeating_timer_ms(500, tud_status_cb, &tud_status_ctx, &tud_status_timer);
uint32_t tid_gp_check = TaskQueue::Core0::get_new_task_id();
TaskQueue::Core0::queue_delayed_task(tid_gp_check, UserSettings::GP_CHECK_DELAY_MS, true, [&user_settings]
{
//Check gamepad inputs for button combo to change usb device driver
if (user_settings.check_for_driver_change(gamepads_[0]))
{
//This will store the new mode and reboot the pico
user_settings.store_driver_type_safe(user_settings.get_current_driver());
}
});
DeviceDriver* device_driver = device_manager.get_driver();
I2CDriver* i2c_driver = i2c_manager.get_driver();
//Wait for something to call tud_init
while (!tud_inited())
{
TaskQueue::Core0::process_tasks();
sleep_ms(10);
}
while (true)
{
switch (tud_status_ctx.status)
{
case TUDStatus::NOCHANGE:
break;
case TUDStatus::INIT:
tud_init(BOARD_TUD_RHPORT);
break;
case TUDStatus::DEINIT:
tud_disconnect();
sleep_ms(300);
board_api::reboot();
break;
}
TaskQueue::Core0::process_tasks();
i2c_driver->process(gamepads_);
device_driver->process(0, gamepads_[0]);
tud_task();
sleep_us(100);
i2c_driver::process();
if (gp_check_ctx.driver_changed)
{
cancel_repeating_timer(&gp_check_timer);
user_settings.store_driver_type_safe(user_settings.get_current_driver());
}
}
}

View File

@@ -1,7 +1,8 @@
#include "board_config.h"
#if (OGXM_BOARD == PI_PICOW)
#include <array>
#include <pico/stdlib.h>
#include <hardware/sync.h>
#include <pico/multicore.h>
#include <hardware/gpio.h>
#include <hardware/clocks.h>
@@ -17,7 +18,7 @@
namespace OGXMini {
std::array<Gamepad, MAX_GAMEPADS> gamepads_;
Gamepad gamepads_[MAX_GAMEPADS];
void core1_task()
{
@@ -32,7 +33,7 @@ void core1_task()
bool gp_check_cb(repeating_timer_t* rt)
{
GPCheckContext* gp_check_ctx = static_cast<GPCheckContext*>(rt->user_data);
gp_check_ctx->driver_changed = gp_check_ctx->user_settings.check_for_driver_change(gamepads_.front());
gp_check_ctx->driver_changed = gp_check_ctx->user_settings.check_for_driver_change(gamepads_[0]);
return true;
}
@@ -65,7 +66,7 @@ void run_program()
while (true)
{
for (uint8_t i = 0; i < gamepads_.size(); ++i)
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
{
device_driver->process(i, gamepads_[i]);
tud_task();

View File

@@ -2,6 +2,7 @@
#if (OGXM_BOARD == ADA_FEATHER) || (OGXM_BOARD == RP_ZERO) || (OGXM_BOARD == PI_PICO)
#include <array>
#include <atomic>
#include <pico/multicore.h>
#include <hardware/gpio.h>
#include <hardware/clocks.h>
@@ -19,20 +20,12 @@
namespace OGXMini {
std::atomic<TUDStatus> tud_status_ = TUDStatus::NOCHANGE;
std::array<Gamepad, MAX_GAMEPADS> gamepads_;
Gamepad gamepads_[MAX_GAMEPADS];
void update_tuh_status(bool mounted)
{
if (mounted)
{
tud_status_.store(TUDStatus::INIT);
board_api::set_led(true);
}
else
{
tud_status_.store(TUDStatus::DEINIT);
board_api::set_led(false);
}
tud_status_.store(mounted ? TUDStatus::INIT : TUDStatus::DEINIT);
board_api::set_led(mounted);
}
bool feedback_cb(repeating_timer_t* rt)
@@ -61,15 +54,32 @@ void core1_task()
}
}
// bool gp_check_cb(repeating_timer_t* rt)
// {
// GPCheckContext* gp_check_ctx = static_cast<GPCheckContext*>(rt->user_data);
// // gp_check_ctx->driver_changed = gp_check_ctx->user_settings.check_for_driver_change(gamepads_[0]);
// if (gp_check_ctx->user_settings.check_for_driver_change(gamepads_[0]))
// {
// gp_check_ctx->user_settings.store_driver_type_safe(gp_check_ctx->user_settings.get_current_driver());
// return false;
// }
// return true;
// }
bool gp_check_cb(repeating_timer_t* rt)
{
GPCheckContext* gp_check_ctx = static_cast<GPCheckContext*>(rt->user_data);
gp_check_ctx->driver_changed = gp_check_ctx->user_settings.check_for_driver_change(gamepads_.front());
UserSettings* user_settings = static_cast<UserSettings*>(rt->user_data);
if (user_settings->check_for_driver_change(gamepads_[0]))
{
user_settings->store_driver_type_safe(user_settings->get_current_driver());
return false;
}
return true;
}
void run_program()
{
set_sys_clock_khz(250000, true);
UserSettings user_settings;
user_settings.initialize_flash();
@@ -89,22 +99,26 @@ void run_program()
multicore_reset_core1();
multicore_launch_core1(core1_task);
GPCheckContext gp_check_ctx = { false, user_settings };
// GPCheckContext gp_check_ctx = { false, user_settings };
// repeating_timer_t gp_check_timer;
// add_repeating_timer_ms(UserSettings::GP_CHECK_DELAY_MS, gp_check_cb, &gp_check_ctx, &gp_check_timer);
repeating_timer_t gp_check_timer;
add_repeating_timer_ms(UserSettings::GP_CHECK_DELAY_MS, gp_check_cb, &gp_check_ctx, &gp_check_timer);
add_repeating_timer_ms(UserSettings::GP_CHECK_DELAY_MS, gp_check_cb, &user_settings, &gp_check_timer);
DeviceDriver* device_driver = device_manager.get_driver();
while (tud_status_.load() != TUDStatus::INIT)
{
sleep_ms(1);
}
tud_init(BOARD_TUD_RHPORT);
while (true)
{
switch (tud_status_.load())
switch(tud_status_.load())
{
case TUDStatus::NOCHANGE:
break;
case TUDStatus::INIT:
tud_init(BOARD_TUD_RHPORT);
tud_status_.store(TUDStatus::NOCHANGE);
break;
case TUDStatus::DEINIT:
tud_disconnect();
sleep_ms(300);
@@ -112,21 +126,17 @@ void run_program()
sleep_ms(300);
board_api::reboot();
break;
default:
break;
}
for (uint8_t i = 0; i < gamepads_.size(); ++i)
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
{
device_driver->process(i, gamepads_[i]);
tud_task();
}
sleep_us(100);
if (gp_check_ctx.driver_changed)
{
cancel_repeating_timer(&gp_check_timer);
user_settings.store_driver_type_safe(user_settings.get_current_driver());
}
}
}

151
Firmware/RP2040/src/Scale.h Normal file
View File

@@ -0,0 +1,151 @@
#ifndef _SCALE_H_
#define _SCALE_H_
#include <cstdint>
namespace INT_16
{
static constexpr int16_t MIN = INT16_MIN;
static constexpr int16_t MID = 0;
static constexpr int16_t MAX = INT16_MAX;
}
namespace UINT_16
{
static constexpr uint16_t MIN = 0;
static constexpr uint16_t MID = 0x8000;
static constexpr uint16_t MAX = 0xFFFF;
}
namespace UINT_8
{
static constexpr uint8_t MAX = 0xFF;
static constexpr uint8_t MID = 0x80;
static constexpr uint8_t MIN = 0x00;
}
namespace INT_10
{
static constexpr int32_t MIN = -512;
static constexpr int32_t MAX = 511;
}
namespace UINT_10
{
static constexpr int32_t MAX = 1023;
}
namespace Scale //Scale and invert values
{
static inline uint8_t invert_joy(uint8_t value)
{
return static_cast<uint8_t>(UINT_8::MAX - value);
}
static inline int8_t invert_joy(int8_t value)
{
return (value == std::numeric_limits<int8_t>::min()) ? std::numeric_limits<int8_t>::max() : -value;
}
static inline uint16_t invert_joy(uint16_t value)
{
return static_cast<uint16_t>(std::numeric_limits<uint16_t>::max() - value);
}
static inline int16_t invert_joy(int16_t value)
{
return (value == std::numeric_limits<int16_t>::min()) ? std::numeric_limits<int16_t>::max() : -value;
}
static inline uint8_t int16_to_uint8(int16_t value)
{
uint16_t shifted_value = static_cast<uint16_t>(value + UINT_16::MID);
return static_cast<uint8_t>(shifted_value >> 8);
}
static inline uint16_t int16_to_uint16(int16_t value)
{
return static_cast<uint16_t>(value + UINT_16::MID);
}
static inline int8_t int16_to_int8(int16_t value)
{
return static_cast<int8_t>((value + UINT_16::MID) >> 8);
}
static inline uint8_t uint16_to_uint8(uint16_t value)
{
return static_cast<uint8_t>(value >> 8);
}
static inline int16_t uint16_to_int16(uint16_t value)
{
return static_cast<int16_t>(value - UINT_16::MID);
}
static inline int8_t uint16_to_int8(uint16_t value)
{
return static_cast<int8_t>((value >> 8) - UINT_8::MID);
}
static inline int16_t uint8_to_int16(uint8_t value)
{
return static_cast<int16_t>((static_cast<int32_t>(value) << 8) - UINT_16::MID);
}
static inline uint16_t uint8_to_uint16(uint8_t value)
{
return static_cast<uint16_t>(value) << 8;
}
static inline int8_t uint8_to_int8(uint8_t value)
{
return static_cast<int8_t>(value - UINT_8::MID);
}
static inline int16_t int8_to_int16(int8_t value)
{
return static_cast<int16_t>(value) << 8;
}
static inline uint16_t int8_to_uint16(int8_t value)
{
return static_cast<uint16_t>((value + UINT_8::MID) << 8);
}
static inline uint8_t int8_to_uint8(int8_t value)
{
return static_cast<uint8_t>(value + UINT_8::MID);
}
static inline uint8_t int10_to_uint8(int32_t value)
{
value = value - INT_10::MIN;
if (value >= UINT_10::MAX)
{
return UINT_8::MAX;
}
else if (value <= 0)
{
return 0;
}
return static_cast<uint8_t>(value >> 2);
}
static inline int16_t int10_to_int16(int32_t value)
{
constexpr int32_t scale_factor = INT_16::MAX - INT_16::MIN;
constexpr int32_t range = INT_10::MAX - INT_10::MIN;
if (value >= INT_10::MAX)
{
return INT_16::MAX;
}
else if (value <= INT_10::MIN)
{
return INT_16::MIN;
}
int32_t scaled_value = (value - INT_10::MIN) * scale_factor;
return static_cast<int16_t>(scaled_value / range + INT_16::MIN);
}
static inline uint8_t uint10_to_uint8(int32_t value)
{
if (value > UINT_10::MAX)
{
value = UINT_10::MAX;
}
else if (value < 0)
{
value = 0;
}
return static_cast<uint8_t>(value >> 2);
}
} // namespace Scale
#endif // _SCALE_H_

View File

@@ -0,0 +1,426 @@
#include <array>
#include <algorithm>
#include <pico/stdlib.h>
#include <hardware/timer.h>
#include <hardware/irq.h>
#include <hardware/sync.h>
#include "Board/board_api.h"
#include "TaskQueue/TaskQueue.h"
namespace TaskQueue {
struct Task
{
std::function<void()> function = nullptr;
};
struct DelayedTask
{
uint32_t task_id = 0;
uint32_t interval_ms = 0;
uint64_t target_time = 0;
std::function<void()> function = nullptr;
};
static constexpr uint8_t MAX_TASKS = 8;
static constexpr uint8_t MAX_DELAYED_TASKS = MAX_TASKS * 2;
static inline uint32_t TIMER_IRQ(int alarm_num)
{
return timer_hardware_alarm_get_irq_num(timer_hw, alarm_num);
}
static uint64_t get_time_64_us()
{
static spin_lock_t* spinlock_64_us = spin_lock_instance(4);
uint32_t irq_state = spin_lock_blocking(spinlock_64_us);
uint32_t lo = timer_hw->timelr;
uint32_t hi = timer_hw->timehr;
spin_unlock(spinlock_64_us, irq_state);
return ((uint64_t) hi << 32u) | lo;;
}
namespace Core1 {
static constexpr uint32_t CORE = 1;
static constexpr uint32_t ALARM_NUM = CORE;
static std::array<Task, MAX_TASKS> tasks_;
static std::array<DelayedTask, MAX_DELAYED_TASKS> delayed_tasks_;
static bool delay_irq_set_ = false;
static uint32_t new_task_id_ = 1;
static spin_lock_t* spinlock_ = spin_lock_instance(CORE);
static spin_lock_t* spinlock_delayed_ = spin_lock_instance(CORE + 2);
uint32_t get_new_task_id()
{
return new_task_id_++;
}
static void timer_irq_handler()
{
hw_clear_bits(&timer_hw->intr, 1u << ALARM_NUM);
uint64_t now = get_time_64_us();
uint32_t irq_state = spin_lock_blocking(spinlock_delayed_);
for (auto& task : delayed_tasks_)
{
if (task.function && task.target_time <= now)
{
auto function = task.function;
if (task.interval_ms)
{
task.target_time += (task.interval_ms * 1000);
}
else
{
task.function = nullptr;
task.task_id = 0;
}
spin_unlock(spinlock_delayed_, irq_state);
queue_task(function);
irq_state = spin_lock_blocking(spinlock_delayed_);
}
}
auto it = std::min_element(delayed_tasks_.begin(), delayed_tasks_.end(), [](const DelayedTask& a, const DelayedTask& b)
{
return a.function && (!b.function || a.target_time < b.target_time);
});
if (it != delayed_tasks_.end() && it->function)
{
timer_hw->alarm[ALARM_NUM] = static_cast<uint32_t>(it->target_time);
}
spin_unlock(spinlock_delayed_, irq_state);
}
bool queue_delayed_task(uint32_t task_id, uint32_t delay_ms, bool repeating, const std::function<void()>& function)
{
uint32_t irq_state = spin_lock_blocking(spinlock_delayed_);
for (const auto& task : delayed_tasks_)
{
if (task.task_id == task_id)
{
spin_unlock(spinlock_delayed_, irq_state);
return false;
}
}
spin_unlock(spinlock_delayed_, irq_state);
hw_set_bits(&timer_hw->inte, 1u << ALARM_NUM);
if (!delay_irq_set_)
{
delay_irq_set_ = true;
irq_set_exclusive_handler(TIMER_IRQ(ALARM_NUM), timer_irq_handler);
irq_set_enabled(TIMER_IRQ(ALARM_NUM), true);
}
irq_state = spin_lock_blocking(spinlock_delayed_);
uint64_t target_time = timer_hw->timerawl + static_cast<uint64_t>(delay_ms) * 1000;
for (auto& task : delayed_tasks_)
{
if (!task.function)
{
task.target_time = target_time;
task.interval_ms = repeating ? delay_ms : 0;
task.function = function;
task.task_id = task_id;
auto it = std::min_element(delayed_tasks_.begin(), delayed_tasks_.end(), [](const DelayedTask& a, const DelayedTask& b)
{
return a.function && (!b.function || a.target_time < b.target_time);
});
if (it != delayed_tasks_.end() && it->function)
{
timer_hw->alarm[ALARM_NUM] = static_cast<uint32_t>(it->target_time);
}
spin_unlock(spinlock_delayed_, irq_state);
return true;
}
}
spin_unlock(spinlock_delayed_, irq_state);
return false;
}
void cancel_delayed_task(uint32_t task_id)
{
uint32_t irq_state = spin_lock_blocking(spinlock_delayed_);
bool found = false;
for (auto& task : delayed_tasks_)
{
if (task.task_id == task_id)
{
task.function = nullptr;
task.task_id = 0;
found = true;
}
}
if (!found || !delay_irq_set_)
{
spin_unlock(spinlock_delayed_, irq_state);
return;
}
hw_set_bits(&timer_hw->inte, 1u << ALARM_NUM);
auto it = std::min_element(delayed_tasks_.begin(), delayed_tasks_.end(), [](const DelayedTask& a, const DelayedTask& b)
{
return a.function && (!b.function || a.target_time < b.target_time);
});
if (it != delayed_tasks_.end() && it->function)
{
timer_hw->alarm[ALARM_NUM] = static_cast<uint32_t>(it->target_time);
}
spin_unlock(spinlock_delayed_, irq_state);
}
bool queue_task(const std::function<void()>& function)
{
uint32_t irq_state = spin_lock_blocking(spinlock_);
for (auto& task : tasks_)
{
if (!task.function)
{
task.function = function;
spin_unlock(spinlock_, irq_state);
return true;
}
}
spin_unlock(spinlock_, irq_state);
return false;
}
void process_tasks()
{
uint32_t irq_state = spin_lock_blocking(spinlock_);
for (auto& task : tasks_)
{
if (task.function)
{
auto function = task.function;
task.function = nullptr;
spin_unlock(spinlock_, irq_state);
function();
irq_state = spin_lock_blocking(spinlock_);
}
else
{
break; //No more tasks
}
}
spin_unlock(spinlock_, irq_state);
}
} // namespace Core1
namespace Core0 {
static constexpr uint32_t CORE = 0;
static constexpr uint32_t ALARM_NUM = CORE;
static std::array<Task, MAX_TASKS> tasks_;
static std::array<DelayedTask, MAX_DELAYED_TASKS> delayed_tasks_;
static bool delay_irq_set_ = false;
static uint32_t new_task_id_ = 1;
static spin_lock_t* spinlock_ = spin_lock_instance(CORE);
static spin_lock_t* spinlock_delayed_ = spin_lock_instance(CORE + 2);
uint32_t get_new_task_id()
{
return new_task_id_++;
}
static void timer_irq_handler()
{
hw_clear_bits(&timer_hw->intr, 1u << ALARM_NUM);
uint64_t now = get_time_64_us();
uint32_t irq_state = spin_lock_blocking(spinlock_delayed_);
for (auto& task : delayed_tasks_)
{
if (task.function && task.target_time <= now)
{
auto function = task.function;
if (task.interval_ms)
{
task.target_time += (task.interval_ms * 1000);
}
else
{
task.function = nullptr;
task.task_id = 0;
}
spin_unlock(spinlock_delayed_, irq_state);
queue_task(function);
irq_state = spin_lock_blocking(spinlock_delayed_);
}
}
auto it = std::min_element(delayed_tasks_.begin(), delayed_tasks_.end(), [](const DelayedTask& a, const DelayedTask& b)
{
return a.function && (!b.function || a.target_time < b.target_time);
});
if (it != delayed_tasks_.end() && it->function)
{
timer_hw->alarm[ALARM_NUM] = static_cast<uint32_t>(it->target_time);
}
spin_unlock(spinlock_delayed_, irq_state);
}
bool queue_delayed_task(uint32_t task_id, uint32_t delay_ms, bool repeating, const std::function<void()>& function)
{
uint32_t irq_state = spin_lock_blocking(spinlock_delayed_);
for (const auto& task : delayed_tasks_)
{
if (task.task_id == task_id)
{
spin_unlock(spinlock_delayed_, irq_state);
return false;
}
}
spin_unlock(spinlock_delayed_, irq_state);
hw_set_bits(&timer_hw->inte, 1u << ALARM_NUM);
if (!delay_irq_set_)
{
delay_irq_set_ = true;
irq_set_exclusive_handler(TIMER_IRQ(ALARM_NUM), timer_irq_handler);
irq_set_enabled(TIMER_IRQ(ALARM_NUM), true);
}
irq_state = spin_lock_blocking(spinlock_delayed_);
uint64_t target_time = timer_hw->timerawl + static_cast<uint64_t>(delay_ms) * 1000;
for (auto& task : delayed_tasks_)
{
if (!task.function)
{
task.target_time = target_time;
task.interval_ms = repeating ? delay_ms : 0;
task.function = function;
task.task_id = task_id;
auto it = std::min_element(delayed_tasks_.begin(), delayed_tasks_.end(), [](const DelayedTask& a, const DelayedTask& b)
{
return a.function && (!b.function || a.target_time < b.target_time);
});
if (it != delayed_tasks_.end() && it->function)
{
timer_hw->alarm[ALARM_NUM] = static_cast<uint32_t>(it->target_time);
}
spin_unlock(spinlock_delayed_, irq_state);
return true;
}
}
spin_unlock(spinlock_delayed_, irq_state);
return false;
}
void cancel_delayed_task(uint32_t task_id)
{
uint32_t irq_state = spin_lock_blocking(spinlock_delayed_);
bool found = false;
for (auto& task : delayed_tasks_)
{
if (task.task_id == task_id)
{
task.function = nullptr;
task.task_id = 0;
found = true;
}
}
if (!found || !delay_irq_set_)
{
spin_unlock(spinlock_delayed_, irq_state);
return;
}
hw_set_bits(&timer_hw->inte, 1u << ALARM_NUM);
auto it = std::min_element(delayed_tasks_.begin(), delayed_tasks_.end(), [](const DelayedTask& a, const DelayedTask& b)
{
return a.function && (!b.function || a.target_time < b.target_time);
});
if (it != delayed_tasks_.end() && it->function)
{
timer_hw->alarm[ALARM_NUM] = static_cast<uint32_t>(it->target_time);
}
spin_unlock(spinlock_delayed_, irq_state);
}
bool queue_task(const std::function<void()>& function)
{
uint32_t irq_state = spin_lock_blocking(spinlock_);
for (auto& task : tasks_)
{
if (!task.function)
{
task.function = function;
spin_unlock(spinlock_, irq_state);
return true;
}
}
spin_unlock(spinlock_, irq_state);
return false;
}
void process_tasks()
{
uint32_t irq_state = spin_lock_blocking(spinlock_);
for (auto& task : tasks_)
{
if (task.function)
{
auto function = task.function;
task.function = nullptr;
spin_unlock(spinlock_, irq_state);
function();
irq_state = spin_lock_blocking(spinlock_);
}
else
{
break; //No more tasks
}
}
spin_unlock(spinlock_, irq_state);
}
} // namespace Core0
} // namespace TaskQueue

View File

@@ -0,0 +1,30 @@
#ifndef TASK_QUEUE_H
#define TASK_QUEUE_H
#include <cstdint>
#include <functional>
/* Queue tasks to be executed with process_tasks() */
namespace TaskQueue
{
namespace Core0
{
uint32_t get_new_task_id();
void cancel_delayed_task(uint32_t task_id);
bool queue_delayed_task(uint32_t task_id, uint32_t delay_ms, bool repeating, const std::function<void()>& function);
bool queue_task(const std::function<void()>& function);
void process_tasks();
}
namespace Core1
{
uint32_t get_new_task_id();
void cancel_delayed_task(uint32_t task_id);
bool queue_delayed_task(uint32_t task_id, uint32_t delay_ms, bool repeating, const std::function<void()>& function);
bool queue_task(const std::function<void()>& function);
void process_tasks();
}
} // namespace TaskQueue
#endif // TASK_QUEUE_H

View File

@@ -18,16 +18,14 @@ bool DInputDevice::control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_r
void DInputDevice::initialize()
{
std::memset(&in_report_, 0, sizeof(DInput::InReport));
in_report_.dpad = DInput::DPad::CENTER;
in_report_.joystick_lx = DInput::AXIS_MID;
in_report_.joystick_ly = DInput::AXIS_MID;
in_report_.joystick_rx = DInput::AXIS_MID;
in_report_.joystick_ry = DInput::AXIS_MID;
for (auto& prev_in_report : prev_in_reports_)
for (auto& in_report : in_reports_)
{
std::memcpy(&prev_in_report, &in_report_, sizeof(DInput::InReport));
std::memset(&in_report, 0, sizeof(DInput::InReport));
in_report.dpad = DInput::DPad::CENTER;
in_report.joystick_lx = DInput::AXIS_MID;
in_report.joystick_ly = DInput::AXIS_MID;
in_report.joystick_rx = DInput::AXIS_MID;
in_report.joystick_ry = DInput::AXIS_MID;
}
class_driver_ = {
@@ -45,95 +43,102 @@ void DInputDevice::initialize()
void DInputDevice::process(const uint8_t idx, Gamepad& gamepad)
{
switch (gamepad.get_dpad_buttons())
if (!gamepad.new_pad_in())
{
case Gamepad::DPad::UP:
in_report_.dpad = DInput::DPad::UP;
return;
}
Gamepad::PadIn gp_in = gamepad.get_pad_in();
DInput::InReport& in_report = in_reports_[idx];
switch (gp_in.dpad)
{
case Gamepad::DPAD_UP:
in_report.dpad = DInput::DPad::UP;
break;
case Gamepad::DPad::DOWN:
in_report_.dpad = DInput::DPad::DOWN;
case Gamepad::DPAD_DOWN:
in_report.dpad = DInput::DPad::DOWN;
break;
case Gamepad::DPad::LEFT:
in_report_.dpad = DInput::DPad::LEFT;
case Gamepad::DPAD_LEFT:
in_report.dpad = DInput::DPad::LEFT;
break;
case Gamepad::DPad::RIGHT:
in_report_.dpad = DInput::DPad::RIGHT;
case Gamepad::DPAD_RIGHT:
in_report.dpad = DInput::DPad::RIGHT;
break;
case Gamepad::DPad::UP_LEFT:
in_report_.dpad = DInput::DPad::UP_LEFT;
case Gamepad::DPAD_UP_LEFT:
in_report.dpad = DInput::DPad::UP_LEFT;
break;
case Gamepad::DPad::UP_RIGHT:
in_report_.dpad = DInput::DPad::UP_RIGHT;
case Gamepad::DPAD_UP_RIGHT:
in_report.dpad = DInput::DPad::UP_RIGHT;
break;
case Gamepad::DPad::DOWN_LEFT:
in_report_.dpad = DInput::DPad::DOWN_LEFT;
case Gamepad::DPAD_DOWN_LEFT:
in_report.dpad = DInput::DPad::DOWN_LEFT;
break;
case Gamepad::DPad::DOWN_RIGHT:
in_report_.dpad = DInput::DPad::DOWN_RIGHT;
case Gamepad::DPAD_DOWN_RIGHT:
in_report.dpad = DInput::DPad::DOWN_RIGHT;
break;
default:
in_report_.dpad = DInput::DPad::CENTER;
in_report.dpad = DInput::DPad::CENTER;
break;
}
std::memset(in_report_.buttons, 0, sizeof(in_report_.buttons));
std::memset(in_report.buttons, 0, sizeof(in_report.buttons));
uint16_t gamepad_buttons = gamepad.get_buttons();
if (gp_in.buttons & Gamepad::BUTTON_A) in_report.buttons[0] |= DInput::Buttons0::CROSS;
if (gp_in.buttons & Gamepad::BUTTON_B) in_report.buttons[0] |= DInput::Buttons0::CIRCLE;
if (gp_in.buttons & Gamepad::BUTTON_X) in_report.buttons[0] |= DInput::Buttons0::SQUARE;
if (gp_in.buttons & Gamepad::BUTTON_Y) in_report.buttons[0] |= DInput::Buttons0::TRIANGLE;
if (gp_in.buttons & Gamepad::BUTTON_LB) in_report.buttons[0] |= DInput::Buttons0::L1;
if (gp_in.buttons & Gamepad::BUTTON_RB) in_report.buttons[0] |= DInput::Buttons0::R1;
if (gamepad_buttons & Gamepad::Button::A) in_report_.buttons[0] |= DInput::Buttons0::CROSS;
if (gamepad_buttons & Gamepad::Button::B) in_report_.buttons[0] |= DInput::Buttons0::CIRCLE;
if (gamepad_buttons & Gamepad::Button::X) in_report_.buttons[0] |= DInput::Buttons0::SQUARE;
if (gamepad_buttons & Gamepad::Button::Y) in_report_.buttons[0] |= DInput::Buttons0::TRIANGLE;
if (gamepad_buttons & Gamepad::Button::LB) in_report_.buttons[0] |= DInput::Buttons0::L1;
if (gamepad_buttons & Gamepad::Button::RB) in_report_.buttons[0] |= DInput::Buttons0::R1;
if (gamepad_buttons & Gamepad::Button::L3) in_report_.buttons[1] |= DInput::Buttons1::L3;
if (gamepad_buttons & Gamepad::Button::R3) in_report_.buttons[1] |= DInput::Buttons1::R3;
if (gamepad_buttons & Gamepad::Button::BACK) in_report_.buttons[1] |= DInput::Buttons1::SELECT;
if (gamepad_buttons & Gamepad::Button::START) in_report_.buttons[1] |= DInput::Buttons1::START;
if (gamepad_buttons & Gamepad::Button::SYS) in_report_.buttons[1] |= DInput::Buttons1::PS;
if (gamepad_buttons & Gamepad::Button::MISC) in_report_.buttons[1] |= DInput::Buttons1::TP;
if (gp_in.buttons & Gamepad::BUTTON_L3) in_report.buttons[1] |= DInput::Buttons1::L3;
if (gp_in.buttons & Gamepad::BUTTON_R3) in_report.buttons[1] |= DInput::Buttons1::R3;
if (gp_in.buttons & Gamepad::BUTTON_BACK) in_report.buttons[1] |= DInput::Buttons1::SELECT;
if (gp_in.buttons & Gamepad::BUTTON_START) in_report.buttons[1] |= DInput::Buttons1::START;
if (gp_in.buttons & Gamepad::BUTTON_SYS) in_report.buttons[1] |= DInput::Buttons1::PS;
if (gp_in.buttons & Gamepad::BUTTON_MISC) in_report.buttons[1] |= DInput::Buttons1::TP;
if (gamepad.analog_enabled())
{
in_report_.up_axis = gamepad.get_analog_up();
in_report_.down_axis = gamepad.get_analog_down();
in_report_.right_axis = gamepad.get_analog_right();
in_report_.left_axis = gamepad.get_analog_left();
in_report.up_axis = gp_in.analog[Gamepad::ANALOG_OFF_UP];
in_report.down_axis = gp_in.analog[Gamepad::ANALOG_OFF_DOWN];
in_report.right_axis = gp_in.analog[Gamepad::ANALOG_OFF_RIGHT];
in_report.left_axis = gp_in.analog[Gamepad::ANALOG_OFF_LEFT];
in_report_.triangle_axis = gamepad.get_analog_y();
in_report_.circle_axis = gamepad.get_analog_x();
in_report_.cross_axis = gamepad.get_analog_b();
in_report_.square_axis = gamepad.get_analog_a();
in_report.triangle_axis = gp_in.analog[Gamepad::ANALOG_OFF_Y];
in_report.circle_axis = gp_in.analog[Gamepad::ANALOG_OFF_X];
in_report.cross_axis = gp_in.analog[Gamepad::ANALOG_OFF_B];
in_report.square_axis = gp_in.analog[Gamepad::ANALOG_OFF_A];
in_report_.r1_axis = gamepad.get_analog_rb();
in_report_.l1_axis = gamepad.get_analog_lb();
in_report.r1_axis = gp_in.analog[Gamepad::ANALOG_OFF_RB];
in_report.l1_axis = gp_in.analog[Gamepad::ANALOG_OFF_LB];
}
in_report_.joystick_lx = gamepad.get_joystick_lx().uint8();
in_report_.joystick_ly = gamepad.get_joystick_ly().uint8();
in_report_.joystick_rx = gamepad.get_joystick_rx().uint8();
in_report_.joystick_ry = gamepad.get_joystick_ry().uint8();
in_report.joystick_lx = Scale::int16_to_uint8(gp_in.joystick_lx);
in_report.joystick_ly = Scale::int16_to_uint8(gp_in.joystick_ly);
in_report.joystick_rx = Scale::int16_to_uint8(gp_in.joystick_rx);
in_report.joystick_ry = Scale::int16_to_uint8(gp_in.joystick_ry);
in_report_.l2_axis = gamepad.get_trigger_l().uint8();
in_report_.r2_axis = gamepad.get_trigger_r().uint8();
in_report.l2_axis = gp_in.trigger_l;
in_report.r2_axis = gp_in.trigger_r;
if (tud_suspended())
{
tud_remote_wakeup();
}
if (tud_hid_n_ready(idx) &&
// std::memcmp(&in_report_, &prev_in_reports_[idx], sizeof(DInput::InReport)) != 0 &&
tud_hid_n_report(idx, 0, reinterpret_cast<void*>(&in_report_), sizeof(DInput::InReport)))
if (tud_hid_n_ready(idx))
{
std::memcpy(&prev_in_reports_[idx], &in_report_, sizeof(DInput::InReport));
tud_hid_n_report(idx, 0, reinterpret_cast<void*>(&in_report), sizeof(DInput::InReport));
}
}
uint16_t DInputDevice::get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
{
std::memcpy(buffer, &in_report_, sizeof(DInput::InReport));
if (report_type != HID_REPORT_TYPE_INPUT || itf >= MAX_GAMEPADS)
{
return 0;
}
std::memcpy(buffer, &in_reports_[itf], sizeof(DInput::InReport));
return sizeof(DInput::InReport);
}

View File

@@ -23,8 +23,7 @@ public:
const uint8_t* get_descriptor_device_qualifier_cb() override;
private:
DInput::InReport in_report_;
std::array<DInput::InReport, MAX_GAMEPADS> prev_in_reports_;
std::array<DInput::InReport, MAX_GAMEPADS> in_reports_;
static bool control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
};

View File

@@ -28,7 +28,7 @@ public:
};
virtual void initialize() = 0;
virtual void process(const uint8_t idx, Gamepad& gamepad) = 0;
virtual void process(const uint8_t idx, Gamepad& gamepad) = 0;
virtual uint16_t get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t req_len) = 0;
virtual void set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t buffer_size) = 0;
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) = 0;

View File

@@ -40,111 +40,110 @@ void PS3Device::initialize()
void PS3Device::process(const uint8_t idx, Gamepad& gamepad)
{
uint8_t gp_dpad = gamepad.get_dpad_buttons();
uint16_t gp_buttons = gamepad.get_buttons();
uint8_t gp_trigger_l = gamepad.get_trigger_l().uint8();
uint8_t gp_trigger_r = gamepad.get_trigger_r().uint8();
std::memset(in_report_.buttons, 0, sizeof(in_report_.buttons));
switch (gp_dpad)
if (gamepad.new_pad_in())
{
case Gamepad::DPad::UP:
in_report_.buttons[0] = PS3::Buttons0::DPAD_UP;
break;
case Gamepad::DPad::DOWN:
in_report_.buttons[0] = PS3::Buttons0::DPAD_DOWN;
break;
case Gamepad::DPad::LEFT:
in_report_.buttons[0] = PS3::Buttons0::DPAD_LEFT;
break;
case Gamepad::DPad::RIGHT:
in_report_.buttons[0] = PS3::Buttons0::DPAD_RIGHT;
break;
case Gamepad::DPad::UP_LEFT:
in_report_.buttons[0] = PS3::Buttons0::DPAD_UP | PS3::Buttons0::DPAD_LEFT;
break;
case Gamepad::DPad::UP_RIGHT:
in_report_.buttons[0] = PS3::Buttons0::DPAD_UP | PS3::Buttons0::DPAD_RIGHT;
break;
case Gamepad::DPad::DOWN_LEFT:
in_report_.buttons[0] = PS3::Buttons0::DPAD_DOWN | PS3::Buttons0::DPAD_LEFT;
break;
case Gamepad::DPad::DOWN_RIGHT:
in_report_.buttons[0] = PS3::Buttons0::DPAD_DOWN | PS3::Buttons0::DPAD_RIGHT;
break;
default:
break;
Gamepad::PadIn gp_in = gamepad.get_pad_in();
std::memset(in_report_.buttons, 0, sizeof(in_report_.buttons));
switch (gp_in.dpad)
{
case Gamepad::DPAD_UP:
in_report_.buttons[0] = PS3::Buttons0::DPAD_UP;
break;
case Gamepad::DPAD_DOWN:
in_report_.buttons[0] = PS3::Buttons0::DPAD_DOWN;
break;
case Gamepad::DPAD_LEFT:
in_report_.buttons[0] = PS3::Buttons0::DPAD_LEFT;
break;
case Gamepad::DPAD_RIGHT:
in_report_.buttons[0] = PS3::Buttons0::DPAD_RIGHT;
break;
case Gamepad::DPAD_UP_LEFT:
in_report_.buttons[0] = PS3::Buttons0::DPAD_UP | PS3::Buttons0::DPAD_LEFT;
break;
case Gamepad::DPAD_UP_RIGHT:
in_report_.buttons[0] = PS3::Buttons0::DPAD_UP | PS3::Buttons0::DPAD_RIGHT;
break;
case Gamepad::DPAD_DOWN_LEFT:
in_report_.buttons[0] = PS3::Buttons0::DPAD_DOWN | PS3::Buttons0::DPAD_LEFT;
break;
case Gamepad::DPAD_DOWN_RIGHT:
in_report_.buttons[0] = PS3::Buttons0::DPAD_DOWN | PS3::Buttons0::DPAD_RIGHT;
break;
default:
break;
}
if (gp_in.buttons & Gamepad::BUTTON_X) in_report_.buttons[1] |= PS3::Buttons1::SQUARE;
if (gp_in.buttons & Gamepad::BUTTON_A) in_report_.buttons[1] |= PS3::Buttons1::CROSS;
if (gp_in.buttons & Gamepad::BUTTON_Y) in_report_.buttons[1] |= PS3::Buttons1::TRIANGLE;
if (gp_in.buttons & Gamepad::BUTTON_B) in_report_.buttons[1] |= PS3::Buttons1::CIRCLE;
if (gp_in.buttons & Gamepad::BUTTON_LB) in_report_.buttons[1] |= PS3::Buttons1::L1;
if (gp_in.buttons & Gamepad::BUTTON_RB) in_report_.buttons[1] |= PS3::Buttons1::R1;
if (gp_in.buttons & Gamepad::BUTTON_BACK) in_report_.buttons[0] |= PS3::Buttons0::SELECT;
if (gp_in.buttons & Gamepad::BUTTON_START) in_report_.buttons[0] |= PS3::Buttons0::START;
if (gp_in.buttons & Gamepad::BUTTON_L3) in_report_.buttons[0] |= PS3::Buttons0::L3;
if (gp_in.buttons & Gamepad::BUTTON_R3) in_report_.buttons[0] |= PS3::Buttons0::R3;
if (gp_in.buttons & Gamepad::BUTTON_SYS) in_report_.buttons[2] |= PS3::Buttons2::PS;
if (gp_in.buttons & Gamepad::BUTTON_MISC) in_report_.buttons[2] |= PS3::Buttons2::TP;
if (gp_in.trigger_l) in_report_.buttons[1] |= PS3::Buttons1::L2;
if (gp_in.trigger_r) in_report_.buttons[1] |= PS3::Buttons1::R2;
in_report_.joystick_lx = Scale::int16_to_uint8(gp_in.joystick_lx);
in_report_.joystick_ly = Scale::int16_to_uint8(gp_in.joystick_ly);
in_report_.joystick_rx = Scale::int16_to_uint8(gp_in.joystick_rx);
in_report_.joystick_ry = Scale::int16_to_uint8(gp_in.joystick_ry);
if (gamepad.analog_enabled())
{
in_report_.up_axis = gp_in.analog[Gamepad::ANALOG_OFF_UP];
in_report_.down_axis = gp_in.analog[Gamepad::ANALOG_OFF_DOWN];
in_report_.right_axis = gp_in.analog[Gamepad::ANALOG_OFF_RIGHT];
in_report_.left_axis = gp_in.analog[Gamepad::ANALOG_OFF_LEFT];
in_report_.triangle_axis = gp_in.analog[Gamepad::ANALOG_OFF_Y];
in_report_.circle_axis = gp_in.analog[Gamepad::ANALOG_OFF_B];
in_report_.cross_axis = gp_in.analog[Gamepad::ANALOG_OFF_A];
in_report_.square_axis = gp_in.analog[Gamepad::ANALOG_OFF_X];
in_report_.r1_axis = gp_in.analog[Gamepad::ANALOG_OFF_RB];
in_report_.l1_axis = gp_in.analog[Gamepad::ANALOG_OFF_LB];
}
else
{
in_report_.up_axis = (gp_in.dpad & Gamepad::DPAD_UP) ? 0xFF : 0;
in_report_.down_axis = (gp_in.dpad & Gamepad::DPAD_DOWN) ? 0xFF : 0;
in_report_.right_axis = (gp_in.dpad & Gamepad::DPAD_RIGHT) ? 0xFF : 0;
in_report_.left_axis = (gp_in.dpad & Gamepad::DPAD_LEFT) ? 0xFF : 0;
in_report_.triangle_axis = (gp_in.buttons & Gamepad::BUTTON_Y) ? 0xFF : 0;
in_report_.circle_axis = (gp_in.buttons & Gamepad::BUTTON_X) ? 0xFF : 0;
in_report_.cross_axis = (gp_in.buttons & Gamepad::BUTTON_B) ? 0xFF : 0;
in_report_.square_axis = (gp_in.buttons & Gamepad::BUTTON_A) ? 0xFF : 0;
in_report_.r1_axis = (gp_in.buttons & Gamepad::BUTTON_RB) ? 0xFF : 0;
in_report_.l1_axis = (gp_in.buttons & Gamepad::BUTTON_LB) ? 0xFF : 0;
}
if (tud_suspended())
{
tud_remote_wakeup();
}
if (tud_hid_ready())
{
tud_hid_report(0, reinterpret_cast<uint8_t*>(&in_report_), sizeof(PS3::InReport));
}
}
if (gp_buttons & Gamepad::Button::X) in_report_.buttons[1] |= PS3::Buttons1::SQUARE;
if (gp_buttons & Gamepad::Button::A) in_report_.buttons[1] |= PS3::Buttons1::CROSS;
if (gp_buttons & Gamepad::Button::Y) in_report_.buttons[1] |= PS3::Buttons1::TRIANGLE;
if (gp_buttons & Gamepad::Button::B) in_report_.buttons[1] |= PS3::Buttons1::CIRCLE;
if (gp_buttons & Gamepad::Button::LB) in_report_.buttons[1] |= PS3::Buttons1::L1;
if (gp_buttons & Gamepad::Button::RB) in_report_.buttons[1] |= PS3::Buttons1::R1;
if (gp_buttons & Gamepad::Button::BACK) in_report_.buttons[0] |= PS3::Buttons0::SELECT;
if (gp_buttons & Gamepad::Button::START) in_report_.buttons[0] |= PS3::Buttons0::START;
if (gp_buttons & Gamepad::Button::L3) in_report_.buttons[0] |= PS3::Buttons0::L3;
if (gp_buttons & Gamepad::Button::R3) in_report_.buttons[0] |= PS3::Buttons0::R3;
if (gp_buttons & Gamepad::Button::SYS) in_report_.buttons[2] |= PS3::Buttons2::PS;
if (gp_buttons & Gamepad::Button::MISC) in_report_.buttons[2] |= PS3::Buttons2::TP;
if (gp_trigger_l > 0) in_report_.buttons[1] |= PS3::Buttons1::L2;
if (gp_trigger_r > 0) in_report_.buttons[1] |= PS3::Buttons1::R2;
in_report_.joystick_lx = gamepad.get_joystick_lx().uint8();
in_report_.joystick_ly = gamepad.get_joystick_ly().uint8();
in_report_.joystick_rx = gamepad.get_joystick_rx().uint8();
in_report_.joystick_ry = gamepad.get_joystick_ry().uint8();
if (gamepad.analog_enabled())
{
in_report_.up_axis = gamepad.get_analog_up();
in_report_.down_axis = gamepad.get_analog_down();
in_report_.right_axis = gamepad.get_analog_right();
in_report_.left_axis = gamepad.get_analog_left();
in_report_.triangle_axis = gamepad.get_analog_y();
in_report_.circle_axis = gamepad.get_analog_x();
in_report_.cross_axis = gamepad.get_analog_b();
in_report_.square_axis = gamepad.get_analog_a();
in_report_.r1_axis = gamepad.get_analog_rb();
in_report_.l1_axis = gamepad.get_analog_lb();
}
else
{
in_report_.up_axis = (gp_dpad & Gamepad::DPad::UP) ? 0xFF : 0;
in_report_.down_axis = (gp_dpad & Gamepad::DPad::DOWN) ? 0xFF : 0;
in_report_.right_axis = (gp_dpad & Gamepad::DPad::RIGHT) ? 0xFF : 0;
in_report_.left_axis = (gp_dpad & Gamepad::DPad::LEFT) ? 0xFF : 0;
in_report_.triangle_axis = (gp_buttons & Gamepad::Button::Y) ? 0xFF : 0;
in_report_.circle_axis = (gp_buttons & Gamepad::Button::X) ? 0xFF : 0;
in_report_.cross_axis = (gp_buttons & Gamepad::Button::B) ? 0xFF : 0;
in_report_.square_axis = (gp_buttons & Gamepad::Button::A) ? 0xFF : 0;
in_report_.r1_axis = (gp_buttons & Gamepad::Button::RB) ? 0xFF : 0;
in_report_.l1_axis = (gp_buttons & Gamepad::Button::LB) ? 0xFF : 0;
}
if (tud_suspended())
{
tud_remote_wakeup();
}
if (std::memcmp(&prev_in_report_, &in_report_, sizeof(PS3::InReport)) != 0 &&
tud_hid_ready() &&
tud_hid_report(0, reinterpret_cast<uint8_t*>(&in_report_), sizeof(PS3::InReport)))
{
std::memcpy(&prev_in_report_, &in_report_, sizeof(PS3::InReport));
}
if (new_out_report_)
{
gamepad.set_rumble_l(out_report_.rumble.left_motor_force);
gamepad.set_rumble_r(out_report_.rumble.right_motor_on);
Gamepad::PadOut gp_out;
gp_out.rumble_l = out_report_.rumble.left_motor_force;
gp_out.rumble_r = out_report_.rumble.right_motor_on ? 0xFF : 0;
gamepad.set_pad_out(gp_out);
new_out_report_ = false;
}
}

View File

@@ -23,7 +23,6 @@ public:
private:
PS3::InReport in_report_;
PS3::InReport prev_in_report_;
PS3::OutReport out_report_;
PS3::BTInfo bt_info_;
uint8_t ef_byte_;

View File

@@ -20,30 +20,36 @@ void PSClassicDevice::initialize()
void PSClassicDevice::process(const uint8_t idx, Gamepad& gamepad)
{
switch (gamepad.get_dpad_buttons())
if (!gamepad.new_pad_in())
{
case Gamepad::DPad::UP:
return;
}
Gamepad::PadIn gp_in = gamepad.get_pad_in();
switch (gp_in.dpad)
{
case Gamepad::DPAD_UP:
in_report_.buttons = PSClassic::Buttons::UP;
break;
case Gamepad::DPad::DOWN:
case Gamepad::DPAD_DOWN:
in_report_.buttons = PSClassic::Buttons::DOWN;
break;
case Gamepad::DPad::LEFT:
case Gamepad::DPAD_LEFT:
in_report_.buttons = PSClassic::Buttons::LEFT;
break;
case Gamepad::DPad::RIGHT:
case Gamepad::DPAD_RIGHT:
in_report_.buttons = PSClassic::Buttons::RIGHT;
break;
case Gamepad::DPad::UP_LEFT:
case Gamepad::DPAD_UP_LEFT:
in_report_.buttons = PSClassic::Buttons::UP_LEFT;
break;
case Gamepad::DPad::UP_RIGHT:
case Gamepad::DPAD_UP_RIGHT:
in_report_.buttons = PSClassic::Buttons::UP_RIGHT;
break;
case Gamepad::DPad::DOWN_LEFT:
case Gamepad::DPAD_DOWN_LEFT:
in_report_.buttons = PSClassic::Buttons::DOWN_LEFT;
break;
case Gamepad::DPad::DOWN_RIGHT:
case Gamepad::DPAD_DOWN_RIGHT:
in_report_.buttons = PSClassic::Buttons::DOWN_RIGHT;
break;
default:
@@ -51,10 +57,10 @@ void PSClassicDevice::process(const uint8_t idx, Gamepad& gamepad)
break;
}
int16_t joy_lx = gamepad.get_joystick_lx().int16();
int16_t joy_ly = gamepad.get_joystick_ly().int16(true);
int16_t joy_rx = gamepad.get_joystick_rx().int16();
int16_t joy_ry = gamepad.get_joystick_ry().int16(true);
int16_t joy_lx = gp_in.joystick_lx;
int16_t joy_ly = Scale::invert_joy(gp_in.joystick_ly);
int16_t joy_rx = gp_in.joystick_rx;
int16_t joy_ry = Scale::invert_joy(gp_in.joystick_ry);
if (meets_pos_threshold(joy_lx, joy_rx))
{
@@ -95,30 +101,25 @@ void PSClassicDevice::process(const uint8_t idx, Gamepad& gamepad)
in_report_.buttons = PSClassic::Buttons::UP;
}
uint16_t gamepad_buttons = gamepad.get_buttons();
if (gamepad_buttons & Gamepad::Button::A) in_report_.buttons |= PSClassic::Buttons::CROSS;
if (gamepad_buttons & Gamepad::Button::B) in_report_.buttons |= PSClassic::Buttons::CIRCLE;
if (gamepad_buttons & Gamepad::Button::X) in_report_.buttons |= PSClassic::Buttons::SQUARE;
if (gamepad_buttons & Gamepad::Button::Y) in_report_.buttons |= PSClassic::Buttons::TRIANGLE;
if (gamepad_buttons & Gamepad::Button::LB) in_report_.buttons |= PSClassic::Buttons::L1;
if (gamepad_buttons & Gamepad::Button::RB) in_report_.buttons |= PSClassic::Buttons::R1;
if (gamepad_buttons & Gamepad::Button::BACK) in_report_.buttons |= PSClassic::Buttons::SELECT;
if (gamepad_buttons & Gamepad::Button::START) in_report_.buttons |= PSClassic::Buttons::START;
if (gp_in.buttons & Gamepad::BUTTON_A) in_report_.buttons |= PSClassic::Buttons::CROSS;
if (gp_in.buttons & Gamepad::BUTTON_B) in_report_.buttons |= PSClassic::Buttons::CIRCLE;
if (gp_in.buttons & Gamepad::BUTTON_X) in_report_.buttons |= PSClassic::Buttons::SQUARE;
if (gp_in.buttons & Gamepad::BUTTON_Y) in_report_.buttons |= PSClassic::Buttons::TRIANGLE;
if (gp_in.buttons & Gamepad::BUTTON_LB) in_report_.buttons |= PSClassic::Buttons::L1;
if (gp_in.buttons & Gamepad::BUTTON_RB) in_report_.buttons |= PSClassic::Buttons::R1;
if (gp_in.buttons & Gamepad::BUTTON_BACK) in_report_.buttons |= PSClassic::Buttons::SELECT;
if (gp_in.buttons & Gamepad::BUTTON_START) in_report_.buttons |= PSClassic::Buttons::START;
if (gamepad.get_trigger_l().uint8()) in_report_.buttons |= PSClassic::Buttons::L2;
if (gamepad.get_trigger_r().uint8()) in_report_.buttons |= PSClassic::Buttons::R2;
if (gp_in.trigger_l) in_report_.buttons |= PSClassic::Buttons::L2;
if (gp_in.trigger_r) in_report_.buttons |= PSClassic::Buttons::R2;
if (tud_suspended())
{
tud_remote_wakeup();
}
if (tud_hid_n_ready(idx) &&
std::memcmp(&in_report_, &prev_in_report_, sizeof(PSClassic::InReport)) != 0 &&
tud_hid_n_report(idx, 0, reinterpret_cast<uint8_t*>(&in_report_), sizeof(PSClassic::InReport)))
if (tud_hid_n_ready(idx))
{
std::memcpy(&prev_in_report_, &in_report_, sizeof(PSClassic::InReport));
tud_hid_n_report(idx, 0, reinterpret_cast<uint8_t*>(&in_report_), sizeof(PSClassic::InReport));
}
}

View File

@@ -29,7 +29,6 @@ private:
static constexpr int16_t JOY_POS_45_THRESHOLD = JOY_POS_THRESHOLD * 2;
static constexpr int16_t JOY_NEG_45_THRESHOLD = JOY_NEG_THRESHOLD * 2;
PSClassic::InReport prev_in_report_{0};
PSClassic::InReport in_report_{0};
inline bool meets_pos_threshold(int16_t joy_l, int16_t joy_r) { return (joy_l >= JOY_POS_THRESHOLD) || (joy_r >= JOY_POS_THRESHOLD); }

View File

@@ -17,89 +17,91 @@ void SwitchDevice::initialize()
.sof = NULL
};
in_report_ = SwitchWired::InReport();
for (auto& prev_in_report : prev_in_reports_)
{
prev_in_report = SwitchWired::InReport();
}
in_report_.fill(SwitchWired::InReport());
}
void SwitchDevice::process(const uint8_t idx, Gamepad& gamepad)
{
switch (gamepad.get_dpad_buttons())
if (!gamepad.new_pad_in())
{
case Gamepad::DPad::UP:
in_report_.dpad = SwitchWired::DPad::UP;
return;
}
Gamepad::PadIn gp_in = gamepad.get_pad_in();
SwitchWired::InReport& in_report = in_report_[idx];
switch (gp_in.dpad)
{
case Gamepad::DPAD_UP:
in_report.dpad = SwitchWired::DPad::UP;
break;
case Gamepad::DPad::DOWN:
in_report_.dpad = SwitchWired::DPad::DOWN;
case Gamepad::DPAD_DOWN:
in_report.dpad = SwitchWired::DPad::DOWN;
break;
case Gamepad::DPad::LEFT:
in_report_.dpad = SwitchWired::DPad::LEFT;
case Gamepad::DPAD_LEFT:
in_report.dpad = SwitchWired::DPad::LEFT;
break;
case Gamepad::DPad::RIGHT:
in_report_.dpad = SwitchWired::DPad::RIGHT;
case Gamepad::DPAD_RIGHT:
in_report.dpad = SwitchWired::DPad::RIGHT;
break;
case Gamepad::DPad::UP_LEFT:
in_report_.dpad = SwitchWired::DPad::UP_LEFT;
case Gamepad::DPAD_UP_LEFT:
in_report.dpad = SwitchWired::DPad::UP_LEFT;
break;
case Gamepad::DPad::UP_RIGHT:
in_report_.dpad = SwitchWired::DPad::UP_RIGHT;
case Gamepad::DPAD_UP_RIGHT:
in_report.dpad = SwitchWired::DPad::UP_RIGHT;
break;
case Gamepad::DPad::DOWN_LEFT:
in_report_.dpad = SwitchWired::DPad::DOWN_LEFT;
case Gamepad::DPAD_DOWN_LEFT:
in_report.dpad = SwitchWired::DPad::DOWN_LEFT;
break;
case Gamepad::DPad::DOWN_RIGHT:
in_report_.dpad = SwitchWired::DPad::DOWN_RIGHT;
case Gamepad::DPAD_DOWN_RIGHT:
in_report.dpad = SwitchWired::DPad::DOWN_RIGHT;
break;
default:
in_report_.dpad = SwitchWired::DPad::CENTER;
in_report.dpad = SwitchWired::DPad::CENTER;
break;
}
in_report_.buttons = 0;
uint16_t gp_buttons = gamepad.get_buttons();
in_report.buttons = 0;
if (gp_buttons & Gamepad::Button::X) in_report_.buttons |= SwitchWired::Buttons::Y;
if (gp_buttons & Gamepad::Button::A) in_report_.buttons |= SwitchWired::Buttons::B;
if (gp_buttons & Gamepad::Button::Y) in_report_.buttons |= SwitchWired::Buttons::X;
if (gp_buttons & Gamepad::Button::B) in_report_.buttons |= SwitchWired::Buttons::A;
if (gp_buttons & Gamepad::Button::LB) in_report_.buttons |= SwitchWired::Buttons::L;
if (gp_buttons & Gamepad::Button::RB) in_report_.buttons |= SwitchWired::Buttons::R;
if (gp_buttons & Gamepad::Button::BACK) in_report_.buttons |= SwitchWired::Buttons::MINUS;
if (gp_buttons & Gamepad::Button::START) in_report_.buttons |= SwitchWired::Buttons::PLUS;
if (gp_buttons & Gamepad::Button::L3) in_report_.buttons |= SwitchWired::Buttons::L3;
if (gp_buttons & Gamepad::Button::R3) in_report_.buttons |= SwitchWired::Buttons::R3;
if (gp_buttons & Gamepad::Button::SYS) in_report_.buttons |= SwitchWired::Buttons::HOME;
if (gp_buttons & Gamepad::Button::MISC) in_report_.buttons |= SwitchWired::Buttons::CAPTURE;
if (gp_in.buttons & Gamepad::BUTTON_X) in_report.buttons |= SwitchWired::Buttons::Y;
if (gp_in.buttons & Gamepad::BUTTON_A) in_report.buttons |= SwitchWired::Buttons::B;
if (gp_in.buttons & Gamepad::BUTTON_Y) in_report.buttons |= SwitchWired::Buttons::X;
if (gp_in.buttons & Gamepad::BUTTON_B) in_report.buttons |= SwitchWired::Buttons::A;
if (gp_in.buttons & Gamepad::BUTTON_LB) in_report.buttons |= SwitchWired::Buttons::L;
if (gp_in.buttons & Gamepad::BUTTON_RB) in_report.buttons |= SwitchWired::Buttons::R;
if (gp_in.buttons & Gamepad::BUTTON_BACK) in_report.buttons |= SwitchWired::Buttons::MINUS;
if (gp_in.buttons & Gamepad::BUTTON_START) in_report.buttons |= SwitchWired::Buttons::PLUS;
if (gp_in.buttons & Gamepad::BUTTON_L3) in_report.buttons |= SwitchWired::Buttons::L3;
if (gp_in.buttons & Gamepad::BUTTON_R3) in_report.buttons |= SwitchWired::Buttons::R3;
if (gp_in.buttons & Gamepad::BUTTON_SYS) in_report.buttons |= SwitchWired::Buttons::HOME;
if (gp_in.buttons & Gamepad::BUTTON_MISC) in_report.buttons |= SwitchWired::Buttons::CAPTURE;
if (gamepad.get_trigger_l().uint8()) in_report_.buttons |= SwitchWired::Buttons::ZL;
if (gamepad.get_trigger_r().uint8()) in_report_.buttons |= SwitchWired::Buttons::ZR;
if (gp_in.trigger_l) in_report.buttons |= SwitchWired::Buttons::ZL;
if (gp_in.trigger_r) in_report.buttons |= SwitchWired::Buttons::ZR;
in_report_.joystick_lx = gamepad.get_joystick_lx().uint8();
in_report_.joystick_ly = gamepad.get_joystick_ly().uint8();
in_report_.joystick_rx = gamepad.get_joystick_rx().uint8();
in_report_.joystick_ry = gamepad.get_joystick_ry().uint8();
in_report.joystick_lx = Scale::int16_to_uint8(gp_in.joystick_lx);
in_report.joystick_ly = Scale::int16_to_uint8(gp_in.joystick_ly);
in_report.joystick_rx = Scale::int16_to_uint8(gp_in.joystick_rx);
in_report.joystick_ry = Scale::int16_to_uint8(gp_in.joystick_ry);
if (tud_suspended())
{
tud_remote_wakeup();
}
if (std::memcmp(&prev_in_reports_[idx], &in_report_, sizeof(SwitchWired::InReport)) != 0 &&
tud_hid_n_ready(idx) &&
tud_hid_n_report(idx, 0, reinterpret_cast<uint8_t*>(&in_report_), sizeof(SwitchWired::InReport)))
{
std::memcpy(&prev_in_reports_[idx], &in_report_, sizeof(SwitchWired::InReport));
}
if (tud_hid_n_ready(idx))
{
tud_hid_n_report(idx, 0, reinterpret_cast<uint8_t*>(&in_report), sizeof(SwitchWired::InReport));
}
}
uint16_t SwitchDevice::get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
{
// std::memcpy(buffer, &in_report_, sizeof(SwitchWired::InReport));
// return sizeof(SwitchWired::InReport);
return 0;
if (report_type != HID_REPORT_TYPE_INPUT || itf >= MAX_GAMEPADS)
{
return 0;
}
std::memcpy(buffer, &in_report_[itf], sizeof(SwitchWired::InReport));
return sizeof(SwitchWired::InReport);
}
void SwitchDevice::set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {}

View File

@@ -22,8 +22,7 @@ public:
const uint8_t* get_descriptor_device_qualifier_cb() override;
private:
SwitchWired::InReport in_report_;
std::array<SwitchWired::InReport, MAX_GAMEPADS> prev_in_reports_;
std::array<SwitchWired::InReport, MAX_GAMEPADS> in_report_;
};
#endif // _SWITCH_DEVICE_H_

View File

@@ -1,5 +1,4 @@
#include <cstring>
#include <vector>
#include "USBDevice/DeviceDriver/XInput/tud_xinput/tud_xinput.h"
#include "USBDevice/DeviceDriver/XInput/XInput.h"
@@ -7,79 +6,84 @@
void XInputDevice::initialize()
{
class_driver_ = *tud_xinput::class_driver();
std::memset(&in_report_, 0, sizeof(XInput::InReport));
std::memset(&prev_in_report_, 0, sizeof(XInput::InReport));
in_report_.report_size = XInput::ENDPOINT_IN_SIZE;
}
void XInputDevice::process(const uint8_t idx, Gamepad& gamepad)
void XInputDevice::process(const uint8_t idx, Gamepad& gamepad)
{
std::memset(&in_report_.buttons, 0, sizeof(in_report_.buttons));
switch (gamepad.get_dpad_buttons())
if (gamepad.new_pad_in())
{
case Gamepad::DPad::UP:
in_report_.buttons[0] = XInput::Buttons0::DPAD_UP;
break;
case Gamepad::DPad::DOWN:
in_report_.buttons[0] = XInput::Buttons0::DPAD_DOWN;
break;
case Gamepad::DPad::LEFT:
in_report_.buttons[0] = XInput::Buttons0::DPAD_LEFT;
break;
case Gamepad::DPad::RIGHT:
in_report_.buttons[0] = XInput::Buttons0::DPAD_RIGHT;
break;
case Gamepad::DPad::UP_LEFT:
in_report_.buttons[0] = (XInput::Buttons0::DPAD_UP | XInput::Buttons0::DPAD_LEFT);
break;
case Gamepad::DPad::UP_RIGHT:
in_report_.buttons[0] = XInput::Buttons0::DPAD_UP | XInput::Buttons0::DPAD_RIGHT;
break;
case Gamepad::DPad::DOWN_LEFT:
in_report_.buttons[0] = XInput::Buttons0::DPAD_DOWN | XInput::Buttons0::DPAD_LEFT;
break;
case Gamepad::DPad::DOWN_RIGHT:
in_report_.buttons[0] = XInput::Buttons0::DPAD_DOWN | XInput::Buttons0::DPAD_RIGHT;
break;
default:
break;
}
uint16_t gp_buttons = gamepad.get_buttons();
std::memset(&in_report_.buttons, 0, sizeof(in_report_.buttons));
Gamepad::PadIn gp_in = gamepad.get_pad_in();
if (gp_buttons & Gamepad::Button::BACK) in_report_.buttons[0] |= XInput::Buttons0::BACK;
if (gp_buttons & Gamepad::Button::START) in_report_.buttons[0] |= XInput::Buttons0::START;
if (gp_buttons & Gamepad::Button::L3) in_report_.buttons[0] |= XInput::Buttons0::L3;
if (gp_buttons & Gamepad::Button::R3) in_report_.buttons[0] |= XInput::Buttons0::R3;
switch (gp_in.dpad)
{
case Gamepad::DPAD_UP:
in_report_.buttons[0] = XInput::Buttons0::DPAD_UP;
break;
case Gamepad::DPAD_DOWN:
in_report_.buttons[0] = XInput::Buttons0::DPAD_DOWN;
break;
case Gamepad::DPAD_LEFT:
in_report_.buttons[0] = XInput::Buttons0::DPAD_LEFT;
break;
case Gamepad::DPAD_RIGHT:
in_report_.buttons[0] = XInput::Buttons0::DPAD_RIGHT;
break;
case Gamepad::DPAD_UP_LEFT:
in_report_.buttons[0] = XInput::Buttons0::DPAD_UP | XInput::Buttons0::DPAD_LEFT;
break;
case Gamepad::DPAD_UP_RIGHT:
in_report_.buttons[0] = XInput::Buttons0::DPAD_UP | XInput::Buttons0::DPAD_RIGHT;
break;
case Gamepad::DPAD_DOWN_LEFT:
in_report_.buttons[0] = XInput::Buttons0::DPAD_DOWN | XInput::Buttons0::DPAD_LEFT;
break;
case Gamepad::DPAD_DOWN_RIGHT:
in_report_.buttons[0] = XInput::Buttons0::DPAD_DOWN | XInput::Buttons0::DPAD_RIGHT;
break;
default:
break;
}
if (gp_buttons & Gamepad::Button::X) in_report_.buttons[1] |= XInput::Buttons1::X;
if (gp_buttons & Gamepad::Button::A) in_report_.buttons[1] |= XInput::Buttons1::A;
if (gp_buttons & Gamepad::Button::Y) in_report_.buttons[1] |= XInput::Buttons1::Y;
if (gp_buttons & Gamepad::Button::B) in_report_.buttons[1] |= XInput::Buttons1::B;
if (gp_buttons & Gamepad::Button::LB) in_report_.buttons[1] |= XInput::Buttons1::LB;
if (gp_buttons & Gamepad::Button::RB) in_report_.buttons[1] |= XInput::Buttons1::RB;
if (gp_buttons & Gamepad::Button::SYS) in_report_.buttons[1] |= XInput::Buttons1::HOME;
if (gp_in.buttons & Gamepad::BUTTON_BACK) in_report_.buttons[0] |= XInput::Buttons0::BACK;
if (gp_in.buttons & Gamepad::BUTTON_START) in_report_.buttons[0] |= XInput::Buttons0::START;
if (gp_in.buttons & Gamepad::BUTTON_L3) in_report_.buttons[0] |= XInput::Buttons0::L3;
if (gp_in.buttons & Gamepad::BUTTON_R3) in_report_.buttons[0] |= XInput::Buttons0::R3;
in_report_.trigger_l = gamepad.get_trigger_l().uint8();
in_report_.trigger_r = gamepad.get_trigger_r().uint8();
if (gp_in.buttons & Gamepad::BUTTON_X) in_report_.buttons[1] |= XInput::Buttons1::X;
if (gp_in.buttons & Gamepad::BUTTON_A) in_report_.buttons[1] |= XInput::Buttons1::A;
if (gp_in.buttons & Gamepad::BUTTON_Y) in_report_.buttons[1] |= XInput::Buttons1::Y;
if (gp_in.buttons & Gamepad::BUTTON_B) in_report_.buttons[1] |= XInput::Buttons1::B;
if (gp_in.buttons & Gamepad::BUTTON_LB) in_report_.buttons[1] |= XInput::Buttons1::LB;
if (gp_in.buttons & Gamepad::BUTTON_RB) in_report_.buttons[1] |= XInput::Buttons1::RB;
if (gp_in.buttons & Gamepad::BUTTON_SYS) in_report_.buttons[1] |= XInput::Buttons1::HOME;
in_report_.joystick_lx = gamepad.get_joystick_lx().int16();
in_report_.joystick_ly = gamepad.get_joystick_ly().int16(true);
in_report_.joystick_rx = gamepad.get_joystick_rx().int16();
in_report_.joystick_ry = gamepad.get_joystick_ry().int16(true);
in_report_.trigger_l = gp_in.trigger_l;
in_report_.trigger_r = gp_in.trigger_r;
if (std::memcmp(&prev_in_report_, &in_report_, sizeof(in_report_)) != 0 &&
tud_xinput::send_report(reinterpret_cast<uint8_t*>(&in_report_), sizeof(XInput::InReport)))
{
std::memcpy(&prev_in_report_, &in_report_, sizeof(XInput::InReport));
in_report_.joystick_lx = gp_in.joystick_lx;
in_report_.joystick_ly = Scale::invert_joy(gp_in.joystick_ly);
in_report_.joystick_rx = gp_in.joystick_rx;
in_report_.joystick_ry = Scale::invert_joy(gp_in.joystick_ry);
if (tud_suspended())
{
tud_remote_wakeup();
}
if (tud_xinput::send_report_ready())
{
tud_xinput::send_report(reinterpret_cast<uint8_t*>(&in_report_), sizeof(XInput::InReport));
}
}
if (tud_xinput::receive_report(reinterpret_cast<uint8_t*>(&out_report_), sizeof(XInput::OutReport)) &&
out_report_.report_id == XInput::OutReportID::RUMBLE)
{
gamepad.set_rumble_l(out_report_.rumble_l);
gamepad.set_rumble_r(out_report_.rumble_r);
Gamepad::PadOut gp_out;
gp_out.rumble_l = out_report_.rumble_l;
gp_out.rumble_r = out_report_.rumble_r;
gamepad.set_pad_out(gp_out);
}
}

View File

@@ -1,6 +1,8 @@
#ifndef _XINPUT_DEVICE_H_
#define _XINPUT_DEVICE_H_
#include <pico/time.h>
#include "USBDevice/DeviceDriver/DeviceDriver.h"
#include "Descriptors/XInput.h"
@@ -8,7 +10,7 @@ class XInputDevice : public DeviceDriver
{
public:
void initialize() override;
void process(const uint8_t idx, Gamepad& gamepad) override;
void process(const uint8_t idx, Gamepad& gamepad) override;
uint16_t get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) override;
void set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) override;
bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) override;
@@ -20,8 +22,9 @@ public:
private:
XInput::InReport in_report_;
XInput::InReport prev_in_report_;
XInput::OutReport out_report_;
XInput::InReport prev_in_report_;
XInput::OutReport prev_out_report_;
};
#endif // _XINPUT_DEVICE_H_

View File

@@ -3,7 +3,6 @@
#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_XINPUT)
#include <cstring>
#include <array>
#include <algorithm>
#include "tusb.h"
@@ -18,19 +17,20 @@ static constexpr uint8_t ENDPOINT_SIZE = 32;
uint8_t endpoint_in_ = 0xFF;
uint8_t endpoint_out_ = 0xFF;
std::array<uint8_t, ENDPOINT_SIZE> out_buffer_;
uint8_t out_buffer_[ENDPOINT_SIZE];
uint8_t in_buffer_[ENDPOINT_SIZE];
//Class Driver
static void init(void)
{
out_buffer_.fill(0);
endpoint_in_ = 0xFF;
endpoint_out_ = 0xFF;
std::memset(out_buffer_, 0, ENDPOINT_SIZE);
}
static void reset(uint8_t rhport)
{
endpoint_in_ = 0xFF;
endpoint_out_ = 0xFF;
init();
}
@@ -73,62 +73,54 @@ static bool xfer_callback(uint8_t rhport, uint8_t ep_addr, xfer_result_t result,
{
if (ep_addr == endpoint_out_)
{
usbd_edpt_xfer(0, endpoint_out_, out_buffer_.data(), ENDPOINT_SIZE);
usbd_edpt_xfer(BOARD_TUD_RHPORT, endpoint_out_, out_buffer_, ENDPOINT_SIZE);
}
return true;
}
const usbd_class_driver_t tud_class_driver_ =
{
#if CFG_TUSB_DEBUG >= 2
.name = "XINPUT",
#endif
.init = init,
.reset = reset,
.open = open,
.control_xfer_cb = control_xfer_cb,
.xfer_cb = xfer_callback,
.sof = NULL
};
// Public API
const usbd_class_driver_t* class_driver()
{
static const usbd_class_driver_t tud_class_driver_ =
{
#if CFG_TUSB_DEBUG >= 2
.name = "XINPUT",
#endif
.init = init,
.reset = reset,
.open = open,
.control_xfer_cb = control_xfer_cb,
.xfer_cb = xfer_callback,
.sof = NULL
};
return &tud_class_driver_;
}
bool send_report_ready()
{
return (tud_ready() && endpoint_in_ != 0xFF && !usbd_edpt_busy(BOARD_TUD_RHPORT, endpoint_in_));
TU_VERIFY(tud_ready() && endpoint_in_ != 0xFF && !usbd_edpt_busy(BOARD_TUD_RHPORT, endpoint_in_));
return true;
}
bool send_report(const uint8_t *report, uint16_t len)
{
if (tud_suspended())
{
tud_remote_wakeup();
}
if (send_report_ready())
{
usbd_edpt_claim(BOARD_TUD_RHPORT, endpoint_in_);
usbd_edpt_xfer(BOARD_TUD_RHPORT, endpoint_in_, const_cast<uint8_t*>(report), len);
usbd_edpt_release(BOARD_TUD_RHPORT, endpoint_in_);
return true;
}
return false;
usbd_edpt_claim(BOARD_TUD_RHPORT, endpoint_in_);
usbd_edpt_xfer(BOARD_TUD_RHPORT, endpoint_in_, const_cast<uint8_t*>(report), ENDPOINT_SIZE);
usbd_edpt_release(BOARD_TUD_RHPORT, endpoint_in_);
return true;
}
bool receive_report(uint8_t *report, uint16_t len)
{
if (len > ENDPOINT_SIZE || endpoint_out_ == 0xFF)
TU_VERIFY(endpoint_out_ != 0xFF && len <= ENDPOINT_SIZE);
if (tud_ready() && !usbd_edpt_busy(BOARD_TUD_RHPORT, endpoint_out_))
{
return false;
usbd_edpt_xfer(BOARD_TUD_RHPORT, endpoint_out_, out_buffer_, len);
}
std::memcpy(report, out_buffer_.data(), len);
usbd_edpt_xfer(BOARD_TUD_RHPORT, endpoint_out_, out_buffer_.data(), ENDPOINT_SIZE);
std::memcpy(report, out_buffer_, len);
return true;
}

View File

@@ -11,88 +11,93 @@ void XboxOGDevice::initialize()
std::memset(&in_report_, 0, sizeof(XboxOG::GP::InReport));
in_report_.report_len = sizeof(XboxOG::GP::InReport);
std::memcpy(&prev_in_report_, &in_report_, sizeof(XboxOG::GP::InReport));
}
void XboxOGDevice::process(const uint8_t idx, Gamepad& gamepad)
void XboxOGDevice::process(const uint8_t idx, Gamepad& gamepad)
{
std::memset(&in_report_.buttons, 0, 8);
switch (gamepad.get_dpad_buttons())
if (gamepad.new_pad_in())
{
case Gamepad::DPad::UP:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_UP;
break;
case Gamepad::DPad::DOWN:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_DOWN;
break;
case Gamepad::DPad::LEFT:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_LEFT;
break;
case Gamepad::DPad::RIGHT:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_RIGHT;
break;
case Gamepad::DPad::UP_LEFT:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_UP | XboxOG::GP::Buttons::DPAD_LEFT;
break;
case Gamepad::DPad::UP_RIGHT:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_UP | XboxOG::GP::Buttons::DPAD_RIGHT;
break;
case Gamepad::DPad::DOWN_LEFT:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_DOWN | XboxOG::GP::Buttons::DPAD_LEFT;
break;
case Gamepad::DPad::DOWN_RIGHT:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_DOWN | XboxOG::GP::Buttons::DPAD_RIGHT;
break;
default:
break;
}
uint16_t gp_buttons = gamepad.get_buttons();
std::memset(&in_report_.buttons, 0, 8);
Gamepad::PadIn gp_in = gamepad.get_pad_in();
if (gp_buttons & Gamepad::Button::BACK) in_report_.buttons |= XboxOG::GP::Buttons::BACK;
if (gp_buttons & Gamepad::Button::START) in_report_.buttons |= XboxOG::GP::Buttons::START;
if (gp_buttons & Gamepad::Button::L3) in_report_.buttons |= XboxOG::GP::Buttons::L3;
if (gp_buttons & Gamepad::Button::R3) in_report_.buttons |= XboxOG::GP::Buttons::R3;
switch (gp_in.dpad)
{
case Gamepad::DPAD_UP:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_UP;
break;
case Gamepad::DPAD_DOWN:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_DOWN;
break;
case Gamepad::DPAD_LEFT:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_LEFT;
break;
case Gamepad::DPAD_RIGHT:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_RIGHT;
break;
case Gamepad::DPAD_UP_LEFT:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_UP | XboxOG::GP::Buttons::DPAD_LEFT;
break;
case Gamepad::DPAD_UP_RIGHT:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_UP | XboxOG::GP::Buttons::DPAD_RIGHT;
break;
case Gamepad::DPAD_DOWN_LEFT:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_DOWN | XboxOG::GP::Buttons::DPAD_LEFT;
break;
case Gamepad::DPAD_DOWN_RIGHT:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_DOWN | XboxOG::GP::Buttons::DPAD_RIGHT;
break;
default:
break;
}
if (gp_in.buttons & Gamepad::BUTTON_BACK) in_report_.buttons |= XboxOG::GP::Buttons::BACK;
if (gp_in.buttons & Gamepad::BUTTON_START) in_report_.buttons |= XboxOG::GP::Buttons::START;
if (gp_in.buttons & Gamepad::BUTTON_L3) in_report_.buttons |= XboxOG::GP::Buttons::L3;
if (gp_in.buttons & Gamepad::BUTTON_R3) in_report_.buttons |= XboxOG::GP::Buttons::R3;
if (gamepad.analog_enabled())
{
in_report_.a = gamepad.get_analog_a();
in_report_.b = gamepad.get_analog_b();
in_report_.x = gamepad.get_analog_x();
in_report_.y = gamepad.get_analog_y();
in_report_.white = gamepad.get_analog_lb();
in_report_.black = gamepad.get_analog_rb();
}
else
{
if (gp_buttons & Gamepad::Button::X) in_report_.x = 0xFF;
if (gp_buttons & Gamepad::Button::A) in_report_.a = 0xFF;
if (gp_buttons & Gamepad::Button::Y) in_report_.y = 0xFF;
if (gp_buttons & Gamepad::Button::B) in_report_.b = 0xFF;
if (gp_buttons & Gamepad::Button::LB) in_report_.white = 0xFF;
if (gp_buttons & Gamepad::Button::RB) in_report_.black = 0xFF;
}
if (gamepad.analog_enabled())
{
in_report_.a = gp_in.analog[Gamepad::ANALOG_OFF_A];
in_report_.b = gp_in.analog[Gamepad::ANALOG_OFF_B];
in_report_.x = gp_in.analog[Gamepad::ANALOG_OFF_X];
in_report_.y = gp_in.analog[Gamepad::ANALOG_OFF_Y];
in_report_.white = gp_in.analog[Gamepad::ANALOG_OFF_LB];
in_report_.black = gp_in.analog[Gamepad::ANALOG_OFF_RB];
}
else
{
if (gp_in.buttons & Gamepad::BUTTON_X) in_report_.x = 0xFF;
if (gp_in.buttons & Gamepad::BUTTON_A) in_report_.a = 0xFF;
if (gp_in.buttons & Gamepad::BUTTON_Y) in_report_.y = 0xFF;
if (gp_in.buttons & Gamepad::BUTTON_B) in_report_.b = 0xFF;
if (gp_in.buttons & Gamepad::BUTTON_LB) in_report_.white = 0xFF;
if (gp_in.buttons & Gamepad::BUTTON_RB) in_report_.black = 0xFF;
}
in_report_.trigger_l = gamepad.get_trigger_l().uint8();
in_report_.trigger_r = gamepad.get_trigger_r().uint8();
in_report_.trigger_l = gp_in.trigger_l;
in_report_.trigger_r = gp_in.trigger_r;
in_report_.joystick_lx = gamepad.get_joystick_lx().int16();
in_report_.joystick_ly = gamepad.get_joystick_ly().int16(true);
in_report_.joystick_rx = gamepad.get_joystick_rx().int16();
in_report_.joystick_ry = gamepad.get_joystick_ry().int16(true);
in_report_.joystick_lx = gp_in.joystick_lx;
in_report_.joystick_ly = Scale::invert_joy(gp_in.joystick_ly);
in_report_.joystick_rx = gp_in.joystick_rx;
in_report_.joystick_ry = Scale::invert_joy(gp_in.joystick_ry);
if (std::memcmp(&prev_in_report_, &in_report_, sizeof(in_report_)) != 0 &&
tud_xid::send_report(0, reinterpret_cast<uint8_t*>(&in_report_), sizeof(XboxOG::GP::InReport)))
{
std::memcpy(&prev_in_report_, &in_report_, sizeof(XboxOG::GP::InReport));
if (tud_suspended())
{
tud_remote_wakeup();
}
if (tud_xid::send_report_ready(0))
{
tud_xid::send_report(0, reinterpret_cast<uint8_t*>(&in_report_), sizeof(XboxOG::GP::InReport));
}
}
if (tud_xid::receive_report(0, reinterpret_cast<uint8_t*>(&out_report_), sizeof(XboxOG::GP::OutReport)))
{
gamepad.set_rumble_l(out_report_.rumble_l);
gamepad.set_rumble_r(out_report_.rumble_r);
Gamepad::PadOut gp_out;
gp_out.rumble_l = Scale::uint16_to_uint8(out_report_.rumble_l);
gp_out.rumble_r = Scale::uint16_to_uint8(out_report_.rumble_r);
gamepad.set_pad_out(gp_out);
}
}

View File

@@ -10,7 +10,7 @@ class XboxOGDevice : public DeviceDriver
{
public:
void initialize() override;
void process(const uint8_t idx, Gamepad& gamepad) override;
void process(uint8_t idx, Gamepad& gamepad) override;
uint16_t get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) override;
void set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) override;
bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) override;
@@ -22,7 +22,6 @@ public:
private:
XboxOG::GP::InReport in_report_;
XboxOG::GP::InReport prev_in_report_;
XboxOG::GP::OutReport out_report_;
};

View File

@@ -8,15 +8,15 @@
static constexpr std::array<XboxOGSBDevice::ButtonMap, 9> GP_MAP =
{{
{Gamepad::Button::START, XboxOG::SB::Buttons0::START, 0},
{Gamepad::Button::LB, XboxOG::SB::Buttons0::RIGHTJOYFIRE, 0},
{Gamepad::Button::R3, XboxOG::SB::Buttons0::RIGHTJOYLOCKON, 0},
{Gamepad::Button::B, XboxOG::SB::Buttons0::RIGHTJOYLOCKON, 0},
{Gamepad::Button::RB, XboxOG::SB::Buttons0::RIGHTJOYMAINWEAPON, 0},
{Gamepad::Button::A, XboxOG::SB::Buttons0::RIGHTJOYMAINWEAPON, 0},
{Gamepad::Button::SYS, XboxOG::SB::Buttons0::EJECT, 0},
{Gamepad::Button::L3, XboxOG::SB::Buttons2::LEFTJOYSIGHTCHANGE, 2},
{Gamepad::Button::Y, XboxOG::SB::Buttons1::CHAFF, 1}
{Gamepad::BUTTON_START, XboxOG::SB::Buttons0::START, 0},
{Gamepad::BUTTON_LB, XboxOG::SB::Buttons0::RIGHTJOYFIRE, 0},
{Gamepad::BUTTON_R3, XboxOG::SB::Buttons0::RIGHTJOYLOCKON, 0},
{Gamepad::BUTTON_B, XboxOG::SB::Buttons0::RIGHTJOYLOCKON, 0},
{Gamepad::BUTTON_RB, XboxOG::SB::Buttons0::RIGHTJOYMAINWEAPON, 0},
{Gamepad::BUTTON_A, XboxOG::SB::Buttons0::RIGHTJOYMAINWEAPON, 0},
{Gamepad::BUTTON_SYS, XboxOG::SB::Buttons0::EJECT, 0},
{Gamepad::BUTTON_L3, XboxOG::SB::Buttons2::LEFTJOYSIGHTCHANGE, 2},
{Gamepad::BUTTON_Y, XboxOG::SB::Buttons1::CHAFF, 1}
}};
static constexpr std::array<XboxOGSBDevice::ButtonMap, 19> CHATPAD_MAP =
@@ -87,29 +87,29 @@ void XboxOGSBDevice::initialize()
void XboxOGSBDevice::process(const uint8_t idx, Gamepad& gamepad)
{
// // uint8_t xid_index = tud_xid::get_index_by_type(0, tud_xid::Type::STEELBATTALION);
if (gamepad.new_pad_in())
{
Gamepad::PadIn gp_in = gamepad.get_pad_in();
// // if (tud_xid::send_report_ready(xid_index))
// // {
in_report_.dButtons[0] = 0;
in_report_.dButtons[1] = 0;
in_report_.dButtons[2] &= XboxOG::SB::BUTTONS2_TOGGLE_MID;
uint16_t gp_buttons = gamepad.get_buttons();
// uint16_t gp_buttons = gamepad.get_buttons();
for (const auto& map : GP_MAP)
{
if (gp_buttons & map.gp_mask)
if (gp_in.buttons & map.gp_mask)
{
in_report_.dButtons[map.button_offset] |= map.sb_mask;
}
}
Gamepad::Chatpad gp_chatpad = gamepad.get_chatpad();
// Gamepad::Chatpad gp_chatpad = gamepad.get_chatpad();
for (const auto& map : CHATPAD_MAP)
{
if (chatpad_pressed(gp_chatpad, map.gp_mask))
if (chatpad_pressed(gp_in.chatpad, map.gp_mask))
{
in_report_.dButtons[map.button_offset] |= map.sb_mask;
}
@@ -117,13 +117,13 @@ void XboxOGSBDevice::process(const uint8_t idx, Gamepad& gamepad)
for (const auto& map : CHATPAD_TOGGLE_MAP)
{
if (chatpad_pressed(gp_chatpad, map.gp_mask))
if (chatpad_pressed(gp_in.chatpad, map.gp_mask))
{
in_report_.dButtons[map.button_offset] |= map.sb_mask;
}
}
if (gp_buttons & Gamepad::Button::X)
if (gp_in.buttons & Gamepad::BUTTON_X)
{
if (out_report_.Chaff_Extinguisher & 0x0F)
{
@@ -139,63 +139,61 @@ void XboxOGSBDevice::process(const uint8_t idx, Gamepad& gamepad)
}
}
uint8_t gp_dpad = gamepad.get_dpad_buttons();
if (chatpad_pressed(gp_chatpad, XInput::Chatpad::CODE_MESSENGER) || gp_buttons & Gamepad::Button::BACK)
if (chatpad_pressed(gp_in.chatpad, XInput::Chatpad::CODE_MESSENGER) || gp_in.buttons & Gamepad::BUTTON_BACK)
{
for (const auto& map : CHATPAD_MAP_ALT1)
{
if (chatpad_pressed(gp_chatpad, map.gp_mask))
if (chatpad_pressed(gp_in.chatpad, map.gp_mask))
{
in_report_.dButtons[map.button_offset] |= map.sb_mask;
}
}
// for (uint8_t i = 0; i < sizeof(CHATPAD_MAP_ALT1) / sizeof(CHATPAD_MAP_ALT1[0]); i++)
// {
// if (chatpad_pressed(gp_chatpad, CHATPAD_MAP_ALT1[i].gp_mask))
// if (chatpad_pressed(gp_in.chatpad, CHATPAD_MAP_ALT1[i].gp_mask))
// {
// in_report_.dButtons[CHATPAD_MAP_ALT1[i].button_offset] |= CHATPAD_MAP_ALT1[i].sb_mask;
// }
// }
if (gp_dpad & Gamepad::DPad::UP || gp_dpad & Gamepad::DPad::RIGHT)
if (gp_in.dpad & Gamepad::DPAD_UP || gp_in.dpad & Gamepad::DPAD_RIGHT)
{
in_report_.tunerDial += (prev_in_report_.tunerDial < 15) ? 1 : -15;
}
if (gp_dpad & Gamepad::DPad::DOWN || gp_dpad & Gamepad::DPad::LEFT)
if (gp_in.dpad & Gamepad::DPAD_DOWN || gp_in.dpad & Gamepad::DPAD_LEFT)
{
in_report_.tunerDial -= (prev_in_report_.tunerDial > 0) ? 1 : -15;
}
}
else if (chatpad_pressed(gp_chatpad, XInput::Chatpad::CODE_ORANGE))
else if (chatpad_pressed(gp_in.chatpad, XInput::Chatpad::CODE_ORANGE))
{
for (const auto& map : CHATPAD_MAP_ALT2)
{
if (chatpad_pressed(gp_chatpad, map.gp_mask))
if (chatpad_pressed(gp_in.chatpad, map.gp_mask))
{
in_report_.dButtons[map.button_offset] |= map.sb_mask;
}
}
// for (uint8_t i = 0; i < sizeof(CHATPAD_MAP_ALT2) / sizeof(CHATPAD_MAP_ALT2[0]); i++)
// {
// if (chatpad_pressed(gp_chatpad, CHATPAD_MAP_ALT2[i].gp_mask))
// if (chatpad_pressed(gp_in.chatpad, CHATPAD_MAP_ALT2[i].gp_mask))
// {
// in_report_.dButtons[CHATPAD_MAP_ALT2[i].button_offset] |= CHATPAD_MAP_ALT2[i].sb_mask;
// }
// }
if (!(gp_dpad & Gamepad::DPad::LEFT) && !(gp_dpad & Gamepad::DPad::RIGHT))
if (!(gp_in.dpad & Gamepad::DPAD_LEFT) && !(gp_in.dpad & Gamepad::DPAD_RIGHT))
{
if (gp_dpad & Gamepad::DPad::UP)
if (gp_in.dpad & Gamepad::DPAD_UP)
{
in_report_.gearLever += (prev_in_report_.gearLever < XboxOG::SB::Gear::G5) ? 1 : 0;
}
if (gp_dpad & Gamepad::DPad::DOWN)
if (gp_in.dpad & Gamepad::DPAD_DOWN)
{
in_report_.gearLever -= (prev_in_report_.gearLever > XboxOG::SB::Gear::R) ? 1 : 0;
}
}
}
if (chatpad_pressed(gp_chatpad, XInput::Chatpad::CODE_SHIFT))
if (chatpad_pressed(gp_in.chatpad, XInput::Chatpad::CODE_SHIFT))
{
if (in_report_.dButtons[2] & XboxOG::SB::BUTTONS2_TOGGLE_MID)
{
@@ -207,25 +205,25 @@ void XboxOGSBDevice::process(const uint8_t idx, Gamepad& gamepad)
}
}
in_report_.leftPedal = gamepad.get_trigger_l().uint16();
in_report_.rightPedal = gamepad.get_trigger_r().uint16();
in_report_.middlePedal = chatpad_pressed(gp_chatpad, XInput::Chatpad::CODE_BACK) ? 0xFF00 : 0x0000;
in_report_.rotationLever = chatpad_pressed(gp_chatpad, XInput::Chatpad::CODE_MESSENGER) ? 0 :
(gp_buttons & Gamepad::Button::BACK) ? 0 :
(gp_dpad & Gamepad::DPad::LEFT) ? INT16_MIN :
(gp_dpad & Gamepad::DPad::RIGHT) ? INT16_MAX : 0;
in_report_.leftPedal = Scale::uint8_to_uint16(gp_in.trigger_l);
in_report_.rightPedal = Scale::uint8_to_uint16(gp_in.trigger_r);
in_report_.middlePedal = chatpad_pressed(gp_in.chatpad, XInput::Chatpad::CODE_BACK) ? 0xFF00 : 0x0000;
in_report_.rotationLever = chatpad_pressed(gp_in.chatpad, XInput::Chatpad::CODE_MESSENGER) ? 0 :
(gp_in.buttons & Gamepad::BUTTON_BACK) ? 0 :
(gp_in.dpad & Gamepad::DPAD_LEFT) ? INT16_MIN :
(gp_in.dpad & Gamepad::DPAD_RIGHT) ? INT16_MAX : 0;
in_report_.sightChangeX = gamepad.get_joystick_lx().int16(true);
in_report_.sightChangeY = gamepad.get_joystick_ly().int16();
in_report_.sightChangeX = Scale::invert_joy(gp_in.joystick_lx);
in_report_.sightChangeY = gp_in.joystick_ly;
int32_t axis_value = static_cast<int32_t>(gamepad.get_joystick_rx().int16(true));
int32_t axis_value = static_cast<int32_t>(Scale::invert_joy(gp_in.joystick_rx));
if (axis_value > XboxOG::SB::DEFAULT_DEADZONE)
{
vmouse_x_ += axis_value / sensitivity_;
}
axis_value = static_cast<int32_t>(gamepad.get_joystick_ry().int16(true));
axis_value = static_cast<int32_t>(Scale::invert_joy(gp_in.joystick_ry));
if (axis_value > XboxOG::SB::DEFAULT_DEADZONE)
{
@@ -237,7 +235,7 @@ void XboxOGSBDevice::process(const uint8_t idx, Gamepad& gamepad)
if (vmouse_y_ > UINT16_MAX) vmouse_y_ = UINT16_MAX;
if (vmouse_y_ < 0) vmouse_y_ = 0;
if (gp_buttons & Gamepad::Button::L3)
if (gp_in.buttons & Gamepad::BUTTON_L3)
{
if ((time_us_32() / 1000) - aim_reset_timer_ > 500)
{
@@ -257,75 +255,71 @@ void XboxOGSBDevice::process(const uint8_t idx, Gamepad& gamepad)
{
tud_remote_wakeup();
}
if (std::memcmp(&prev_in_report_, &in_report_, sizeof(XboxOG::SB::InReport)) != 0 &&
tud_xid::send_report(0, reinterpret_cast<uint8_t*>(&in_report_), sizeof(XboxOG::SB::InReport)))
if (tud_xid::send_report_ready(0))
{
std::memcpy(&prev_in_report_, &in_report_, sizeof(XboxOG::SB::InReport));
tud_xid::send_report(0, reinterpret_cast<uint8_t*>(&in_report_), sizeof(XboxOG::SB::InReport));
}
// }
// Gamepad::Chatpad gp_chatpad = gamepad.chatpad();
// gp_chatpad = gamepad.get_chatpad();
if (chatpad_pressed(gp_in.chatpad, XInput::Chatpad::CODE_ORANGE))
{
uint16_t new_sense = 0;
// if (chatpad_pressed(gp_chatpad, XInput::Chatpad::CODE_ORANGE))
// {
// uint16_t new_sense = 0;
if (chatpad_pressed(gp_in.chatpad, XInput::Chatpad::CODE_9))
{
new_sense = 200;
}
else if (chatpad_pressed(gp_in.chatpad, XInput::Chatpad::CODE_8))
{
new_sense = 250;
}
else if (chatpad_pressed(gp_in.chatpad, XInput::Chatpad::CODE_7))
{
new_sense = 300;
}
else if (chatpad_pressed(gp_in.chatpad, XInput::Chatpad::CODE_6))
{
new_sense = 350;
}
else if (chatpad_pressed(gp_in.chatpad, XInput::Chatpad::CODE_5))
{
new_sense = 400;
}
else if (chatpad_pressed(gp_in.chatpad, XInput::Chatpad::CODE_4))
{
new_sense = 650;
}
else if (chatpad_pressed(gp_in.chatpad, XInput::Chatpad::CODE_3))
{
new_sense = 800;
}
else if (chatpad_pressed(gp_in.chatpad, XInput::Chatpad::CODE_2))
{
new_sense = 1000;
}
else if (chatpad_pressed(gp_in.chatpad, XInput::Chatpad::CODE_1))
{
new_sense = 1200;
}
// if (chatpad_pressed(gp_chatpad, XInput::Chatpad::CODE_9))
// {
// new_sense = 200;
// }
// else if (chatpad_pressed(gp_chatpad, XInput::Chatpad::CODE_8))
// {
// new_sense = 250;
// }
// else if (chatpad_pressed(gp_chatpad, XInput::Chatpad::CODE_7))
// {
// new_sense = 300;
// }
// else if (chatpad_pressed(gp_chatpad, XInput::Chatpad::CODE_6))
// {
// new_sense = 350;
// }
// else if (chatpad_pressed(gp_chatpad, XInput::Chatpad::CODE_5))
// {
// new_sense = 400;
// }
// else if (chatpad_pressed(gp_chatpad, XInput::Chatpad::CODE_4))
// {
// new_sense = 650;
// }
// else if (chatpad_pressed(gp_chatpad, XInput::Chatpad::CODE_3))
// {
// new_sense = 800;
// }
// else if (chatpad_pressed(gp_chatpad, XInput::Chatpad::CODE_2))
// {
// new_sense = 1000;
// }
// else if (chatpad_pressed(gp_chatpad, XInput::Chatpad::CODE_1))
// {
// new_sense = 1200;
// }
if (new_sense != 0 && new_sense != sensitivity_)
{
sensitivity_ = new_sense;
}
}
}
// if (new_sense != 0 && new_sense != sensitivity_)
// {
// sensitivity_ = new_sense;
// }
// }
if (tud_xid::receive_report(0, reinterpret_cast<uint8_t*>(&out_report_), sizeof(XboxOG::SB::OutReport)) &&
out_report_.bLength == sizeof(XboxOG::SB::OutReport))
{
Gamepad::PadOut gp_out;
gp_out.rumble_l = out_report_.Chaff_Extinguisher;
gp_out.rumble_l |= out_report_.Chaff_Extinguisher << 4;
gp_out.rumble_l |= out_report_.Comm1_MagazineChange << 4;
gp_out.rumble_l |= out_report_.CockpitHatch_EmergencyEject << 4;
gp_out.rumble_r = gp_out.rumble_l;
// if (tud_xid::receive_report(0, reinterpret_cast<uint8_t*>(&out_report_), sizeof(XboxOG::SB::OutReport)) &&
// out_report_.bLength == sizeof(XboxOG::SB::OutReport))
// {
// uint8_t rumble = out_report_.Chaff_Extinguisher;
// rumble |= out_report_.Chaff_Extinguisher << 4;
// rumble |= out_report_.Comm1_MagazineChange << 4;
// rumble |= out_report_.CockpitHatch_EmergencyEject << 4;
// gamepad.set_rumble_l(rumble);
// gamepad.set_rumble_r(rumble);
// }
gamepad.set_pad_out(gp_out);
}
}
uint16_t XboxOGSBDevice::get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)

View File

@@ -39,9 +39,9 @@ private:
XboxOG::SB::InReport prev_in_report_;
XboxOG::SB::OutReport out_report_;
static inline bool chatpad_pressed(const Gamepad::Chatpad& chatpad_array, const uint16_t keycode)
static inline bool chatpad_pressed(const uint8_t* chatpad_array, const uint16_t keycode)
{
if (std::accumulate(chatpad_array.data(), chatpad_array.data() + sizeof(Gamepad::Chatpad), 0) == 0)
if (std::accumulate(chatpad_array, chatpad_array + 3, 0) == 0)
{
return false;
}

View File

@@ -21,48 +21,42 @@ void XboxOGXRDevice::process(const uint8_t idx, Gamepad& gamepad)
return;
}
uint8_t index = tud_xid::get_index_by_type(0, tud_xid::Type::XREMOTE);
uint32_t time_elapsed = to_ms_since_boot(get_absolute_time()) - ms_timer_;
uint8_t index = tud_xid::get_index_by_type(0, tud_xid::Type::XREMOTE);
if (tud_suspended())
{
tud_remote_wakeup();
}
if (!tud_xid::send_report_ready(index) || time_elapsed < 64)
if (index == 0xFF || !gamepad.new_pad_in() || time_elapsed < 64)
{
return;
}
Gamepad::PadIn gp_in = gamepad.get_pad_in();
in_report_.buttonCode = 0;
uint16_t gp_buttons = gamepad.get_buttons();
uint8_t gp_dpad = gamepad.get_dpad_buttons();
if (gp_in.dpad & Gamepad::DPAD_UP) in_report_.buttonCode |= XboxOG::XR::ButtonCode::UP ;
if (gp_in.dpad & Gamepad::DPAD_DOWN) in_report_.buttonCode |= XboxOG::XR::ButtonCode::DOWN ;
if (gp_in.dpad & Gamepad::DPAD_LEFT) in_report_.buttonCode |= XboxOG::XR::ButtonCode::LEFT ;
if (gp_in.dpad & Gamepad::DPAD_RIGHT) in_report_.buttonCode |= XboxOG::XR::ButtonCode::RIGHT;
if (gp_dpad & Gamepad::DPad::UP) in_report_.buttonCode |= XboxOG::XR::ButtonCode::UP ;
if (gp_dpad & Gamepad::DPad::DOWN) in_report_.buttonCode |= XboxOG::XR::ButtonCode::DOWN ;
if (gp_dpad & Gamepad::DPad::LEFT) in_report_.buttonCode |= XboxOG::XR::ButtonCode::LEFT ;
if (gp_dpad & Gamepad::DPad::RIGHT) in_report_.buttonCode |= XboxOG::XR::ButtonCode::RIGHT;
if (gp_in.buttons & Gamepad::BUTTON_SYS) in_report_.buttonCode |= XboxOG::XR::ButtonCode::DISPLAY;
if (gp_in.buttons & Gamepad::BUTTON_START) in_report_.buttonCode |= XboxOG::XR::ButtonCode::PLAY ;
if (gp_in.buttons & Gamepad::BUTTON_BACK) in_report_.buttonCode |= XboxOG::XR::ButtonCode::STOP ;
if (gp_buttons & Gamepad::Button::SYS) in_report_.buttonCode |= XboxOG::XR::ButtonCode::DISPLAY;
if (gp_buttons & Gamepad::Button::START) in_report_.buttonCode |= XboxOG::XR::ButtonCode::PLAY ;
if (gp_buttons & Gamepad::Button::BACK) in_report_.buttonCode |= XboxOG::XR::ButtonCode::STOP ;
if (gp_in.buttons & Gamepad::BUTTON_L3 && !(gp_in.buttons & Gamepad::BUTTON_R3)) in_report_.buttonCode |= XboxOG::XR::ButtonCode::TITLE;
if (gp_in.buttons & Gamepad::BUTTON_R3 && !(gp_in.buttons & Gamepad::BUTTON_L3)) in_report_.buttonCode |= XboxOG::XR::ButtonCode::MENU;
if (gp_in.buttons & (Gamepad::BUTTON_L3 | Gamepad::BUTTON_R3)) in_report_.buttonCode |= XboxOG::XR::ButtonCode::INFO;
if (gp_buttons & Gamepad::Button::L3 && !(gp_buttons & Gamepad::Button::R3)) in_report_.buttonCode |= XboxOG::XR::ButtonCode::TITLE;
if (gp_buttons & Gamepad::Button::R3 && !(gp_buttons & Gamepad::Button::L3)) in_report_.buttonCode |= XboxOG::XR::ButtonCode::MENU;
if (gp_buttons & (Gamepad::Button::L3 | Gamepad::Button::R3)) in_report_.buttonCode |= XboxOG::XR::ButtonCode::INFO;
if (gp_in.buttons & Gamepad::BUTTON_A) in_report_.buttonCode |= XboxOG::XR::ButtonCode::SELECT ;
if (gp_in.buttons & Gamepad::BUTTON_Y) in_report_.buttonCode |= XboxOG::XR::ButtonCode::PAUSE ;
if (gp_in.buttons & Gamepad::BUTTON_X) in_report_.buttonCode |= XboxOG::XR::ButtonCode::DISPLAY;
if (gp_in.buttons & Gamepad::BUTTON_B) in_report_.buttonCode |= XboxOG::XR::ButtonCode::BACK ;
if (gp_buttons & Gamepad::Button::A) in_report_.buttonCode |= XboxOG::XR::ButtonCode::SELECT ;
if (gp_buttons & Gamepad::Button::Y) in_report_.buttonCode |= XboxOG::XR::ButtonCode::PAUSE ;
if (gp_buttons & Gamepad::Button::X) in_report_.buttonCode |= XboxOG::XR::ButtonCode::DISPLAY;
if (gp_buttons & Gamepad::Button::B) in_report_.buttonCode |= XboxOG::XR::ButtonCode::BACK ;
if (gp_in.buttons & Gamepad::BUTTON_LB && !(gp_in.buttons & Gamepad::BUTTON_RB)) in_report_.buttonCode |= XboxOG::XR::ButtonCode::SKIP_MINUS;
if (gp_in.buttons & Gamepad::BUTTON_RB && !(gp_in.buttons & Gamepad::BUTTON_LB)) in_report_.buttonCode |= XboxOG::XR::ButtonCode::SKIP_PLUS ;
if (gp_in.buttons & (Gamepad::BUTTON_LB | Gamepad::BUTTON_RB)) in_report_.buttonCode |= XboxOG::XR::ButtonCode::DISPLAY;
if (gp_buttons & Gamepad::Button::LB && !(gp_buttons & Gamepad::Button::RB)) in_report_.buttonCode |= XboxOG::XR::ButtonCode::SKIP_MINUS;
if (gp_buttons & Gamepad::Button::RB && !(gp_buttons & Gamepad::Button::LB)) in_report_.buttonCode |= XboxOG::XR::ButtonCode::SKIP_PLUS ;
if (gp_buttons & (Gamepad::Button::LB | Gamepad::Button::RB)) in_report_.buttonCode |= XboxOG::XR::ButtonCode::DISPLAY;
if (gamepad.get_trigger_l().uint8() >= 100) in_report_.buttonCode |= XboxOG::XR::ButtonCode::REVERSE;
if (gamepad.get_trigger_r().uint8() >= 100) in_report_.buttonCode |= XboxOG::XR::ButtonCode::FORWARD;
if (gp_in.trigger_l >= 100) in_report_.buttonCode |= XboxOG::XR::ButtonCode::REVERSE;
if (gp_in.trigger_r >= 100) in_report_.buttonCode |= XboxOG::XR::ButtonCode::FORWARD;
if (in_report_.buttonCode == 0x0000)
{
@@ -70,8 +64,13 @@ void XboxOGXRDevice::process(const uint8_t idx, Gamepad& gamepad)
}
in_report_.timeElapsed = static_cast<uint16_t>(time_elapsed);
if (tud_xid::send_report(index, reinterpret_cast<uint8_t*>(&in_report_), sizeof(XboxOG::XR::InReport)))
if (tud_suspended())
{
tud_remote_wakeup();
}
if (tud_xid::send_report_ready(index) &&
tud_xid::send_report(index, reinterpret_cast<uint8_t*>(&in_report_), sizeof(XboxOG::XR::InReport)))
{
ms_timer_ = to_ms_since_boot(get_absolute_time());
}

View File

@@ -20,86 +20,88 @@ void DInputHost::process_report(Gamepad& gamepad, uint8_t address, uint8_t insta
return;
}
gamepad.reset_buttons();
Gamepad::PadIn gp_in;
switch (in_report->dpad & DInput::DPAD_MASK)
{
case DInput::DPad::UP:
gamepad.set_dpad_up();
gp_in.dpad |= gamepad.MAP_DPAD_UP;
break;
case DInput::DPad::DOWN:
gamepad.set_dpad_down();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN;
break;
case DInput::DPad::LEFT:
gamepad.set_dpad_left();
gp_in.dpad |= gamepad.MAP_DPAD_LEFT;
break;
case DInput::DPad::RIGHT:
gamepad.set_dpad_right();
gp_in.dpad |= gamepad.MAP_DPAD_RIGHT;
break;
case DInput::DPad::UP_RIGHT:
gamepad.set_dpad_up_right();
gp_in.dpad |= gamepad.MAP_DPAD_UP_RIGHT;
break;
case DInput::DPad::DOWN_RIGHT:
gamepad.set_dpad_down_right();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN_RIGHT;
break;
case DInput::DPad::DOWN_LEFT:
gamepad.set_dpad_down_left();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN_LEFT;
break;
case DInput::DPad::UP_LEFT:
gamepad.set_dpad_up_left();
gp_in.dpad |= gamepad.MAP_DPAD_UP_LEFT;
break;
default:
break;
}
if (in_report->buttons[0] & DInput::Buttons0::SQUARE) gamepad.set_button_x();
if (in_report->buttons[0] & DInput::Buttons0::CROSS) gamepad.set_button_a();
if (in_report->buttons[0] & DInput::Buttons0::CIRCLE) gamepad.set_button_b();
if (in_report->buttons[0] & DInput::Buttons0::TRIANGLE) gamepad.set_button_y();
if (in_report->buttons[0] & DInput::Buttons0::L1) gamepad.set_button_lb();
if (in_report->buttons[0] & DInput::Buttons0::R1) gamepad.set_button_rb();
if (in_report->buttons[1] & DInput::Buttons1::L3) gamepad.set_button_l3();
if (in_report->buttons[1] & DInput::Buttons1::R3) gamepad.set_button_r3();
if (in_report->buttons[1] & DInput::Buttons1::SELECT) gamepad.set_button_back();
if (in_report->buttons[1] & DInput::Buttons1::START) gamepad.set_button_start();
if (in_report->buttons[1] & DInput::Buttons1::PS) gamepad.set_button_sys();
if (in_report->buttons[1] & DInput::Buttons1::TP) gamepad.set_button_misc();
if (in_report->buttons[0] & DInput::Buttons0::SQUARE) gp_in.buttons |= gamepad.MAP_BUTTON_X;
if (in_report->buttons[0] & DInput::Buttons0::CROSS) gp_in.buttons |= gamepad.MAP_BUTTON_A;
if (in_report->buttons[0] & DInput::Buttons0::CIRCLE) gp_in.buttons |= gamepad.MAP_BUTTON_B;
if (in_report->buttons[0] & DInput::Buttons0::TRIANGLE) gp_in.buttons |= gamepad.MAP_BUTTON_Y;
if (in_report->buttons[0] & DInput::Buttons0::L1) gp_in.buttons |= gamepad.MAP_BUTTON_LB;
if (in_report->buttons[0] & DInput::Buttons0::R1) gp_in.buttons |= gamepad.MAP_BUTTON_RB;
if (in_report->buttons[1] & DInput::Buttons1::L3) gp_in.buttons |= gamepad.MAP_BUTTON_L3;
if (in_report->buttons[1] & DInput::Buttons1::R3) gp_in.buttons |= gamepad.MAP_BUTTON_R3;
if (in_report->buttons[1] & DInput::Buttons1::SELECT) gp_in.buttons |= gamepad.MAP_BUTTON_BACK;
if (in_report->buttons[1] & DInput::Buttons1::START) gp_in.buttons |= gamepad.MAP_BUTTON_START;
if (in_report->buttons[1] & DInput::Buttons1::PS) gp_in.buttons |= gamepad.MAP_BUTTON_SYS;
if (in_report->buttons[1] & DInput::Buttons1::TP) gp_in.buttons |= gamepad.MAP_BUTTON_MISC;
if (gamepad.analog_enabled())
{
gamepad.set_analog_up(in_report->up_axis);
gamepad.set_analog_down(in_report->down_axis);
gamepad.set_analog_left(in_report->left_axis);
gamepad.set_analog_right(in_report->right_axis);
gamepad.set_analog_a(in_report->cross_axis);
gamepad.set_analog_b(in_report->circle_axis);
gamepad.set_analog_x(in_report->square_axis);
gamepad.set_analog_y(in_report->triangle_axis);
gamepad.set_analog_lb(in_report->l1_axis);
gamepad.set_analog_rb(in_report->r1_axis);
gp_in.analog[gamepad.MAP_ANALOG_OFF_UP] = in_report->up_axis;
gp_in.analog[gamepad.MAP_ANALOG_OFF_DOWN] = in_report->down_axis;
gp_in.analog[gamepad.MAP_ANALOG_OFF_LEFT] = in_report->left_axis;
gp_in.analog[gamepad.MAP_ANALOG_OFF_RIGHT] = in_report->right_axis;
gp_in.analog[gamepad.MAP_ANALOG_OFF_A] = in_report->cross_axis;
gp_in.analog[gamepad.MAP_ANALOG_OFF_B] = in_report->circle_axis;
gp_in.analog[gamepad.MAP_ANALOG_OFF_X] = in_report->square_axis;
gp_in.analog[gamepad.MAP_ANALOG_OFF_Y] = in_report->triangle_axis;
gp_in.analog[gamepad.MAP_ANALOG_OFF_LB] = in_report->l1_axis;
gp_in.analog[gamepad.MAP_ANALOG_OFF_RB] = in_report->r1_axis;
}
if (in_report->l2_axis != 0)
if (in_report->l2_axis > 0)
{
gamepad.set_trigger_l(in_report->l2_axis);
gp_in.trigger_l = in_report->l2_axis;
}
else
{
gamepad.set_trigger_l((in_report->buttons[0] & DInput::Buttons0::L2) ? UINT_8::MAX : UINT_8::MIN);
gp_in.trigger_l = (in_report->buttons[0] & DInput::Buttons0::L2) ? UINT_8::MAX : UINT_8::MIN;
}
if (in_report->r2_axis != 0)
if (in_report->r2_axis > 0)
{
gamepad.set_trigger_r(in_report->r2_axis);
gp_in.trigger_r = in_report->r2_axis;
}
else
{
gamepad.set_trigger_r((in_report->buttons[0] & DInput::Buttons0::R2) ? UINT_8::MAX : UINT_8::MIN);
gp_in.trigger_r = (in_report->buttons[0] & DInput::Buttons0::R2) ? UINT_8::MAX : UINT_8::MIN;
}
gamepad.set_joystick_lx(in_report->joystick_lx);
gamepad.set_joystick_ly(in_report->joystick_ly);
gamepad.set_joystick_rx(in_report->joystick_rx);
gamepad.set_joystick_ry(in_report->joystick_ry);
gp_in.joystick_lx = Scale::uint8_to_int16(in_report->joystick_lx);
gp_in.joystick_ly = Scale::uint8_to_int16(in_report->joystick_ly);
gp_in.joystick_rx = Scale::uint8_to_int16(in_report->joystick_rx);
gp_in.joystick_ry = Scale::uint8_to_int16(in_report->joystick_ry);
gamepad.set_pad_in(gp_in);
tuh_hid_receive_report(address, instance);
std::memcpy(&prev_in_report_, in_report, sizeof(DInput::InReport));

View File

@@ -32,57 +32,59 @@ void HIDHost::process_report(Gamepad& gamepad, uint8_t address, uint8_t instance
return;
}
gamepad.reset_pad();
Gamepad::PadIn gp_in;
switch (hid_joystick_data_.hat_switch)
{
case HIDJoystickHatSwitch::UP:
gamepad.set_dpad_up();
gp_in.dpad |= gamepad.MAP_DPAD_UP;
break;
case HIDJoystickHatSwitch::UP_RIGHT:
gamepad.set_dpad_up_right();
gp_in.dpad |= gamepad.MAP_DPAD_UP_RIGHT;
break;
case HIDJoystickHatSwitch::RIGHT:
gamepad.set_dpad_right();
gp_in.dpad |= gamepad.MAP_DPAD_RIGHT;
break;
case HIDJoystickHatSwitch::DOWN_RIGHT:
gamepad.set_dpad_down_right();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN_RIGHT;
break;
case HIDJoystickHatSwitch::DOWN:
gamepad.set_dpad_down();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN;
break;
case HIDJoystickHatSwitch::DOWN_LEFT:
gamepad.set_dpad_down_left();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN_LEFT;
break;
case HIDJoystickHatSwitch::LEFT:
gamepad.set_dpad_left();
gp_in.dpad |= gamepad.MAP_DPAD_LEFT;
break;
case HIDJoystickHatSwitch::UP_LEFT:
gamepad.set_dpad_up_left();
gp_in.dpad |= gamepad.MAP_DPAD_UP_LEFT;
break;
default:
break;
}
gamepad.set_joystick_lx(hid_joystick_data_.X);
gamepad.set_joystick_ly(hid_joystick_data_.Y);
gamepad.set_joystick_rx(hid_joystick_data_.Z);
gamepad.set_joystick_ry(hid_joystick_data_.Rz);
gp_in.joystick_lx = hid_joystick_data_.X;
gp_in.joystick_ly = hid_joystick_data_.Y;
gp_in.joystick_rx = hid_joystick_data_.Z;
gp_in.joystick_ry = hid_joystick_data_.Rz;
if (hid_joystick_data_.buttons[1]) gamepad.set_button_x();
if (hid_joystick_data_.buttons[2]) gamepad.set_button_a();
if (hid_joystick_data_.buttons[3]) gamepad.set_button_b();
if (hid_joystick_data_.buttons[4]) gamepad.set_button_y();
if (hid_joystick_data_.buttons[5]) gamepad.set_button_lb();
if (hid_joystick_data_.buttons[6]) gamepad.set_button_rb();
if (hid_joystick_data_.buttons[7]) gamepad.set_trigger_l(UINT_8::MAX);
if (hid_joystick_data_.buttons[8]) gamepad.set_trigger_r(UINT_8::MAX);
if (hid_joystick_data_.buttons[9]) gamepad.set_button_back();
if (hid_joystick_data_.buttons[10]) gamepad.set_button_start();
if (hid_joystick_data_.buttons[11]) gamepad.set_button_l3();
if (hid_joystick_data_.buttons[12]) gamepad.set_button_r3();
if (hid_joystick_data_.buttons[13]) gamepad.set_button_sys();
if (hid_joystick_data_.buttons[14]) gamepad.set_button_misc();
if (hid_joystick_data_.buttons[1]) gp_in.buttons |= gamepad.MAP_BUTTON_X;
if (hid_joystick_data_.buttons[2]) gp_in.buttons |= gamepad.MAP_BUTTON_A;
if (hid_joystick_data_.buttons[3]) gp_in.buttons |= gamepad.MAP_BUTTON_B;
if (hid_joystick_data_.buttons[4]) gp_in.buttons |= gamepad.MAP_BUTTON_Y;
if (hid_joystick_data_.buttons[5]) gp_in.buttons |= gamepad.MAP_BUTTON_LB;
if (hid_joystick_data_.buttons[6]) gp_in.buttons |= gamepad.MAP_BUTTON_RB;
if (hid_joystick_data_.buttons[7]) gp_in.trigger_l = UINT_8::MAX;
if (hid_joystick_data_.buttons[8]) gp_in.trigger_r = UINT_8::MAX;
if (hid_joystick_data_.buttons[9]) gp_in.buttons |= gamepad.MAP_BUTTON_BACK;
if (hid_joystick_data_.buttons[10]) gp_in.buttons |= gamepad.MAP_BUTTON_START;
if (hid_joystick_data_.buttons[11]) gp_in.buttons |= gamepad.MAP_BUTTON_L3;
if (hid_joystick_data_.buttons[12]) gp_in.buttons |= gamepad.MAP_BUTTON_R3;
if (hid_joystick_data_.buttons[13]) gp_in.buttons |= gamepad.MAP_BUTTON_SYS;
if (hid_joystick_data_.buttons[14]) gp_in.buttons |= gamepad.MAP_BUTTON_MISC;
gamepad.set_pad_in(gp_in);
tuh_hid_receive_report(address, instance);
}

View File

@@ -44,13 +44,21 @@ protected:
void manage_rumble(Gamepad& gamepad)
{
if (gamepad.get_rumble_l().uint8() != UINT8_MAX)
Gamepad::PadOut gp_out = gamepad.get_pad_out();
bool reset = false;
if (gp_out.rumble_l != UINT_8::MAX)
{
gamepad.set_rumble_l(static_cast<uint8_t>(0));
gp_out.rumble_l = 0;
reset = true;
}
if (gamepad.get_rumble_r().uint8() != UINT8_MAX)
if (gp_out.rumble_r != UINT_8::MAX)
{
gamepad.set_rumble_r(static_cast<uint8_t>(0));
gp_out.rumble_r = 0;
reset = true;
}
if (reset)
{
gamepad.set_pad_out(gp_out);
}
}
};

View File

@@ -16,43 +16,43 @@ void N64Host::process_report(Gamepad& gamepad, uint8_t address, uint8_t instance
return;
}
gamepad.reset_buttons();
Gamepad::PadIn gp_in;
switch (in_report->buttons & N64::DPAD_MASK)
{
case N64::Buttons::DPAD_UP:
gamepad.set_dpad_up();
gp_in.dpad |= gamepad.MAP_DPAD_UP;
break;
case N64::Buttons::DPAD_UP_RIGHT:
gamepad.set_dpad_up_right();
gp_in.dpad |= gamepad.MAP_DPAD_UP_RIGHT;
break;
case N64::Buttons::DPAD_RIGHT:
gamepad.set_dpad_right();
gp_in.dpad |= gamepad.MAP_DPAD_RIGHT;
break;
case N64::Buttons::DPAD_RIGHT_DOWN:
gamepad.set_dpad_down_right();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN_RIGHT;
break;
case N64::Buttons::DPAD_DOWN:
gamepad.set_dpad_down();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN;
break;
case N64::Buttons::DPAD_DOWN_LEFT:
gamepad.set_dpad_down_left();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN_LEFT;
break;
case N64::Buttons::DPAD_LEFT:
gamepad.set_dpad_left();
gp_in.dpad |= gamepad.MAP_DPAD_LEFT;
break;
case N64::Buttons::DPAD_LEFT_UP:
gamepad.set_dpad_up_left();
gp_in.dpad |= gamepad.MAP_DPAD_UP_LEFT;
break;
default:
break;
}
if (in_report->buttons & N64::Buttons::A) gamepad.set_button_a();
if (in_report->buttons & N64::Buttons::B) gamepad.set_button_b();
if (in_report->buttons & N64::Buttons::L) gamepad.set_button_lb();
if (in_report->buttons & N64::Buttons::R) gamepad.set_button_rb();
if (in_report->buttons & N64::Buttons::START) gamepad.set_button_start();
if (in_report->buttons & N64::Buttons::A) gp_in.buttons |= gamepad.MAP_BUTTON_A;
if (in_report->buttons & N64::Buttons::B) gp_in.buttons |= gamepad.MAP_BUTTON_B;
if (in_report->buttons & N64::Buttons::L) gp_in.buttons |= gamepad.MAP_BUTTON_LB;
if (in_report->buttons & N64::Buttons::R) gp_in.buttons |= gamepad.MAP_BUTTON_RB;
if (in_report->buttons & N64::Buttons::START) gp_in.buttons |= gamepad.MAP_BUTTON_START;
uint8_t joy_ry = N64::JOY_MID;
uint8_t joy_rx = N64::JOY_MID;
@@ -91,16 +91,17 @@ void N64Host::process_report(Gamepad& gamepad, uint8_t address, uint8_t instance
break;
}
gamepad.set_joystick_ry(joy_ry);
gamepad.set_joystick_rx(joy_rx);
gp_in.joystick_ry = Scale::uint8_to_int16(in_report->joystick_y);
gp_in.joystick_rx = Scale::uint8_to_int16(in_report->joystick_x);
gamepad.set_trigger_l((in_report->buttons & N64::Buttons::Z) ? UINT_8::MAX : UINT_8::MIN);
gp_in.trigger_l = (in_report->buttons & N64::Buttons::L) ? UINT_8::MAX : UINT_8::MIN;
gamepad.set_joystick_ly(in_report->joystick_y);
gamepad.set_joystick_lx(in_report->joystick_x);
gp_in.joystick_ly = Scale::uint8_to_int16(joy_ry);
gp_in.joystick_lx = Scale::uint8_to_int16(joy_rx);
gamepad.set_pad_in(gp_in);
tuh_hid_receive_report(address, instance);
std::memcpy(&prev_in_report_, in_report, sizeof(N64::InReport));
}

View File

@@ -102,46 +102,48 @@ void PS3Host::process_report(Gamepad& gamepad, uint8_t address, uint8_t instance
return;
}
gamepad.reset_buttons();
Gamepad::PadIn gp_in;
if (in_report->buttons[0] & PS3::Buttons0::DPAD_UP) gamepad.set_dpad_up();
if (in_report->buttons[0] & PS3::Buttons0::DPAD_DOWN) gamepad.set_dpad_down();
if (in_report->buttons[0] & PS3::Buttons0::DPAD_LEFT) gamepad.set_dpad_left();
if (in_report->buttons[0] & PS3::Buttons0::DPAD_RIGHT) gamepad.set_dpad_right();
if (in_report->buttons[0] & PS3::Buttons0::DPAD_UP) gp_in.dpad |= gamepad.MAP_DPAD_UP;
if (in_report->buttons[0] & PS3::Buttons0::DPAD_DOWN) gp_in.dpad |= gamepad.MAP_DPAD_DOWN;
if (in_report->buttons[0] & PS3::Buttons0::DPAD_LEFT) gp_in.dpad |= gamepad.MAP_DPAD_LEFT;
if (in_report->buttons[0] & PS3::Buttons0::DPAD_RIGHT) gp_in.dpad |= gamepad.MAP_DPAD_RIGHT;
if (in_report->buttons[0] & PS3::Buttons0::SELECT) gamepad.set_button_back();
if (in_report->buttons[0] & PS3::Buttons0::START) gamepad.set_button_start();
if (in_report->buttons[0] & PS3::Buttons0::L3) gamepad.set_button_l3();
if (in_report->buttons[0] & PS3::Buttons0::R3) gamepad.set_button_r3();
if (in_report->buttons[1] & PS3::Buttons1::L1) gamepad.set_button_lb();
if (in_report->buttons[1] & PS3::Buttons1::R1) gamepad.set_button_rb();
if (in_report->buttons[1] & PS3::Buttons1::TRIANGLE) gamepad.set_button_y();
if (in_report->buttons[1] & PS3::Buttons1::CIRCLE) gamepad.set_button_b();
if (in_report->buttons[1] & PS3::Buttons1::CROSS) gamepad.set_button_a();
if (in_report->buttons[1] & PS3::Buttons1::SQUARE) gamepad.set_button_x();
if (in_report->buttons[2] & PS3::Buttons2::PS) gamepad.set_button_sys();
if (in_report->buttons[0] & PS3::Buttons0::SELECT) gp_in.buttons |= gamepad.MAP_BUTTON_BACK;
if (in_report->buttons[0] & PS3::Buttons0::START) gp_in.buttons |= gamepad.MAP_BUTTON_START;
if (in_report->buttons[0] & PS3::Buttons0::L3) gp_in.buttons |= gamepad.MAP_BUTTON_L3;
if (in_report->buttons[0] & PS3::Buttons0::R3) gp_in.buttons |= gamepad.MAP_BUTTON_R3;
if (in_report->buttons[1] & PS3::Buttons1::L1) gp_in.buttons |= gamepad.MAP_BUTTON_LB;
if (in_report->buttons[1] & PS3::Buttons1::R1) gp_in.buttons |= gamepad.MAP_BUTTON_RB;
if (in_report->buttons[1] & PS3::Buttons1::TRIANGLE) gp_in.buttons |= gamepad.MAP_BUTTON_Y;
if (in_report->buttons[1] & PS3::Buttons1::CIRCLE) gp_in.buttons |= gamepad.MAP_BUTTON_B;
if (in_report->buttons[1] & PS3::Buttons1::CROSS) gp_in.buttons |= gamepad.MAP_BUTTON_A;
if (in_report->buttons[1] & PS3::Buttons1::SQUARE) gp_in.buttons |= gamepad.MAP_BUTTON_X;
if (in_report->buttons[2] & PS3::Buttons2::PS) gp_in.buttons |= gamepad.MAP_BUTTON_SYS;
if (gamepad.analog_enabled())
{
gamepad.set_analog_up(in_report->up_axis);
gamepad.set_analog_down(in_report->down_axis);
gamepad.set_analog_left(in_report->left_axis);
gamepad.set_analog_right(in_report->right_axis);
gamepad.set_analog_a(in_report->cross_axis);
gamepad.set_analog_b(in_report->circle_axis);
gamepad.set_analog_x(in_report->square_axis);
gamepad.set_analog_y(in_report->triangle_axis);
gamepad.set_analog_lb(in_report->l1_axis);
gamepad.set_analog_rb(in_report->r1_axis);
gp_in.analog[gamepad.MAP_ANALOG_OFF_UP] = in_report->up_axis;
gp_in.analog[gamepad.MAP_ANALOG_OFF_DOWN] = in_report->down_axis;
gp_in.analog[gamepad.MAP_ANALOG_OFF_LEFT] = in_report->left_axis;
gp_in.analog[gamepad.MAP_ANALOG_OFF_RIGHT] = in_report->right_axis;
gp_in.analog[gamepad.MAP_ANALOG_OFF_A] = in_report->cross_axis;
gp_in.analog[gamepad.MAP_ANALOG_OFF_B] = in_report->circle_axis;
gp_in.analog[gamepad.MAP_ANALOG_OFF_X] = in_report->square_axis;
gp_in.analog[gamepad.MAP_ANALOG_OFF_Y] = in_report->triangle_axis;
gp_in.analog[gamepad.MAP_ANALOG_OFF_LB] = in_report->l1_axis;
gp_in.analog[gamepad.MAP_ANALOG_OFF_RB] = in_report->r1_axis;
}
gamepad.set_trigger_l(in_report->l2_axis);
gamepad.set_trigger_r(in_report->r2_axis);
gp_in.trigger_l = in_report->l2_axis;
gp_in.trigger_r = in_report->r2_axis;
gamepad.set_joystick_lx(in_report->joystick_lx);
gamepad.set_joystick_ly(in_report->joystick_ly);
gamepad.set_joystick_rx(in_report->joystick_rx);
gamepad.set_joystick_ry(in_report->joystick_ry);
gp_in.joystick_lx = Scale::uint8_to_int16(in_report->joystick_lx);
gp_in.joystick_ly = Scale::uint8_to_int16(in_report->joystick_ly);
gp_in.joystick_rx = Scale::uint8_to_int16(in_report->joystick_rx);
gp_in.joystick_ry = Scale::uint8_to_int16(in_report->joystick_ry);
gamepad.set_pad_in(gp_in);
tuh_hid_receive_report(address, instance);
std::memcpy(&prev_in_report_, in_report, sizeof(PS3::InReport));
@@ -150,19 +152,19 @@ void PS3Host::process_report(Gamepad& gamepad, uint8_t address, uint8_t instance
bool PS3Host::send_feedback(Gamepad& gamepad, uint8_t address, uint8_t instance)
{
static uint32_t last_rumble_ms = 0;
uint32_t current_ms = time_us_32() / 1000;
Gamepad::PadOut gp_out = gamepad.get_pad_out();
//Spamming control xfers doesn't work, limit the rate
if (init_state_.reports_enabled &&
current_ms - last_rumble_ms >= 300)
{
uint8_t rumble_l = gamepad.get_rumble_l().uint8();
uint8_t rumble_r = gamepad.get_rumble_r().uint8();
out_report_.rumble.right_duration = (gp_out.rumble_r > 0) ? 20 : 0;
out_report_.rumble.right_motor_on = (gp_out.rumble_r > 0) ? 1 : 0;
out_report_.rumble.right_duration = (rumble_r > 0) ? 20 : 0;
out_report_.rumble.right_motor_on = (rumble_r > 0) ? 1 : 0;
out_report_.rumble.left_duration = (rumble_l > 0) ? 20 : 0;
out_report_.rumble.left_motor_force = rumble_l;
out_report_.rumble.left_duration = (gp_out.rumble_l > 0) ? 20 : 0;
out_report_.rumble.left_motor_force = gp_out.rumble_l;
last_rumble_ms = current_ms;

View File

@@ -1,4 +1,5 @@
#include <cstring>
#include <algorithm>
#include "host/usbh.h"
#include "class/hid/hid_host.h"
@@ -23,58 +24,60 @@ void PS4Host::process_report(Gamepad& gamepad, uint8_t address, uint8_t instance
return;
}
gamepad.reset_buttons();
Gamepad::PadIn gp_in;
switch (in_report_.buttons[0] & PS4::DPAD_MASK)
{
case PS4::Buttons0::DPAD_UP:
gamepad.set_dpad_up();
gp_in.dpad |= gamepad.MAP_DPAD_UP;
break;
case PS4::Buttons0::DPAD_DOWN:
gamepad.set_dpad_down();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN;
break;
case PS4::Buttons0::DPAD_LEFT:
gamepad.set_dpad_left();
gp_in.dpad |= gamepad.MAP_DPAD_LEFT;
break;
case PS4::Buttons0::DPAD_RIGHT:
gamepad.set_dpad_right();
gp_in.dpad |= gamepad.MAP_DPAD_RIGHT;
break;
case PS4::Buttons0::DPAD_UP_RIGHT:
gamepad.set_dpad_up_right();
gp_in.dpad |= gamepad.MAP_DPAD_UP_RIGHT;
break;
case PS4::Buttons0::DPAD_RIGHT_DOWN:
gamepad.set_dpad_down_right();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN_RIGHT;
break;
case PS4::Buttons0::DPAD_DOWN_LEFT:
gamepad.set_dpad_down_left();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN_LEFT;
break;
case PS4::Buttons0::DPAD_LEFT_UP:
gamepad.set_dpad_up_left();
gp_in.dpad |= gamepad.MAP_DPAD_UP_LEFT;
break;
default:
break;
}
if (in_report_.buttons[0] & PS4::Buttons0::SQUARE) gamepad.set_button_x();
if (in_report_.buttons[0] & PS4::Buttons0::CROSS) gamepad.set_button_a();
if (in_report_.buttons[0] & PS4::Buttons0::CIRCLE) gamepad.set_button_b();
if (in_report_.buttons[0] & PS4::Buttons0::TRIANGLE) gamepad.set_button_y();
if (in_report_.buttons[1] & PS4::Buttons1::L1) gamepad.set_button_lb();
if (in_report_.buttons[1] & PS4::Buttons1::R1) gamepad.set_button_rb();
if (in_report_.buttons[1] & PS4::Buttons1::L3) gamepad.set_button_l3();
if (in_report_.buttons[1] & PS4::Buttons1::R3) gamepad.set_button_r3();
if (in_report_.buttons[1] & PS4::Buttons1::SHARE) gamepad.set_button_back();
if (in_report_.buttons[1] & PS4::Buttons1::OPTIONS) gamepad.set_button_start();
if (in_report_.buttons[2] & PS4::Buttons2::PS) gamepad.set_button_sys();
if (in_report_.buttons[2] & PS4::Buttons2::TP) gamepad.set_button_misc();
if (in_report_.buttons[0] & PS4::Buttons0::SQUARE) gp_in.buttons |= gamepad.MAP_BUTTON_X;
if (in_report_.buttons[0] & PS4::Buttons0::CROSS) gp_in.buttons |= gamepad.MAP_BUTTON_A;
if (in_report_.buttons[0] & PS4::Buttons0::CIRCLE) gp_in.buttons |= gamepad.MAP_BUTTON_B;
if (in_report_.buttons[0] & PS4::Buttons0::TRIANGLE) gp_in.buttons |= gamepad.MAP_BUTTON_Y;
if (in_report_.buttons[1] & PS4::Buttons1::L1) gp_in.buttons |= gamepad.MAP_BUTTON_LB;
if (in_report_.buttons[1] & PS4::Buttons1::R1) gp_in.buttons |= gamepad.MAP_BUTTON_RB;
if (in_report_.buttons[1] & PS4::Buttons1::L3) gp_in.buttons |= gamepad.MAP_BUTTON_L3;
if (in_report_.buttons[1] & PS4::Buttons1::R3) gp_in.buttons |= gamepad.MAP_BUTTON_R3;
if (in_report_.buttons[1] & PS4::Buttons1::SHARE) gp_in.buttons |= gamepad.MAP_BUTTON_BACK;
if (in_report_.buttons[1] & PS4::Buttons1::OPTIONS) gp_in.buttons |= gamepad.MAP_BUTTON_START;
if (in_report_.buttons[2] & PS4::Buttons2::PS) gp_in.buttons |= gamepad.MAP_BUTTON_SYS;
if (in_report_.buttons[2] & PS4::Buttons2::TP) gp_in.buttons |= gamepad.MAP_BUTTON_MISC;
gamepad.set_trigger_l(in_report_.trigger_l);
gamepad.set_trigger_r(in_report_.trigger_r);
gp_in.trigger_l = in_report_.trigger_l;
gp_in.trigger_r = in_report_.trigger_r;
gamepad.set_joystick_lx(in_report_.joystick_lx);
gamepad.set_joystick_ly(in_report_.joystick_ly);
gamepad.set_joystick_rx(in_report_.joystick_rx);
gamepad.set_joystick_ry(in_report_.joystick_ry);
gp_in.joystick_lx = Scale::uint8_to_int16(in_report_.joystick_lx);
gp_in.joystick_ly = Scale::uint8_to_int16(in_report_.joystick_ly);
gp_in.joystick_rx = Scale::uint8_to_int16(in_report_.joystick_rx);
gp_in.joystick_ry = Scale::uint8_to_int16(in_report_.joystick_ry);
gamepad.set_pad_in(gp_in);
tuh_hid_receive_report(address, instance);
std::memcpy(&prev_in_report_, &in_report_, sizeof(PS4::InReport));
@@ -82,8 +85,9 @@ void PS4Host::process_report(Gamepad& gamepad, uint8_t address, uint8_t instance
bool PS4Host::send_feedback(Gamepad& gamepad, uint8_t address, uint8_t instance)
{
out_report_.motor_left = gamepad.get_rumble_l().uint8();
out_report_.motor_right = gamepad.get_rumble_r().uint8();
Gamepad::PadOut gp_out = gamepad.get_pad_out();
out_report_.motor_left = gp_out.rumble_l;
out_report_.motor_right = gp_out.rumble_r;
out_report_.set_rumble = (out_report_.motor_left != 0 || out_report_.motor_right != 0) ? 1 : 0;
if (tuh_hid_send_report(address, instance, 0, reinterpret_cast<const uint8_t*>(&out_report_), sizeof(PS4::OutReport)))

View File

@@ -27,58 +27,60 @@ void PS5Host::process_report(Gamepad& gamepad, uint8_t address, uint8_t instance
return;
}
gamepad.reset_buttons();
Gamepad::PadIn gp_in;
switch (in_report_.buttons[0] & PS5::DPAD_MASK)
{
case PS5::Buttons0::DPAD_UP:
gamepad.set_dpad_up();
gp_in.dpad |= gamepad.MAP_DPAD_UP;
break;
case PS5::Buttons0::DPAD_UP_RIGHT:
gamepad.set_dpad_up_right();
gp_in.dpad |= gamepad.MAP_DPAD_UP_RIGHT;
break;
case PS5::Buttons0::DPAD_RIGHT:
gamepad.set_dpad_right();
gp_in.dpad |= gamepad.MAP_DPAD_RIGHT;
break;
case PS5::Buttons0::DPAD_RIGHT_DOWN:
gamepad.set_dpad_down_right();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN_RIGHT;
break;
case PS5::Buttons0::DPAD_DOWN:
gamepad.set_dpad_down();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN;
break;
case PS5::Buttons0::DPAD_DOWN_LEFT:
gamepad.set_dpad_down_left();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN_LEFT;
break;
case PS5::Buttons0::DPAD_LEFT:
gamepad.set_dpad_left();
gp_in.dpad |= gamepad.MAP_DPAD_LEFT;
break;
case PS5::Buttons0::DPAD_LEFT_UP:
gamepad.set_dpad_up_left();
gp_in.dpad |= gamepad.MAP_DPAD_UP_LEFT;
break;
default:
break;
}
if (in_report_.buttons[0] & PS5::Buttons0::SQUARE) gamepad.set_button_x();
if (in_report_.buttons[0] & PS5::Buttons0::CROSS) gamepad.set_button_a();
if (in_report_.buttons[0] & PS5::Buttons0::CIRCLE) gamepad.set_button_b();
if (in_report_.buttons[0] & PS5::Buttons0::TRIANGLE) gamepad.set_button_y();
if (in_report_.buttons[1] & PS5::Buttons1::L1) gamepad.set_button_lb();
if (in_report_.buttons[1] & PS5::Buttons1::R1) gamepad.set_button_rb();
if (in_report_.buttons[1] & PS5::Buttons1::L3) gamepad.set_button_l3();
if (in_report_.buttons[1] & PS5::Buttons1::R3) gamepad.set_button_r3();
if (in_report_.buttons[1] & PS5::Buttons1::SHARE) gamepad.set_button_back();
if (in_report_.buttons[1] & PS5::Buttons1::OPTIONS) gamepad.set_button_start();
if (in_report_.buttons[2] & PS5::Buttons2::PS) gamepad.set_button_sys();
if (in_report_.buttons[2] & PS5::Buttons2::MUTE) gamepad.set_button_misc();
gamepad.set_trigger_l(in_report_.trigger_l);
gamepad.set_trigger_r(in_report_.trigger_r);
if (in_report_.buttons[0] & PS5::Buttons0::SQUARE) gp_in.buttons |= gamepad.MAP_BUTTON_X;
if (in_report_.buttons[0] & PS5::Buttons0::CROSS) gp_in.buttons |= gamepad.MAP_BUTTON_A;
if (in_report_.buttons[0] & PS5::Buttons0::CIRCLE) gp_in.buttons |= gamepad.MAP_BUTTON_B;
if (in_report_.buttons[0] & PS5::Buttons0::TRIANGLE) gp_in.buttons |= gamepad.MAP_BUTTON_Y;
if (in_report_.buttons[1] & PS5::Buttons1::L1) gp_in.buttons |= gamepad.MAP_BUTTON_LB;
if (in_report_.buttons[1] & PS5::Buttons1::R1) gp_in.buttons |= gamepad.MAP_BUTTON_RB;
if (in_report_.buttons[1] & PS5::Buttons1::L3) gp_in.buttons |= gamepad.MAP_BUTTON_L3;
if (in_report_.buttons[1] & PS5::Buttons1::R3) gp_in.buttons |= gamepad.MAP_BUTTON_R3;
if (in_report_.buttons[1] & PS5::Buttons1::SHARE) gp_in.buttons |= gamepad.MAP_BUTTON_BACK;
if (in_report_.buttons[1] & PS5::Buttons1::OPTIONS) gp_in.buttons |= gamepad.MAP_BUTTON_START;
if (in_report_.buttons[2] & PS5::Buttons2::PS) gp_in.buttons |= gamepad.MAP_BUTTON_SYS;
if (in_report_.buttons[2] & PS5::Buttons2::MUTE) gp_in.buttons |= gamepad.MAP_BUTTON_MISC;
gamepad.set_joystick_lx(in_report_.joystick_lx);
gamepad.set_joystick_ly(in_report_.joystick_ly);
gamepad.set_joystick_rx(in_report_.joystick_rx);
gamepad.set_joystick_ry(in_report_.joystick_ry);
gp_in.trigger_l = in_report_.trigger_l;
gp_in.trigger_r = in_report_.trigger_r;
gp_in.joystick_lx = Scale::uint8_to_int16(in_report_.joystick_lx);
gp_in.joystick_ly = Scale::uint8_to_int16(in_report_.joystick_ly);
gp_in.joystick_rx = Scale::uint8_to_int16(in_report_.joystick_rx);
gp_in.joystick_ry = Scale::uint8_to_int16(in_report_.joystick_ry);
gamepad.set_pad_in(gp_in);
tuh_hid_receive_report(address, instance);
std::memcpy(&prev_in_report_, &in_report_, PS5::IN_REPORT_CMP_SIZE);
@@ -86,8 +88,9 @@ void PS5Host::process_report(Gamepad& gamepad, uint8_t address, uint8_t instance
bool PS5Host::send_feedback(Gamepad& gamepad, uint8_t address, uint8_t instance)
{
out_report_.motor_left = gamepad.get_rumble_l().uint8();
out_report_.motor_right = gamepad.get_rumble_r().uint8();
Gamepad::PadOut gp_out = gamepad.get_pad_out();
out_report_.motor_left = gp_out.rumble_l;
out_report_.motor_right = gp_out.rumble_r;
if (tuh_hid_send_report(address, instance, 0, &out_report_, sizeof(PS5::OutReport)))
{

View File

@@ -19,49 +19,51 @@ void PSClassicHost::process_report(Gamepad& gamepad, uint8_t address, uint8_t in
return;
}
gamepad.reset_buttons();
Gamepad::PadIn gp_in;
switch (in_report->buttons & PSClassic::DPAD_MASK)
{
case PSClassic::Buttons::UP:
gamepad.set_dpad_up();
gp_in.dpad |= gamepad.MAP_DPAD_UP;
break;
case PSClassic::Buttons::DOWN:
gamepad.set_dpad_down();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN;
break;
case PSClassic::Buttons::LEFT:
gamepad.set_dpad_left();
gp_in.dpad |= gamepad.MAP_DPAD_LEFT;
break;
case PSClassic::Buttons::RIGHT:
gamepad.set_dpad_right();
gp_in.dpad |= gamepad.MAP_DPAD_RIGHT;
break;
case PSClassic::Buttons::UP_RIGHT:
gamepad.set_dpad_up_right();
gp_in.dpad |= gamepad.MAP_DPAD_UP_RIGHT;
break;
case PSClassic::Buttons::DOWN_RIGHT:
gamepad.set_dpad_down_right();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN_RIGHT;
break;
case PSClassic::Buttons::DOWN_LEFT:
gamepad.set_dpad_down_left();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN_LEFT;
break;
case PSClassic::Buttons::UP_LEFT:
gamepad.set_dpad_up_left();
gp_in.dpad |= gamepad.MAP_DPAD_UP_LEFT;
break;
default:
break;
}
if (in_report->buttons & PSClassic::Buttons::SQUARE) gamepad.set_button_x();
if (in_report->buttons & PSClassic::Buttons::CROSS) gamepad.set_button_a();
if (in_report->buttons & PSClassic::Buttons::CIRCLE) gamepad.set_button_b();
if (in_report->buttons & PSClassic::Buttons::TRIANGLE) gamepad.set_button_y();
if (in_report->buttons & PSClassic::Buttons::L1) gamepad.set_button_lb();
if (in_report->buttons & PSClassic::Buttons::R1) gamepad.set_button_rb();
if (in_report->buttons & PSClassic::Buttons::SELECT) gamepad.set_button_back();
if (in_report->buttons & PSClassic::Buttons::START) gamepad.set_button_start();
if (in_report->buttons & PSClassic::Buttons::SQUARE) gp_in.buttons |= gamepad.MAP_BUTTON_X;
if (in_report->buttons & PSClassic::Buttons::CROSS) gp_in.buttons |= gamepad.MAP_BUTTON_A;
if (in_report->buttons & PSClassic::Buttons::CIRCLE) gp_in.buttons |= gamepad.MAP_BUTTON_B;
if (in_report->buttons & PSClassic::Buttons::TRIANGLE) gp_in.buttons |= gamepad.MAP_BUTTON_Y;
if (in_report->buttons & PSClassic::Buttons::L1) gp_in.buttons |= gamepad.MAP_BUTTON_LB;
if (in_report->buttons & PSClassic::Buttons::R1) gp_in.buttons |= gamepad.MAP_BUTTON_RB;
if (in_report->buttons & PSClassic::Buttons::SELECT) gp_in.buttons |= gamepad.MAP_BUTTON_BACK;
if (in_report->buttons & PSClassic::Buttons::START) gp_in.buttons |= gamepad.MAP_BUTTON_START;
gamepad.set_trigger_l(in_report->buttons);
gamepad.set_trigger_r(in_report->buttons);
gp_in.trigger_l = (in_report->buttons & PSClassic::Buttons::L2) ? UINT_8::MAX : UINT_8::MIN;
gp_in.trigger_r = (in_report->buttons & PSClassic::Buttons::R2) ? UINT_8::MAX : UINT_8::MIN;
gamepad.set_pad_in(gp_in);
tuh_hid_receive_report(address, instance);
std::memcpy(&prev_in_report_, &in_report, sizeof(PSClassic::InReport));

View File

@@ -9,82 +9,177 @@
void SwitchProHost::initialize(Gamepad& gamepad, uint8_t address, uint8_t instance, const uint8_t* report_desc, uint16_t desc_len)
{
std::memset(&out_report_, 0, sizeof(out_report_));
state_.handshake_sent = send_handshake(address, instance);
tuh_hid_receive_report(address, instance);
init_switch_host(gamepad, address, instance);
}
bool SwitchProHost::send_handshake(uint8_t address, uint8_t instance)
{
std::array<uint8_t, 2> handshake = { SwitchPro::CMD::HID, SwitchPro::CMD::HANDSHAKE };
return tuh_hid_send_report(address, instance, 0, handshake.data(), handshake.size());
}
// bool SwitchProHost::send_handshake(uint8_t address, uint8_t instance)
// {
// std::array<uint8_t, 2> handshake = { SwitchPro::CMD::HID, SwitchPro::CMD::HANDSHAKE };
// return tuh_hid_send_report(address, instance, 0, handshake.data(), handshake.size());
// }
bool SwitchProHost::disable_timeout(uint8_t address, uint8_t instance)
{
std::array<uint8_t, 2> timeout = { SwitchPro::CMD::HID, SwitchPro::CMD::DISABLE_TIMEOUT };
return tuh_hid_send_report(address, instance, 0, timeout.data(), timeout.size());
}
// bool SwitchProHost::disable_timeout(uint8_t address, uint8_t instance)
// {
// std::array<uint8_t, 2> timeout = { SwitchPro::CMD::HID, SwitchPro::CMD::DISABLE_TIMEOUT };
// return tuh_hid_send_report(address, instance, 0, timeout.data(), timeout.size());
// }
uint8_t SwitchProHost::get_output_sequence_counter()
{
uint8_t counter = state_.sequence_counter;
state_.sequence_counter = (state_.sequence_counter + 1) & 0x0F;
uint8_t counter = sequence_counter_;
sequence_counter_ = (sequence_counter_ + 1) & 0x0F;
return counter;
}
// The other way is to write a class driver just for switch pro, we'll see if there are issues with this
void SwitchProHost::init_switch_host(Gamepad& gamepad, uint8_t address, uint8_t instance)
{
// See: https://github.com/Dan611/hid-procon
// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering
// https://github.com/HisashiKato/USB_Host_Shield_Library_2.0
std::memset(&out_report_, 0, sizeof(out_report_));
uint8_t report_size = 10;
out_report_.command = SwitchPro::CMD::RUMBLE_ONLY;
out_report_.sequence_counter = get_output_sequence_counter();
out_report_.rumble_l[0] = 0x00;
out_report_.rumble_l[1] = 0x01;
out_report_.rumble_l[2] = 0x40;
out_report_.rumble_l[3] = 0x40;
out_report_.rumble_r[0] = 0x00;
out_report_.rumble_r[1] = 0x01;
out_report_.rumble_r[2] = 0x40;
out_report_.rumble_r[3] = 0x40;
switch (init_state_)
{
case InitState::HANDSHAKE:
report_size = 2;
out_report_.command = SwitchPro::CMD::HID;
out_report_.sequence_counter = SwitchPro::CMD::HANDSHAKE;
if(tuh_hid_send_report(address, instance, 0, &out_report_, report_size))
{
init_state_ = InitState::TIMEOUT;
}
break;
case InitState::TIMEOUT:
report_size = 2;
out_report_.command = SwitchPro::CMD::HID;
out_report_.sequence_counter = SwitchPro::CMD::DISABLE_TIMEOUT;
if(tuh_hid_send_report(address, instance, 0, &out_report_, report_size))
{
init_state_ = InitState::LED;
}
break;
case InitState::LED:
report_size = 12;
out_report_.command = SwitchPro::CMD::AND_RUMBLE;
out_report_.sub_command = SwitchPro::CMD::LED;
out_report_.sub_command_args[0] = idx_ + 1;
if(tuh_hid_send_report(address, instance, 0, &out_report_, report_size))
{
init_state_ = InitState::LED_HOME;
}
break;
case InitState::LED_HOME:
report_size = 14;
out_report_.command = SwitchPro::CMD::AND_RUMBLE;
out_report_.sub_command = SwitchPro::CMD::LED_HOME;
out_report_.sub_command_args[0] = (0 /* Number of cycles */ << 4) | (true ? 0xF : 0);
out_report_.sub_command_args[1] = (0xF /* LED start intensity */ << 4) | 0x0 /* Number of full cycles */;
out_report_.sub_command_args[2] = (0xF /* Mini Cycle 1 LED intensity */ << 4) | 0x0 /* Mini Cycle 2 LED intensity */;
if(tuh_hid_send_report(address, instance, 0, &out_report_, report_size))
{
init_state_ = InitState::FULL_REPORT;
}
break;
case InitState::FULL_REPORT:
report_size = 12;
out_report_.command = SwitchPro::CMD::AND_RUMBLE;
out_report_.sub_command = SwitchPro::CMD::MODE;
out_report_.sub_command_args[0] = SwitchPro::CMD::FULL_REPORT_MODE;
if (tuh_hid_send_report(address, instance, 0, &out_report_, report_size))
{
init_state_ = InitState::IMU;
}
break;
case InitState::IMU:
report_size = 12;
out_report_.command = SwitchPro::CMD::AND_RUMBLE;
out_report_.sub_command = SwitchPro::CMD::GYRO;
out_report_.sub_command_args[0] = 1 ? 1 : 0;
if (tuh_hid_send_report(address, instance, 0, &out_report_, report_size))
{
init_state_ = InitState::DONE;
}
break;
default:
break;
}
tuh_hid_receive_report(address, instance);
}
void SwitchProHost::process_report(Gamepad& gamepad, uint8_t address, uint8_t instance, const uint8_t* report, uint16_t len)
{
if (!state_.handshake_sent)
if (init_state_ != InitState::DONE)
{
return;
}
else if (!state_.timeout_disabled)
{
state_.timeout_disabled = disable_timeout(address, instance);
tuh_hid_receive_report(address, instance);
init_switch_host(gamepad, address, instance);
return;
}
const SwitchPro::InReport* in_report = reinterpret_cast<const SwitchPro::InReport*>(report);
if (std::memcmp(&prev_in_report_.buttons, in_report->buttons, 9) == 0)
{
tuh_hid_receive_report(address, instance);
return;
}
gamepad.reset_buttons();
Gamepad::PadIn gp_in;
if (in_report->buttons[0] & SwitchPro::Buttons0::Y) gamepad.set_button_x();
if (in_report->buttons[0] & SwitchPro::Buttons0::B) gamepad.set_button_a();
if (in_report->buttons[0] & SwitchPro::Buttons0::A) gamepad.set_button_b();
if (in_report->buttons[0] & SwitchPro::Buttons0::X) gamepad.set_button_y();
if (in_report->buttons[2] & SwitchPro::Buttons2::L) gamepad.set_button_lb();
if (in_report->buttons[0] & SwitchPro::Buttons0::R) gamepad.set_button_rb();
if (in_report->buttons[1] & SwitchPro::Buttons1::L3) gamepad.set_button_l3();
if (in_report->buttons[1] & SwitchPro::Buttons1::R3) gamepad.set_button_r3();
if (in_report->buttons[1] & SwitchPro::Buttons1::MINUS) gamepad.set_button_back();
if (in_report->buttons[1] & SwitchPro::Buttons1::PLUS) gamepad.set_button_start();
if (in_report->buttons[1] & SwitchPro::Buttons1::HOME) gamepad.set_button_sys();
if (in_report->buttons[1] & SwitchPro::Buttons1::CAPTURE) gamepad.set_button_misc();
if (in_report->buttons[0] & SwitchPro::Buttons0::Y) gp_in.buttons |= gamepad.MAP_BUTTON_X;
if (in_report->buttons[0] & SwitchPro::Buttons0::B) gp_in.buttons |= gamepad.MAP_BUTTON_A;
if (in_report->buttons[0] & SwitchPro::Buttons0::A) gp_in.buttons |= gamepad.MAP_BUTTON_B;
if (in_report->buttons[0] & SwitchPro::Buttons0::X) gp_in.buttons |= gamepad.MAP_BUTTON_Y;
if (in_report->buttons[2] & SwitchPro::Buttons2::L) gp_in.buttons |= gamepad.MAP_BUTTON_LB;
if (in_report->buttons[0] & SwitchPro::Buttons0::R) gp_in.buttons |= gamepad.MAP_BUTTON_RB;
if (in_report->buttons[1] & SwitchPro::Buttons1::L3) gp_in.buttons |= gamepad.MAP_BUTTON_L3;
if (in_report->buttons[1] & SwitchPro::Buttons1::R3) gp_in.buttons |= gamepad.MAP_BUTTON_R3;
if (in_report->buttons[1] & SwitchPro::Buttons1::MINUS) gp_in.buttons |= gamepad.MAP_BUTTON_BACK;
if (in_report->buttons[1] & SwitchPro::Buttons1::PLUS) gp_in.buttons |= gamepad.MAP_BUTTON_START;
if (in_report->buttons[1] & SwitchPro::Buttons1::HOME) gp_in.buttons |= gamepad.MAP_BUTTON_SYS;
if (in_report->buttons[1] & SwitchPro::Buttons1::CAPTURE) gp_in.buttons |= gamepad.MAP_BUTTON_MISC;
if (in_report->buttons[2] & SwitchPro::Buttons2::DPAD_UP) gamepad.set_dpad_up();
if (in_report->buttons[2] & SwitchPro::Buttons2::DPAD_DOWN) gamepad.set_dpad_down();
if (in_report->buttons[2] & SwitchPro::Buttons2::DPAD_LEFT) gamepad.set_dpad_left();
if (in_report->buttons[2] & SwitchPro::Buttons2::DPAD_RIGHT) gamepad.set_dpad_right();
gamepad.set_trigger_l(in_report->buttons[2] & SwitchPro::Buttons2::ZL ? UINT_8::MAX : UINT_8::MIN);
gamepad.set_trigger_r(in_report->buttons[0] & SwitchPro::Buttons0::ZR ? UINT_8::MAX : UINT_8::MIN);
if (in_report->buttons[2] & SwitchPro::Buttons2::DPAD_UP) gp_in.dpad |= gamepad.MAP_DPAD_UP;
if (in_report->buttons[2] & SwitchPro::Buttons2::DPAD_DOWN) gp_in.dpad |= gamepad.MAP_DPAD_DOWN;
if (in_report->buttons[2] & SwitchPro::Buttons2::DPAD_LEFT) gp_in.dpad |= gamepad.MAP_DPAD_LEFT;
if (in_report->buttons[2] & SwitchPro::Buttons2::DPAD_RIGHT) gp_in.dpad |= gamepad.MAP_DPAD_RIGHT;
int16_t joy_lx = normalize_axis(in_report->joysticks[0] | ((in_report->joysticks[1] & 0xF) << 8));
int16_t joy_ly = normalize_axis((in_report->joysticks[1] >> 4) | (in_report->joysticks[2] << 4));
int16_t joy_rx = normalize_axis(in_report->joysticks[3] | ((in_report->joysticks[4] & 0xF) << 8));
int16_t joy_ry = normalize_axis((in_report->joysticks[4] >> 4) | (in_report->joysticks[5] << 4));
gp_in.trigger_l = in_report->buttons[2] & SwitchPro::Buttons2::ZL ? UINT_8::MAX : UINT_8::MIN;
gp_in.trigger_r = in_report->buttons[0] & SwitchPro::Buttons0::ZR ? UINT_8::MAX : UINT_8::MIN;
gamepad.set_joystick_lx(joy_lx);
gamepad.set_joystick_ly(joy_ly, true);
gamepad.set_joystick_rx(joy_rx);
gamepad.set_joystick_ry(joy_ry, true);
gp_in.joystick_lx = normalize_axis(in_report->joysticks[0] | ((in_report->joysticks[1] & 0xF) << 8));
gp_in.joystick_ly = Scale::invert_joy(normalize_axis((in_report->joysticks[1] >> 4) | (in_report->joysticks[2] << 4)));
gp_in.joystick_rx = normalize_axis(in_report->joysticks[3] | ((in_report->joysticks[4] & 0xF) << 8));
gp_in.joystick_ry = Scale::invert_joy(normalize_axis((in_report->joysticks[4] >> 4) | (in_report->joysticks[5] << 4)));
gamepad.set_pad_in(gp_in);
tuh_hid_receive_report(address, instance);
std::memcpy(&prev_in_report_, in_report, sizeof(SwitchPro::InReport));
@@ -92,12 +187,9 @@ void SwitchProHost::process_report(Gamepad& gamepad, uint8_t address, uint8_t in
bool SwitchProHost::send_feedback(Gamepad& gamepad, uint8_t address, uint8_t instance)
{
if (!state_.handshake_sent)
{
state_.handshake_sent = send_handshake(address, instance);
}
else if (!state_.timeout_disabled)
if (init_state_ != InitState::DONE)
{
init_switch_host(gamepad, address, instance);
return false;
}
@@ -112,12 +204,11 @@ bool SwitchProHost::send_feedback(Gamepad& gamepad, uint8_t address, uint8_t ins
out_report_.command = SwitchPro::CMD::RUMBLE_ONLY;
out_report_.sequence_counter = get_output_sequence_counter();
uint8_t gp_rumble_l = gamepad.get_rumble_l().uint8();
uint8_t gp_rumble_r = gamepad.get_rumble_r().uint8();
Gamepad::PadOut gp_out = gamepad.get_pad_out();
if (gp_rumble_l > 0)
if (gp_out.rumble_l > 0)
{
uint8_t amplitude_l = static_cast<uint8_t>(((gp_rumble_l / 255.0f) * 0.8f + 0.5f) * (0xC0 - 0x40) + 0x40);
uint8_t amplitude_l = static_cast<uint8_t>(((gp_out.rumble_l / 255.0f) * 0.8f + 0.5f) * (0xC0 - 0x40) + 0x40);
out_report_.rumble_l[0] = amplitude_l;
out_report_.rumble_l[1] = 0x88;
@@ -132,9 +223,9 @@ bool SwitchProHost::send_feedback(Gamepad& gamepad, uint8_t address, uint8_t ins
out_report_.rumble_l[3] = 0x40;
}
if (gp_rumble_r > 0)
if (gp_out.rumble_r > 0)
{
uint8_t amplitude_r = static_cast<uint8_t>(((gp_rumble_r / 255.0f) * 0.8f + 0.5f) * (0xC0 - 0x40) + 0x40);
uint8_t amplitude_r = static_cast<uint8_t>(((gp_out.rumble_r / 255.0f) * 0.8f + 0.5f) * (0xC0 - 0x40) + 0x40);
out_report_.rumble_r[0] = amplitude_r;
out_report_.rumble_r[1] = 0x88;
@@ -149,63 +240,5 @@ bool SwitchProHost::send_feedback(Gamepad& gamepad, uint8_t address, uint8_t ins
out_report_.rumble_r[3] = 0x40;
}
if (!state_.commands_sent)
{
if (!state_.led_set)
{
report_size = 12;
out_report_.command = SwitchPro::CMD::AND_RUMBLE;
out_report_.sub_command = SwitchPro::CMD::LED;
out_report_.sub_command_args[0] = idx_ + 1;
state_.led_set = tuh_hid_send_report(address, instance, 0, &out_report_, report_size);
return state_.led_set;
}
else if (!state_.led_home_set)
{
report_size = 14;
out_report_.command = SwitchPro::CMD::AND_RUMBLE;
out_report_.sub_command = SwitchPro::CMD::LED_HOME;
out_report_.sub_command_args[0] = (0 /* Number of cycles */ << 4) | (true ? 0xF : 0);
out_report_.sub_command_args[1] = (0xF /* LED start intensity */ << 4) | 0x0 /* Number of full cycles */;
out_report_.sub_command_args[2] = (0xF /* Mini Cycle 1 LED intensity */ << 4) | 0x0 /* Mini Cycle 2 LED intensity */;
state_.led_home_set = tuh_hid_send_report(address, instance, 0, &out_report_, report_size);
return state_.led_home_set;
}
else if (!state_.full_report_enabled)
{
report_size = 12;
out_report_.command = SwitchPro::CMD::AND_RUMBLE;
out_report_.sub_command = SwitchPro::CMD::MODE;
out_report_.sub_command_args[0] = SwitchPro::CMD::FULL_REPORT_MODE;
state_.full_report_enabled = tuh_hid_send_report(address, instance, 0, &out_report_, report_size);
return state_.full_report_enabled;
}
else if (!state_.imu_enabled)
{
report_size = 12;
out_report_.command = SwitchPro::CMD::AND_RUMBLE;
out_report_.sub_command = SwitchPro::CMD::GYRO;
out_report_.sub_command_args[0] = 1 ? 1 : 0;
state_.imu_enabled = tuh_hid_send_report(address, instance, 0, &out_report_, report_size);
return state_.imu_enabled;
}
else
{
state_.commands_sent = true;
}
}
return tuh_hid_send_report(address, instance, 0, &out_report_, report_size);
}

View File

@@ -17,24 +17,26 @@ public:
bool send_feedback(Gamepad& gamepad, uint8_t address, uint8_t instance) override;
private:
struct State
enum class InitState
{
bool handshake_sent{false};
bool timeout_disabled{false};
bool full_report_enabled{false};
bool led_set{false};
bool led_home_set{false};
bool imu_enabled{false};
bool commands_sent{false};
uint8_t sequence_counter{0};
HANDSHAKE,
TIMEOUT,
FULL_REPORT,
LED,
LED_HOME,
IMU,
DONE
};
State state_{};
InitState init_state_{InitState::HANDSHAKE};
uint8_t sequence_counter_{0};
SwitchPro::InReport prev_in_report_{};
SwitchPro::OutReport out_report_{};
bool send_handshake(uint8_t address, uint8_t instance);
bool disable_timeout(uint8_t address, uint8_t instance);
void init_switch_host(Gamepad& gamepad, uint8_t address, uint8_t instance);
// bool send_handshake(uint8_t address, uint8_t instance);
// bool disable_timeout(uint8_t address, uint8_t instance);
uint8_t get_output_sequence_counter();
static inline int16_t normalize_axis(uint16_t value)

View File

@@ -19,58 +19,60 @@ void SwitchWiredHost::process_report(Gamepad& gamepad, uint8_t address, uint8_t
return;
}
gamepad.reset_buttons();
Gamepad::PadIn gp_in;
switch (in_report->dpad)
{
case SwitchWired::DPad::UP:
gamepad.set_dpad_up();
gp_in.dpad |= gamepad.MAP_DPAD_UP;
break;
case SwitchWired::DPad::DOWN:
gamepad.set_dpad_down();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN;
break;
case SwitchWired::DPad::LEFT:
gamepad.set_dpad_left();
gp_in.dpad |= gamepad.MAP_DPAD_LEFT;
break;
case SwitchWired::DPad::RIGHT:
gamepad.set_dpad_right();
gp_in.dpad |= gamepad.MAP_DPAD_RIGHT;
break;
case SwitchWired::DPad::UP_RIGHT:
gamepad.set_dpad_up_right();
gp_in.dpad |= gamepad.MAP_DPAD_UP_RIGHT;
break;
case SwitchWired::DPad::DOWN_RIGHT:
gamepad.set_dpad_down_right();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN_RIGHT;
break;
case SwitchWired::DPad::DOWN_LEFT:
gamepad.set_dpad_down_left();
gp_in.dpad |= gamepad.MAP_DPAD_DOWN_LEFT;
break;
case SwitchWired::DPad::UP_LEFT:
gamepad.set_dpad_up_left();
gp_in.dpad |= gamepad.MAP_DPAD_UP_LEFT;
break;
default:
break;
}
if (in_report->buttons & SwitchWired::Buttons::Y) gamepad.set_button_x();
if (in_report->buttons & SwitchWired::Buttons::B) gamepad.set_button_a();
if (in_report->buttons & SwitchWired::Buttons::A) gamepad.set_button_b();
if (in_report->buttons & SwitchWired::Buttons::X) gamepad.set_button_y();
if (in_report->buttons & SwitchWired::Buttons::L) gamepad.set_button_lb();
if (in_report->buttons & SwitchWired::Buttons::R) gamepad.set_button_rb();
if (in_report->buttons & SwitchWired::Buttons::MINUS) gamepad.set_button_back();
if (in_report->buttons & SwitchWired::Buttons::PLUS) gamepad.set_button_start();
if (in_report->buttons & SwitchWired::Buttons::HOME) gamepad.set_button_sys();
if (in_report->buttons & SwitchWired::Buttons::CAPTURE) gamepad.set_button_misc();
if (in_report->buttons & SwitchWired::Buttons::L3) gamepad.set_button_l3();
if (in_report->buttons & SwitchWired::Buttons::R3) gamepad.set_button_r3();
if (in_report->buttons & SwitchWired::Buttons::Y) gp_in.buttons |= gamepad.MAP_BUTTON_X;
if (in_report->buttons & SwitchWired::Buttons::B) gp_in.buttons |= gamepad.MAP_BUTTON_A;
if (in_report->buttons & SwitchWired::Buttons::A) gp_in.buttons |= gamepad.MAP_BUTTON_B;
if (in_report->buttons & SwitchWired::Buttons::X) gp_in.buttons |= gamepad.MAP_BUTTON_Y;
if (in_report->buttons & SwitchWired::Buttons::L) gp_in.buttons |= gamepad.MAP_BUTTON_LB;
if (in_report->buttons & SwitchWired::Buttons::R) gp_in.buttons |= gamepad.MAP_BUTTON_RB;
if (in_report->buttons & SwitchWired::Buttons::MINUS) gp_in.buttons |= gamepad.MAP_BUTTON_BACK;
if (in_report->buttons & SwitchWired::Buttons::PLUS) gp_in.buttons |= gamepad.MAP_BUTTON_START;
if (in_report->buttons & SwitchWired::Buttons::HOME) gp_in.buttons |= gamepad.MAP_BUTTON_SYS;
if (in_report->buttons & SwitchWired::Buttons::CAPTURE) gp_in.buttons |= gamepad.MAP_BUTTON_MISC;
if (in_report->buttons & SwitchWired::Buttons::L3) gp_in.buttons |= gamepad.MAP_BUTTON_L3;
if (in_report->buttons & SwitchWired::Buttons::R3) gp_in.buttons |= gamepad.MAP_BUTTON_R3;
gamepad.set_trigger_l((in_report->buttons & SwitchWired::Buttons::ZL) ? UINT_8::MAX : UINT_8::MIN);
gamepad.set_trigger_r((in_report->buttons & SwitchWired::Buttons::ZR) ? UINT_8::MAX : UINT_8::MIN);
gp_in.trigger_l = (in_report->buttons & SwitchWired::Buttons::ZL) ? UINT_8::MAX : UINT_8::MIN;
gp_in.trigger_r = (in_report->buttons & SwitchWired::Buttons::ZR) ? UINT_8::MAX : UINT_8::MIN;
gamepad.set_joystick_lx(in_report->joystick_lx);
gamepad.set_joystick_ly(in_report->joystick_ly);
gamepad.set_joystick_rx(in_report->joystick_rx);
gamepad.set_joystick_ry(in_report->joystick_ry);
gp_in.joystick_lx = Scale::uint8_to_int16(in_report->joystick_lx);
gp_in.joystick_ly = Scale::uint8_to_int16(in_report->joystick_ly);
gp_in.joystick_rx = Scale::uint8_to_int16(in_report->joystick_rx);
gp_in.joystick_ry = Scale::uint8_to_int16(in_report->joystick_ry);
gamepad.set_pad_in(gp_in);
tuh_hid_receive_report(address, instance);
std::memcpy(&prev_in_report_, in_report, sizeof(SwitchWired::InReport));

View File

@@ -21,32 +21,34 @@ void Xbox360Host::process_report(Gamepad& gamepad, uint8_t address, uint8_t inst
return;
}
gamepad.reset_buttons();
Gamepad::PadIn gp_in;
if (in_report_->buttons[0] & XInput::Buttons0::DPAD_UP) gamepad.set_dpad_up();
if (in_report_->buttons[0] & XInput::Buttons0::DPAD_DOWN) gamepad.set_dpad_down();
if (in_report_->buttons[0] & XInput::Buttons0::DPAD_LEFT) gamepad.set_dpad_left();
if (in_report_->buttons[0] & XInput::Buttons0::DPAD_RIGHT) gamepad.set_dpad_right();
if (in_report_->buttons[0] & XInput::Buttons0::DPAD_UP) gp_in.dpad |= gamepad.MAP_DPAD_UP;
if (in_report_->buttons[0] & XInput::Buttons0::DPAD_DOWN) gp_in.dpad |= gamepad.MAP_DPAD_DOWN;
if (in_report_->buttons[0] & XInput::Buttons0::DPAD_LEFT) gp_in.dpad |= gamepad.MAP_DPAD_LEFT;
if (in_report_->buttons[0] & XInput::Buttons0::DPAD_RIGHT) gp_in.dpad |= gamepad.MAP_DPAD_RIGHT;
if (in_report_->buttons[0] & XInput::Buttons0::START) gamepad.set_button_start();
if (in_report_->buttons[0] & XInput::Buttons0::BACK) gamepad.set_button_back();
if (in_report_->buttons[0] & XInput::Buttons0::L3) gamepad.set_button_l3();
if (in_report_->buttons[0] & XInput::Buttons0::R3) gamepad.set_button_r3();
if (in_report_->buttons[1] & XInput::Buttons1::LB) gamepad.set_button_lb();
if (in_report_->buttons[1] & XInput::Buttons1::RB) gamepad.set_button_rb();
if (in_report_->buttons[1] & XInput::Buttons1::HOME) gamepad.set_button_sys();
if (in_report_->buttons[1] & XInput::Buttons1::A) gamepad.set_button_a();
if (in_report_->buttons[1] & XInput::Buttons1::B) gamepad.set_button_b();
if (in_report_->buttons[1] & XInput::Buttons1::X) gamepad.set_button_x();
if (in_report_->buttons[1] & XInput::Buttons1::Y) gamepad.set_button_y();
if (in_report_->buttons[0] & XInput::Buttons0::START) gp_in.buttons |= gamepad.MAP_BUTTON_START;
if (in_report_->buttons[0] & XInput::Buttons0::BACK) gp_in.buttons |= gamepad.MAP_BUTTON_BACK;
if (in_report_->buttons[0] & XInput::Buttons0::L3) gp_in.buttons |= gamepad.MAP_BUTTON_L3;
if (in_report_->buttons[0] & XInput::Buttons0::R3) gp_in.buttons |= gamepad.MAP_BUTTON_R3;
if (in_report_->buttons[1] & XInput::Buttons1::LB) gp_in.buttons |= gamepad.MAP_BUTTON_LB;
if (in_report_->buttons[1] & XInput::Buttons1::RB) gp_in.buttons |= gamepad.MAP_BUTTON_RB;
if (in_report_->buttons[1] & XInput::Buttons1::HOME) gp_in.buttons |= gamepad.MAP_BUTTON_SYS;
if (in_report_->buttons[1] & XInput::Buttons1::A) gp_in.buttons |= gamepad.MAP_BUTTON_A;
if (in_report_->buttons[1] & XInput::Buttons1::B) gp_in.buttons |= gamepad.MAP_BUTTON_B;
if (in_report_->buttons[1] & XInput::Buttons1::X) gp_in.buttons |= gamepad.MAP_BUTTON_X;
if (in_report_->buttons[1] & XInput::Buttons1::Y) gp_in.buttons |= gamepad.MAP_BUTTON_Y;
gamepad.set_trigger_l(in_report_->trigger_l);
gamepad.set_trigger_r(in_report_->trigger_r);
gp_in.trigger_l = in_report_->trigger_l;
gp_in.trigger_r = in_report_->trigger_r;
gamepad.set_joystick_lx(in_report_->joystick_lx);
gamepad.set_joystick_ly(in_report_->joystick_ly, true);
gamepad.set_joystick_rx(in_report_->joystick_rx);
gamepad.set_joystick_ry(in_report_->joystick_ry, true);
gp_in.joystick_lx = in_report_->joystick_lx;
gp_in.joystick_ly = Scale::invert_joy(in_report_->joystick_ly);
gp_in.joystick_rx = in_report_->joystick_rx;
gp_in.joystick_ry = Scale::invert_joy(in_report_->joystick_ry);
gamepad.set_pad_in(gp_in);
tuh_xinput::receive_report(address, instance);
std::memcpy(&prev_in_report_, in_report_, sizeof(XInput::InReport));
@@ -54,5 +56,6 @@ void Xbox360Host::process_report(Gamepad& gamepad, uint8_t address, uint8_t inst
bool Xbox360Host::send_feedback(Gamepad& gamepad, uint8_t address, uint8_t instance)
{
return tuh_xinput::set_rumble(address, 0, gamepad.get_rumble_l().uint8(), gamepad.get_rumble_r().uint8(), false);
Gamepad::PadOut gp_out = gamepad.get_pad_out();
return tuh_xinput::set_rumble(address, 0, gp_out.rumble_l, gp_out.rumble_r, false);
}

View File

@@ -1,7 +1,7 @@
#include <cstring>
#include "pico/stdlib.h"
#include "hardware/timer.h"
#include "hardware/irq.h"
#include <pico/stdlib.h>
#include <hardware/timer.h>
#include <hardware/irq.h>
#include "host/usbh.h"
@@ -10,7 +10,7 @@
Xbox360WHost::~Xbox360WHost()
{
cancel_repeating_timer(&timer_info_.timer);
TaskQueue::Core1::cancel_delayed_task(timer_info_.task_id);
}
void Xbox360WHost::initialize(Gamepad& gamepad, uint8_t address, uint8_t instance, const uint8_t* report_desc, uint16_t desc_len)
@@ -20,18 +20,17 @@ void Xbox360WHost::initialize(Gamepad& gamepad, uint8_t address, uint8_t instanc
timer_info_.address = address;
timer_info_.instance = instance;
timer_info_.led_quadrant = idx_ + 1;
timer_info_.task_id = TaskQueue::Core1::get_new_task_id();
add_repeating_timer_ms(1000, timer_cb, &timer_info_, &timer_info_.timer);
//Repeatedly set the LED incase of disconnect, may rework the XInput driver to handle this
TaskQueue::Core1::queue_delayed_task(timer_info_.task_id, 1000, true, [this]
{
tuh_xinput::set_led(timer_info_.address, timer_info_.instance, timer_info_.led_quadrant, false);
});
tuh_xinput::receive_report(address, instance);
}
bool Xbox360WHost::timer_cb(struct repeating_timer *t)
{
TimerInfo *info = static_cast<TimerInfo *>(t->user_data);
tuh_xinput::set_led(info->address, info->instance, info->led_quadrant, false);
return true;
}
void Xbox360WHost::process_report(Gamepad& gamepad, uint8_t address, uint8_t instance, const uint8_t* report, uint16_t len)
{
const XInput::InReportWireless* in_report = reinterpret_cast<const XInput::InReportWireless*>(report);
@@ -41,50 +40,41 @@ void Xbox360WHost::process_report(Gamepad& gamepad, uint8_t address, uint8_t ins
return;
}
gamepad.reset_buttons();
Gamepad::PadIn gp_in;
if (in_report->buttons[0] & XInput::Buttons0::DPAD_UP) gamepad.set_dpad_up();
if (in_report->buttons[0] & XInput::Buttons0::DPAD_DOWN) gamepad.set_dpad_down();
if (in_report->buttons[0] & XInput::Buttons0::DPAD_LEFT) gamepad.set_dpad_left();
if (in_report->buttons[0] & XInput::Buttons0::DPAD_RIGHT) gamepad.set_dpad_right();
if (in_report->buttons[0] & XInput::Buttons0::DPAD_UP) gp_in.dpad |= gamepad.MAP_DPAD_UP;
if (in_report->buttons[0] & XInput::Buttons0::DPAD_DOWN) gp_in.dpad |= gamepad.MAP_DPAD_DOWN;
if (in_report->buttons[0] & XInput::Buttons0::DPAD_LEFT) gp_in.dpad |= gamepad.MAP_DPAD_LEFT;
if (in_report->buttons[0] & XInput::Buttons0::DPAD_RIGHT) gp_in.dpad |= gamepad.MAP_DPAD_RIGHT;
if (in_report->buttons[0] & XInput::Buttons0::START) gamepad.set_button_start();
if (in_report->buttons[0] & XInput::Buttons0::BACK) gamepad.set_button_back();
if (in_report->buttons[0] & XInput::Buttons0::L3) gamepad.set_button_l3();
if (in_report->buttons[0] & XInput::Buttons0::R3) gamepad.set_button_r3();
if (in_report->buttons[1] & XInput::Buttons1::LB) gamepad.set_button_lb();
if (in_report->buttons[1] & XInput::Buttons1::RB) gamepad.set_button_rb();
if (in_report->buttons[1] & XInput::Buttons1::HOME) gamepad.set_button_sys();
if (in_report->buttons[1] & XInput::Buttons1::A) gamepad.set_button_a();
if (in_report->buttons[1] & XInput::Buttons1::B) gamepad.set_button_b();
if (in_report->buttons[1] & XInput::Buttons1::X) gamepad.set_button_x();
if (in_report->buttons[1] & XInput::Buttons1::Y) gamepad.set_button_y();
if (in_report->buttons[0] & XInput::Buttons0::START) gp_in.buttons |= gamepad.MAP_BUTTON_START;
if (in_report->buttons[0] & XInput::Buttons0::BACK) gp_in.buttons |= gamepad.MAP_BUTTON_BACK;
if (in_report->buttons[0] & XInput::Buttons0::L3) gp_in.buttons |= gamepad.MAP_BUTTON_L3;
if (in_report->buttons[0] & XInput::Buttons0::R3) gp_in.buttons |= gamepad.MAP_BUTTON_R3;
if (in_report->buttons[1] & XInput::Buttons1::LB) gp_in.buttons |= gamepad.MAP_BUTTON_LB;
if (in_report->buttons[1] & XInput::Buttons1::RB) gp_in.buttons |= gamepad.MAP_BUTTON_RB;
if (in_report->buttons[1] & XInput::Buttons1::HOME) gp_in.buttons |= gamepad.MAP_BUTTON_SYS;
if (in_report->buttons[1] & XInput::Buttons1::A) gp_in.buttons |= gamepad.MAP_BUTTON_A;
if (in_report->buttons[1] & XInput::Buttons1::B) gp_in.buttons |= gamepad.MAP_BUTTON_B;
if (in_report->buttons[1] & XInput::Buttons1::X) gp_in.buttons |= gamepad.MAP_BUTTON_X;
if (in_report->buttons[1] & XInput::Buttons1::Y) gp_in.buttons |= gamepad.MAP_BUTTON_Y;
gamepad.set_trigger_l(in_report->trigger_l);
gamepad.set_trigger_r(in_report->trigger_r);
gp_in.trigger_l = in_report->trigger_l;
gp_in.trigger_r = in_report->trigger_r;
gamepad.set_joystick_lx(in_report->joystick_lx);
gamepad.set_joystick_ly(in_report->joystick_ly, true);
gamepad.set_joystick_rx(in_report->joystick_rx);
gamepad.set_joystick_ry(in_report->joystick_ry, true);
Gamepad::Chatpad gp_chatpad;
gp_in.joystick_lx = in_report->joystick_lx;
gp_in.joystick_ly = Scale::invert_joy(in_report->joystick_ly);
gp_in.joystick_rx = in_report->joystick_rx;
gp_in.joystick_ry = Scale::invert_joy(in_report->joystick_ry);
if ((in_report->command[1] & 2) && (in_report->chatpad_status == 0x00))
{
gp_chatpad =
{
in_report->chatpad[0],
in_report->chatpad[1],
in_report->chatpad[2],
};
}
else
{
gp_chatpad.fill(0);
gp_in.chatpad[0] = in_report->chatpad[0];
gp_in.chatpad[1] = in_report->chatpad[1];
gp_in.chatpad[2] = in_report->chatpad[2];
}
gamepad.set_chatpad(gp_chatpad);
gamepad.set_pad_in(gp_in);
tuh_xinput::receive_report(address, instance);
std::memcpy(&prev_in_report_, in_report, sizeof(XInput::InReportWireless));
@@ -92,5 +82,6 @@ void Xbox360WHost::process_report(Gamepad& gamepad, uint8_t address, uint8_t ins
bool Xbox360WHost::send_feedback(Gamepad& gamepad, uint8_t address, uint8_t instance)
{
return tuh_xinput::set_rumble(address, instance, gamepad.get_rumble_l().uint8(), gamepad.get_rumble_r().uint8(), false);
Gamepad::PadOut gp_out = gamepad.get_pad_out();
return tuh_xinput::set_rumble(address, instance, gp_out.rumble_l, gp_out.rumble_r, false);
}

View File

@@ -3,6 +3,7 @@
#include <cstdint>
#include "TaskQueue/TaskQueue.h"
#include "Descriptors/XInput.h"
#include "USBHost/HostDriver/HostDriver.h"
@@ -24,7 +25,7 @@ private:
uint8_t address;
uint8_t instance;
uint8_t led_quadrant;
struct repeating_timer timer;
uint32_t task_id;
};
TimerInfo timer_info_;

View File

@@ -21,46 +21,48 @@ void XboxOGHost::process_report(Gamepad& gamepad, uint8_t address, uint8_t insta
return;
}
gamepad.reset_buttons();
Gamepad::PadIn gp_in;
if (in_report->buttons & XboxOG::GP::Buttons::DPAD_UP) gamepad.set_dpad_up();
if (in_report->buttons & XboxOG::GP::Buttons::DPAD_DOWN) gamepad.set_dpad_down();
if (in_report->buttons & XboxOG::GP::Buttons::DPAD_LEFT) gamepad.set_dpad_left();
if (in_report->buttons & XboxOG::GP::Buttons::DPAD_RIGHT) gamepad.set_dpad_right();
if (in_report->buttons & XboxOG::GP::Buttons::DPAD_UP) gp_in.dpad |= gamepad.MAP_DPAD_UP;
if (in_report->buttons & XboxOG::GP::Buttons::DPAD_DOWN) gp_in.dpad |= gamepad.MAP_DPAD_DOWN;
if (in_report->buttons & XboxOG::GP::Buttons::DPAD_LEFT) gp_in.dpad |= gamepad.MAP_DPAD_LEFT;
if (in_report->buttons & XboxOG::GP::Buttons::DPAD_RIGHT) gp_in.dpad |= gamepad.MAP_DPAD_RIGHT;
if (in_report->a) gamepad.set_button_a();
if (in_report->b) gamepad.set_button_b();
if (in_report->x) gamepad.set_button_x();
if (in_report->y) gamepad.set_button_y();
if (in_report->black) gamepad.set_button_rb();
if (in_report->white) gamepad.set_button_lb();
if (in_report->a) gp_in.buttons |= gamepad.MAP_BUTTON_A;
if (in_report->b) gp_in.buttons |= gamepad.MAP_BUTTON_B;
if (in_report->x) gp_in.buttons |= gamepad.MAP_BUTTON_X;
if (in_report->y) gp_in.buttons |= gamepad.MAP_BUTTON_Y;
if (in_report->black) gp_in.buttons |= gamepad.MAP_BUTTON_LB;
if (in_report->white) gp_in.buttons |= gamepad.MAP_BUTTON_RB;
if (in_report->buttons & XboxOG::GP::Buttons::START) gamepad.set_button_start();
if (in_report->buttons & XboxOG::GP::Buttons::BACK) gamepad.set_button_back();
if (in_report->buttons & XboxOG::GP::Buttons::L3) gamepad.set_button_l3();
if (in_report->buttons & XboxOG::GP::Buttons::R3) gamepad.set_button_r3();
if (in_report->buttons & XboxOG::GP::Buttons::START) gp_in.buttons |= gamepad.MAP_BUTTON_START;
if (in_report->buttons & XboxOG::GP::Buttons::BACK) gp_in.buttons |= gamepad.MAP_BUTTON_BACK;
if (in_report->buttons & XboxOG::GP::Buttons::L3) gp_in.buttons |= gamepad.MAP_BUTTON_L3;
if (in_report->buttons & XboxOG::GP::Buttons::R3) gp_in.buttons |= gamepad.MAP_BUTTON_R3;
if (gamepad.analog_enabled())
{
gamepad.set_analog_a(in_report->a);
gamepad.set_analog_b(in_report->b);
gamepad.set_analog_x(in_report->x);
gamepad.set_analog_y(in_report->y);
gamepad.set_analog_lb(in_report->black);
gamepad.set_analog_rb(in_report->white);
gamepad.set_analog_up((in_report->buttons & XboxOG::GP::Buttons::DPAD_UP) ? UINT_8::MAX : UINT_8::MIN);
gamepad.set_analog_down((in_report->buttons & XboxOG::GP::Buttons::DPAD_DOWN) ? UINT_8::MAX : UINT_8::MIN);
gamepad.set_analog_left((in_report->buttons & XboxOG::GP::Buttons::DPAD_LEFT) ? UINT_8::MAX : UINT_8::MIN);
gamepad.set_analog_right((in_report->buttons & XboxOG::GP::Buttons::DPAD_RIGHT) ? UINT_8::MAX : UINT_8::MIN);
gp_in.analog[gamepad.MAP_ANALOG_OFF_A] = in_report->a;
gp_in.analog[gamepad.MAP_ANALOG_OFF_B] = in_report->b;
gp_in.analog[gamepad.MAP_ANALOG_OFF_X] = in_report->x;
gp_in.analog[gamepad.MAP_ANALOG_OFF_Y] = in_report->y;
gp_in.analog[gamepad.MAP_ANALOG_OFF_LB] = in_report->black;
gp_in.analog[gamepad.MAP_ANALOG_OFF_RB] = in_report->white;
gp_in.analog[gamepad.MAP_ANALOG_OFF_UP] = (in_report->buttons & XboxOG::GP::Buttons::DPAD_UP) ? UINT_8::MAX : UINT_8::MIN;
gp_in.analog[gamepad.MAP_ANALOG_OFF_DOWN] = (in_report->buttons & XboxOG::GP::Buttons::DPAD_DOWN) ? UINT_8::MAX : UINT_8::MIN;
gp_in.analog[gamepad.MAP_ANALOG_OFF_LEFT] = (in_report->buttons & XboxOG::GP::Buttons::DPAD_LEFT) ? UINT_8::MAX : UINT_8::MIN;
gp_in.analog[gamepad.MAP_ANALOG_OFF_RIGHT] = (in_report->buttons & XboxOG::GP::Buttons::DPAD_RIGHT) ? UINT_8::MAX : UINT_8::MIN;
}
gamepad.set_trigger_l(in_report->trigger_l);
gamepad.set_trigger_r(in_report->trigger_r);
gp_in.trigger_l = in_report->trigger_l;
gp_in.trigger_r = in_report->trigger_r;
gamepad.set_joystick_lx(in_report->joystick_lx);
gamepad.set_joystick_ly(in_report->joystick_ly, true);
gamepad.set_joystick_rx(in_report->joystick_rx);
gamepad.set_joystick_ry(in_report->joystick_ry, true);
gp_in.joystick_lx = in_report->joystick_lx;
gp_in.joystick_ly = Scale::invert_joy(in_report->joystick_ly);
gp_in.joystick_rx = in_report->joystick_rx;
gp_in.joystick_ry = Scale::invert_joy(in_report->joystick_ry);
gamepad.set_pad_in(gp_in);
tuh_xinput::receive_report(address, instance);
std::memcpy(&prev_in_report_, in_report, sizeof(XboxOG::GP::InReport));
@@ -68,5 +70,6 @@ void XboxOGHost::process_report(Gamepad& gamepad, uint8_t address, uint8_t insta
bool XboxOGHost::send_feedback(Gamepad& gamepad, uint8_t address, uint8_t instance)
{
return tuh_xinput::set_rumble(address, instance, gamepad.get_rumble_l().uint8(), gamepad.get_rumble_r().uint8(), false);
Gamepad::PadOut gp_out = gamepad.get_pad_out();
return tuh_xinput::set_rumble(address, instance, gp_out.rumble_l, gp_out.rumble_r, false);
}

View File

@@ -19,33 +19,35 @@ void XboxOneHost::process_report(Gamepad& gamepad, uint8_t address, uint8_t inst
return;
}
gamepad.reset_buttons();
Gamepad::PadIn gp_in;
if (in_report->buttons[1] & XboxOne::Buttons1::DPAD_UP) gamepad.set_dpad_up();
if (in_report->buttons[1] & XboxOne::Buttons1::DPAD_DOWN) gamepad.set_dpad_down();
if (in_report->buttons[1] & XboxOne::Buttons1::DPAD_LEFT) gamepad.set_dpad_left();
if (in_report->buttons[1] & XboxOne::Buttons1::DPAD_RIGHT) gamepad.set_dpad_right();
if (in_report->buttons[1] & XboxOne::Buttons1::DPAD_UP) gp_in.dpad |= gamepad.MAP_DPAD_UP;
if (in_report->buttons[1] & XboxOne::Buttons1::DPAD_DOWN) gp_in.dpad |= gamepad.MAP_DPAD_DOWN;
if (in_report->buttons[1] & XboxOne::Buttons1::DPAD_LEFT) gp_in.dpad |= gamepad.MAP_DPAD_LEFT;
if (in_report->buttons[1] & XboxOne::Buttons1::DPAD_RIGHT) gp_in.dpad |= gamepad.MAP_DPAD_RIGHT;
if (in_report->buttons[1] & XboxOne::Buttons1::L3) gamepad.set_button_l3();
if (in_report->buttons[1] & XboxOne::Buttons1::R3) gamepad.set_button_r3();
if (in_report->buttons[1] & XboxOne::Buttons1::LB) gamepad.set_button_lb();
if (in_report->buttons[1] & XboxOne::Buttons1::RB) gamepad.set_button_rb();
if (in_report->buttons[0] & XboxOne::Buttons0::BACK) gamepad.set_button_back();
if (in_report->buttons[0] & XboxOne::Buttons0::START) gamepad.set_button_start();
if (in_report->buttons[0] & XboxOne::Buttons0::SYNC) gamepad.set_button_misc();
if (in_report->buttons[0] & XboxOne::Buttons0::GUIDE) gamepad.set_button_sys();
if (in_report->buttons[0] & XboxOne::Buttons0::A) gamepad.set_button_a();
if (in_report->buttons[0] & XboxOne::Buttons0::B) gamepad.set_button_b();
if (in_report->buttons[0] & XboxOne::Buttons0::X) gamepad.set_button_x();
if (in_report->buttons[0] & XboxOne::Buttons0::Y) gamepad.set_button_y();
if (in_report->buttons[1] & XboxOne::Buttons1::L3) gp_in.buttons |= gamepad.MAP_BUTTON_L3;
if (in_report->buttons[1] & XboxOne::Buttons1::R3) gp_in.buttons |= gamepad.MAP_BUTTON_R3;
if (in_report->buttons[1] & XboxOne::Buttons1::LB) gp_in.buttons |= gamepad.MAP_BUTTON_LB;
if (in_report->buttons[1] & XboxOne::Buttons1::RB) gp_in.buttons |= gamepad.MAP_BUTTON_RB;
if (in_report->buttons[0] & XboxOne::Buttons0::BACK) gp_in.buttons |= gamepad.MAP_BUTTON_BACK;
if (in_report->buttons[0] & XboxOne::Buttons0::START) gp_in.buttons |= gamepad.MAP_BUTTON_START;
if (in_report->buttons[0] & XboxOne::Buttons0::SYNC) gp_in.buttons |= gamepad.MAP_BUTTON_MISC;
if (in_report->buttons[0] & XboxOne::Buttons0::GUIDE) gp_in.buttons |= gamepad.MAP_BUTTON_SYS;
if (in_report->buttons[0] & XboxOne::Buttons0::A) gp_in.buttons |= gamepad.MAP_BUTTON_A;
if (in_report->buttons[0] & XboxOne::Buttons0::B) gp_in.buttons |= gamepad.MAP_BUTTON_B;
if (in_report->buttons[0] & XboxOne::Buttons0::X) gp_in.buttons |= gamepad.MAP_BUTTON_X;
if (in_report->buttons[0] & XboxOne::Buttons0::Y) gp_in.buttons |= gamepad.MAP_BUTTON_Y;
gamepad.set_trigger_l(static_cast<uint8_t>(in_report->trigger_l >> 2));
gamepad.set_trigger_r(static_cast<uint8_t>(in_report->trigger_r >> 2));
gp_in.trigger_l = static_cast<uint8_t>(in_report->trigger_l >> 2);
gp_in.trigger_r = static_cast<uint8_t>(in_report->trigger_r >> 2);
gamepad.set_joystick_lx(in_report->joystick_lx);
gamepad.set_joystick_ly(in_report->joystick_ly, true);
gamepad.set_joystick_rx(in_report->joystick_rx);
gamepad.set_joystick_ry(in_report->joystick_ry, true);
gp_in.joystick_lx = in_report->joystick_lx;
gp_in.joystick_ly = Scale::invert_joy(in_report->joystick_ly);
gp_in.joystick_rx = in_report->joystick_rx;
gp_in.joystick_ry = Scale::invert_joy(in_report->joystick_ry);
gamepad.set_pad_in(gp_in);
tuh_xinput::receive_report(address, instance);
std::memcpy(&prev_in_report_, in_report, 18);
@@ -53,5 +55,6 @@ void XboxOneHost::process_report(Gamepad& gamepad, uint8_t address, uint8_t inst
bool XboxOneHost::send_feedback(Gamepad& gamepad, uint8_t address, uint8_t instance)
{
return tuh_xinput::set_rumble(address, instance, gamepad.get_rumble_l().uint8(), gamepad.get_rumble_r().uint8(), false);
Gamepad::PadOut gp_out = gamepad.get_pad_out();
return tuh_xinput::set_rumble(address, instance, gp_out.rumble_l, gp_out.rumble_r, false);
}

View File

@@ -4,6 +4,7 @@
#include <cstring>
#include "Board/board_api.h"
#include "USBHost/HostDriver/XInput/tuh_xinput/tuh_xinput.h"
#include "USBHost/HostDriver/XInput/tuh_xinput/tuh_xinput_cmd.h"
@@ -11,76 +12,93 @@ namespace tuh_xinput {
static constexpr uint8_t MAX_INTERFACES = CFG_TUH_XINPUT * 2;
static constexpr uint8_t MAX_DEVICES = CFG_TUH_DEVICE_MAX;
static constexpr uint32_t KEEPALIVE_MS = 1000;
static constexpr uint8_t INVALID_IDX = 0xFF;
struct Device
{
std::array<Interface, MAX_INTERFACES> interfaces;
Device()
{
interfaces.fill(Interface());
}
std::array<Interface, MAX_INTERFACES> interfaces{Interface()};
};
std::array<Device, MAX_DEVICES> devices_;
TU_ATTR_ALWAYS_INLINE static inline Device* get_device_by_addr(uint8_t dev_addr)
{
TU_VERIFY((dev_addr <= devices_.size() && dev_addr > 0), nullptr);
return &devices_[dev_addr - 1];
}
// TU_ATTR_ALWAYS_INLINE static inline Device* get_device_by_addr(uint8_t dev_addr)
// {
// TU_VERIFY((dev_addr <= devices_.size() && dev_addr > 0), nullptr);
// return &devices_[dev_addr - 1];
// }
TU_ATTR_ALWAYS_INLINE static inline Interface* get_itf_by_instance(uint8_t dev_addr, uint8_t instance)
{
Device* device = get_device_by_addr(dev_addr);
TU_VERIFY(device != nullptr, nullptr);
TU_VERIFY(instance < device->interfaces.size(), nullptr);
return &device->interfaces[instance];
}
// TU_ATTR_ALWAYS_INLINE static inline Interface* get_itf_by_instance(uint8_t dev_addr, uint8_t instance)
// {
// Device* device = get_device_by_addr(dev_addr);
// TU_VERIFY(device != nullptr, nullptr);
// TU_VERIFY(instance < device->interfaces.size(), nullptr);
// return &device->interfaces[instance];
// }
TU_ATTR_ALWAYS_INLINE static inline Interface* get_free_interface(uint8_t dev_addr)
{
Device* device = get_device_by_addr(dev_addr);
TU_VERIFY(device != nullptr, nullptr);
// TU_ATTR_ALWAYS_INLINE static inline Interface* get_free_interface(uint8_t dev_addr)
// {
// Device* device = get_device_by_addr(dev_addr);
// TU_VERIFY(device != nullptr, nullptr);
for (auto& interface : device->interfaces)
{
if (interface.itf_num == 0xFF)
{
return &interface;
}
}
return nullptr;
// for (auto& interface : device->interfaces)
// {
// if (interface.itf_num == 0xFF)
// {
// return &interface;
// }
// }
// return nullptr;
// }
TU_ATTR_ALWAYS_INLINE static inline uint8_t get_device_idx_by_addr(uint8_t dev_addr)
{
TU_VERIFY((dev_addr <= devices_.size() && dev_addr > 0), INVALID_IDX);
return dev_addr - 1;
}
TU_ATTR_ALWAYS_INLINE static inline uint8_t get_instance_by_itf_num(uint8_t dev_addr, uint8_t itf_num)
{
Device* device = get_device_by_addr(dev_addr);
TU_VERIFY(device != nullptr, 0xFF);
uint8_t dev_idx = get_device_idx_by_addr(dev_addr);
TU_VERIFY(dev_idx != INVALID_IDX, INVALID_IDX);
for (uint8_t i = 0; i < device->interfaces.size(); ++i)
for (uint8_t i = 0; i < devices_[dev_idx].interfaces.size(); ++i)
{
if (device->interfaces[i].itf_num == itf_num)
if (devices_[dev_idx].interfaces[i].itf_num == itf_num)
{
return i;
}
}
return 0xFF;
return INVALID_IDX;
}
TU_ATTR_ALWAYS_INLINE static inline uint8_t get_instance_by_ep(uint8_t dev_addr, uint8_t ep_addr)
{
Device* device = get_device_by_addr(dev_addr);
TU_VERIFY(device != nullptr, 0xFF);
for (uint8_t i = 0; i < device->interfaces.size(); ++i)
uint8_t dev_idx = get_device_idx_by_addr(dev_addr);
TU_VERIFY(dev_idx != INVALID_IDX, INVALID_IDX);
for (uint8_t i = 0; i < devices_[dev_idx].interfaces.size(); ++i)
{
if (device->interfaces[i].ep_in == ep_addr || device->interfaces[i].ep_out == ep_addr)
if (devices_[dev_idx].interfaces[i].ep_in == ep_addr || devices_[dev_idx].interfaces[i].ep_out == ep_addr)
{
return i;
}
}
return 0xFF;
return INVALID_IDX;
}
TU_ATTR_ALWAYS_INLINE static inline uint8_t get_free_itf_idx(uint8_t dev_addr)
{
uint8_t dev_idx = get_device_idx_by_addr(dev_addr);
TU_VERIFY(dev_idx != INVALID_IDX, INVALID_IDX);
for (uint8_t i = 0; i < devices_[dev_idx].interfaces.size(); ++i)
{
if (devices_[dev_idx].interfaces[i].itf_num == INVALID_IDX)
{
return i;
}
}
return INVALID_IDX;
}
static void wait_for_tx_complete(uint8_t dev_addr, uint8_t ep_addr)
@@ -125,40 +143,44 @@ static void xbox360w_chatpad_init(Interface *interface, uint8_t address, uint8_t
interface->chatpad_stage = ChatpadStage::KEEPALIVE_1;
}
static bool xbox360_chatpad_keepalive_cb(repeating_timer_t* rt)
{
Interface* interface = static_cast<Interface*>(rt->user_data);
uint8_t instance = get_instance_by_ep(interface->dev_addr, interface->ep_in);
bool xbox360_chatpad_keepalive(uint8_t address, uint8_t instance)
{
uint8_t dev_idx = get_device_idx_by_addr(address);
uint8_t itf_idx = get_instance_by_itf_num(address, instance);
TU_VERIFY(dev_idx != INVALID_IDX && itf_idx != INVALID_IDX, false);
switch (interface->chatpad_stage)
Interface& interface = devices_[dev_idx].interfaces[itf_idx];
TU_VERIFY(interface.connected, false);
switch (interface.chatpad_stage)
{
case ChatpadStage::KEEPALIVE_1:
switch (interface->dev_type)
switch (interface.dev_type)
{
case DevType::XBOX360:
send_ctrl_xfer(interface->dev_addr, &Xbox360::Chatpad::KEEPALIVE_1, nullptr, nullptr, 0);
send_ctrl_xfer(interface.dev_addr, &Xbox360::Chatpad::KEEPALIVE_1, nullptr, nullptr, 0);
break;
case DevType::XBOX360W:
send_report(interface->dev_addr, instance, Xbox360W::Chatpad::KEEPALIVE_1, sizeof(Xbox360W::Chatpad::KEEPALIVE_1));
send_report(interface.dev_addr, instance, Xbox360W::Chatpad::KEEPALIVE_1, sizeof(Xbox360W::Chatpad::KEEPALIVE_1));
break;
default:
break;
}
interface->chatpad_stage = ChatpadStage::KEEPALIVE_2;
interface.chatpad_stage = ChatpadStage::KEEPALIVE_2;
break;
case ChatpadStage::KEEPALIVE_2:
switch (interface->dev_type)
switch (interface.dev_type)
{
case DevType::XBOX360:
send_ctrl_xfer(interface->dev_addr, &Xbox360::Chatpad::KEEPALIVE_2, nullptr, nullptr, 0);
send_ctrl_xfer(interface.dev_addr, &Xbox360::Chatpad::KEEPALIVE_2, nullptr, nullptr, 0);
break;
case DevType::XBOX360W:
send_report(interface->dev_addr, instance, Xbox360W::Chatpad::KEEPALIVE_2, sizeof(Xbox360W::Chatpad::KEEPALIVE_2));
send_report(interface.dev_addr, instance, Xbox360W::Chatpad::KEEPALIVE_2, sizeof(Xbox360W::Chatpad::KEEPALIVE_2));
break;
default:
break;
}
interface->chatpad_stage = ChatpadStage::KEEPALIVE_1;
interface.chatpad_stage = ChatpadStage::KEEPALIVE_1;
break;
}
return true;
@@ -194,16 +216,14 @@ static void xboxone_init(Interface *interface, uint8_t dev_addr, uint8_t instanc
static bool init()
{
TU_LOG2("XInput Init\r\n");
devices_.fill(Device());
for (auto& device : devices_)
{
device.interfaces.fill(Interface());
}
return true;
}
static bool open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
{
TU_LOG2("XInput Open\r\n");
TU_VERIFY(desc_itf->bNumEndpoints > 0);
DevType dev_type = DevType::UNKNOWN;
@@ -232,8 +252,11 @@ static bool open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *
TU_VERIFY(dev_type != DevType::UNKNOWN);
Interface* interface = get_free_interface(dev_addr);
TU_VERIFY(interface != nullptr);
uint8_t dev_idx = get_device_idx_by_addr(dev_addr);
uint8_t itf_idx = get_free_itf_idx(dev_addr);
TU_VERIFY(itf_idx != INVALID_IDX && dev_idx != INVALID_IDX);
Interface& interface = devices_[dev_idx].interfaces[itf_idx];
const uint8_t *p_desc = reinterpret_cast<const uint8_t*>(desc_itf);
int endpoint = 0;
@@ -252,20 +275,20 @@ static bool open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *
TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType);
TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep));
interface->itf_num = desc_itf->bInterfaceNumber;
interface->itf_type = itf_type;
interface->dev_type = dev_type;
interface->dev_addr = dev_addr;
interface.itf_num = desc_itf->bInterfaceNumber;
interface.itf_type = itf_type;
interface.dev_type = dev_type;
interface.dev_addr = dev_addr;
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_OUT)
{
interface->ep_out = desc_ep->bEndpointAddress;
interface->ep_out_size = tu_edpt_packet_size(desc_ep);
interface.ep_out = desc_ep->bEndpointAddress;
interface.ep_out_size = tu_edpt_packet_size(desc_ep);
}
else
{
interface->ep_in = desc_ep->bEndpointAddress;
interface->ep_in_size = tu_edpt_packet_size(desc_ep);
interface.ep_in = desc_ep->bEndpointAddress;
interface.ep_in_size = tu_edpt_packet_size(desc_ep);
}
endpoint++;
@@ -279,20 +302,21 @@ static bool open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *
static bool set_config(uint8_t dev_addr, uint8_t itf_num)
{
uint8_t instance = get_instance_by_itf_num(dev_addr, itf_num);
Interface* interface = get_itf_by_instance(dev_addr, instance);
TU_VERIFY(interface != nullptr);
uint8_t dev_idx = get_device_idx_by_addr(dev_addr);
TU_VERIFY(instance != INVALID_IDX && dev_idx != INVALID_IDX);
Interface& interface = devices_[dev_idx].interfaces[instance];
interface->connected = true;
interface.connected = true;
switch (interface->dev_type)
switch (interface.dev_type)
{
case DevType::XBOX360W:
interface->connected = false;
interface.connected = false;
send_report(dev_addr, instance, Xbox360W::INQUIRE_PRESENT, sizeof(Xbox360W::INQUIRE_PRESENT));
wait_for_tx_complete(dev_addr, interface->ep_out);
wait_for_tx_complete(dev_addr, interface.ep_out);
break;
case DevType::XBOXONE:
xboxone_init(interface, dev_addr, instance);
xboxone_init(&interface, dev_addr, instance);
break;
default:
break;
@@ -300,38 +324,40 @@ static bool set_config(uint8_t dev_addr, uint8_t itf_num)
if (mount_cb)
{
mount_cb(dev_addr, instance, interface);
mount_cb(dev_addr, instance, &interface);
}
usbh_driver_set_config_complete(dev_addr, interface->itf_num);
usbh_driver_set_config_complete(dev_addr, interface.itf_num);
return true;
}
static bool xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
{
const uint8_t dir = tu_edpt_dir(ep_addr);
const uint8_t instance = get_instance_by_ep(dev_addr, ep_addr);
Interface* interface = get_itf_by_instance(dev_addr, instance);
TU_VERIFY(interface != nullptr);
uint8_t dev_idx = get_device_idx_by_addr(dev_addr);
uint8_t instance = get_instance_by_ep(dev_addr, ep_addr);
TU_VERIFY(dev_idx != INVALID_IDX && instance != INVALID_IDX);
Interface& interface = devices_[dev_idx].interfaces[instance];
if (result != XFER_RESULT_SUCCESS)
{
if (dir == TUSB_DIR_IN)
{
report_received_cb(dev_addr, instance, interface->ep_in_buffer.data(), static_cast<uint16_t>(interface->ep_in_size));
report_received_cb(dev_addr, instance, interface.ep_in_buffer.data(), static_cast<uint16_t>(interface.ep_in_size));
}
else if (report_sent_cb)
{
report_sent_cb(dev_addr, instance, interface->ep_out_buffer.data(), static_cast<uint16_t>(interface->ep_out_size));
report_sent_cb(dev_addr, instance, interface.ep_out_buffer.data(), static_cast<uint16_t>(interface.ep_out_size));
}
}
if (dir == TUSB_DIR_IN)
{
bool new_pad_data = false;
uint8_t* in_buffer = interface->ep_in_buffer.data();
uint8_t* in_buffer = interface.ep_in_buffer.data();
switch (interface->dev_type)
switch (interface.dev_type)
{
case DevType::XBOX360:
if (in_buffer[1] == 0x14)
@@ -342,22 +368,21 @@ static bool xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uin
case DevType::XBOX360W:
if (in_buffer[0] & 0x08)
{
if (in_buffer[1] != 0x00 && !interface->connected)
if (in_buffer[1] != 0x00 && !interface.connected)
{
interface->connected = true;
xbox360w_chatpad_init(interface, dev_addr, instance);
interface.connected = true;
// xbox360w_chatpad_init(interface, dev_addr, instance);
send_report(dev_addr, instance, Xbox360W::RUMBLE_ENABLE, sizeof(Xbox360W::RUMBLE_ENABLE));
add_repeating_timer_ms(KEEPALIVE_MS, xbox360_chatpad_keepalive_cb, interface, &interface->keepalive_timer);
if (xbox360w_connect_cb)
{
xbox360w_connect_cb(dev_addr, instance);
}
}
else if (in_buffer[1] == 0x00 && interface->connected)
else if (in_buffer[1] == 0x00 && interface.connected)
{
interface->connected = false;
interface->chatpad_inited = false;
cancel_repeating_timer(&interface->keepalive_timer);
interface.connected = false;
interface.chatpad_inited = false;
if (xbox360w_disconnect_cb)
{
xbox360w_disconnect_cb(dev_addr, instance);
@@ -388,7 +413,7 @@ static bool xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uin
}
break;
case XboxOne::GIP_CMD_ANNOUNCE:
xboxone_init(interface, dev_addr, instance);
xboxone_init(&interface, dev_addr, instance);
break;
}
break;
@@ -414,57 +439,70 @@ static bool xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uin
{
if (report_sent_cb)
{
report_sent_cb(dev_addr, instance, interface->ep_out_buffer.data(), static_cast<uint16_t>(xferred_bytes));
report_sent_cb(dev_addr, instance, interface.ep_out_buffer.data(), static_cast<uint16_t>(xferred_bytes));
}
}
return true;
}
void close(uint8_t dev_addr)
bool deinit()
{
Device* device = get_device_by_addr(dev_addr);
TU_VERIFY(device != nullptr, );
for (uint8_t i = 0; i < device->interfaces.size(); ++i)
{
if (device->interfaces[i].itf_num != 0xFF && unmount_cb)
{
unmount_cb(dev_addr, i, &device->interfaces[i]);
}
cancel_repeating_timer(&device->interfaces[i].keepalive_timer);
}
*device = Device();
TU_LOG2("XInput deinit\r\n");
return true;
}
const usbh_class_driver_t class_driver_ =
void close(uint8_t dev_addr)
{
.init = init,
.open = open,
.set_config = set_config,
.xfer_cb = xfer_cb,
.close = close
};
TU_LOG2("XInput close\r\n");
uint8_t dev_idx = get_device_idx_by_addr(dev_addr);
TU_VERIFY(dev_idx != INVALID_IDX, );
TU_LOG2("XInput dev addr verified\r\n");
Device& device = devices_[dev_idx];
for (uint8_t i = 0; i < device.interfaces.size(); ++i)
{
if (device.interfaces[i].itf_num != 0xFF && unmount_cb)
{
TU_LOG2("XInput unmounting\r\n");
unmount_cb(dev_addr, i, &device.interfaces[i]);
TU_LOG2("XInput unmount\r\n");
device.interfaces[i].itf_num = 0xFF;
device.interfaces[i].connected = false;
}
}
// device = Device();
}
//Public API
const usbh_class_driver_t* class_driver()
{
return &class_driver_;
static const usbh_class_driver_t class_driver =
{
.init = init,
.deinit = deinit,
.open = open,
.set_config = set_config,
.xfer_cb = xfer_cb,
.close = close
};
return &class_driver;
}
bool send_report(uint8_t dev_addr, uint8_t instance, const uint8_t *buffer, uint16_t len)
{
Interface *interface = get_itf_by_instance(dev_addr, instance);
TU_VERIFY(interface != nullptr);
TU_ASSERT(len <= interface->ep_out_size);
TU_VERIFY(usbh_edpt_claim(dev_addr, interface->ep_out));
uint8_t dev_idx = get_device_idx_by_addr(dev_addr);
TU_VERIFY(dev_idx != INVALID_IDX && instance < MAX_INTERFACES, false);
std::memcpy(interface->ep_out_buffer.data(), buffer, len);
Interface& interface = devices_[dev_idx].interfaces[instance];
if (!usbh_edpt_xfer(dev_addr, interface->ep_out, interface->ep_out_buffer.data(), len))
TU_VERIFY(usbh_edpt_claim(dev_addr, interface.ep_out));
std::memcpy(interface.ep_out_buffer.data(), buffer, len);
if (!usbh_edpt_xfer(dev_addr, interface.ep_out, interface.ep_out_buffer.data(), len))
{
usbh_edpt_release(dev_addr, interface->ep_out);
usbh_edpt_release(dev_addr, interface.ep_out);
return false;
}
return true;
@@ -472,12 +510,14 @@ bool send_report(uint8_t dev_addr, uint8_t instance, const uint8_t *buffer, uint
bool receive_report(uint8_t dev_addr, uint8_t instance)
{
Interface* interface = get_itf_by_instance(dev_addr, instance);
TU_VERIFY(interface != nullptr);
uint8_t dev_idx = get_device_idx_by_addr(dev_addr);
TU_VERIFY(dev_idx != INVALID_IDX && instance < MAX_INTERFACES, false);
if (!usbh_edpt_xfer(dev_addr, interface->ep_in, interface->ep_in_buffer.data(), interface->ep_in_size))
Interface& interface = devices_[dev_idx].interfaces[instance];
if (!usbh_edpt_xfer(dev_addr, interface.ep_in, interface.ep_in_buffer.data(), interface.ep_in_size))
{
usbh_edpt_release(dev_addr, interface->ep_in);
usbh_edpt_release(dev_addr, interface.ep_in);
return false;
}
return true;
@@ -485,13 +525,15 @@ bool receive_report(uint8_t dev_addr, uint8_t instance)
bool set_led(uint8_t dev_addr, uint8_t instance, uint8_t quadrant, bool block)
{
Interface* interface = get_itf_by_instance(dev_addr, instance);
TU_VERIFY(interface != nullptr);
uint8_t dev_idx = get_device_idx_by_addr(dev_addr);
TU_VERIFY(dev_idx != INVALID_IDX && instance < MAX_INTERFACES, false);
Interface& interface = devices_[dev_idx].interfaces[instance];
uint8_t buffer[32];
uint16_t len;
switch (interface->dev_type)
switch (interface.dev_type)
{
case DevType::XBOX360W:
std::memcpy(buffer, Xbox360W::LED, sizeof(Xbox360W::LED));
@@ -510,20 +552,22 @@ bool set_led(uint8_t dev_addr, uint8_t instance, uint8_t quadrant, bool block)
bool ret = send_report(dev_addr, instance, buffer, len);
if (block && ret)
{
wait_for_tx_complete(dev_addr, interface->ep_out);
wait_for_tx_complete(dev_addr, interface.ep_out);
}
return ret;
}
bool set_rumble(uint8_t dev_addr, uint8_t instance, uint8_t rumble_l, uint8_t rumble_r, bool block)
{
Interface* interface = get_itf_by_instance(dev_addr, instance);
TU_VERIFY(interface != nullptr);
uint8_t dev_idx = get_device_idx_by_addr(dev_addr);
TU_VERIFY(dev_idx != INVALID_IDX && instance < MAX_INTERFACES, false);
Interface& interface = devices_[dev_idx].interfaces[instance];
uint8_t buffer[32];
uint16_t len;
switch (interface->dev_type)
switch (interface.dev_type)
{
case DevType::XBOX360W:
std::memcpy(buffer, Xbox360W::RUMBLE, sizeof(Xbox360W::RUMBLE));
@@ -558,7 +602,7 @@ bool set_rumble(uint8_t dev_addr, uint8_t instance, uint8_t rumble_l, uint8_t ru
bool ret = send_report(dev_addr, instance, buffer, len);
if (block && ret)
{
wait_for_tx_complete(dev_addr, interface->ep_out);
wait_for_tx_complete(dev_addr, interface.ep_out);
}
return true;
}

View File

@@ -31,7 +31,6 @@ SOFTWARE.
#include <cstdint>
#include <array>
#include <pico/time.h>
#include "tusb.h"
#include "host/usbh.h"
@@ -55,14 +54,16 @@ namespace tuh_xinput
};
static constexpr uint8_t ENDPOINT_SIZE = 64;
static constexpr uint32_t KEEPALIVE_MS = 1000;
struct Interface
{
bool connected{false};
bool chatpad_inited{false};
DevType dev_type{DevType::UNKNOWN};
ItfType itf_type{ItfType::UNKNOWN};
bool chatpad_inited{false};
ChatpadStage chatpad_stage{ChatpadStage::INIT_1};
uint8_t dev_addr{0xFF};
@@ -74,16 +75,8 @@ namespace tuh_xinput
uint8_t ep_in_size{0xFF};
uint8_t ep_out_size{0xFF};
std::array<uint8_t, ENDPOINT_SIZE> ep_in_buffer;
std::array<uint8_t, ENDPOINT_SIZE> ep_out_buffer;
repeating_timer_t keepalive_timer;
Interface()
{
ep_in_buffer.fill(0);
ep_out_buffer.fill(0);
}
std::array<uint8_t, ENDPOINT_SIZE> ep_in_buffer{0};
std::array<uint8_t, ENDPOINT_SIZE> ep_out_buffer{0};
};
// API
@@ -93,6 +86,7 @@ namespace tuh_xinput
bool receive_report(uint8_t address, uint8_t instance);
bool set_rumble(uint8_t address, uint8_t instance, uint8_t rumble_l, uint8_t rumble_r, bool block);
bool set_led(uint8_t address, uint8_t instance, uint8_t led_number, bool block);
bool xbox360_chatpad_keepalive(uint8_t address, uint8_t instance);
// User implemented callbacks

View File

@@ -1,122 +0,0 @@
#include <array>
#include "tusb_option.h"
#include "tusb.h"
#include "host/usbh.h"
#include "host/usbh_pvt.h"
#include "class/hid/hid_host.h"
#include "USBHost/HostDriver/tuh_uni/tuh_uni.h"
#include "USBHost/HostDriver/Xinput/tuh_xinput/tuh_xinput.h"
namespace tuh_uni {
enum class HostType { UNKNOWN = 0, HID, XINPUT };
static std::array<HostType, CFG_TUH_DEVICE_MAX> host_type_;
const usbh_class_driver_t* xinput_class_driver_ = nullptr;
static inline HostType& get_host_type(uint8_t dev_addr)
{
return host_type_[dev_addr - 1];
}
bool init()
{
host_type_.fill(HostType::UNKNOWN);
hidh_init();
xinput_class_driver_ = tuh_xinput::class_driver();
xinput_class_driver_->init();
return true;
}
bool deinit()
{
hidh_deinit();
xinput_class_driver_->deinit();
host_type_.fill(HostType::UNKNOWN);
return true;
}
bool open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const* desc_itf, uint16_t max_len)
{
HostType& host_type = get_host_type(dev_addr);
switch (host_type)
{
case HostType::HID:
return hidh_open(rhport, dev_addr, desc_itf, max_len);
case HostType::XINPUT:
return xinput_class_driver_->open(rhport, dev_addr, desc_itf, max_len);
default:
if (xinput_class_driver_->open(rhport, dev_addr, desc_itf, max_len))
{
host_type = HostType::XINPUT;
return true;
}
else if (hidh_open(rhport, dev_addr, desc_itf, max_len))
{
host_type = HostType::HID;
return true;
}
break;
}
return false;
}
bool set_config(uint8_t dev_addr, uint8_t itf_num)
{
switch (get_host_type(dev_addr))
{
case HostType::HID:
return hidh_set_config(dev_addr, itf_num);
case HostType::XINPUT:
return xinput_class_driver_->set_config(dev_addr, itf_num);
default:
return false;
}
}
bool xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
{
switch (get_host_type(dev_addr))
{
case HostType::HID:
return hidh_xfer_cb(dev_addr, ep_addr, result, xferred_bytes);
case HostType::XINPUT:
return xinput_class_driver_->xfer_cb(dev_addr, ep_addr, result, xferred_bytes);
default:
return false;
}
}
void close(uint8_t dev_addr)
{
HostType& host_type = get_host_type(dev_addr);
switch (host_type)
{
case HostType::HID:
hidh_close(dev_addr);
break;
case HostType::XINPUT:
xinput_class_driver_->close(dev_addr);
break;
default:
break;
}
host_type = HostType::UNKNOWN;
}
const usbh_class_driver_t* class_driver()
{
static const usbh_class_driver_t class_driver = {
.init = init,
.deinit = deinit,
.open = open,
.set_config = set_config,
.xfer_cb = xfer_cb,
.close = close
};
return &class_driver;
}
} // namespace tuh_uni

View File

@@ -1,16 +0,0 @@
#ifndef _TUH_UNI_CLASS_DRIVER_H_
#define _TUH_UNI_CLASS_DRIVER_H_
#include <cstdint>
#include "tusb.h"
#include "host/usbh.h"
#include "host/usbh_pvt.h"
/* There seems to be a conflict with tinyusb using multiple host class drivers */
namespace tuh_uni
{
const usbh_class_driver_t* class_driver();
} // namespace tuh_uni
#endif // _TUH_UNI_CLASS_DRIVER_H_

View File

@@ -1,10 +1,377 @@
// #ifndef _HOST_MANAGER_H_
// #define _HOST_MANAGER_H_
// #include <cstdint>
// #include <memory>
// #include "board_config.h"
// #include "Gamepad.h"
// #include "OGXMini/OGXMini.h"
// #include "USBHost/HardwareIDs.h"
// #include "USBHost/HostDriver/XInput/tuh_xinput/tuh_xinput.h"
// #include "USBHost/HostDriver/HostDriver.h"
// // #include "USBHost/HostDriver/PS5/PS5.h"
// // #include "USBHost/HostDriver/PS4/PS4.h"
// // #include "USBHost/HostDriver/PS3/PS3.h"
// // #include "USBHost/HostDriver/PSClassic/PSClassic.h"
// // #include "USBHost/HostDriver/DInput/DInput.h"
// // #include "USBHost/HostDriver/SwitchWired/SwitchWired.h"
// // #include "USBHost/HostDriver/SwitchPro/SwitchPro.h"
// #include "USBHost/HostDriver/XInput/XboxOne.h"
// #include "USBHost/HostDriver/XInput/Xbox360.h"
// #include "USBHost/HostDriver/XInput/Xbox360W.h"
// #include "USBHost/HostDriver/XInput/XboxOG.h"
// // #include "USBHost/HostDriver/N64/N64.h"
// // #include "USBHost/HostDriver/HIDGeneric/HIDGeneric.h"
// #define MAX_INTERFACES MAX_GAMEPADS //This may change if support is added for audio or other chatpads beside 360 wireless
// class HostManager
// {
// public:
// enum class DriverClass { NONE, HID, XINPUT };
// HostManager(HostManager const&) = delete;
// void operator=(HostManager const&) = delete;
// static HostManager& get_instance()
// {
// static HostManager instance;
// return instance;
// }
// inline void initialize(Gamepad (&gamepads)[MAX_GAMEPADS])
// {
// for (size_t i = 0; i < MAX_GAMEPADS; ++i)
// {
// gamepads_[i] = &gamepads[i];
// }
// }
// inline bool setup_driver(const HostDriver::Type driver_type, const uint8_t address, const uint8_t instance, uint8_t const* report_desc = nullptr, uint16_t desc_len = 0)
// {
// uint8_t gp_idx = find_free_gamepad();
// if (gp_idx == INVALID_IDX)
// {
// return false;
// }
// DriverClass driver_class = determine_driver_class(driver_type);
// uint8_t hs_idx = get_host_slot(driver_class, address);
// if (hs_idx == INVALID_IDX) //This is a new device, else it's another interface on an already mounted device
// {
// if ((hs_idx = find_free_host_slot()) == INVALID_IDX)
// {
// return false;
// }
// }
// HostSlot* host_slot = &host_slots_[hs_idx];
// if (instance >= MAX_INTERFACES)
// {
// return false;
// }
// HostSlot::Interface* interface = &host_slot->interfaces[instance];
// switch (driver_type)
// {
// // case HostDriver::Type::PS5:
// // interface->driver = std::make_unique<PS5Host>(gp_idx);
// // break;
// // case HostDriver::Type::PS4:
// // interface->driver = std::make_unique<PS4Host>(gp_idx);
// // break;
// // case HostDriver::Type::PS3:
// // interface->driver = std::make_unique<PS3Host>(gp_idx);
// // break;
// // case HostDriver::Type::DINPUT:
// // interface->driver = std::make_unique<DInputHost>(gp_idx);
// // break;
// // case HostDriver::Type::SWITCH:
// // interface->driver = std::make_unique<SwitchWiredHost>(gp_idx);
// // break;
// // case HostDriver::Type::SWITCH_PRO:
// // interface->driver = std::make_unique<SwitchProHost>(gp_idx);
// // break;
// // case HostDriver::Type::N64:
// // interface->driver = std::make_unique<N64Host>(gp_idx);
// // break;
// // case HostDriver::Type::PSCLASSIC:
// // interface->driver = std::make_unique<PSClassicHost>(gp_idx);
// // break;
// case HostDriver::Type::XBOXOG:
// interface->driver = std::make_unique<XboxOGHost>(gp_idx);
// break;
// case HostDriver::Type::XBOXONE:
// interface->driver = std::make_unique<XboxOneHost>(gp_idx);
// break;
// case HostDriver::Type::XBOX360:
// interface->driver = std::make_unique<Xbox360Host>(gp_idx);
// break;
// case HostDriver::Type::XBOX360W: //Composite device, takes up all 4 gamepads when mounted
// interface->driver = std::make_unique<Xbox360WHost>(gp_idx);
// break;
// default:
// // if (is_hid_gamepad(report_desc, desc_len))
// // {
// // interface->driver = std::make_unique<HIDHost>(gp_idx);
// // }
// // else
// {
// return false;
// }
// break;
// }
// host_slot->address = address;
// host_slot->driver_class = driver_class;
// interface->gamepad_idx = gp_idx;
// interface->gamepad = gamepads_[gp_idx];
// interface->driver->initialize(*interface->gamepad, host_slot->address, instance, report_desc, desc_len);
// // OGXMini::update_tuh_status(true);
// return true;
// }
// inline void process_report(DriverClass driver_class, uint8_t address, uint8_t instance, const uint8_t* report, uint16_t len)
// {
// for (auto& host_slot : host_slots_)
// {
// if (host_slot.address == address &&
// host_slot.driver_class == driver_class &&
// host_slot.interfaces[instance].driver &&
// host_slot.interfaces[instance].gamepad)
// {
// host_slot.interfaces[instance].driver->process_report(*host_slot.interfaces[instance].gamepad, address, instance, report, len);
// }
// }
// }
// //Call on a timer
// inline void send_feedback()
// {
// for (auto& host_slot : host_slots_)
// {
// if (host_slot.address == INVALID_IDX)
// {
// continue;
// }
// for (uint8_t i = 0; i < MAX_INTERFACES; ++i)
// {
// if (host_slot.interfaces[i].driver != nullptr && host_slot.interfaces[i].gamepad->new_pad_out())
// {
// host_slot.interfaces[i].driver->send_feedback(*host_slot.interfaces[i].gamepad, host_slot.address, i);
// tuh_task();
// }
// }
// }
// }
// void deinit_driver(DriverClass driver_class, uint8_t address, uint8_t instance)
// {
// for (auto& host_slot : host_slots_)
// {
// if (host_slot.driver_class == driver_class && host_slot.address == address)
// {
// TU_LOG2("Deinit driver\r\n");
// // host_slot.reset();
// TU_LOG2("Driver deinitialized\r\n");
// }
// }
// // OGXMini::update_tuh_status(any_mounted());
// }
// static inline HostDriver::Type get_type(const HardwareID& ids)
// {
// for (const auto& map : HOST_TYPE_MAP)
// {
// for (size_t i = 0; i < map.num_ids; i++)
// {
// if (ids.pid == map.ids[i].pid && ids.vid == map.ids[i].vid)
// {
// return map.type;
// }
// }
// }
// return HostDriver::Type::UNKNOWN;
// }
// static inline HostDriver::Type get_type(const tuh_xinput::DevType xinput_type)
// {
// switch (xinput_type)
// {
// case tuh_xinput::DevType::XBOXONE:
// return HostDriver::Type::XBOXONE;
// case tuh_xinput::DevType::XBOX360W:
// return HostDriver::Type::XBOX360W;
// case tuh_xinput::DevType::XBOX360:
// return HostDriver::Type::XBOX360;
// // case tuh_xinput::DevType::XBOX360_CHATPAD:
// // return HostDriver::Type::XBOX360_CHATPAD;
// case tuh_xinput::DevType::XBOXOG:
// return HostDriver::Type::XBOXOG;
// default:
// return HostDriver::Type::UNKNOWN;
// }
// }
// inline uint8_t get_gamepad_idx(DriverClass driver_class, uint8_t address, uint8_t instance)
// {
// for (auto& host_slot : host_slots_)
// {
// if (host_slot.driver_class == driver_class && host_slot.address == address && instance < MAX_INTERFACES)
// {
// return host_slot.interfaces[instance].gamepad_idx;
// }
// }
// return INVALID_IDX;
// }
// inline bool any_mounted()
// {
// for (auto& host_slot : host_slots_)
// {
// if (host_slot.address != INVALID_IDX)
// {
// return true;
// }
// }
// return false;
// }
// private:
// static constexpr uint8_t INVALID_IDX = 0xFF;
// struct HostSlot
// {
// DriverClass driver_class{DriverClass::NONE};
// uint8_t address{INVALID_IDX};
// struct Interface
// {
// std::unique_ptr<HostDriver> driver{nullptr};
// uint8_t gamepad_idx{INVALID_IDX};
// Gamepad* gamepad{nullptr};
// inline void reset()
// {
// // gamepad->reset_pad_in();
// gamepad = nullptr;
// gamepad_idx = INVALID_IDX;
// driver.reset();
// }
// };
// Interface interfaces[MAX_INTERFACES];
// inline void reset()
// {
// // address = INVALID_IDX;
// for (auto& interface : interfaces)
// {
// interface.reset();
// }
// driver_class = DriverClass::NONE;
// }
// };
// HostSlot host_slots_[MAX_GAMEPADS];
// Gamepad* gamepads_[MAX_GAMEPADS];
// HostManager() {}
// inline uint8_t find_free_host_slot()
// {
// for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
// {
// if (host_slots_[i].address == INVALID_IDX)
// {
// return i;
// }
// }
// return INVALID_IDX;
// }
// inline uint8_t find_free_gamepad()
// {
// uint8_t count = 0;
// for (auto& host_slot : host_slots_)
// {
// for (auto& interface : host_slot.interfaces)
// {
// if (interface.gamepad_idx != INVALID_IDX)
// {
// ++count;
// }
// }
// }
// return (count < MAX_GAMEPADS) ? count : INVALID_IDX;
// }
// inline uint8_t get_host_slot(DriverClass host_class, uint8_t address)
// {
// for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
// {
// if (host_slots_[i].driver_class == host_class &&
// host_slots_[i].address == address)
// {
// return i;
// }
// }
// return INVALID_IDX;
// }
// inline DriverClass determine_driver_class(HostDriver::Type host_type)
// {
// switch (host_type)
// {
// case HostDriver::Type::XBOXOG:
// case HostDriver::Type::XBOXONE:
// case HostDriver::Type::XBOX360:
// case HostDriver::Type::XBOX360W:
// return DriverClass::XINPUT;
// default:
// return DriverClass::HID;
// }
// }
// bool is_hid_gamepad(const uint8_t* report_desc, uint16_t desc_len)
// {
// std::array<uint8_t, 6> start_bytes = { 0x05, 0x01, 0x09, 0x05, 0xA1, 0x01 };
// if (desc_len < start_bytes.size())
// {
// return false;
// }
// for (size_t i = 0; i < start_bytes.size(); ++i)
// {
// if (report_desc[i] != start_bytes[i])
// {
// return false;
// }
// }
// return true;
// }
// };
// #endif // _HOST_MANAGER_H_
#ifndef _HOST_MANAGER_H_
#define _HOST_MANAGER_H_
#include <cstdint>
#include <memory>
#include <array>
#include <atomic>
#include <hardware/regs/usb.h>
#include <hardware/irq.h>
#include <hardware/structs/usb.h>
#include <hardware/resets.h>
#include "board_config.h"
#include "Gamepad.h"
@@ -12,19 +379,21 @@
#include "USBHost/HardwareIDs.h"
#include "USBHost/HostDriver/XInput/tuh_xinput/tuh_xinput.h"
#include "USBHost/HostDriver/HostDriver.h"
#include "USBHost/HostDriver/PS5/PS5.h"
#include "USBHost/HostDriver/PS4/PS4.h"
#include "USBHost/HostDriver/PS3/PS3.h"
#include "USBHost/HostDriver/PSClassic/PSClassic.h"
#include "USBHost/HostDriver/DInput/DInput.h"
#include "USBHost/HostDriver/SwitchWired/SwitchWired.h"
#include "USBHost/HostDriver/SwitchPro/SwitchPro.h"
// #include "USBHost/HostDriver/PS5/PS5.h"
// #include "USBHost/HostDriver/PS4/PS4.h"
// #include "USBHost/HostDriver/PS3/PS3.h"
// #include "USBHost/HostDriver/PSClassic/PSClassic.h"
// #include "USBHost/HostDriver/DInput/DInput.h"
// #include "USBHost/HostDriver/SwitchWired/SwitchWired.h"
// #include "USBHost/HostDriver/SwitchPro/SwitchPro.h"
#include "USBHost/HostDriver/XInput/XboxOne.h"
#include "USBHost/HostDriver/XInput/Xbox360.h"
#include "USBHost/HostDriver/XInput/Xbox360W.h"
#include "USBHost/HostDriver/XInput/XboxOG.h"
#include "USBHost/HostDriver/N64/N64.h"
#include "USBHost/HostDriver/HIDGeneric/HIDGeneric.h"
// #include "USBHost/HostDriver/N64/N64.h"
// #include "USBHost/HostDriver/HIDGeneric/HIDGeneric.h"
#define MAX_INTERFACES MAX_GAMEPADS //This may change if support is added for audio or other chatpads beside 360 wireless
class HostManager
{
@@ -40,7 +409,7 @@ public:
return instance;
}
inline void initialize(std::array<Gamepad, MAX_GAMEPADS>& gamepads)
inline void initialize(Gamepad (&gamepads)[MAX_GAMEPADS])
{
for (size_t i = 0; i < MAX_GAMEPADS; ++i)
{
@@ -51,102 +420,90 @@ public:
inline bool setup_driver(const HostDriver::Type driver_type, const uint8_t address, const uint8_t instance, uint8_t const* report_desc = nullptr, uint16_t desc_len = 0)
{
uint8_t gp_idx = find_free_gamepad();
if (gp_idx == INVALID_IDX)
if (gp_idx == INVALID_IDX || instance >= MAX_INTERFACES)
{
return false;
}
DriverClass driver_class = determine_driver_class(driver_type);
uint8_t hs_idx = get_host_slot(driver_class, address);
// DriverClass driver_class = determine_driver_class(driver_type);
uint8_t dev_idx = get_device_slot(address);
if (hs_idx == INVALID_IDX) //This is a new device, else it's another interface on an already mounted device
{
if ((hs_idx = find_free_host_slot()) == INVALID_IDX)
{
return false;
}
}
HostSlot* host_slot = &host_slots_[hs_idx];
if (instance >= host_slot->interfaces.size())
//This is a new device, else it's another interface on an already mounted device
if (dev_idx == INVALID_IDX && ((dev_idx = find_free_device_slot()) == INVALID_IDX))
{
return false;
}
HostSlot::Interface* interface = &host_slot->interfaces[instance];
Device& device_slot = device_slots_[dev_idx];
Interface& interface = device_slot.interfaces[instance];
switch (driver_type)
{
case HostDriver::Type::PS5:
interface->driver = std::make_unique<PS5Host>(gp_idx);
break;
case HostDriver::Type::PS4:
interface->driver = std::make_unique<PS4Host>(gp_idx);
break;
case HostDriver::Type::PS3:
interface->driver = std::make_unique<PS3Host>(gp_idx);
break;
case HostDriver::Type::DINPUT:
interface->driver = std::make_unique<DInputHost>(gp_idx);
break;
case HostDriver::Type::SWITCH:
interface->driver = std::make_unique<SwitchWiredHost>(gp_idx);
break;
case HostDriver::Type::SWITCH_PRO:
interface->driver = std::make_unique<SwitchProHost>(gp_idx);
break;
case HostDriver::Type::N64:
interface->driver = std::make_unique<N64Host>(gp_idx);
break;
case HostDriver::Type::PSCLASSIC:
interface->driver = std::make_unique<PSClassicHost>(gp_idx);
break;
// case HostDriver::Type::PS5:
// interface.driver = std::make_unique<PS5Host>(gp_idx);
// break;
// case HostDriver::Type::PS4:
// interface.driver = std::make_unique<PS4Host>(gp_idx);
// break;
// case HostDriver::Type::PS3:
// interface.driver = std::make_unique<PS3Host>(gp_idx);
// break;
// case HostDriver::Type::DINPUT:
// interface.driver = std::make_unique<DInputHost>(gp_idx);
// break;
// case HostDriver::Type::SWITCH:
// interface.driver = std::make_unique<SwitchWiredHost>(gp_idx);
// break;
// case HostDriver::Type::SWITCH_PRO:
// interface.driver = std::make_unique<SwitchProHost>(gp_idx);
// break;
// case HostDriver::Type::N64:
// interface.driver = std::make_unique<N64Host>(gp_idx);
// break;
// case HostDriver::Type::PSCLASSIC:
// interface.driver = std::make_unique<PSClassicHost>(gp_idx);
// break;
case HostDriver::Type::XBOXOG:
interface->driver = std::make_unique<XboxOGHost>(gp_idx);
interface.driver = std::make_unique<XboxOGHost>(gp_idx);
break;
case HostDriver::Type::XBOXONE:
interface->driver = std::make_unique<XboxOneHost>(gp_idx);
interface.driver = std::make_unique<XboxOneHost>(gp_idx);
break;
case HostDriver::Type::XBOX360:
interface->driver = std::make_unique<Xbox360Host>(gp_idx);
interface.driver = std::make_unique<Xbox360Host>(gp_idx);
break;
case HostDriver::Type::XBOX360W: //Composite device, takes up all 4 gamepads when mounted
interface->driver = std::make_unique<Xbox360WHost>(gp_idx);
interface.driver = std::make_unique<Xbox360WHost>(gp_idx);
break;
default:
if (is_hid_gamepad(report_desc, desc_len))
{
interface->driver = std::make_unique<HIDHost>(gp_idx);
}
else
// if (is_hid_gamepad(report_desc, desc_len))
// {
// interface.driver = std::make_unique<HIDHost>(gp_idx);
// }
// else
{
return false;
}
break;
}
host_slot->address = address;
host_slot->driver_class = driver_class;
interface->gamepad_idx = gp_idx;
interface->gamepad = gamepads_[gp_idx];
interface->driver->initialize(*interface->gamepad, host_slot->address, instance, report_desc, desc_len);
if (OGXMini::update_tuh_status)
{
OGXMini::update_tuh_status(true);
}
device_slot.address = address;
interface.gamepad_idx = gp_idx;
interface.gamepad = gamepads_[gp_idx];
interface.driver->initialize(*interface.gamepad, device_slot.address, instance, report_desc, desc_len);
return true;
}
inline void process_report(DriverClass driver_class, uint8_t address, uint8_t instance, const uint8_t* report, uint16_t len)
{
for (auto& host_slot : host_slots_)
for (auto& device_slot : device_slots_)
{
if (host_slot.address == address && host_slot.driver_class == driver_class && host_slot.interfaces[instance].driver != nullptr)
if (device_slot.address == address &&
device_slot.interfaces[instance].driver &&
device_slot.interfaces[instance].gamepad)
{
host_slot.interfaces[instance].driver->process_report(*host_slot.interfaces[instance].gamepad, address, instance, report, len);
device_slot.interfaces[instance].driver->process_report(*device_slot.interfaces[instance].gamepad, address, instance, report, len);
}
}
}
@@ -154,17 +511,17 @@ public:
//Call on a timer
inline void send_feedback()
{
for (auto& host_slot : host_slots_)
for (auto& device_slot : device_slots_)
{
if (host_slot.address == INVALID_IDX)
if (device_slot.address == INVALID_IDX)
{
continue;
}
for (uint8_t i = 0; i < host_slot.interfaces.size(); ++i)
for (uint8_t i = 0; i < MAX_INTERFACES; ++i)
{
if (host_slot.interfaces[i].driver != nullptr)
if (device_slot.interfaces[i].driver != nullptr && device_slot.interfaces[i].gamepad->new_pad_out())
{
host_slot.interfaces[i].driver->send_feedback(*host_slot.interfaces[i].gamepad, host_slot.address, i);
device_slot.interfaces[i].driver->send_feedback(*device_slot.interfaces[i].gamepad, device_slot.address, i);
tuh_task();
}
}
@@ -173,22 +530,17 @@ public:
void deinit_driver(DriverClass driver_class, uint8_t address, uint8_t instance)
{
for (auto& host_slot : host_slots_)
for (auto& device_slot : device_slots_)
{
if (host_slot.driver_class == driver_class && host_slot.address == address)
if (device_slot.address == address)
{
host_slot.reset();
TU_LOG2("Deinit driver\r\n");
device_slot.reset();
TU_LOG2("Driver deinitialized\r\n");
}
// if (host_slot.address == address)
// {
// host_slot.reset();
// }
}
if (OGXMini::update_tuh_status)
{
OGXMini::update_tuh_status(any_mounted());
}
// OGXMini::update_tuh_status(any_mounted());
}
static inline HostDriver::Type get_type(const HardwareID& ids)
@@ -227,64 +579,68 @@ public:
inline uint8_t get_gamepad_idx(DriverClass driver_class, uint8_t address, uint8_t instance)
{
for (auto& host_slot : host_slots_)
for (auto& device_slot : device_slots_)
{
if (host_slot.driver_class == driver_class && host_slot.address == address && instance < host_slot.interfaces.size())
if (device_slot.address == address && instance < MAX_INTERFACES)
{
return host_slot.interfaces[instance].gamepad_idx;
return device_slot.interfaces[instance].gamepad_idx;
}
}
return INVALID_IDX;
}
inline bool any_mounted()
{
for (auto& device_slot : device_slots_)
{
if (device_slot.address != INVALID_IDX)
{
return true;
}
}
return false;
}
private:
static constexpr uint8_t INVALID_IDX = 0xFF;
struct HostSlot
struct Interface
{
std::unique_ptr<HostDriver> driver{nullptr};
Gamepad* gamepad{nullptr};
uint8_t gamepad_idx{INVALID_IDX};
};
struct Device
{
DriverClass driver_class{DriverClass::NONE};
uint8_t address{INVALID_IDX};
Interface interfaces[MAX_INTERFACES];
struct Interface
{
std::unique_ptr<HostDriver> driver{nullptr};
uint8_t gamepad_idx{INVALID_IDX};
Gamepad* gamepad{nullptr};
inline void reset()
{
driver.reset();
gamepad_idx = INVALID_IDX;
gamepad->reset_pad();
gamepad = nullptr;
}
};
std::array<Interface, MAX_GAMEPADS>interfaces;
inline void reset()
void reset()
{
address = INVALID_IDX;
for (auto& interface : interfaces)
{
interface.reset();
interface.driver.reset();
interface.gamepad_idx = INVALID_IDX;
interface.gamepad = nullptr;
}
driver_class = DriverClass::NONE;
}
};
std::array<HostSlot, MAX_GAMEPADS> host_slots_;
std::array<Gamepad*, MAX_GAMEPADS> gamepads_;
Device device_slots_[MAX_GAMEPADS];
Gamepad* gamepads_[MAX_GAMEPADS];
HostManager() {}
inline uint8_t find_free_host_slot()
HostManager()
{
for (uint8_t i = 0; i < host_slots_.size(); ++i)
// irq_set_exclusive_handler(USBCTRL_IRQ, disconnect_irq_handler);
// irq_set_enabled(USBCTRL_IRQ, true);
}
inline uint8_t find_free_device_slot()
{
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
{
if (host_slots_[i].address == INVALID_IDX)
if (device_slots_[i].address == INVALID_IDX)
{
return i;
}
@@ -296,9 +652,9 @@ private:
{
uint8_t count = 0;
for (auto& host_slot : host_slots_)
for (auto& device_slot : device_slots_)
{
for (auto& interface : host_slot.interfaces)
for (auto& interface : device_slot.interfaces)
{
if (interface.gamepad_idx != INVALID_IDX)
{
@@ -309,32 +665,28 @@ private:
return (count < MAX_GAMEPADS) ? count : INVALID_IDX;
}
inline uint8_t get_host_slot(DriverClass host_class, uint8_t address)
inline uint8_t get_device_slot(uint8_t address)
{
for (uint8_t i = 0; i < host_slots_.size(); ++i)
if (address > MAX_GAMEPADS)
{
if (host_slots_[i].driver_class == host_class &&
host_slots_[i].address == address)
{
return i;
}
return INVALID_IDX;
}
return INVALID_IDX;
return address - 1;
}
inline DriverClass determine_driver_class(HostDriver::Type host_type)
{
switch (host_type)
{
case HostDriver::Type::XBOXOG:
case HostDriver::Type::XBOXONE:
case HostDriver::Type::XBOX360:
case HostDriver::Type::XBOX360W:
return DriverClass::XINPUT;
default:
return DriverClass::HID;
}
}
// inline DriverClass determine_driver_class(HostDriver::Type host_type)
// {
// switch (host_type)
// {
// case HostDriver::Type::XBOXOG:
// case HostDriver::Type::XBOXONE:
// case HostDriver::Type::XBOX360:
// case HostDriver::Type::XBOX360W:
// return DriverClass::XINPUT;
// default:
// return DriverClass::HID;
// }
// }
bool is_hid_gamepad(const uint8_t* report_desc, uint16_t desc_len)
{
@@ -353,16 +705,23 @@ private:
return true;
}
inline bool any_mounted()
{
for (auto& host_slot : host_slots_)
{
if (host_slot.address != INVALID_IDX)
{
return true;
}
}
return false;
/* This should not be necessary, but Pico-PIO-USB/TinyUSB
cannot detect a disconnect correctly, sad! */
static void __isr disconnect_irq_handler()
{
// uint32_t portsc = usb_hw->portsc1;
// // Check for connect status change
// if (portsc & USBHS_PORTSC1_CSC)
// {
// if (!(portsc & USBHS_PORTSC1_CCS))
// {
// // Device disconnected
// printf("Device disconnected!\n");
// }
// // Clear the CSC flag
// usb_hw->portsc1 |= USBHS_PORTSC1_CSC;
// }
}
};

View File

@@ -6,21 +6,19 @@
#include "host/usbh.h"
#include "class/hid/hid_host.h"
#include "USBHost/HostDriver/tuh_uni/tuh_uni.h"
#include "USBHost/HostDriver/XInput/tuh_xinput/tuh_xinput.h"
#include "USBHost/HostManager.h"
#include "OGXMini/OGXMini.h"
#include "Board/board_api.h"
#if defined(CONFIG_EN_4CH)
#include "I2CDriver/I2CDriver.h"
#include "I2CDriver/4Channel/I2CManager.h"
#endif //defined(CONFIG_EN_4CH)
usbh_class_driver_t const* usbh_app_driver_get_cb(uint8_t* driver_count)
{
*driver_count = 1;
// return tuh_xinput::class_driver();
return tuh_uni::class_driver();
*driver_count += 1;
return tuh_xinput::class_driver();
}
//HID
@@ -31,23 +29,30 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
tuh_vid_pid_get(dev_addr, &vid, &pid);
HostManager& host_manager = HostManager::get_instance();
if (host_manager.setup_driver(HostManager::get_type({ vid, pid }), dev_addr, instance, desc_report, desc_len))
{
#if defined(CONFIG_EN_4CH)
i2c_driver::notify_tuh_mounted();
I2CManager::get_instance().get_driver()->notify_tuh_mounted();
#endif //defined(CONFIG_EN_4CH)
OGXMini::update_tuh_status(true);
}
}
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
{
board_api::set_led(false);
HostManager& host_manager = HostManager::get_instance();
host_manager.deinit_driver(HostManager::DriverClass::HID, dev_addr, instance);
#if defined(CONFIG_EN_4CH)
i2c_driver::notify_tuh_unmounted();
#endif //defined(CONFIG_EN_4CH)
if (!host_manager.any_mounted())
{
// #if defined(CONFIG_EN_4CH)
// I2CManager::get_instance().get_driver()->notify_tuh_unmounted();
// #endif //defined(CONFIG_EN_4CH)
OGXMini::update_tuh_status(false);
}
}
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
@@ -64,9 +69,11 @@ void tuh_xinput::mount_cb(uint8_t dev_addr, uint8_t instance, const tuh_xinput::
if (host_manager.setup_driver(host_type, dev_addr, instance))
{
#if defined(CONFIG_EN_4CH)
i2c_driver::notify_tuh_mounted(host_type);
#endif //defined(CONFIG_EN_4CH)
// #if defined(CONFIG_EN_4CH)
// I2CManager::get_instance().get_driver()->notify_tuh_mounted(host_type);
// #endif //defined(CONFIG_EN_4CH)
OGXMini::update_tuh_status(true);
}
}
@@ -75,9 +82,14 @@ void tuh_xinput::unmount_cb(uint8_t dev_addr, uint8_t instance, const tuh_xinput
HostManager& host_manager = HostManager::get_instance();
host_manager.deinit_driver(HostManager::DriverClass::XINPUT, dev_addr, instance);
#if defined(CONFIG_EN_4CH)
i2c_driver::notify_tuh_unmounted(host_manager.get_type(interface->dev_type));
#endif //defined(CONFIG_EN_4CH)
if (!host_manager.any_mounted())
{
// #if defined(CONFIG_EN_4CH)
// I2CManager::get_instance().get_driver()->notify_tuh_mounted(host_manager.get_type(interface->dev_type));
// #endif //defined(CONFIG_EN_4CH)
OGXMini::update_tuh_status(false);
}
}
void tuh_xinput::report_received_cb(uint8_t dev_addr, uint8_t instance, const uint8_t* report, uint16_t len)
@@ -85,16 +97,18 @@ void tuh_xinput::report_received_cb(uint8_t dev_addr, uint8_t instance, const ui
HostManager::get_instance().process_report(HostManager::DriverClass::XINPUT, dev_addr, instance, report, len);
}
#if defined(CONFIG_EN_4CH)
void tuh_xinput::xbox360w_connect_cb(uint8_t dev_addr, uint8_t instance)
{
uint8_t idx = HostManager::get_instance().get_gamepad_idx(HostManager::DriverClass::XINPUT, dev_addr, instance);
i2c_driver::notify_xbox360w_connected(idx);
// #if defined(CONFIG_EN_4CH)
// uint8_t idx = HostManager::get_instance().get_gamepad_idx(HostManager::DriverClass::XINPUT, dev_addr, instance);
// I2CManager::get_instance().get_driver()->notify_xbox360w_connected(idx);
// #endif //defined(CONFIG_EN_4CH)
}
void tuh_xinput::xbox360w_disconnect_cb(uint8_t dev_addr, uint8_t instance)
{
uint8_t idx = HostManager::get_instance().get_gamepad_idx(HostManager::DriverClass::XINPUT, dev_addr, instance);
i2c_driver::notify_xbox360w_disconnected(idx);
}
#endif //defined(CONFIG_EN_4CH)
// #if defined(CONFIG_EN_4CH)
// uint8_t idx = HostManager::get_instance().get_gamepad_idx(HostManager::DriverClass::XINPUT, dev_addr, instance);
// I2CManager::get_instance().get_driver()->notify_xbox360w_disconnected(idx);
// #endif //defined(CONFIG_EN_4CH)
}

View File

@@ -15,23 +15,23 @@ UserProfile::UserProfile()
invert_ly = 0;
invert_ry = 0;
dpad_up = Gamepad::DPad::UP;
dpad_down = Gamepad::DPad::DOWN;
dpad_left = Gamepad::DPad::LEFT;
dpad_right = Gamepad::DPad::RIGHT;
dpad_up = Gamepad::DPAD_UP;
dpad_down = Gamepad::DPAD_DOWN;
dpad_left = Gamepad::DPAD_LEFT;
dpad_right = Gamepad::DPAD_RIGHT;
button_a = Gamepad::Button::A;
button_b = Gamepad::Button::B;
button_x = Gamepad::Button::X;
button_y = Gamepad::Button::Y;
button_l3 = Gamepad::Button::L3;
button_r3 = Gamepad::Button::R3;
button_back = Gamepad::Button::BACK;
button_start = Gamepad::Button::START;
button_lb = Gamepad::Button::LB;
button_rb = Gamepad::Button::RB;
button_sys = Gamepad::Button::SYS;
button_misc = Gamepad::Button::MISC;
button_a = Gamepad::BUTTON_A;
button_b = Gamepad::BUTTON_B;
button_x = Gamepad::BUTTON_X;
button_y = Gamepad::BUTTON_Y;
button_l3 = Gamepad::BUTTON_L3;
button_r3 = Gamepad::BUTTON_R3;
button_back = Gamepad::BUTTON_BACK;
button_start = Gamepad::BUTTON_START;
button_lb = Gamepad::BUTTON_LB;
button_rb = Gamepad::BUTTON_RB;
button_sys = Gamepad::BUTTON_SYS;
button_misc = Gamepad::BUTTON_MISC;
analog_enabled = 1;

View File

@@ -17,15 +17,15 @@ static constexpr uint32_t button_combo(const uint16_t& buttons, const uint8_t& d
namespace ButtonCombo
{
static constexpr uint32_t PS3 = button_combo(Gamepad::Button::START, Gamepad::DPad::LEFT);
static constexpr uint32_t DINPUT = button_combo(Gamepad::Button::START | Gamepad::Button::RB, Gamepad::DPad::LEFT);
static constexpr uint32_t XINPUT = button_combo(Gamepad::Button::START, Gamepad::DPad::UP);
static constexpr uint32_t SWITCH = button_combo(Gamepad::Button::START, Gamepad::DPad::DOWN);
static constexpr uint32_t XBOXOG = button_combo(Gamepad::Button::START, Gamepad::DPad::RIGHT);
static constexpr uint32_t XBOXOG_SB = button_combo(Gamepad::Button::START | Gamepad::Button::RB, Gamepad::DPad::RIGHT);
static constexpr uint32_t XBOXOG_XR = button_combo(Gamepad::Button::START | Gamepad::Button::LB, Gamepad::DPad::RIGHT);
static constexpr uint32_t PSCLASSIC = button_combo(Gamepad::Button::START | Gamepad::Button::A);
static constexpr uint32_t WEBAPP = button_combo(Gamepad::Button::START | Gamepad::Button::LB | Gamepad::Button::RB);
static constexpr uint32_t PS3 = button_combo(Gamepad::BUTTON_START, Gamepad::DPAD_LEFT);
static constexpr uint32_t DINPUT = button_combo(Gamepad::BUTTON_START | Gamepad::BUTTON_RB, Gamepad::DPAD_LEFT);
static constexpr uint32_t XINPUT = button_combo(Gamepad::BUTTON_START, Gamepad::DPAD_UP);
static constexpr uint32_t SWITCH = button_combo(Gamepad::BUTTON_START, Gamepad::DPAD_DOWN);
static constexpr uint32_t XBOXOG = button_combo(Gamepad::BUTTON_START, Gamepad::DPAD_RIGHT);
static constexpr uint32_t XBOXOG_SB = button_combo(Gamepad::BUTTON_START | Gamepad::BUTTON_RB, Gamepad::DPAD_RIGHT);
static constexpr uint32_t XBOXOG_XR = button_combo(Gamepad::BUTTON_START | Gamepad::BUTTON_LB, Gamepad::DPAD_RIGHT);
static constexpr uint32_t PSCLASSIC = button_combo(Gamepad::BUTTON_START | Gamepad::BUTTON_A);
static constexpr uint32_t WEBAPP = button_combo(Gamepad::BUTTON_START | Gamepad::BUTTON_LB | Gamepad::BUTTON_RB);
};
static constexpr DeviceDriver::Type VALID_DRIVER_TYPES[] =
@@ -34,6 +34,7 @@ static constexpr DeviceDriver::Type VALID_DRIVER_TYPES[] =
DeviceDriver::Type::XBOXOG,
DeviceDriver::Type::XBOXOG_SB,
DeviceDriver::Type::XBOXOG_XR,
DeviceDriver::Type::PS3,
DeviceDriver::Type::WEBAPP,
#elif MAX_GAMEPADS > 1
@@ -165,7 +166,7 @@ bool UserSettings::write_firmware_version_safe()
DeviceDriver::Type UserSettings::get_current_driver()
{
// return DeviceDriver::Type::XINPUT;
return DeviceDriver::Type::XINPUT;
if (current_driver_ != DeviceDriver::Type::NONE)
{
@@ -226,12 +227,13 @@ void UserSettings::store_driver_type_safe(DeviceDriver::Type new_mode)
//Checks if button combo has been held for 3 seconds, returns true if mode has been changed
bool UserSettings::check_for_driver_change(Gamepad& gamepad)
{
static uint32_t last_button_combo = button_combo(gamepad.get_buttons(), gamepad.get_dpad_buttons());
Gamepad::PadIn gp_in = gamepad.get_pad_in();
static uint32_t last_button_combo = button_combo(gp_in.buttons, gp_in.dpad);
static uint8_t call_count = 0;
uint32_t current_button_combo = button_combo(gamepad.get_buttons(), gamepad.get_dpad_buttons());
uint32_t current_button_combo = button_combo(gp_in.buttons, gp_in.dpad);
if (!(current_button_combo & (static_cast<uint32_t>(Gamepad::Button::START) << 16)) ||
if (!(current_button_combo & (static_cast<uint32_t>(Gamepad::BUTTON_START) << 16)) ||
last_button_combo != current_button_combo)
{
last_button_combo = current_button_combo;

View File

@@ -16,7 +16,7 @@ class UserSettings
{
public:
static constexpr uint8_t MAX_PROFILES = 8;
static constexpr int32_t GP_CHECK_DELAY_MS = 500;
static constexpr int32_t GP_CHECK_DELAY_MS = 600;
UserSettings() = default;
~UserSettings() = default;

View File

@@ -13,6 +13,8 @@
#define EXTERNAL_4CH 6
#define W_ESP32 7
#define SYSCLOCK_HZ 250000
#ifndef MAX_GAMEPADS
#define MAX_GAMEPADS 1
#endif

View File

@@ -1,10 +1,13 @@
#include <pico/stdlib.h>
#include <cstdint>
#include <hardware/clocks.h>
#include "OGXMini/OGXMini.h"
#include "board_config.h"
int main()
{
set_sys_clock_khz(250000, true);
OGXMini::run_program();
if (set_sys_clock_hz(SYSCLOCK_HZ*1000, true))
{
OGXMini::run_program();
}
}

View File

@@ -67,12 +67,8 @@
#define CFG_TUSB_OS OPT_OS_NONE
#endif
// #ifndef CFG_TUSB_DEBUG
// #define CFG_TUSB_DEBUG 0
// #endif
#ifdef CFG_TUSB_DEBUG
#undef CFG_TUSB_DEBUG
#define CFG_TUSB_DEBUG 2
#ifndef CFG_TUSB_DEBUG
#define CFG_TUSB_DEBUG 0
#endif
// Enable Device stack, Default is max speed that hardware controller could support with on-chip PHY
@@ -141,13 +137,18 @@
// Size of buffer to hold descriptors and other data used for enumeration
#define CFG_TUH_ENUMERATION_BUFSIZE 512
#define CFG_TUH_HUB MAX_GAMEPADS
#define CFG_TUH_HUB 0
#define CFG_TUH_CDC 0
#define CFG_TUH_HID 1 // typical keyboard + mouse device can have 3-4 HID interfaces
// #define CFG_TUH_HID_CSTM MAX_GAMEPADS
#if defined(CONFIG_EN_4CH)
#define CFG_TUH_HID 0
#else
#define CFG_TUH_HID MAX_GAMEPADS
#endif
#define CFG_TUH_MSC 0
#define CFG_TUH_VENDOR 0
#define CFG_TUH_XINPUT MAX_GAMEPADS
#define CFG_TUH_XINPUT 4
#define CFG_TUH_XINPUT_WIRED_CHATPAD_EN 0

View File

@@ -41,24 +41,24 @@ function(apply_lib_patches EXTERNAL_DIR)
message(FATAL_ERROR "Failed to apply Bluepad32 patch: ${BLUEPAD32_PATCH_ERROR}")
endif ()
set(TUSB_PATCH "${EXTERNAL_DIR}/patches/tinyusb_disable_hidh.diff")
set(TUSB_PATH "${EXTERNAL_DIR}/tinyusb")
# set(TUSB_PATCH "${EXTERNAL_DIR}/patches/tinyusb_disable_hidh.diff")
# set(TUSB_PATH "${EXTERNAL_DIR}/tinyusb")
message(STATUS "Applying tinyusb patch: ${TUSB_PATCH}")
# message(STATUS "Applying tinyusb patch: ${TUSB_PATCH}")
execute_process(
COMMAND git apply --ignore-whitespace ${TUSB_PATCH}
WORKING_DIRECTORY ${TUSB_PATH}
RESULT_VARIABLE TUSB_PATCH_RESULT
OUTPUT_VARIABLE TUSB_PATCH_OUTPUT
ERROR_VARIABLE TUSB_PATCH_ERROR
)
# execute_process(
# COMMAND git apply --ignore-whitespace ${TUSB_PATCH}
# WORKING_DIRECTORY ${TUSB_PATH}
# RESULT_VARIABLE TUSB_PATCH_RESULT
# OUTPUT_VARIABLE TUSB_PATCH_OUTPUT
# ERROR_VARIABLE TUSB_PATCH_ERROR
# )
if (TUSB_PATCH_RESULT EQUAL 0)
message(STATUS "tinyusb patch applied successfully.")
elseif (TUSB_PATCH_ERROR MATCHES "patch does not apply")
message(STATUS "tinyusb patch already applied.")
else ()
message(FATAL_ERROR "Failed to apply tinyusb patch: ${TUSB_PATCH_ERROR}")
endif ()
# if (TUSB_PATCH_RESULT EQUAL 0)
# message(STATUS "tinyusb patch applied successfully.")
# elseif (TUSB_PATCH_ERROR MATCHES "patch does not apply")
# message(STATUS "tinyusb patch already applied.")
# else ()
# message(FATAL_ERROR "Failed to apply tinyusb patch: ${TUSB_PATCH_ERROR}")
# endif ()
endfunction()

View File

@@ -7,7 +7,7 @@ Firmware for the RP2040, capable of emulating gamepads for several game consoles
- Original Xbox
- Playstation 3
- Nintendo Switch (docked)
- XInput (use [UsbdSecPatch](https://github.com/InvoxiPlayGames/UsbdSecPatch) for Xbox 360)
- XInput (use [UsbdSecPatch](https://github.com/InvoxiPlayGames/UsbdSecPatch) for Xbox 360, or select the patch in J-Runner while flashing your NAND)
- Playstation Classic
## Supported devices
@@ -22,12 +22,12 @@ Firmware for the RP2040, capable of emulating gamepads for several game consoles
- Nintendo 64 Generic USB
- Playstation Classic
- Generic DInput
- Generic HID (Limited)
- Generic HID (mappings may need to be editted in the web app)
Note: There are some third party controllers that can change their VID/PID, these might not work correctly.
### Wireless adapters
- Xbox 360 PC adapter (Microsoft or clones, syncs 1 controller)
- Xbox 360 PC adapter (Microsoft or clones)
- 8Bitdo v1 and v2 Bluetooth adapters (set to XInput mode)
- Most wireless adapters that present themselves as Switch/XInput/PlayStation controllers should work
@@ -40,34 +40,35 @@ Note: Bluetooth functionality is in early testing, some may have quirks.
- Switch Pro
- Steam
- Stadia
Please visit [this page](https://bluepad32.readthedocs.io/en/latest/supported_gamepads/) for a more comprehensive list of supported controllers.
- And more
Please visit [this page](https://bluepad32.readthedocs.io/en/latest/supported_gamepads/) for a more comprehensive list of supported controllers and Bluetooth pairing instructions.
## Changing input mode
By default the input mode is set to OG Xbox, you must hold a button combo for 3 seconds to change which platform you want to play on. Your chosen input mode will persist after powering off the device.
## Changing platforms
By default the OGX-Mini will emulate an OG Xbox controller, you must hold a button combo for 3 seconds to change which platform you want to play on. Your chosen mode will persist after powering off the device.
Start = Plus (Switch) = Options (Dualsense/DS4)
- XInput
- Start + Dpad Up
Start + Dpad Up
- Original Xbox
- Start + Dpad Right
Start + Dpad Right
- Original Xbox Steel Battalion
- Start + Dpad Right + Right Bumper
Start + Dpad Right + Right Bumper
- Original Xbox DVD Remote
- Start + Dpad Right + Left Bumper
Start + Dpad Right + Left Bumper
- Switch
- Start + Dpad Down
Start + Dpad Down
- PlayStation 3
- Start + Dpad Left
Start + Dpad Left
- PlayStation Classic
- Start + A (Cross for PlayStation and B for Switch gamepads)
Start + A (Cross for PlayStation and B for Switch gamepads)
- Web Application Mode
- Start + Left Bumper + Right Bumper
Start + Left Bumper + Right Bumper
After a new mode is stored, the RP2040 will reset itself so you don't need to unplug it.
After a new mode is stored, the RP2040 will reset itself so you don't need to unplug it.
## Features new to v1.0.0
- Web application for configuring deadzones and buttons mappings, supports up to 8 saved configurations.
- Web application for configuring deadzones and buttons mappings, supports up to 8 saved profiles.
- Bluetooth functionality for the Pico W and ESP32 (in combination with an RP2040).
- 4 channel functionality, connect 4 Picos via I2C and use your Xbox 360 wireless adapter.
- Delayed USB mount until a controller is plugged in, useful for internal installation.
@@ -76,6 +77,21 @@ After a new mode is stored, the RP2040 will reset itself so you don't need to un
- Steel Battalion controller emulation with a wireless Xbox 360 chatpad.
- Xbox DVD dongle emulation, you must provide or dump your own firmware, see the Tools directory.
- Analog button support on OG Xbox and PS3.
- RGB LED support for RP2040-Zero and Adafruit Feather boards.
## Planned additions
- Bluetooth web application
- Deadzone scaling
- Anti-deadzone settings
- More accurate report parser for unknown HID controllers
- Hardware design for internal OG Xbox install
- Hardware design for 4 channel adapter
- Wired Xbox 360 chatpad support
- Wired Xbox One chatpad support
- Switch (as input) rumble support
- OG Xbox communicator support (in some form, will probably require custom hardware)
- Generic bluetooth dongle support
- Removal of some abstraction between TinyUSB class drivers and the rest of the app for decreased memory usage and (possible) speed improvement
## Hardware
For Pi Pico, RP2040-Zero, 4 channel, and ESP32 configurations, please see the hardware folder for diagrams.
@@ -89,9 +105,22 @@ If you would like a prebuilt unit, you can purchase one, with cable and Xbox ada
## Adding supported controllers
If your third party controller isn't working, but the original version is listed above, send me the device's VID and PID and I'll add it so it's recognized properly.
## Compiling
You can compile this for different boards with CMake arguments while configuring the project.
## Build
### RP2040
You can compile this for different boards with the CMake argument ```OGXM_BOARD``` while configuring the project. The options are:
```PI_PICO``` ```RP_ZERO``` ```ADA_FEATHER``` ```PI_PICOW``` ```W_ESP32``` ```EXTERNAL_4CH```
You can also set ```MAX_GAMEPADS``` which, if greater than one, will only support DInput (PS3) and Switch.
Choosing OGXM_PI_PICO will set the D+ and D- host pins to GPIO 0 and 1.
You'll need CMake, Ninja and the GCC ARM toolchain installed. Here's an example on Windows:
```
git clone --recursive https://github.com/wiredopposite/OGX-Mini.git
cd OGX-Mini/Firmware/RP2040
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DOGXM_BOARD=PI_PICOW -DMAX_GAMEPADS=1
cmake --build build
```
Or just install the GCC ARM toolchain and use the CMake Tools extension in VSCode.
You can also choose OGXM_RPZERO_INTERPOSER for the RP2040-Zero and that will set D+ and D- to GPIO 10 and 11, so connecting a USB port is easier. You can still use the Pi Pico firmware on the RP2040-Zero (the other way around has not been tested though).
CMake scripts will patch some files in TinyUSB, Bluepad32 and BTStack. If the patches fail, it's because of a text encoding issue, so open each .diff file in ```OGX-Mini/Firmware/external/patches``` in Notepad++. At the top of the window, click Encoding > UTF-8 and save. They should work after that.
### ESP32
You will need ESP-IDF v5.1 and esptools installed. If you use VSCode you can install the ESP-IDF extension and configure the project for v5.1, it'll download everything for you and then you just click the build button at the bottom of the window.