Fix XInput send_report + cleanup esp32 i2c logic

This commit is contained in:
wiredopposite
2024-12-31 14:10:53 -07:00
parent 8e53aa5d6b
commit 404997686f
25 changed files with 295 additions and 713 deletions

View File

@@ -100,5 +100,7 @@
},
"idf.portWin": "COM26",
"idf.flashType": "UART",
"C_Cpp.intelliSenseEngine": "default"
"C_Cpp.intelliSenseEngine": "default",
"idf.espIdfPathWin": "C:\\Programming\\esp\\v5.1\\esp-idf",
"idf.toolsPathWin": "C:\\Programming\\.espressif"
}

View File

@@ -4,9 +4,11 @@ set(CMAKE_CXX_STANDARD 17)
set(EXTERNAL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../external)
include(${EXTERNAL_DIR}/init_submodules.cmake)
include(${EXTERNAL_DIR}/patch_libs.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/integrate_btstack.cmake)
init_git_submodules(${EXTERNAL_DIR})
apply_lib_patches(${EXTERNAL_DIR})
integrate_btstack(${EXTERNAL_DIR})

View File

@@ -45,6 +45,7 @@ static inline void send_feedback_cb(void* context)
}
}
//This will have to be changed once full support for multiple devices is added
static inline void feedback_timer_cb(btstack_timer_source *ts)
{
static btstack_context_callback_registration_t cb_registration[MAX_DEVICES];
@@ -63,18 +64,13 @@ static inline void feedback_timer_cb(btstack_timer_source *ts)
cb_registration[i].callback = send_feedback_cb;
cb_registration[i].context = reinterpret_cast<void*>(&packets_out[i]);
//Get i2c rumble packet then register callback on BTStack thread
i2c_driver_.push_task([i]
{
I2CDriver::PacketOut packet_out;
if (i2c_driver_.i2c_read_blocking( I2CDriver::MULTI_SLAVE ? i + 1 : 0x01,
reinterpret_cast<uint8_t*>(&packet_out),
sizeof(I2CDriver::PacketOut)) == ESP_OK)
{
packets_out[i].store(packet_out);
btstack_run_loop_execute_on_main_thread(&cb_registration[i]);
}
});
//Register a read on i2c thread, with callback to send feedback on btstack thread
i2c_driver_.i2c_read_blocking_safe( I2CDriver::MULTI_SLAVE ? i + 1 : 0x01,
[i](const I2CDriver::PacketOut& packet_out)
{
packets_out[i].store(packet_out);
btstack_run_loop_execute_on_main_thread(&cb_registration[i]);
});
}
btstack_run_loop_set_timer(ts, FEEDBACK_TIME_MS);
@@ -160,12 +156,7 @@ void device_disconnected_cb(uni_hid_device_t* device)
I2CDriver::PacketIn packet_in = I2CDriver::PacketIn();
packet_in.index = static_cast<uint8_t>(idx);
i2c_driver_.push_task([packet_in]
{
i2c_driver_.i2c_write_blocking( I2CDriver::MULTI_SLAVE ? packet_in.index + 1 : 0x01,
reinterpret_cast<const uint8_t*>(&packet_in),
sizeof(I2CDriver::PacketIn));
});
i2c_driver_.i2c_write_blocking_safe(I2CDriver::MULTI_SLAVE ? packet_in.index + 1 : 0x01, packet_in);
}
static uni_error_t device_ready_cb(uni_hid_device_t* device)
@@ -258,12 +249,7 @@ static inline void controller_data_cb(uni_hid_device_t* device, uni_controller_t
packet_in.joystick_rx = Scale::int10_to_int16(uni_gp->axis_rx);
packet_in.joystick_ry = Scale::int10_to_int16(uni_gp->axis_ry);
i2c_driver_.push_task([packet_in]
{
i2c_driver_.i2c_write_blocking( I2CDriver::MULTI_SLAVE ? packet_in.index + 1 : 0x01,
reinterpret_cast<const uint8_t*>(&packet_in),
sizeof(I2CDriver::PacketIn));
});
i2c_driver_.i2c_write_blocking_safe(I2CDriver::MULTI_SLAVE ? packet_in.index + 1 : 0x01, packet_in);
std::memcpy(&prev_uni_gps[idx], uni_gp, sizeof(uni_gamepad_t));
}
@@ -296,6 +282,12 @@ uni_platform* get_driver()
return &driver;
}
void run_i2c_task(void* parameter)
{
i2c_driver_.initialize_i2c();
i2c_driver_.run_tasks();
}
//Public
bool any_connected()
@@ -319,10 +311,8 @@ void run_task()
{
board_api::init_pins();
i2c_driver_.initialize_i2c();
xTaskCreatePinnedToCore(
i2c_driver_.run_tasks,
run_i2c_task,
"i2c",
2048 * 2,
nullptr,

View File

@@ -7,8 +7,6 @@
#include "I2CDriver/I2CDriver.h"
#include "Bluepad32/Bluepad32.h"
I2CDriver::TaskQueue I2CDriver::task_queue_;
I2CDriver::~I2CDriver()
{
i2c_driver_delete(I2C_NUM_0);
@@ -30,7 +28,7 @@ void I2CDriver::initialize_i2c()
i2c_driver_install(I2C_NUM_0, conf.mode, 0, 0, 0);
}
void I2CDriver::run_tasks(void* parameter)
void I2CDriver::run_tasks()
{
std::function<void()> task;

View File

@@ -70,15 +70,32 @@ public:
void initialize_i2c();
//Does not return
static void run_tasks(void* parameter);
void run_tasks();
//Thread safe
inline void push_task(std::function<void()> task)
{
task_queue_.push(task);
inline void i2c_write_blocking_safe(uint8_t address, const PacketIn& packet_in)
{
task_queue_.push([this, address, packet_in]()
{
i2c_write_blocking(address, reinterpret_cast<const uint8_t*>(&packet_in), sizeof(PacketIn));
});
}
//Don't call directly from another thread, use in push_task
inline void i2c_read_blocking_safe(uint8_t address, std::function<void(const PacketOut&)> callback)
{
task_queue_.push([this, address, callback]()
{
PacketOut packet_out;
if (i2c_read_blocking(address, reinterpret_cast<uint8_t*>(&packet_out), sizeof(PacketOut)) == ESP_OK)
{
callback(packet_out);
}
});
}
private:
using TaskQueue = RingBuffer<std::function<void()>, 6>;
TaskQueue task_queue_;
inline esp_err_t i2c_write_blocking(uint8_t address, const uint8_t* buffer, size_t len)
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
@@ -92,7 +109,6 @@ public:
return ret;
}
//Don't call directly from another thread, use in push_task
inline esp_err_t i2c_read_blocking(uint8_t address, uint8_t* buffer, size_t len)
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
@@ -111,10 +127,6 @@ public:
i2c_cmd_link_delete(cmd);
return ret;
}
private:
using TaskQueue = RingBuffer<std::function<void()>, 6>;
static TaskQueue task_queue_;
};
#endif // _I2C_DRIVER_H_

View File

@@ -1,6 +1,6 @@
#
# Automatically generated file. DO NOT EDIT.
# Espressif IoT Development Framework (ESP-IDF) Project Configuration
# Espressif IoT Development Framework (ESP-IDF) 5.1.5 Project Configuration
#
CONFIG_SOC_BROWNOUT_RESET_SUPPORTED="Not determined"
CONFIG_SOC_TWAI_BRP_DIV_SUPPORTED="Not determined"

View File

@@ -7,7 +7,7 @@
"PICO_SDK_PATH": "C:/Programming/pico-sdk"
},
"cmake.configureArgs": [
"-DOGXM_BOARD=PI_PICO",
"-DOGXM_BOARD=W_ESP32",
"-DMAX_GAMEPADS=1"
],
"files.associations": {

View File

@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.13)
set(FW_NAME "OGX-Mini")
set(FW_VERSION "v1.0.0a")
set(FW_VERSION "v1.0.0a2")
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
@@ -13,9 +13,11 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(SRC ${CMAKE_CURRENT_LIST_DIR}/src)
set(EXTERNAL_DIR ${CMAKE_CURRENT_LIST_DIR}/../external)
include(${EXTERNAL_DIR}/init_submodules.cmake)
include(${EXTERNAL_DIR}/patch_libs.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/cmake/get_pico_sdk.cmake)
init_git_submodules(${EXTERNAL_DIR})
apply_lib_patches(${EXTERNAL_DIR})
get_pico_sdk(${EXTERNAL_DIR})

