v1.0.0-alpha
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -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
3
.gitmodules
vendored
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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_
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
// run_bluepad32();
|
||||
xTaskCreatePinnedToCore(
|
||||
run_bluepad32,
|
||||
"bp32",
|
||||
|
||||
@@ -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
|
||||
|
||||
12
Firmware/RP2040/.vscode/settings.json
vendored
12
Firmware/RP2040/.vscode/settings.json
vendored
@@ -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"
|
||||
]
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
//
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
77
Firmware/RP2040/src/I2CDriver/4Channel/I2CDriver.h
Normal file
77
Firmware/RP2040/src/I2CDriver/4Channel/I2CDriver.h
Normal 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
|
||||
91
Firmware/RP2040/src/I2CDriver/4Channel/I2CManager.h
Normal file
91
Firmware/RP2040/src/I2CDriver/4Channel/I2CManager.h
Normal 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
|
||||
192
Firmware/RP2040/src/I2CDriver/4Channel/I2CMaster.cpp
Normal file
192
Firmware/RP2040/src/I2CDriver/4Channel/I2CMaster.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
57
Firmware/RP2040/src/I2CDriver/4Channel/I2CMaster.h
Normal file
57
Firmware/RP2040/src/I2CDriver/4Channel/I2CMaster.h
Normal 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
|
||||
160
Firmware/RP2040/src/I2CDriver/4Channel/I2CSlave.cpp
Normal file
160
Firmware/RP2040/src/I2CDriver/4Channel/I2CSlave.cpp
Normal 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;
|
||||
|
||||
}
|
||||
}
|
||||
36
Firmware/RP2040/src/I2CDriver/4Channel/I2CSlave.h
Normal file
36
Firmware/RP2040/src/I2CDriver/4Channel/I2CSlave.h
Normal 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
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
151
Firmware/RP2040/src/Scale.h
Normal 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_
|
||||
426
Firmware/RP2040/src/TaskQueue/TaskQueue.cpp
Normal file
426
Firmware/RP2040/src/TaskQueue/TaskQueue.cpp
Normal 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
|
||||
30
Firmware/RP2040/src/TaskQueue/TaskQueue.h
Normal file
30
Firmware/RP2040/src/TaskQueue/TaskQueue.h
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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)))
|
||||
{
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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;
|
||||
// }
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#define EXTERNAL_4CH 6
|
||||
#define W_ESP32 7
|
||||
|
||||
#define SYSCLOCK_HZ 250000
|
||||
|
||||
#ifndef MAX_GAMEPADS
|
||||
#define MAX_GAMEPADS 1
|
||||
#endif
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
1
Firmware/external/Pico-PIO-USB
vendored
1
Firmware/external/Pico-PIO-USB
vendored
Submodule Firmware/external/Pico-PIO-USB deleted from 528616d809
34
Firmware/external/patch_libs.cmake
vendored
34
Firmware/external/patch_libs.cmake
vendored
@@ -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()
|
||||
69
README.md
69
README.md
@@ -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.
|
||||
Reference in New Issue
Block a user