View File

@@ -12,7 +12,7 @@
#include "Board/board_api.h"
#ifndef CONFIG_BLUEPAD32_PLATFORM_CUSTOM
#error "Pico W must use BLUEPAD32_PLATFORM_CUSTOM"
#error "Pico W must use BLUEPAD32_PLATFORM_CUSTOM"
#endif
static_assert((CONFIG_BLUEPAD32_MAX_DEVICES == MAX_GAMEPADS), "Mismatch between BP32 and Gamepad max devices");
@@ -124,7 +124,14 @@ static void check_led_cb(btstack_timer_source *ts)
static void init(int argc, const char** arg_V)
{
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 void init_complete_cb(void)
@@ -310,12 +317,6 @@ void run_task(Gamepad (&gamepads)[MAX_GAMEPADS])
uni_platform_set_custom(get_driver());
uni_init(0, nullptr);
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();
}

View File

@@ -6,7 +6,6 @@
#include "Gamepad.h"
#include "board_config.h"
#include "UserSettings/UserProfile.h"
/* NOTE: Everything bluepad32/uni needs to be wrapped
and kept away from tinyusb due to naming conflicts */

View File

@@ -191,9 +191,12 @@ void init_board()
return;
}
if (!set_sys_clock_khz(SYSCLOCK_KHZ, true) && !set_sys_clock_khz(120000, true))
if (!set_sys_clock_khz(SYSCLOCK_KHZ, true))
{
panic("Failed to set sys clock");
if (!set_sys_clock_khz((SYSCLOCK_KHZ / 2), true))
{
panic("Failed to set sys clock");
}
}
stdio_init_all();
@@ -216,7 +219,7 @@ void init_board()
mutex_exit(&gpio_mutex_);
#if (OGXM_BOARD != PI_PICOW)
#if (OGXM_BOARD != PI_PICOW) // cyw43_arch needs to be inited from core1 first
set_led(false);
#endif

View File

@@ -108,15 +108,26 @@ namespace XInput
int16_t joystick_rx;
int16_t joystick_ry;
uint8_t reserved[6];
InReport()
{
std::memset(this, 0, sizeof(InReport));
report_size = sizeof(InReport);
}
};
static_assert(sizeof(InReport) == 20, "XInput::InReport is not the correct size");
static_assert(sizeof(InReport) == 20, "XInput::InReport is misaligned");
struct WiredChatpadReport
{
uint8_t report_id;
uint8_t chatpad[3];
WiredChatpadReport()
{
std::memset(this, 0, sizeof(WiredChatpadReport));
}
};
static_assert(sizeof(WiredChatpadReport) == 4, "XInput::WiredChatpadReport is not the correct size");
static_assert(sizeof(WiredChatpadReport) == 4, "XInput::WiredChatpadReport is misaligned");
struct InReportWireless
{
@@ -137,9 +148,10 @@ namespace XInput
InReportWireless()
{
std::memset(this, 0, sizeof(InReportWireless));
report_size = sizeof(InReportWireless);
}
};
static_assert(sizeof(InReportWireless) == 28, "XInput::InReportWireless is not the correct size");
static_assert(sizeof(InReportWireless) == 28, "XInput::InReportWireless is misaligned");
struct OutReport
{
@@ -149,8 +161,13 @@ namespace XInput
uint8_t rumble_l;
uint8_t rumble_r;
uint8_t reserved[3];
OutReport()
{
std::memset(this, 0, sizeof(OutReport));
}
};
static_assert(sizeof(OutReport) == 8, "XInput::OutReport is not the correct size");
static_assert(sizeof(OutReport) == 8, "XInput::OutReport is misaligned");
#pragma pack(pop)
static const uint8_t STRING_LANGUAGE[] = { 0x09, 0x04 };
@@ -158,7 +175,7 @@ namespace XInput
static const uint8_t STRING_PRODUCT[] = "XInput STANDARD GAMEPAD";
static const uint8_t STRING_VERSION[] = "1.0";
static const uint8_t *STRING_DESCRIPTORS[] __attribute__((unused)) =
static const uint8_t *DESC_STRING[] __attribute__((unused)) =
{
STRING_LANGUAGE,
STRING_MANUFACTURER,
@@ -166,7 +183,7 @@ namespace XInput
STRING_VERSION
};
static const uint8_t DEVICE_DESCRIPTORS[] =
static const uint8_t DESC_DEVICE[] =
{
0x12, // bLength
0x01, // bDescriptorType (Device)
@@ -184,7 +201,7 @@ namespace XInput
0x01, // bNumConfigurations 1
};
static const uint8_t CONFIGURATION_DESCRIPTORS[] =
static const uint8_t DESC_CONFIGURATION[] =
{
0x09, // bLength
0x02, // bDescriptorType (Configuration)

View File

@@ -129,7 +129,6 @@ public:
reset_pad_in();
reset_pad_out();
reset_chatpad_in();
setup_deadzones();
};
~Gamepad() = default;
@@ -143,10 +142,8 @@ public:
inline PadIn get_pad_in()
{
PadIn pad_in;
mutex_enter_blocking(&pad_in_mutex_);
pad_in = pad_in_;
PadIn pad_in = pad_in_;
new_pad_in_.store(false);
mutex_exit(&pad_in_mutex_);
@@ -155,10 +152,8 @@ public:
inline PadOut get_pad_out()
{
PadOut pad_out;
mutex_enter_blocking(&pad_out_mutex_);
pad_out = pad_out_;
PadOut pad_out = pad_out_;
new_pad_out_.store(false);
mutex_exit(&pad_out_mutex_);
@@ -167,10 +162,8 @@ public:
inline ChatpadIn get_chatpad_in()
{
ChatpadIn chatpad_in;
mutex_enter_blocking(&chatpad_in_mutex_);
chatpad_in = chatpad_in_;
ChatpadIn chatpad_in = chatpad_in_;
mutex_exit(&chatpad_in_mutex_);
return chatpad_in;
@@ -181,7 +174,7 @@ public:
void set_analog_device(bool value)
{
analog_device_.store(value);
if (analog_host_.load() && analog_device_.load() && profile_.analog_enabled)
if (analog_host_.load() && analog_device_.load() && profile_analog_enabled_)
{
analog_enabled_.store(true);
}
@@ -190,7 +183,7 @@ public:
void set_analog_host(bool value)
{
analog_host_.store(value);
if (analog_host_.load() && analog_device_.load() && profile_.analog_enabled)
if (analog_host_.load() && analog_device_.load() && profile_analog_enabled_)
{
analog_enabled_.store(true);
}
@@ -198,9 +191,9 @@ public:
void set_profile(const UserProfile& user_profile)
{
profile_ = user_profile;
setup_mappings();
setup_deadzones();
set_profile_options(user_profile);
set_profile_mappings(user_profile);
set_profile_deadzones(user_profile);
}
inline void set_pad_in(PadIn pad_in)
@@ -211,8 +204,8 @@ public:
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;
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;
@@ -238,7 +231,7 @@ public:
inline void reset_pad_in()
{
mutex_enter_blocking(&pad_in_mutex_);
std::memset(reinterpret_cast<void*>(&pad_in_), 0, sizeof(pad_in_));
pad_in_ = PadIn();
mutex_exit(&pad_in_mutex_);
new_pad_in_.store(true);
}
@@ -246,7 +239,7 @@ public:
inline void reset_pad_out()
{
mutex_enter_blocking(&pad_out_mutex_);
std::memset(reinterpret_cast<void*>(&pad_out_), 0, sizeof(pad_out_));
pad_out_ = PadOut();
new_pad_out_.store(true);
mutex_exit(&pad_out_mutex_);
}
@@ -274,7 +267,9 @@ private:
std::atomic<bool> analog_host_{false};
std::atomic<bool> analog_device_{false};
UserProfile profile_;
bool profile_invert_ly_{false};
bool profile_invert_ry_{false};
bool profile_analog_enabled_{false};
struct Deadzones
{
@@ -286,51 +281,58 @@ private:
int16_t joystick_r_pos{0};
} dz_;
void setup_mappings()
void set_profile_options(const UserProfile& profile)
{
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;
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;
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;
profile_invert_ly_ = profile.invert_ly ? true : false;
profile_invert_ry_ = profile.invert_ry ? true : false;
profile_analog_enabled_ = profile.analog_enabled ? true : false;
}
void setup_deadzones() //Deadzones in the profile are 0-255 (0-100%)
void set_profile_mappings(const UserProfile& profile)
{
dz_.trigger_l = profile_.dz_trigger_l;
dz_.trigger_r = profile_.dz_trigger_r;
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;
dz_.joystick_l_pos = Scale::uint8_to_int16(profile_.dz_joystick_l / 2);
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;
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;
}
void set_profile_deadzones(const UserProfile& profile) //Deadzones in the profile are 0-255 (0-100%)
{
dz_.trigger_l = profile.dz_trigger_l;
dz_.trigger_r = profile.dz_trigger_r;
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_pos = Scale::uint8_to_int16(profile.dz_joystick_r / 2);
dz_.joystick_r_neg = Scale::invert_joy(dz_.joystick_r_pos);
}
};

View File

@@ -32,6 +32,19 @@ void core1_task()
bluepad32::run_task(gamepads_);
}
void set_gp_check_timer(uint32_t task_id, UserSettings& user_settings)
{
TaskQueue::Core0::queue_delayed_task(task_id, 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());
}
});
}
void run_program()
{
UserSettings user_settings;
@@ -50,15 +63,7 @@ void run_program()
multicore_launch_core1(core1_task);
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());
}
});
set_gp_check_timer(tid_gp_check, user_settings);
DeviceDriver* device_driver = DeviceManager::get_instance().get_driver();

View File

@@ -282,7 +282,7 @@ private:
}
return -1;
}
};
}; // class CoreQueue
CoreQueue* CoreQueue::instances_[static_cast<uint8_t>(CoreQueue::CoreNum::Core1) + 1]{nullptr};

View File

@@ -6,14 +6,15 @@
void XInputDevice::initialize()
{
class_driver_ = *tud_xinput::class_driver();
in_report_.report_size = XInput::ENDPOINT_IN_SIZE;
}
void XInputDevice::process(const uint8_t idx, Gamepad& gamepad)
{
if (gamepad.new_pad_in())
{
std::memset(&in_report_.buttons, 0, sizeof(in_report_.buttons));
in_report_.buttons[0] = 0;
in_report_.buttons[1] = 0;
Gamepad::PadIn gp_in = gamepad.get_pad_in();
switch (gp_in.dpad)
@@ -71,10 +72,8 @@ void XInputDevice::process(const uint8_t idx, Gamepad& gamepad)
{
tud_remote_wakeup();
}
if (tud_xinput::send_report_ready())
{
tud_xinput::send_report(reinterpret_cast<uint8_t*>(&in_report_), sizeof(XInput::InReport));
}
tud_xinput::send_report((uint8_t*)&in_report_, sizeof(XInput::InReport));
}
if (tud_xinput::receive_report(reinterpret_cast<uint8_t*>(&out_report_), sizeof(XInput::OutReport)) &&
@@ -89,7 +88,7 @@ void XInputDevice::process(const uint8_t idx, Gamepad& gamepad)
uint16_t XInputDevice::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(in_report_));
std::memcpy(buffer, &in_report_, sizeof(XInput::InReport));
return sizeof(XInput::InReport);
}
@@ -102,13 +101,13 @@ bool XInputDevice::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_co
const uint16_t * XInputDevice::get_descriptor_string_cb(uint8_t index, uint16_t langid)
{
const char *value = (const char *)XInput::STRING_DESCRIPTORS[index];
const char *value = reinterpret_cast<const char*>(XInput::DESC_STRING[index]);
return get_string_descriptor(value, index);
}
const uint8_t * XInputDevice::get_descriptor_device_cb()
{
return XInput::DEVICE_DESCRIPTORS;
return XInput::DESC_DEVICE;
}
const uint8_t * XInputDevice::get_hid_descriptor_report_cb(uint8_t itf)
@@ -118,7 +117,7 @@ const uint8_t * XInputDevice::get_hid_descriptor_report_cb(uint8_t itf)
const uint8_t * XInputDevice::get_descriptor_configuration_cb(uint8_t index)
{
return XInput::CONFIGURATION_DESCRIPTORS;
return XInput::DESC_CONFIGURATION;
}
const uint8_t * XInputDevice::get_descriptor_device_qualifier_cb()

View File

@@ -1,5 +1,4 @@
#include "tusb_option.h"
#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_XINPUT)
#include <cstring>
@@ -13,12 +12,12 @@
namespace tud_xinput {
static constexpr uint8_t ENDPOINT_SIZE = 32;
static constexpr uint16_t ENDPOINT_SIZE = 32;
uint8_t endpoint_in_ = 0xFF;
uint8_t endpoint_out_ = 0xFF;
uint8_t out_buffer_[ENDPOINT_SIZE];
uint8_t in_buffer_[ENDPOINT_SIZE];
uint8_t ep_in_buffer_[ENDPOINT_SIZE];
uint8_t ep_out_buffer_[ENDPOINT_SIZE];
//Class Driver
@@ -26,7 +25,8 @@ static void init(void)
{
endpoint_in_ = 0xFF;
endpoint_out_ = 0xFF;
std::memset(out_buffer_, 0, ENDPOINT_SIZE);
std::memset(ep_out_buffer_, 0, ENDPOINT_SIZE);
std::memset(ep_in_buffer_, 0, ENDPOINT_SIZE);
}
static bool deinit(void)
@@ -42,26 +42,28 @@ static void reset(uint8_t rhport)
static uint16_t open(uint8_t rhport, tusb_desc_interface_t const *itf_descriptor, uint16_t max_length)
{
uint16_t driver_length = static_cast<uint16_t>(sizeof(tusb_desc_interface_t) + (itf_descriptor->bNumEndpoints * sizeof(tusb_desc_endpoint_t)) + 16);
uint16_t driver_length = sizeof(tusb_desc_interface_t) + (itf_descriptor->bNumEndpoints * sizeof(tusb_desc_endpoint_t)) + 16;
TU_VERIFY(max_length >= driver_length, 0);
uint8_t const *current_descriptor = tu_desc_next(itf_descriptor);
uint8_t found_endpoints = 0;
while ((found_endpoints < itf_descriptor->bNumEndpoints) && (driver_length <= max_length))
{
tusb_desc_endpoint_t const *endpoint_descriptor = reinterpret_cast<const tusb_desc_endpoint_t*>(current_descriptor);
tusb_desc_endpoint_t const *endpoint_descriptor = (tusb_desc_endpoint_t const *)current_descriptor;
if (TUSB_DESC_ENDPOINT == tu_desc_type(endpoint_descriptor))
{
TU_ASSERT(usbd_edpt_open(rhport, endpoint_descriptor));
if (tu_edpt_dir(endpoint_descriptor->bEndpointAddress) == TUSB_DIR_IN)
{
endpoint_in_ = endpoint_descriptor->bEndpointAddress;
}
else
{
endpoint_out_ = endpoint_descriptor->bEndpointAddress;
}
++found_endpoints;
}
@@ -75,11 +77,11 @@ static bool control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_
return true;
}
static bool xfer_callback(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
static bool xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
{
if (ep_addr == endpoint_out_)
{
usbd_edpt_xfer(BOARD_TUD_RHPORT, endpoint_out_, out_buffer_, ENDPOINT_SIZE);
usbd_edpt_xfer(BOARD_TUD_RHPORT, endpoint_out_, ep_out_buffer_, ENDPOINT_SIZE);
}
return true;
}
@@ -100,7 +102,7 @@ const usbd_class_driver_t* class_driver()
.reset = reset,
.open = open,
.control_xfer_cb = control_xfer_cb,
.xfer_cb = xfer_callback,
.xfer_cb = xfer_cb,
.sof = NULL
};
return &tud_class_driver_;
@@ -108,31 +110,52 @@ const usbd_class_driver_t* class_driver()
bool send_report_ready()
{
TU_VERIFY(tud_ready() && endpoint_in_ != 0xFF && !usbd_edpt_busy(BOARD_TUD_RHPORT, endpoint_in_));
return true;
if (tud_ready() &&
(endpoint_in_ != 0xFF) &&
(!usbd_edpt_busy(BOARD_TUD_RHPORT, endpoint_in_)))
{
return true;
}
return false;
}
bool receive_report_ready()
{
if (tud_ready() &&
(endpoint_out_ != 0xFF) &&
(!usbd_edpt_busy(BOARD_TUD_RHPORT, endpoint_out_)))
{
return true;
}
return false;
}
bool send_report(const uint8_t *report, uint16_t len)
{
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;
if (send_report_ready())
{
std::memcpy(ep_in_buffer_, report, std::min(len, ENDPOINT_SIZE));
usbd_edpt_claim(BOARD_TUD_RHPORT, endpoint_in_);
usbd_edpt_xfer(BOARD_TUD_RHPORT, endpoint_in_, ep_in_buffer_, sizeof(XInput::InReport));
usbd_edpt_release(BOARD_TUD_RHPORT, endpoint_in_);
return true;
}
return false;
}
bool receive_report(uint8_t *report, uint16_t len)
{
TU_VERIFY(endpoint_out_ != 0xFF && len <= ENDPOINT_SIZE);
if (tud_ready() && !usbd_edpt_busy(BOARD_TUD_RHPORT, endpoint_out_))
if (receive_report_ready())
{
usbd_edpt_xfer(BOARD_TUD_RHPORT, endpoint_out_, out_buffer_, len);
usbd_edpt_claim(BOARD_TUD_RHPORT, endpoint_out_);
usbd_edpt_xfer(BOARD_TUD_RHPORT, endpoint_out_, ep_out_buffer_, ENDPOINT_SIZE);
usbd_edpt_release(BOARD_TUD_RHPORT, endpoint_out_);
}
std::memcpy(report, out_buffer_, len);
std::memcpy(report, ep_out_buffer_, std::min(len, ENDPOINT_SIZE));
return true;
}
}; // namespace TUDXInput
} // namespace tud_xinput
#endif // (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_XINPUT)

View File

@@ -12,6 +12,7 @@ namespace tud_xinput
bool send_report(const uint8_t *report, uint16_t len);
bool receive_report(uint8_t *report, uint16_t len);
const usbd_class_driver_t* class_driver();
};
} // namespace tud_xinput
#endif // _TUD_XINPUT_H_

View File

@@ -1,454 +1,4 @@
// #include "tusb_option.h"
// #if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_XID)
// #include <cstring>
// #include "USBDevice/DeviceDriver/XboxOG/tud_xid/tud_xid.h"
// #include "Descriptors/XboxOG.h"
// #ifndef CFG_TUD_XID_XREMOTE_ENABLE
// #define CFG_TUD_XID_XREMOTE_ENABLE 0
// #endif
// #ifdef XREMOTE_ROM_AVAILABLE
// #define XREMOTE_ENABLED (CFG_TUD_XID_XREMOTE_ENABLE ? 1 : 0)
// #include "USBDevice/DeviceDriver/XboxOG/tud_xid/tud_xid_xremote_rom.h"
// #else
// #define XREMOTE_ENABLED 0
// #endif
// namespace tud_xid {
// static constexpr uint8_t ENDPOINT_SIZE = 32;
// static constexpr uint8_t INTERFACE_MULT = XREMOTE_ENABLED + 1;
// static constexpr uint8_t INTERFACE_CLASS = 0x58;
// static constexpr uint8_t INTERFACE_SUBCLASS = 0x42;
// enum class RequestType { SET_REPORT, GET_REPORT, GET_DESC, GET_CAPABILITIES_IN, GET_CAPABILITIES_OUT, UNKNOWN };
// struct Interface
// {
// Type type{Type::GAMEPAD};
// uint8_t itf_num{0xFF};
// uint8_t ep_in{0xFF};
// uint8_t ep_out{0xFF};
// uint8_t ep_in_size{0xFF};
// uint8_t ep_out_size{0xFF};
// std::array<uint8_t, ENDPOINT_SIZE> ep_out_buffer;
// std::array<uint8_t, ENDPOINT_SIZE> gp_in_buffer;
// std::array<uint8_t, ENDPOINT_SIZE> gp_out_buffer;
// Interface()
// {
// ep_out_buffer.fill(0);
// gp_in_buffer.fill(0);
// gp_out_buffer.fill(0);
// }
// };
// static std::array<Interface, CFG_TUD_XID * INTERFACE_MULT> interfaces_;
// static Type xid_type_{Type::GAMEPAD};
// static inline RequestType get_request_type(const tusb_control_request_t *request)
// {
// if (request->bmRequestType == XboxOG::GET_REPORT_REQ_TYPE && request->bRequest == XboxOG::GET_REPORT_REQ && request->wValue == XboxOG::GET_REPORT_VALUE)
// {
// return RequestType::GET_REPORT;
// }
// if (request->bmRequestType == XboxOG::SET_REPORT_REQ_TYPE && request->bRequest == XboxOG::SET_REPORT_REQ && request->wValue == XboxOG::SET_REPORT_VALUE && request->wLength == static_cast<uint16_t>(0x06))
// {
// return RequestType::SET_REPORT;
// }
// if (request->bmRequestType == XboxOG::GET_DESC_REQ_TYPE && request->bRequest == XboxOG::GET_DESC_REQ && request->wValue == XboxOG::GET_DESC_VALUE)
// {
// return RequestType::GET_DESC;
// }
// if (request->bmRequestType == XboxOG::GET_CAP_REQ_TYPE && request->bRequest == XboxOG::GET_CAP_REQ)
// {
// if (request->wValue == XboxOG::GET_CAP_VALUE_IN)
// {
// return RequestType::GET_CAPABILITIES_IN;
// }
// else if (request->wValue == XboxOG::GET_CAP_VALUE_OUT)
// {
// return RequestType::GET_CAPABILITIES_OUT;
// }
// }
// return RequestType::UNKNOWN;
// }
// static inline uint8_t get_idx_by_itf(uint8_t itf)
// {
// for (uint8_t i = 0; i < interfaces_.size(); i++)
// {
// if (interfaces_[i].itf_num == itf)
// {
// return i;
// }
// if (interfaces_[i].type == Type::XREMOTE)
// {
// if (itf == interfaces_[i].itf_num + 1)
// {
// return i;
// }
// }
// }
// return 0xFF;
// }
// static inline uint8_t get_idx_by_edpt(uint8_t edpt)
// {
// for (uint8_t i = 0; i < interfaces_.size(); i++)
// {
// if (interfaces_[i].ep_in == edpt || interfaces_[i].ep_out == edpt)
// {
// return i;
// }
// }
// return 0xFF;
// }
// uint8_t get_index_by_type(uint8_t type_idx, Type type)
// {
// uint8_t type_idx_ = 0;
// for (uint8_t i = 0; i < interfaces_.size(); i++)
// {
// if (interfaces_[i].type == type)
// {
// if (type_idx_ == type_idx)
// {
// return i;
// }
// type_idx_++;
// }
// }
// return 0xFF;
// }
// static inline Interface* find_available_interface()
// {
// for (Interface &itf : interfaces_)
// {
// if (itf.itf_num == 0xFF)
// {
// return &itf;
// }
// }
// return nullptr;
// }
// const uint8_t *xremote_get_rom()
// {
// #if XREMOTE_ENABLED
// return XRemote::ROM;
// #else
// return nullptr;
// #endif
// }
// //Class driver
// static void xid_init()
// {
// for (Interface &itf : interfaces_)
// {
// itf = Interface();
// itf.type = xid_type_;
// }
// }
// static void xid_reset(uint8_t rhport)
// {
// xid_init();
// }
// static uint16_t xid_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
// {
// TU_VERIFY(itf_desc->bInterfaceClass == INTERFACE_CLASS, 0);
// TU_VERIFY(itf_desc->bInterfaceSubClass == INTERFACE_SUBCLASS, 0);
// Interface *interface = find_available_interface();
// TU_ASSERT(interface != nullptr, 0);
// uint16_t driver_len = 0;
// switch (interface->type)
// {
// case Type::GAMEPAD:
// driver_len = XboxOG::GP::DRIVER_LEN;
// break;
// case Type::STEELBATTALION:
// driver_len = XboxOG::SB::DRIVER_LEN;
// break;
// case Type::XREMOTE:
// driver_len = XboxOG::XR::DRIVER_LEN;
// break;
// }
// TU_ASSERT(max_len >= driver_len, 0);
// interface->itf_num = itf_desc->bInterfaceNumber;
// tusb_desc_endpoint_t *ep_desc;
// ep_desc = (tusb_desc_endpoint_t *)tu_desc_next(itf_desc);
// if (tu_desc_type(ep_desc) == TUSB_DESC_ENDPOINT)
// {
// usbd_edpt_open(rhport, ep_desc);
// (ep_desc->bEndpointAddress & 0x80) ? (interface->ep_in = ep_desc->bEndpointAddress) :
// (interface->ep_out = ep_desc->bEndpointAddress);
// }
// TU_VERIFY(itf_desc->bNumEndpoints >= 2, driver_len);
// ep_desc = (tusb_desc_endpoint_t *)tu_desc_next(ep_desc);
// if (tu_desc_type(ep_desc) == TUSB_DESC_ENDPOINT)
// {
// usbd_edpt_open(rhport, ep_desc);
// (ep_desc->bEndpointAddress & 0x80) ? (interface->ep_in = ep_desc->bEndpointAddress) :
// (interface->ep_out = ep_desc->bEndpointAddress);
// }
// return driver_len;
// }
// static bool xid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
// {
// uint8_t index = get_idx_by_edpt(ep_addr);
// TU_VERIFY(result == XFER_RESULT_SUCCESS, true);
// TU_VERIFY(index != 0xFF, true);
// TU_VERIFY(xferred_bytes < ENDPOINT_SIZE, true);
// if (ep_addr == interfaces_[index].ep_out)
// {
// std::memcpy(interfaces_[index].gp_out_buffer.data(), interfaces_[index].ep_out_buffer.data(), std::min(static_cast<uint8_t>(xferred_bytes), ENDPOINT_SIZE));
// }
// return true;
// }
// bool xremote_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, Interface *interface)
// {
// if (request->bmRequestType == 0xC1 && request->bRequest == 0x01 && request->wIndex == 1 && request->wValue == 0x0000)
// {
// if (stage == CONTROL_STAGE_SETUP)
// {
// TU_LOG1("Sending XREMOTE INFO\r\n");
// const uint8_t *rom = xremote_get_rom();
// if (rom == nullptr)
// {
// return false; //STALL
// }
// tud_control_xfer(rhport, request, const_cast<uint8_t*>(&rom[0]), request->wLength);
// }
// return true;
// }
// //ROM DATA (Interface 1)
// else if (request->bmRequestType == 0xC1 && request->bRequest == 0x02 && request->wIndex == 1)
// {
// if (stage == CONTROL_STAGE_SETUP)
// {
// const uint8_t *rom = xremote_get_rom();
// if (rom == nullptr)
// {
// return false; //STALL
// }
// tud_control_xfer(rhport, request, const_cast<uint8_t*>(&rom[request->wValue * 1024]), request->wLength);
// }
// return true;
// }
// return false;
// }
// bool xid_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
// {
// TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE);
// uint8_t index = get_idx_by_itf(static_cast<uint8_t>(request->wIndex));
// TU_VERIFY(index != 0xFF, false);
// void* desc_buffer;
// uint16_t desc_buffer_len;
// switch (get_request_type(request))
// {
// case RequestType::GET_REPORT:
// if (stage == CONTROL_STAGE_SETUP)
// {
// tud_control_xfer(rhport, request, interfaces_[index].gp_in_buffer.data(), std::min(static_cast<uint8_t>(request->wLength), ENDPOINT_SIZE));
// }
// return true;
// case RequestType::SET_REPORT:
// if (stage == CONTROL_STAGE_SETUP) //Getting rumble report
// {
// tud_control_xfer(rhport, request, interfaces_[index].ep_out_buffer.data(), std::min(static_cast<uint8_t>(request->wLength), ENDPOINT_SIZE));
// }
// else if (stage == CONTROL_STAGE_ACK) //Got rumble report
// {
// std::memcpy(interfaces_[index].gp_out_buffer.data(), interfaces_[index].ep_out_buffer.data(), std::min(static_cast<uint8_t>(request->wLength), ENDPOINT_SIZE));
// }
// return true;
// case RequestType::GET_DESC:
// if (stage == CONTROL_STAGE_SETUP)
// {
// switch (interfaces_[index].type)
// {
// case Type::GAMEPAD:
// desc_buffer = (void*)XboxOG::GP::XID_DEVICE_DESCRIPTORS;
// desc_buffer_len = sizeof(XboxOG::GP::XID_DEVICE_DESCRIPTORS);
// break;
// case Type::STEELBATTALION:
// desc_buffer = (void*)XboxOG::SB::XID_DEVICE_DESCRIPTORS;
// desc_buffer_len = sizeof(XboxOG::SB::XID_DEVICE_DESCRIPTORS);
// break;
// case Type::XREMOTE:
// desc_buffer = (void*)XboxOG::XR::XID_DEVICE_DESCRIPTORS;
// desc_buffer_len = sizeof(XboxOG::XR::XID_DEVICE_DESCRIPTORS);
// break;
// default:
// return false;
// }
// tud_control_xfer(rhport, request, desc_buffer, desc_buffer_len);
// }
// return true;
// case RequestType::GET_CAPABILITIES_IN:
// if (stage == CONTROL_STAGE_SETUP)
// {
// switch (interfaces_[index].type)
// {
// case Type::GAMEPAD:
// desc_buffer = (void*)XboxOG::GP::XID_CAPABILITIES_IN;
// desc_buffer_len = sizeof(XboxOG::GP::XID_CAPABILITIES_IN);
// break;
// case Type::STEELBATTALION:
// desc_buffer = (void*)XboxOG::SB::XID_CAPABILITIES_IN;
// desc_buffer_len = sizeof(XboxOG::SB::XID_CAPABILITIES_IN);
// break;
// default:
// return false;
// }
// tud_control_xfer(rhport, request, desc_buffer, desc_buffer_len);
// }
// return true;
// case RequestType::GET_CAPABILITIES_OUT:
// if (stage == CONTROL_STAGE_SETUP)
// {
// switch (interfaces_[index].type)
// {
// case Type::GAMEPAD:
// desc_buffer = (void*)XboxOG::GP::XID_CAPABILITIES_OUT;
// desc_buffer_len = sizeof(XboxOG::GP::XID_CAPABILITIES_OUT);
// break;
// case Type::STEELBATTALION:
// desc_buffer = (void*)XboxOG::SB::XID_CAPABILITIES_OUT;
// desc_buffer_len = sizeof(XboxOG::SB::XID_CAPABILITIES_OUT);
// break;
// default:
// return false;
// }
// tud_control_xfer(rhport, request, desc_buffer, desc_buffer_len);
// }
// return true;
// default:
// if (interfaces_[index].type != Type::XREMOTE)
// {
// return false;
// }
// return xremote_control_xfer(rhport, stage, request, &interfaces_[index]);
// }
// return false;
// }
// static const usbd_class_driver_t tud_xid_class_driver_ =
// {
// #if CFG_TUSB_DEBUG >= 2
// .name = "XID DRIVER (DUKE,SB OR XREMOTE)",
// #endif
// .init = xid_init,
// .reset = xid_reset,
// .open = xid_open,
// .control_xfer_cb = xid_control_xfer_cb,
// .xfer_cb = xid_xfer_cb,
// .sof = NULL
// };
// //Public API
// //Call first before device stack is initialized with tud_init(), will default to Duke/Gamepad otherwise
// void initialize(Type xid_type)
// {
// xid_type_ = xid_type;
// }
// const usbd_class_driver_t* class_driver()
// {
// return &tud_xid_class_driver_;
// }
// bool send_report_ready(uint8_t index)
// {
// TU_VERIFY(index < interfaces_.size(), false);
// TU_VERIFY(interfaces_[index].ep_in != 0xFF, false);
// return (tud_ready() && !usbd_edpt_busy(BOARD_TUD_RHPORT, interfaces_[index].ep_in));
// }
// bool send_report(uint8_t index, const uint8_t* report, uint16_t len)
// {
// TU_VERIFY(len < ENDPOINT_SIZE, false);
// TU_VERIFY(send_report_ready(index), false);
// if (tud_suspended())
// {
// tud_remote_wakeup();
// }
// std::memcpy(interfaces_[index].gp_in_buffer.data(), report, len);
// return usbd_edpt_xfer(BOARD_TUD_RHPORT, interfaces_[index].ep_in, interfaces_[index].gp_in_buffer.data(), len);
// }
// bool receive_report(uint8_t index, uint8_t *report, uint16_t len)
// {
// TU_VERIFY(index < interfaces_.size(), false);
// TU_VERIFY(interfaces_[index].ep_out != 0xFF, false);
// TU_VERIFY(len < ENDPOINT_SIZE, false);
// std::memcpy(report, interfaces_[index].gp_out_buffer.data(), len);
// if (tud_ready() && !usbd_edpt_busy(BOARD_TUD_RHPORT, interfaces_[index].ep_out))
// {
// usbd_edpt_xfer(BOARD_TUD_RHPORT, interfaces_[index].ep_out, interfaces_[index].ep_out_buffer.data(), len);
// }
// return true;
// }
// bool xremote_rom_available()
// {
// return (xremote_get_rom() != nullptr);
// }
// } // namespace TUDXID
// #endif // TUSB_OPT_DEVICE_ENABLED && CFG_TUD_XID
#include "tusb_option.h"
#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_XID)
#include <cstring>
@@ -456,12 +6,8 @@
#include "USBDevice/DeviceDriver/XboxOG/tud_xid/tud_xid.h"
#include "Descriptors/XboxOG.h"
#ifndef CFG_TUD_XID_XREMOTE_ENABLE
#define CFG_TUD_XID_XREMOTE_ENABLE 0
#endif
#ifdef XREMOTE_ROM_AVAILABLE
#define XREMOTE_ENABLED (CFG_TUD_XID_XREMOTE_ENABLE ? 1 : 0)
#if defined(XREMOTE_ROM_AVAILABLE)
#define XREMOTE_ENABLED 1
#include "USBDevice/DeviceDriver/XboxOG/tud_xid/tud_xid_xremote_rom.h"
#else
#define XREMOTE_ENABLED 0
@@ -469,7 +15,7 @@
namespace tud_xid {
static constexpr uint8_t ENDPOINT_SIZE = 32;
static constexpr uint16_t ENDPOINT_SIZE = 32;
static constexpr uint8_t INTERFACE_MULT = XREMOTE_ENABLED + 1;
static constexpr uint8_t INTERFACE_CLASS = 0x58;
static constexpr uint8_t INTERFACE_SUBCLASS = 0x42;
@@ -680,44 +226,6 @@ static uint16_t xid_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc,
endpoint++;
}
// interface->itf_num = itf_desc->bInterfaceNumber;
// tusb_desc_endpoint_t *ep_desc;
// ep_desc = (tusb_desc_endpoint_t *)tu_desc_next(itf_desc);
// if (tu_desc_type(ep_desc) == TUSB_DESC_ENDPOINT)
// {
// TU_VERIFY(usbd_edpt_open(rhport, ep_desc), 0);
// if (tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN)
// {
// interface->ep_in = ep_desc->bEndpointAddress;
// interface->ep_in_size = ep_desc->wMaxPacketSize;
// }
// else
// {
// interface->ep_out = ep_desc->bEndpointAddress;
// interface->ep_out_size = ep_desc->wMaxPacketSize;
// }
// }
// TU_VERIFY(itf_desc->bNumEndpoints >= 2, driver_len);
// ep_desc = (tusb_desc_endpoint_t *)tu_desc_next(ep_desc);
// if (tu_desc_type(ep_desc) == TUSB_DESC_ENDPOINT)
// {
// TU_VERIFY(usbd_edpt_open(rhport, ep_desc), driver_len);
// if (tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN)
// {
// interface->ep_in = ep_desc->bEndpointAddress;
// interface->ep_in_size = ep_desc->wMaxPacketSize;
// }
// else
// {
// interface->ep_out = ep_desc->bEndpointAddress;
// interface->ep_out_size = ep_desc->wMaxPacketSize;
// }
// }
return driver_len;
}
@@ -836,22 +344,6 @@ bool xid_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t c
return true;
}
static const usbd_class_driver_t tud_xid_class_driver_ =
{
#if CFG_TUSB_DEBUG >= 2
.name = "XID DRIVER (DUKE,SB OR XREMOTE)",
#else
.name = nullptr,
#endif
.init = xid_init,
.deinit = xid_deinit,
.reset = xid_reset,
.open = xid_open,
.control_xfer_cb = xid_control_xfer_cb,
.xfer_cb = xid_xfer_cb,
.sof = NULL
};
//Public API
//Call first before device stack is initialized with tud_init(), will default to Duke/Gamepad otherwise
@@ -862,7 +354,22 @@ void initialize(Type xid_type)
const usbd_class_driver_t* class_driver()
{
return &tud_xid_class_driver_;
static const usbd_class_driver_t tud_xid_class_driver =
{
#if CFG_TUSB_DEBUG >= 2
.name = "XID",
#else
.name = nullptr,
#endif
.init = xid_init,
.deinit = xid_deinit,
.reset = xid_reset,
.open = xid_open,
.control_xfer_cb = xid_control_xfer_cb,
.xfer_cb = xid_xfer_cb,
.sof = NULL
};
return &tud_xid_class_driver;
}
bool send_report_ready(uint8_t index)
@@ -882,7 +389,7 @@ bool send_report(uint8_t index, const uint8_t* report, uint16_t len)
tud_remote_wakeup();
}
uint16_t size = std::min(len, static_cast<uint16_t>(interfaces_[index].ep_in_size));
uint16_t size = std::min(len, interfaces_[index].ep_in_size);
std::memcpy(interfaces_[index].ep_in_buffer.data(), report, size);
@@ -895,7 +402,7 @@ bool receive_report(uint8_t index, uint8_t *report, uint16_t len)
TU_VERIFY(interfaces_[index].ep_out != 0xFF);
TU_VERIFY(len < ENDPOINT_SIZE);
uint16_t size = std::min(len, static_cast<uint16_t>(interfaces_[index].ep_out_size));
uint16_t size = std::min(len, interfaces_[index].ep_out_size);
if (tud_ready() && !usbd_edpt_busy(BOARD_TUD_RHPORT, interfaces_[index].ep_out))
{

View File

@@ -5,7 +5,6 @@
#include <cstring>
#include <chrono>
#include "Board/board_api.h"
#include "USBHost/HostDriver/XInput/tuh_xinput/tuh_xinput.h"
#include "USBHost/HostDriver/XInput/tuh_xinput/tuh_xinput_cmd.h"
@@ -283,11 +282,11 @@ static bool xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uin
{
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(), 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(), interface->ep_out_size);
}
}

View File

@@ -195,9 +195,7 @@ public:
{
if (device_slot.address == address)
{
TU_LOG2("Deinit driver\r\n");
device_slot.reset();
TU_LOG2("Driver deinitialized\r\n");
}
}
}

View File

@@ -1,18 +1,20 @@
#ifndef _BOARD_CONFIG_H_
#define _BOARD_CONFIG_H_
#ifndef _OGXM_BOARD_CONFIG_H_
#define _OGXM_BOARD_CONFIG_H_
/* Don't edit this file directly, instead use CMake to configure the board.
Add args -DOGXM_BOARD=PI_PICO and -DMAX_GAMEPADS=1 (or = whatever option you want)
to set the board and the number of gamepads.
If you're setting MAX_GAMEPADS > 1 only D-Input, Switch, and WebApp device drivers will work. */
#define ADA_FEATHER 1
#define PI_PICO 2
#define RP_ZERO 3
#define PI_PICOW 4
#define INTERNAL_4CH 5
#define EXTERNAL_4CH 6
#define W_ESP32 7
#define PI_PICO 1
#define PI_PICO2 2
#define PI_PICOW 3
#define PI_PICOW2 4
#define RP_ZERO 5
#define ADA_FEATHER 6
#define INTERNAL_4CH 7
#define EXTERNAL_4CH 8
#define W_ESP32 9
#define SYSCLOCK_KHZ 240000
@@ -24,25 +26,25 @@
#define OGXM_BOARD PI_PICO
#endif
#if OGXM_BOARD == ADA_FEATHER
#define RGB_PWR_PIN 20
#define RGB_PXL_PIN 21
#define PIO_USB_DP_PIN 16 // DM = 17
#define LED_INDICATOR_PIN 13
#define VCC_EN_PIN 18
#elif OGXM_BOARD == PI_PICO || OGXM_BOARD == PI_PICO2
#if OGXM_BOARD == PI_PICO || OGXM_BOARD == PI_PICO2
#define PIO_USB_DP_PIN 0 // DM = 1
#define LED_INDICATOR_PIN 25
#elif OGXM_BOARD == PI_PICOW || OGXM_BOARD == PI_PICOW2
#elif OGXM_BOARD == RP_ZERO
#define RGB_PXL_PIN 16
#define PIO_USB_DP_PIN 10 // DM = 11
#define LED_INDICATOR_PIN 14
#elif OGXM_BOARD == PI_PICOW
#elif OGXM_BOARD == ADA_FEATHER
#define RGB_PWR_PIN 20
#define RGB_PXL_PIN 21
#define PIO_USB_DP_PIN 16 // DM = 17
#define LED_INDICATOR_PIN 13
#define VCC_EN_PIN 18
#elif OGXM_BOARD == INTERNAL_4CH
#define PIO_USB_DP_PIN 16 // DM = 17
@@ -63,7 +65,7 @@
#elif OGXM_BOARD == W_ESP32
#define I2C_SDA_PIN 18 // SCL = 19
#define UART0_TX_PIN 16 // RX = 17
#define UART0_RX_PIN (UART0_TX_PIN + 1)
#define UART0_RX_PIN (UART0_TX_PIN + 1)
#define MODE_SEL_PIN 21
#define ESP_PROG_PIN 20 // ESP32 IO0
#define ESP_RST_PIN 8 // ESP32 EN
@@ -114,4 +116,4 @@
#define DEBUG_UART_PORT __CONCAT(uart,PICO_DEFAULT_UART)
#endif // defined(OGXM_DEBUG)
#endif // _BOARD_CONFIG_H_
#endif // _OGXM_BOARD_CONFIG_H_

View File

@@ -110,8 +110,6 @@
#define CFG_TUD_XID 1
#define CFG_TUD_XINPUT 1
#define CFG_TUD_XID_XREMOTE_ENABLE 1
// HID buffer size Should be sufficient to hold ID (if any) + Data
#define CFG_TUD_HID_EP_BUFSIZE 64
#define CFG_TUD_CDC_EP_BUFSIZE 64

18
Firmware/external/init_submodules.cmake vendored Normal file
View File

@@ -0,0 +1,18 @@
function(init_git_submodules EXTERNAL_DIR)
set(REPO_DIR "${EXTERNAL_DIR}/../../")
message(STATUS "Initializing submodules in ${REPO_DIR}")
execute_process(
COMMAND git submodule update --init --recursive
WORKING_DIRECTORY ${REPO_DIR}
RESULT_VARIABLE INIT_SUBMODULES_RESULT
OUTPUT_VARIABLE INIT_SUBMODULES_OUTPUT
ERROR_VARIABLE INIT_SUBMODULES_ERROR
)
if(INIT_SUBMODULES_RESULT EQUAL 0)
message(STATUS "Subnmodules initialized successfully.")
else()
message(FATAL_ERROR "Failed to initialize submodules: ${INIT_SUBMODULES_ERROR}")
endif()
endfunction()

View File

@@ -3,7 +3,7 @@
Firmware for the RP2040, capable of emulating gamepads for several game consoles. The firmware comes in many flavors, supported on the [Adafruit Feather USB Host board](https://www.adafruit.com/product/5723), Pi Pico, Pi Pico 2, Waveshare RP2040-Zero, Pi Pico W, RP2040/ESP32 hybrid, and a 4-Channel RP2040-Zero setup.
Visit the web app here: [https://wiredopposite.github.io/OGX-Mini-WebApp/](https://wiredopposite.github.io/OGX-Mini-WebApp/) to change your mappings and deadzone settings. To pair the OGX-Mini with the web app, plug your controller in, then connect it to your PC, hold **Start + Left Bumper + Right Bumper** to enter Web app mode. Click "Connect" in the web app and select the OGX-Mini.
Visit the web app here: [https://wiredopposite.github.io/OGX-Mini-WebApp/](https://wiredopposite.github.io/OGX-Mini-WebApp/) to change your mappings and deadzone settings. To pair the OGX-Mini with the web app, plug your controller in, then connect it to your PC, hold **Start + Left Bumper + Right Bumper** to enter web app mode. Click "Connect" in the web app and select the OGX-Mini.
## Supported platforms
- Original Xbox
@@ -127,4 +127,8 @@ Or just install the GCC ARM toolchain and use the CMake Tools extension in VSCod
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.
Please see the Hardware directory for a schematic showing how to hookup the ESP32 to your RP2040.
You will need ESP-IDF v5.1, esptools, and python3 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.
When you build with ESP-IDF, Cmake will run a python script that copies the necessary BTStack files components directory, this is needed since BTStack isn't configured as an IDF component when you download it.