v1.0.0-alpha

This commit is contained in:
wiredopposite
2024-12-19 23:15:27 -07:00
parent f863f84976
commit aabb00f2b5
112 changed files with 3869 additions and 4782 deletions

4
.gitignore vendored
View File

@@ -1,13 +1,11 @@
Firmware/.vscode
Firmware/RP2040/build
Firmware/RP2040/.ignore
Firmware/RP2040/src/USBDevice/DeviceDriver/XboxOG/tud_xid/tud_xid_xremote_rom.h
Firmware/ESP32/.ignore
Firmware/ESP32/build
Firmware/ESP32/components/btstack
Firmware/ESP32/sdkconfig.old
Firmware/external/pico-sdk
Firmware/external/picotool
Tools/dvd-dongle-rom.bin

3
.gitmodules vendored
View File

@@ -7,3 +7,6 @@
[submodule "Tools/dump-dvd-kit"]
path = Tools/dump-dvd-kit
url = https://github.com/XboxDev/dump-dvd-kit.git
[submodule "Firmware/external/Pico-PIO-USB"]
path = Firmware/external/Pico-PIO-USB
url = https://github.com/wiredopposite/Pico-PIO-USB.git

View File

@@ -1,12 +1,4 @@
#include <cstdint>
#include <atomic>
#include <cstring>
#include <array>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/timers.h>
#include <freertos/queue.h>
#include <esp_log.h>
#include <functional>
#include "btstack_port_esp32.h"
#include "btstack_run_loop.h"
@@ -14,60 +6,82 @@
#include "uni.h"
#include "sdkconfig.h"
#include "Board/board_api.h"
#include "I2CDriver/I2CDriver.h"
#include "Board/board_api.h"
#include "Bluepad32/Gamepad.h"
#include "Bluepad32/Bluepad32.h"
namespace bluepad32 {
// I2CDriver i2c_driver;
namespace BP32 {
static constexpr uint8_t MAX_DEVICES = CONFIG_BLUEPAD32_MAX_DEVICES;
static constexpr uint32_t FEEDBACK_TIME_MS = 200;
static constexpr uint32_t LED_TIME_MS = 500;
struct Device
I2CDriver i2c_driver_;
btstack_timer_source_t feedback_timer_;
std::atomic<bool> devs_conn_[MAX_DEVICES]{false};
static inline void send_feedback_cb(void* context)
{
std::atomic<bool> connected{false};
std::atomic<bool> new_report_in{false};
std::atomic<ReportIn> report_in{ReportIn()};
std::atomic<ReportOut> report_out{ReportOut()};
};
I2CDriver::PacketOut packet_out = reinterpret_cast<std::atomic<I2CDriver::PacketOut>*>(context)->load();
uni_hid_device_t* bp_device = nullptr;
std::array<Device, CONFIG_BLUEPAD32_MAX_DEVICES> devices_;
static inline void send_feedback_cb(btstack_timer_source *ts)
{
uni_hid_device_t* bp_device;
for (uint8_t i = 0; i < CONFIG_BLUEPAD32_MAX_DEVICES; ++i)
if (!(bp_device = uni_hid_device_get_instance_for_idx(packet_out.index)) ||
!uni_bt_conn_is_connected(&bp_device->conn) ||
!bp_device->report_parser.play_dual_rumble)
{
bp_device = uni_hid_device_get_instance_for_idx(i);
if (!bp_device || !bp_device->report_parser.play_dual_rumble)
return;
}
if (packet_out.rumble_l || packet_out.rumble_r)
{
bp_device->report_parser.play_dual_rumble(
bp_device,
0,
FEEDBACK_TIME_MS,
packet_out.rumble_l,
packet_out.rumble_r
);
}
}
static inline void feedback_timer_cb(btstack_timer_source *ts)
{
static btstack_context_callback_registration_t cb_registration[MAX_DEVICES];
static std::atomic<I2CDriver::PacketOut> packets_out[MAX_DEVICES];
uni_hid_device_t* bp_device = nullptr;
for (uint8_t i = 0; i < MAX_DEVICES; ++i)
{
if (!(bp_device = uni_hid_device_get_instance_for_idx(i)) ||
!uni_bt_conn_is_connected(&bp_device->conn))
{
continue;
}
ReportOut report_out = devices_[i].report_out.load();
if (!report_out.rumble_l && !report_out.rumble_r)
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]
{
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);
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]);
}
});
}
btstack_run_loop_set_timer(ts, FEEDBACK_TIME_MS);
btstack_run_loop_add_timer(ts);
}
static inline void check_led_cb(btstack_timer_source *ts)
inline void check_led_cb(btstack_timer_source *ts)
{
static bool led_state = false;
led_state = !led_state;
@@ -80,7 +94,7 @@ static inline void check_led_cb(btstack_timer_source *ts)
{
for (uint8_t i = 0; i < board_api::NUM_LEDS; ++i)
{
board_api::set_led(i, devices_[i].connected.load() ? 1 : (led_state ? 1 : 0));
board_api::set_led(i, devs_conn_[i].load() ? 1 : (led_state ? 1 : 0));
}
}
@@ -90,24 +104,21 @@ static inline void check_led_cb(btstack_timer_source *ts)
//BT Driver
static void init(int argc, const char** arg_V)
{
}
static void init(int argc, const char** arg_V) {}
static void init_complete_cb(void)
{
uni_bt_enable_new_connections_unsafe(true);
// // Based on runtime condition, you can delete or list the stored BT keys.
// if (1)
// {
// Based on runtime condition, you can delete or list the stored BT keys.
if (1)
{
uni_bt_del_keys_unsafe();
// }
// else
// {
// uni_bt_list_keys_unsafe();
// }
}
else
{
uni_bt_list_keys_unsafe();
}
uni_property_dump_all();
}
@@ -126,46 +137,59 @@ static void device_connected_cb(uni_hid_device_t* device)
#ifdef CONFIG_BLUEPAD32_USB_CONSOLE_ENABLE
logd("BP32", "Device connected, addr: %p, index: %i\n", device, uni_hid_device_get_idx_for_instance(device));
#endif
int idx = uni_hid_device_get_idx_for_instance(device);
if (idx >= CONFIG_BLUEPAD32_MAX_DEVICES || idx < 0)
{
return;
}
devices_[idx].connected.store(true);
}
static void device_disconnected_cb(uni_hid_device_t* device)
void device_disconnected_cb(uni_hid_device_t* device)
{
#ifdef CONFIG_BLUEPAD32_USB_CONSOLE_ENABLE
logd("BP32", "Device disconnected, addr: %p, index: %i\n", device, uni_hid_device_get_idx_for_instance(device));
#endif
int idx = uni_hid_device_get_idx_for_instance(device);
if (idx >= CONFIG_BLUEPAD32_MAX_DEVICES || idx < 0)
if (idx >= MAX_DEVICES || idx < 0)
{
return;
}
ReportIn report_in = ReportIn();
report_in.index = static_cast<uint8_t>(idx);
devices_[idx].report_in.store(report_in);
devices_[idx].connected.store(false);
devs_conn_[idx].store(false);
if (!any_connected())
{
btstack_run_loop_remove_timer(&feedback_timer_);
}
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));
});
}
static uni_error_t device_ready_cb(uni_hid_device_t* device)
{
int idx = uni_hid_device_get_idx_for_instance(device);
if (idx >= MAX_DEVICES || idx < 0)
{
return UNI_ERROR_IGNORE_DEVICE;
}
devs_conn_[idx].store(true);
feedback_timer_.process = feedback_timer_cb;
feedback_timer_.context = nullptr;
btstack_run_loop_set_timer(&feedback_timer_, FEEDBACK_TIME_MS);
btstack_run_loop_add_timer(&feedback_timer_);
return UNI_ERROR_SUCCESS;
}
static void oob_event_cb(uni_platform_oob_event_t event, void* data)
static inline void controller_data_cb(uni_hid_device_t* device, uni_controller_t* controller)
{
return;
}
static void controller_data_cb(uni_hid_device_t* device, uni_controller_t* controller)
{
static uni_gamepad_t prev_uni_gp[CONFIG_BLUEPAD32_MAX_DEVICES] = {};
static uni_gamepad_t prev_uni_gps[MAX_DEVICES]{0};
if (controller->klass != UNI_CONTROLLER_CLASS_GAMEPAD)
{
@@ -175,77 +199,85 @@ 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 >= CONFIG_BLUEPAD32_MAX_DEVICES || idx < 0 || std::memcmp(uni_gp, &prev_uni_gp[idx], sizeof(uni_gamepad_t)) == 0)
if (idx < 0 || std::memcmp(uni_gp, &prev_uni_gps[idx], sizeof(uni_gamepad_t)) == 0)
{
return;
}
ReportIn report_in;
report_in.index = static_cast<uint8_t>(idx);
I2CDriver::PacketIn packet_in;
packet_in.index = static_cast<uint8_t>(idx);
switch (uni_gp->dpad)
{
case DPAD_UP:
report_in.dpad = Gamepad::DPad::UP;
packet_in.dpad = Gamepad::DPad::UP;
break;
case DPAD_DOWN:
report_in.dpad = Gamepad::DPad::DOWN;
packet_in.dpad = Gamepad::DPad::DOWN;
break;
case DPAD_LEFT:
report_in.dpad = Gamepad::DPad::LEFT;
packet_in.dpad = Gamepad::DPad::LEFT;
break;
case DPAD_RIGHT:
report_in.dpad = Gamepad::DPad::RIGHT;
packet_in.dpad = Gamepad::DPad::RIGHT;
break;
case (DPAD_UP | DPAD_RIGHT):
report_in.dpad = Gamepad::DPad::UP_RIGHT;
packet_in.dpad = Gamepad::DPad::UP_RIGHT;
break;
case (DPAD_DOWN | DPAD_RIGHT):
report_in.dpad = Gamepad::DPad::DOWN_RIGHT;
packet_in.dpad = Gamepad::DPad::DOWN_RIGHT;
break;
case (DPAD_DOWN | DPAD_LEFT):
report_in.dpad = Gamepad::DPad::DOWN_LEFT;
packet_in.dpad = Gamepad::DPad::DOWN_LEFT;
break;
case (DPAD_UP | DPAD_LEFT):
report_in.dpad = Gamepad::DPad::UP_LEFT;
packet_in.dpad = Gamepad::DPad::UP_LEFT;
break;
default:
break;
}
if (uni_gp->buttons & BUTTON_A) report_in.buttons |= Gamepad::Button::A;
if (uni_gp->buttons & BUTTON_B) report_in.buttons |= Gamepad::Button::B;
if (uni_gp->buttons & BUTTON_X) report_in.buttons |= Gamepad::Button::X;
if (uni_gp->buttons & BUTTON_Y) report_in.buttons |= Gamepad::Button::Y;
if (uni_gp->buttons & BUTTON_SHOULDER_L) report_in.buttons |= Gamepad::Button::LB;
if (uni_gp->buttons & BUTTON_SHOULDER_R) report_in.buttons |= Gamepad::Button::RB;
if (uni_gp->buttons & BUTTON_THUMB_L) report_in.buttons |= Gamepad::Button::L3;
if (uni_gp->buttons & BUTTON_THUMB_R) report_in.buttons |= Gamepad::Button::R3;
if (uni_gp->misc_buttons & MISC_BUTTON_BACK) report_in.buttons |= Gamepad::Button::BACK;
if (uni_gp->misc_buttons & MISC_BUTTON_START) report_in.buttons |= Gamepad::Button::START;
if (uni_gp->misc_buttons & MISC_BUTTON_SYSTEM) report_in.buttons |= Gamepad::Button::SYS;
if (uni_gp->misc_buttons & MISC_BUTTON_CAPTURE) report_in.buttons |= Gamepad::Button::MISC;
if (uni_gp->buttons & BUTTON_A) packet_in.buttons |= Gamepad::Button::A;
if (uni_gp->buttons & BUTTON_B) packet_in.buttons |= Gamepad::Button::B;
if (uni_gp->buttons & BUTTON_X) packet_in.buttons |= Gamepad::Button::X;
if (uni_gp->buttons & BUTTON_Y) packet_in.buttons |= Gamepad::Button::Y;
if (uni_gp->buttons & BUTTON_SHOULDER_L) packet_in.buttons |= Gamepad::Button::LB;
if (uni_gp->buttons & BUTTON_SHOULDER_R) packet_in.buttons |= Gamepad::Button::RB;
if (uni_gp->buttons & BUTTON_THUMB_L) packet_in.buttons |= Gamepad::Button::L3;
if (uni_gp->buttons & BUTTON_THUMB_R) packet_in.buttons |= Gamepad::Button::R3;
if (uni_gp->misc_buttons & MISC_BUTTON_BACK) packet_in.buttons |= Gamepad::Button::BACK;
if (uni_gp->misc_buttons & MISC_BUTTON_START) packet_in.buttons |= Gamepad::Button::START;
if (uni_gp->misc_buttons & MISC_BUTTON_SYSTEM) packet_in.buttons |= Gamepad::Button::SYS;
if (uni_gp->misc_buttons & MISC_BUTTON_CAPTURE) packet_in.buttons |= Gamepad::Button::MISC;
report_in.trigger_l = Gamepad::scale_trigger(uni_gp->brake);
report_in.trigger_r = Gamepad::scale_trigger(uni_gp->throttle);
packet_in.trigger_l = Scale::uint10_to_uint8(uni_gp->brake);
packet_in.trigger_r = Scale::uint10_to_uint8(uni_gp->throttle);
report_in.joystick_lx = static_cast<int16_t>(uni_gp->axis_x);
report_in.joystick_ly = static_cast<int16_t>(uni_gp->axis_y);
report_in.joystick_rx = static_cast<int16_t>(uni_gp->axis_rx);
report_in.joystick_ry = static_cast<int16_t>(uni_gp->axis_ry);
packet_in.joystick_lx = Scale::int10_to_int16(uni_gp->axis_x);
packet_in.joystick_ly = Scale::int10_to_int16(uni_gp->axis_y);
packet_in.joystick_rx = Scale::int10_to_int16(uni_gp->axis_rx);
packet_in.joystick_ry = Scale::int10_to_int16(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));
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));
});
std::memcpy(uni_gp, &prev_uni_gp[idx], sizeof(uni_gamepad_t));
std::memcpy(&prev_uni_gps[idx], uni_gp, sizeof(uni_gamepad_t));
}
const uni_property_t* get_property_cb(uni_property_idx_t idx)
static const uni_property_t* get_property_cb(uni_property_idx_t idx)
{
return nullptr;
}
static void oob_event_cb(uni_platform_oob_event_t event, void* data)
{
return;
}
uni_platform* get_driver()
{
static uni_platform driver =
@@ -264,49 +296,45 @@ uni_platform* get_driver()
return &driver;
}
//Public
//Public
ReportIn get_report_in(uint8_t index)
bool any_connected()
{
devices_[index].new_report_in.store(false);
return devices_[index].report_in.load();
for (auto& connected : devs_conn_)
{
if (connected.load())
{
return true;
}
}
return false;
}
void set_report_out(const ReportOut& report_out)
bool connected(uint8_t index)
{
if (report_out.index >= CONFIG_BLUEPAD32_MAX_DEVICES)
{
return;
}
devices_[report_out.index].report_out.store(report_out);
return devs_conn_[index].load();
}
void run_task()
{
for (uint8_t i = 0; i < CONFIG_BLUEPAD32_MAX_DEVICES; ++i)
{
ReportIn report_in;
report_in.index = i;
devices_[i].report_in.store(report_in);
devices_[i].report_out.store(ReportOut());
}
board_api::init_pins();
// i2c_driver.initialize_i2c();
i2c_driver_.initialize_i2c();
xTaskCreatePinnedToCore(
i2c_driver_.run_tasks,
"i2c",
2048 * 2,
nullptr,
configMAX_PRIORITIES-8,
nullptr,
1 );
btstack_init();
uni_platform_set_custom(get_driver());
uni_init(0, nullptr);
btstack_timer_source_t feedback_timer;
feedback_timer.process = send_feedback_cb;
feedback_timer.context = nullptr;
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;
@@ -317,26 +345,4 @@ void run_task()
btstack_run_loop_execute();
}
bool any_connected()
{
for (auto& device : devices_)
{
if (device.connected.load())
{
return true;
}
}
return false;
}
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
} // namespace BP32

View File

@@ -3,18 +3,11 @@
#include <cstdint>
#include "sdkconfig.h"
#include "I2CDriver/I2CDriver.h"
#include "Reports.h"
namespace bluepad32
namespace BP32
{
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);
bool connected(uint8_t index);
}
#endif // _BLUEPAD32_DRIVER_H_

View File

@@ -33,50 +33,68 @@ namespace Gamepad
static constexpr uint16_t MISC = 0x0800;
}
} // namespace Gamepad
namespace Scale
{
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 MID = 0x80;
static constexpr uint8_t MAX = 0xFF;
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;
}
static inline uint8_t scale_joystick(int32_t value)
static inline int16_t int10_to_int16(int32_t value)
{
value = value - INT_10::MIN;
constexpr int32_t scale_factor = INT_16::MAX - INT_16::MIN;
constexpr int32_t range = INT_10::MAX - INT_10::MIN;
if (value >= UINT_10::MAX)
if (value >= INT_10::MAX)
{
return UINT_8::MAX;
return INT_16::MAX;
}
else if (value <= 0)
else if (value <= INT_10::MIN)
{
return 0;
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);
}
static inline uint8_t scale_trigger(int32_t value)
{
if (value >= UINT_10::MAX)
{
return UINT_8::MAX;
}
else if (value <= 0)
{
return 0;
}
return static_cast<uint8_t>(value >> 2);
}
} // namespace Gamepad
} // namespace Scale
#endif // GAMEPAD_H

View File

@@ -38,7 +38,6 @@ namespace board_api
void init_pins();
void set_led(uint8_t index, bool state);
void set_led(bool state);
void check_reset_pin();
}
#endif // _BOARD_API_H_

View File

@@ -1,4 +1,3 @@
#include <array>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/timers.h>
@@ -8,6 +7,13 @@
#include "I2CDriver/I2CDriver.h"
#include "Bluepad32/Bluepad32.h"
I2CDriver::TaskQueue I2CDriver::task_queue_;
I2CDriver::~I2CDriver()
{
i2c_driver_delete(I2C_NUM_0);
}
void I2CDriver::initialize_i2c()
{
i2c_config_t conf;
@@ -18,46 +24,21 @@ void I2CDriver::initialize_i2c()
conf.scl_io_num = GPIO_NUM_22;
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
conf.master.clk_speed = 400 * 1000;
conf.master.clk_speed = 1000 * 1000;
i2c_param_config(I2C_NUM_0, &conf);
i2c_driver_install(I2C_NUM_0, conf.mode, 0, 0, 0);
}
void I2CDriver::run_task()
void I2CDriver::run_tasks(void* parameter)
{
ReportIn report_in;
ReportOut report_out;
initialize_i2c();
std::function<void()> task;
while (true)
{
for (uint8_t i = 0; i < CONFIG_BLUEPAD32_MAX_DEVICES; ++i)
{
while (task_queue_.pop(task))
{
if (!bluepad32::connected(i))
{
vTaskDelay(1);
continue;
}
if (bluepad32::new_report_in(i))
{
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);
if (i2c_read_blocking(MULTI_SLAVE ? (i + 1) : 0x01, reinterpret_cast<uint8_t*>(&report_out), sizeof(ReportOut)) != ESP_OK)
{
continue;
}
bluepad32::set_report_out(report_out);
task();
}
vTaskDelay(1);

View File

@@ -3,12 +3,12 @@
#include <cstdint>
#include <cstring>
#include <atomic>
#include <functional>
#include <driver/i2c.h>
#include "Reports.h"
#include "sdkconfig.h"
#include "RingBuffer.h"
//Will probably refactor this to be event driven
class I2CDriver
{
public:
@@ -19,14 +19,67 @@ public:
true;
#endif
I2CDriver() = default;
~I2CDriver() { i2c_driver_delete(I2C_NUM_0); }
enum class PacketID : uint8_t { UNKNOWN = 0, SET_PAD, GET_PAD };
void run_task();
#pragma pack(push, 1)
struct PacketIn
{
uint8_t packet_len;
uint8_t packet_id;
uint8_t index;
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;
PacketIn()
{
std::memset(this, 0, sizeof(PacketIn));
packet_len = sizeof(PacketIn);
packet_id = static_cast<uint8_t>(PacketID::SET_PAD);
}
};
static_assert(sizeof(PacketIn) == 16, "PacketIn is misaligned");
struct PacketOut
{
uint8_t packet_len;
uint8_t packet_id;
uint8_t index;
uint8_t rumble_l;
uint8_t rumble_r;
uint8_t reserved[3];
PacketOut()
{
std::memset(this, 0, sizeof(PacketOut));
packet_len = sizeof(PacketOut);
packet_id = static_cast<uint8_t>(PacketID::GET_PAD);
}
};
static_assert(sizeof(PacketOut) == 8, "PacketOut is misaligned");
#pragma pack(pop)
I2CDriver() = default;
~I2CDriver();
void initialize_i2c();
static inline esp_err_t i2c_write_blocking(uint8_t address, const uint8_t* buffer, size_t len)
//Does not return
static void run_tasks(void* parameter);
//Thread safe
inline void push_task(std::function<void()> task)
{
task_queue_.push(task);
}
//Don't call directly from another thread, use in push_task
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();
i2c_master_start(cmd);
@@ -39,7 +92,8 @@ public:
return ret;
}
static inline esp_err_t i2c_read_blocking(uint8_t address, uint8_t* buffer, size_t len)
//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();
i2c_master_start(cmd);
@@ -59,17 +113,8 @@ public:
}
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_{};
using TaskQueue = RingBuffer<std::function<void()>, 6>;
static TaskQueue task_queue_;
};
#endif // _I2C_DRIVER_H_

View File

@@ -1,134 +0,0 @@
#ifndef _REPORTS_H_
#define _REPORTS_H_
#include <cstdint>
// #include <array>
#include <cstring>
// #include "freertos/FreeRTOS.h"
// #include "freertos/semphr.h"
enum class ReportID : uint8_t { UNKNOWN = 0, SET_PAD, GET_PAD };
#pragma pack(push, 1)
struct ReportIn
{
uint8_t report_len;
uint8_t report_id;
uint8_t index;
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;
ReportIn()
{
std::memset(this, 0, sizeof(ReportIn));
report_len = sizeof(ReportIn);
report_id = static_cast<uint8_t>(ReportID::SET_PAD);
}
};
static_assert(sizeof(ReportIn) == 16, "ReportIn is misaligned");
struct ReportOut
{
uint8_t report_len;
uint8_t report_id;
uint8_t index;
uint8_t rumble_l;
uint8_t rumble_r;
ReportOut()
{
std::memset(this, 0, sizeof(ReportOut));
report_len = sizeof(ReportOut);
report_id = static_cast<uint8_t>(ReportID::GET_PAD);
}
};
static_assert(sizeof(ReportOut) == 5, "ReportOut is misaligned");
#pragma pack(pop)
// class ReportQueue
// {
// public:
// ReportQueue()
// {
// report_in_mutex_ = xSemaphoreCreateMutex();
// report_out_mutex_ = xSemaphoreCreateMutex();
// }
// ~ReportQueue()
// {
// vSemaphoreDelete(report_in_mutex_);
// vSemaphoreDelete(report_out_mutex_);
// }
// void set_report_in(const ReportIn* report)
// {
// if (xSemaphoreTake(report_in_mutex_, portMAX_DELAY))
// {
// std::memcpy(&report_in_, report, sizeof(ReportIn));
// new_report_in_ = true;
// xSemaphoreGive(report_in_mutex_);
// }
// }
// void set_report_out(const ReportOut* report)
// {
// if (xSemaphoreTake(report_out_mutex_, portMAX_DELAY))
// {
// std::memcpy(&report_out_, report, sizeof(ReportOut));
// new_report_out_ = true;
// xSemaphoreGive(report_out_mutex_);
// }
// }
// //Return false if no new data
// bool get_report_in(ReportIn* report)
// {
// if (xSemaphoreTake(report_in_mutex_, portMAX_DELAY))
// {
// if (new_report_in_)
// {
// std::memcpy(report, &report_in_, sizeof(ReportIn));
// new_report_in_ = false;
// xSemaphoreGive(report_in_mutex_);
// return true;
// }
// xSemaphoreGive(report_in_mutex_);
// }
// return false;
// }
// //Return false if no new data
// bool get_report_out(ReportOut* report)
// {
// if (xSemaphoreTake(report_out_mutex_, portMAX_DELAY))
// {
// if (new_report_out_)
// {
// std::memcpy(report, &report_out_, sizeof(ReportOut));
// new_report_out_ = false;
// xSemaphoreGive(report_out_mutex_);
// return true;
// }
// xSemaphoreGive(report_out_mutex_);
// }
// return false;
// }
// private:
// SemaphoreHandle_t report_in_mutex_;
// SemaphoreHandle_t report_out_mutex_;
// ReportIn report_in_;
// ReportOut report_out_;
// bool new_report_in_{false};
// bool new_report_out_{false};
// };
#endif // _REPORTS_H_

View File

@@ -0,0 +1,57 @@
#ifndef _RING_BUFFER_H_
#define _RING_BUFFER_H_
#include <cstdint>
#include <atomic>
#include <array>
template<typename Type, size_t Size>
class RingBuffer
{
public:
RingBuffer() : head_(0), tail_(0) {}
RingBuffer(const RingBuffer&) = delete;
RingBuffer& operator=(const RingBuffer&) = delete;
RingBuffer(RingBuffer&&) = default;
RingBuffer& operator=(RingBuffer&&) = default;
bool push(const Type& item)
{
size_t head = head_.load(std::memory_order_relaxed);
size_t next_head = (head + 1) % SIZE;
if (next_head == tail_.load(std::memory_order_acquire))
{
tail_.store((tail_.load(std::memory_order_relaxed) + 1) % SIZE, std::memory_order_release);
}
buffer_[head] = item;
head_.store(next_head, std::memory_order_release);
return true;
}
bool pop(Type& item)
{
size_t tail = tail_.load(std::memory_order_relaxed);
if (tail == head_.load(std::memory_order_acquire))
{
return false;
}
item = buffer_[tail];
tail_.store((tail + 1) % SIZE, std::memory_order_release);
return true;
}
private:
const size_t SIZE = Size;
std::array<Type, Size> buffer_;
std::atomic<size_t> head_;
std::atomic<size_t> tail_;
};
#endif // _RING_BUFFER_H_

View File

@@ -1,14 +1,24 @@
#include <functional>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include "c_wrapper.h"
#include "I2CDriver/I2CDriver.h"
#include "sdkconfig.h"
#include "Bluepad32/Bluepad32.h"
void run_bluepad32()
void bp32_run_task(void* parameter)
{
bluepad32::run_task();
BP32::run_task();
}
void run_i2c()
void cpp_main()
{
I2CDriver i2c_driver;
i2c_driver.run_task();
xTaskCreatePinnedToCore(
bp32_run_task,
"bp32",
2048 * 4,
NULL,
configMAX_PRIORITIES-4,
NULL,
0 );
}

View File

@@ -7,8 +7,7 @@
extern "C" {
#endif
void run_bluepad32();
void run_i2c();
void cpp_main();
#ifdef __cplusplus
}

View File

@@ -1,31 +1,9 @@
#include <stdlib.h>
#include <stdint.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include "sdkconfig.h"
#include "c_wrapper.h"
#define STACK_MULTIPLIER (2048 * CONFIG_BLUEPAD32_MAX_DEVICES)
void app_main(void)
{
// run_bluepad32();
xTaskCreatePinnedToCore(
run_bluepad32,
"bp32",
STACK_MULTIPLIER * 4,
NULL,
configMAX_PRIORITIES-6,
NULL,
0 );
xTaskCreatePinnedToCore(
run_i2c,
"i2c",
STACK_MULTIPLIER * 2,
NULL,
configMAX_PRIORITIES-8,
NULL,
1 );
cpp_main();
}

View File

@@ -1,6 +1,6 @@
#
# Automatically generated file. DO NOT EDIT.
# Espressif IoT Development Framework (ESP-IDF) 5.1.5 Project Configuration
# Espressif IoT Development Framework (ESP-IDF) Project Configuration
#
CONFIG_SOC_BROWNOUT_RESET_SUPPORTED="Not determined"
CONFIG_SOC_TWAI_BRP_DIV_SUPPORTED="Not determined"
@@ -362,11 +362,11 @@ CONFIG_ESP_CUSTOM_BOARD=y
# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set
CONFIG_COMPILER_OPTIMIZATION_PERF=y
# CONFIG_COMPILER_OPTIMIZATION_NONE is not set
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE is not set
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y
CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2
CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=0
# CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set
CONFIG_COMPILER_HIDE_PATHS_MACROS=y
# CONFIG_COMPILER_CXX_EXCEPTIONS is not set
@@ -1358,9 +1358,7 @@ CONFIG_FREERTOS_DEBUG_OCDAWARE=y
#
CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y
# CONFIG_HAL_ASSERTION_DISABLE is not set
# CONFIG_HAL_ASSERTION_SILENT is not set
# CONFIG_HAL_ASSERTION_ENABLE is not set
CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2
CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=0
CONFIG_HAL_SPI_MASTER_FUNC_IN_IRAM=y
CONFIG_HAL_SPI_SLAVE_FUNC_IN_IRAM=y
# CONFIG_HAL_ECDSA_GEN_SIG_CM is not set
@@ -1546,7 +1544,6 @@ CONFIG_LWIP_DNS_MAX_SERVERS=3
# end of DNS
CONFIG_LWIP_BRIDGEIF_MAX_PORTS=7
CONFIG_LWIP_ESP_LWIP_ASSERT=y
#
# Hooks
@@ -1981,11 +1978,11 @@ CONFIG_BLUEPAD32_PLATFORM_CUSTOM=y
# CONFIG_BLUEPAD32_PLATFORM_MAKEFILE is not set
CONFIG_BLUEPAD32_MAX_DEVICES=1
CONFIG_BLUEPAD32_GAP_SECURITY=y
# CONFIG_BLUEPAD32_LOG_LEVEL_NONE is not set
CONFIG_BLUEPAD32_LOG_LEVEL_ERROR=y
CONFIG_BLUEPAD32_LOG_LEVEL_NONE=y
# CONFIG_BLUEPAD32_LOG_LEVEL_ERROR is not set
# CONFIG_BLUEPAD32_LOG_LEVEL_INFO is not set
# CONFIG_BLUEPAD32_LOG_LEVEL_DEBUG is not set
CONFIG_BLUEPAD32_LOG_LEVEL=1
CONFIG_BLUEPAD32_LOG_LEVEL=0
# CONFIG_BLUEPAD32_USB_CONSOLE_ENABLE is not set
CONFIG_BLUEPAD32_ENABLE_BLE_BY_DEFAULT=y
CONFIG_BLUEPAD32_MAX_ALLOWLIST=4
@@ -2025,10 +2022,10 @@ CONFIG_MONITOR_BAUD=115200
# CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set
# CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set
# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set
CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y
# CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED is not set
# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set
# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set
CONFIG_OPTIMIZATION_ASSERTION_LEVEL=2
CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED=y
CONFIG_OPTIMIZATION_ASSERTION_LEVEL=0
# CONFIG_CXX_EXCEPTIONS is not set
CONFIG_STACK_CHECK_NONE=y
# CONFIG_STACK_CHECK_NORM is not set
@@ -2372,7 +2369,6 @@ CONFIG_TIMER_TASK_PRIORITY=1
CONFIG_TIMER_TASK_STACK_DEPTH=4096
CONFIG_TIMER_QUEUE_LENGTH=10
# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set
# CONFIG_HAL_ASSERTION_SILIENT is not set
# CONFIG_L2_TO_L3_COPY is not set
CONFIG_ESP_GRATUITOUS_ARP=y
CONFIG_GARP_TMR_INTERVAL=60

View File

@@ -1,15 +1,23 @@
{
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
"cmake.buildEnvironment": {
"PICO_SDK_PATH": "C:/Programming/pico-sdk"
},
"cmake.environment": {
"PICO_SDK_PATH": "C:/Programming/pico-sdk"
},
"cmake.configureArgs": [
"-DOGXM_BOARD=PI_PICO",
"-DMAX_GAMEPADS=1"
],
"files.associations": {
"array": "cpp",
"any": "cpp",
"atomic": "cpp",
"barrier": "cpp",
"any": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"cfenv": "cpp",
"charconv": "cpp",
"chrono": "cpp",
"cinttypes": "cpp",
@@ -17,11 +25,7 @@
"cmath": "cpp",
"codecvt": "cpp",
"compare": "cpp",
"complex": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"coroutine": "cpp",
"csetjmp": "cpp",
"csignal": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
@@ -40,91 +44,44 @@
"set": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"expected": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"netfwd": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"regex": "cpp",
"source_location": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"rope": "cpp",
"slist": "cpp",
"format": "cpp",
"fstream": "cpp",
"future": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"latch": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"ranges": "cpp",
"scoped_allocator": "cpp",
"semaphore": "cpp",
"shared_mutex": "cpp",
"span": "cpp",
"spanstream": "cpp",
"sstream": "cpp",
"stacktrace": "cpp",
"stdexcept": "cpp",
"stdfloat": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"syncstream": "cpp",
"thread": "cpp",
"typeindex": "cpp",
"typeinfo": "cpp",
"valarray": "cpp",
"variant": "cpp",
"xlocmon": "cpp",
"xtr1common": "cpp",
"xutility": "cpp",
"ios": "cpp",
"locale": "cpp",
"queue": "cpp",
"xfacet": "cpp",
"xhash": "cpp",
"xiosbase": "cpp",
"xlocale": "cpp",
"xlocbuf": "cpp",
"xlocinfo": "cpp",
"xlocmes": "cpp",
"xlocnum": "cpp",
"xloctime": "cpp",
"xmemory": "cpp",
"xstring": "cpp",
"filesystem": "cpp",
"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"
]
"variant": "cpp"
}
}

View File

@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.13)
set(FW_NAME "OGX-Mini")
set(FW_VERSION "v1.0.0-alpha")
set(FW_VERSION "v1.0.0a")
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
@@ -19,14 +19,6 @@ include(${CMAKE_CURRENT_LIST_DIR}/cmake/get_pico_sdk.cmake)
apply_lib_patches(${EXTERNAL_DIR})
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 "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)
set(PICO_PIO_USB_PATH ${EXTERNAL_DIR}/Pico-PIO-USB)
set(PICO_TINYUSB_PATH ${EXTERNAL_DIR}/tinyusb)
set(BLUEPAD32_ROOT ${EXTERNAL_DIR}/bluepad32)
@@ -37,7 +29,7 @@ set(SOURCES_BOARD
${SRC}/main.cpp
${SRC}/OGXMini/OGXMini_Standard.cpp
${SRC}/OGXMini/OGXMini_4Ch.cpp
${SRC}/OGXMini/OGXMini_4Channel.cpp
${SRC}/OGXMini/OGXMini_PicoW.cpp
${SRC}/OGXMini/OGXMini_ESP32.cpp
@@ -81,6 +73,7 @@ set(INC_DIRS_BOARD
)
# Config options
# Max gamepads
set(MAX_GAMEPADS 1 CACHE STRING "Set number of gamepads, 1 to 4")
if (MAX_GAMEPADS GREATER 4 OR MAX_GAMEPADS LESS 1)
@@ -97,6 +90,11 @@ set(PICO_BOARD none)
if (OGXM_BOARD STREQUAL "PI_PICO")
set(EN_USB_HOST TRUE)
elseif (OGXM_BOARD STREQUAL "PI_PICO2")
set(EN_USB_HOST TRUE)
set(PICO_PLATFORM rp2350)
set(FLASH_SIZE_MB 4)
elseif(OGXM_BOARD STREQUAL "ADA_FEATHER")
set(EN_USB_HOST TRUE)
set(EN_RGB TRUE)
@@ -135,28 +133,29 @@ if(EN_USB_HOST)
add_compile_definitions(CONFIG_EN_USB_HOST=1)
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/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/XInput/tuh_xinput/tuh_xinput.cpp
# HID
${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/HIDParser/HIDJoystick.cpp
${SRC}/USBHost/HIDParser/HIDReportDescriptor.cpp
${SRC}/USBHost/HIDParser/HIDReportDescriptorElements.cpp
${SRC}/USBHost/HIDParser/HIDReportDescriptorUsages.cpp
${SRC}/USBHost/HIDParser/HIDUtils.cpp
# XInput
${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/XInput/tuh_xinput/tuh_xinput.cpp
)
list(APPEND LIBS_BOARD
tinyusb_host
@@ -211,7 +210,7 @@ if(EN_ESP32)
add_compile_definitions(CONFIG_EN_ESP32=1)
message(STATUS "ESP32 enabled.")
list(APPEND SOURCES_BOARD
${SRC}/I2CDriver/i2c_driver_esp32.cpp
${SRC}/I2CDriver/ESP32/I2CDriver.cpp
)
list(APPEND LIBS_BOARD
hardware_i2c
@@ -238,31 +237,45 @@ 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_XOSC_STARTUP_DELAY_MULTIPLIER=64)
endif()
include(${PICO_SDK_PATH}/pico_sdk_init.cmake)
message("PICO_SDK_VERSION_STRING: ${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)
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
# )
set(BUILD_STR "")
add_link_options(
-Wl,--gc-sections
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(BUILD_STR "-Debug")
pico_enable_stdio_uart(${FW_NAME} 1)
target_compile_definitions(${FW_NAME} PRIVATE
PICO_DEFAULT_UART=1
PICO_DEFAULT_UART_TX_PIN=4
PICO_DEFAULT_UART_RX_PIN=5
)
add_compile_definitions(LOG=1)
add_compile_definitions(CFG_TUSB_DEBUG=1)
add_compile_definitions(OGXM_DEBUG=1)
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
-Wno-unused-parameter # Disable warnings for unused parameters
# -Werror # Treat warnings as errors
)
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
pico_enable_stdio_uart(${FW_NAME} 0)
add_compile_definitions(CFG_TUSB_DEBUG=0)
add_compile_options(
-O3 # Optimize for speed
@@ -301,7 +314,7 @@ endif()
target_link_libraries(${FW_NAME} PRIVATE ${LIBS_BOARD})
set(EXE_FILENAME "${FW_NAME}-${FW_VERSION}-${OGXM_BOARD}")
set(EXE_FILENAME "${FW_NAME}-${FW_VERSION}-${OGXM_BOARD}${BUILD_STR}")
set_target_properties(${FW_NAME} PROPERTIES OUTPUT_NAME ${EXE_FILENAME})
pico_add_extra_outputs(${FW_NAME})

View File

@@ -29,8 +29,10 @@ struct BTDevice
};
BTDevice bt_devices_[MAX_GAMEPADS];
btstack_timer_source_t feedback_timer_;
btstack_timer_source_t led_timer_;
bool led_timer_set_{false};
bool feedback_timer_set_{false};
//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)
@@ -117,11 +119,7 @@ static void init_complete_cb(void)
{
uni_bt_enable_new_connections_unsafe(true);
// Based on runtime condition, you can delete or list the stored BT keys.
if (1)
uni_bt_del_keys_unsafe();
else
uni_bt_list_keys_unsafe();
// uni_bt_del_keys_unsafe();
uni_property_dump_all();
}
@@ -155,6 +153,11 @@ static void device_disconnected_cb(uni_hid_device_t* device)
btstack_run_loop_set_timer(&led_timer_, LED_CHECK_TIME_MS);
btstack_run_loop_add_timer(&led_timer_);
}
if (feedback_timer_set_ && !any_connected())
{
feedback_timer_set_ = false;
btstack_run_loop_remove_timer(&feedback_timer_);
}
}
static uni_error_t device_ready_cb(uni_hid_device_t* device)
@@ -172,6 +175,14 @@ static uni_error_t device_ready_cb(uni_hid_device_t* device)
btstack_run_loop_remove_timer(&led_timer_);
board_api::set_led(true);
}
if (!feedback_timer_set_)
{
feedback_timer_set_ = true;
feedback_timer_.process = send_feedback_cb;
feedback_timer_.context = nullptr;
btstack_run_loop_set_timer(&feedback_timer_, FEEDBACK_TIME_MS);
btstack_run_loop_add_timer(&feedback_timer_);
}
return UNI_ERROR_SUCCESS;
}
@@ -283,12 +294,6 @@ void run_task(Gamepad (&gamepads)[MAX_GAMEPADS])
uni_platform_set_custom(get_driver());
uni_init(0, nullptr);
btstack_timer_source_t feedback_timer;
feedback_timer.process = send_feedback_cb;
feedback_timer.context = nullptr;
btstack_run_loop_set_timer(&feedback_timer, FEEDBACK_TIME_MS);
btstack_run_loop_add_timer(&feedback_timer);
led_timer_set_ = true;
led_timer_.process = check_led_cb;
led_timer_.context = nullptr;
@@ -298,16 +303,6 @@ void run_task(Gamepad (&gamepads)[MAX_GAMEPADS])
btstack_run_loop_execute();
}
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] = bt_devices_[i].connected;
}
return mounted_map;
}
bool any_connected()
{
for (auto& device : bt_devices_)

View File

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

View File

@@ -1,12 +1,11 @@
/*
Copyright ForsakenNGS 2021
https://github.com/ForsakenNGS/Pico_WS2812
*/
#include "Board/Pico_WS2812/WS2812.hpp"
#include "WS2812.pio.h"
//#define DEBUG
#ifdef DEBUG
#include <stdio.h>
#endif
WS2812::WS2812(uint pin, uint length, PIO pio, uint sm) {
initialize(pin, length, pio, sm, NONE, GREEN, RED, BLUE);
}
@@ -42,16 +41,14 @@ void WS2812::initialize(uint pin, uint length, PIO pio, uint sm, DataByte b1, Da
this->length = length;
this->pio = pio;
this->sm = sm;
this->data.fill(0);
this->data = new uint32_t[length];
this->bytes[0] = b1;
this->bytes[1] = b2;
this->bytes[2] = b3;
this->bytes[3] = b4;
uint offset = pio_add_program(pio, &ws2812_program);
uint bits = (b1 == NONE ? 24 : 32);
#ifdef DEBUG
printf("WS2812 / Initializing SM %u with offset %X at pin %u and %u data bits...\n", sm, offset, pin, bits);
#endif
ws2812_program_init(pio, sm, offset, pin, 800000, bits);
}
@@ -111,11 +108,6 @@ void WS2812::fill(uint32_t color, uint first, uint count) {
}
void WS2812::show() {
#ifdef DEBUG
for (uint i = 0; i < length; i++) {
printf("WS2812 / Put data: %08X\n", data[i]);
}
#endif
for (uint i = 0; i < length; i++) {
pio_sm_put_blocking(pio, sm, data[i]);
}

View File

@@ -1,3 +1,8 @@
/*
Copyright ForsakenNGS 2021
https://github.com/ForsakenNGS/Pico_WS2812
*/
#ifndef WS2812_H
#define WS2812_H
@@ -48,7 +53,7 @@ class WS2812 {
PIO pio;
uint sm;
DataByte bytes[4];
std::array<uint32_t, 20> data;
uint32_t *data;
void initialize(uint pin, uint length, PIO pio, uint sm, DataByte b1, DataByte b2, DataByte b3, DataByte b4);
uint32_t convertData(uint32_t rgbw);

View File

@@ -1,11 +1,11 @@
/* This is too messy I'll clean it up at some point */
#include <pico/stdlib.h>
#include <pico/mutex.h>
#include <hardware/clocks.h>
#include <hardware/gpio.h>
#include <hardware/watchdog.h>
#include "Board/board_api.h"
#include "OGXMini/Debug.h"
#include "board_config.h"
#if defined(CONFIG_EN_BLUETOOTH)
@@ -22,45 +22,35 @@ namespace board_api {
bool inited_ = false;
mutex_t gpio_mutex_;
#if defined(CONFIG_EN_RGB)
WS2812 ws2812_ = WS2812(RGB_PXL_PIN, 1, pio1, 0, WS2812::FORMAT_GRB);
#endif // defined(CONFIG_EN_RGB)
void init_gpio()
{
if (inited_)
{
return;
}
if (!mutex_is_initialized(&gpio_mutex_))
{
mutex_init(&gpio_mutex_);
}
mutex_enter_blocking(&gpio_mutex_);
#ifdef VCC_EN_PIN
void init_vcc_en_pin_unsafe()
{
#if defined(VCC_EN_PIN)
gpio_init(VCC_EN_PIN);
gpio_set_dir(VCC_EN_PIN, GPIO_OUT);
gpio_put(VCC_EN_PIN, 1);
#endif
}
#if defined(CONFIG_EN_RGB)
#ifdef RGB_PWR_PIN
void init_rgb_unsafe()
{
#if defined(CONFIG_EN_RGB) && defined(RGB_PWR_PIN)
gpio_init(RGB_PWR_PIN);
gpio_set_dir(RGB_PWR_PIN, GPIO_OUT);
gpio_put(RGB_PWR_PIN, 1);
#endif
#endif // defined(CONFIG_EN_RGB) && defined(RGB_PWR_PIN)
}
#elif defined(CONFIG_EN_BLUETOOTH)
//
#elif defined(LED_INDICATOR_PIN)
void init_led_indicator_unsafe()
{
#if defined(LED_INDICATOR_PIN) && !defined(CONFIG_EN_BLUETOOTH)
gpio_init(LED_INDICATOR_PIN);
gpio_set_dir(LED_INDICATOR_PIN, GPIO_OUT);
gpio_put(LED_INDICATOR_PIN, 0);
#endif // defined(LED_INDICATOR_PIN)
}
#endif
void init_esp32_io_unsafe()
{
#if defined(CONFIG_EN_ESP32)
gpio_init(ESP_PROG_PIN);
gpio_set_dir(ESP_PROG_PIN, GPIO_OUT);
@@ -71,31 +61,46 @@ void init_gpio()
gpio_put(ESP_RST_PIN, 1);
#endif //defined(CONFIG_EN_ESP32)
}
void init_uart_bridge_io_unsafe()
{
#if defined(CONFIG_EN_UART_BRIDGE)
gpio_init(MODE_SEL_PIN);
gpio_set_dir(MODE_SEL_PIN, GPIO_IN);
gpio_pull_up(MODE_SEL_PIN);
#endif // defined(CONFIG_EN_UART_BRIDGE)
}
inited_ = true;
mutex_exit(&gpio_mutex_);
void init_uart_debug_unsafe()
{
#if defined(OGXM_DEBUG)
uart_init(DEBUG_UART_PORT, PICO_DEFAULT_UART_BAUD_RATE);
gpio_set_function(PICO_DEFAULT_UART_TX_PIN, GPIO_FUNC_UART);
gpio_set_function(PICO_DEFAULT_UART_RX_PIN, GPIO_FUNC_UART);
#endif // defined(OGXM_DEBUG)
}
void set_led(bool state)
{
if (!inited_)
{
return;
}
mutex_enter_blocking(&gpio_mutex_);
#if defined(CONFIG_EN_RGB)
ws2812_.setPixelColor(0, state ? WS2812::RGB(0x00, 0xFF, 0x00) : WS2812::RGB(0xFF, 0, 0));
ws2812_.show();
if (!inited_)
{
mutex_exit(&gpio_mutex_);
return;
}
#elif defined(CONFIG_EN_BLUETOOTH)
#if defined(CONFIG_EN_RGB)
static WS2812 ws2812 = WS2812(RGB_PXL_PIN, 1, pio1, 0, WS2812::FORMAT_GRB);
ws2812.setPixelColor(0, state ? WS2812::RGB(0x00, 0xFF, 0x00) : WS2812::RGB(0xFF, 0, 0));
ws2812.show();
#endif // defined(CONFIG_EN_RGB)
#if defined(CONFIG_EN_BLUETOOTH)
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, state ? 1 : 0);
#elif defined(LED_INDICATOR_PIN)
@@ -177,13 +182,43 @@ void reboot()
AIRCR_REG = AIRCR_VECTKEY | AIRCR_SYSRESETREQ;
while(1);
}
// watchdog_enable(500, true); // 10-second timeout
// while (true)
// {
// // Your main loop logic
// watchdog_update(); // Reset the watchdog timer
// }
void init_board()
{
if (inited_)
{
return;
}
if (!set_sys_clock_khz(SYSCLOCK_KHZ, true) && !set_sys_clock_khz(120000, true))
{
panic("Failed to set sys clock");
}
stdio_init_all();
if (!mutex_is_initialized(&gpio_mutex_))
{
mutex_init(&gpio_mutex_);
}
mutex_enter_blocking(&gpio_mutex_);
init_uart_debug_unsafe();
init_vcc_en_pin_unsafe();
init_rgb_unsafe();
init_led_indicator_unsafe();
init_esp32_io_unsafe();
init_uart_bridge_io_unsafe();
inited_ = true;
mutex_exit(&gpio_mutex_);
set_led(false);
OGXM_LOG("Board initialized\n");
}
} // namespace board_api

View File

@@ -1,11 +1,12 @@
#ifndef _BOARD_API_H_
#define _BOARD_API_H_
#ifndef _OGXM_BOARD_API_H_
#define _OGXM_BOARD_API_H_
#include <cstdint>
#include <string>
namespace board_api
{
void init_gpio();
void init_board();
void set_led(bool state);
void reboot();
@@ -14,4 +15,4 @@ namespace board_api
void enter_esp32_prog_mode();
}
#endif // _BOARD_API_H_
#endif // _OGXM_BOARD_API_H_

View File

@@ -9,73 +9,58 @@
namespace CDCDesc
{
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
// #define USB_VID 0xCafe
// #define USB_BCD 0x0200
static const uint16_t VID = 0xCafe;
static const uint16_t PID = (0x4000 | _PID_MAP(CDC, 0));
static const uint16_t USB_VER = 0x0200;
static const tusb_desc_device_t DEVICE_DESCRIPTORS =
const tusb_desc_device_t DESC_DEVICE =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
.bcdUSB = USB_VER,
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = 0xCafe,
.idProduct = USB_PID,
.idVendor = VID,
.idProduct = PID,
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
enum Itf
{
NUM_CDC = 0,
NUM_CDC_DATA,
NUM_TOTAL
CDC_0 = 0,
CDC_0_DATA,
ITF_TOTAL
};
#define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x82
static const int CONFIG_LEN = (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN);
static constexpr int CONFIG_LEN = (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN);
static const uint8_t CONFIGURATION_DESCRIPTORS[] =
static const uint8_t DESC_CONFIG[] =
{
TUD_CONFIG_DESCRIPTOR(1, Itf::NUM_TOTAL, 0, CONFIG_LEN, 0x00, 500),
TUD_CDC_DESCRIPTOR(Itf::NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
TUD_CONFIG_DESCRIPTOR(1, Itf::ITF_TOTAL, 0, CONFIG_LEN, 0x00, 500),
TUD_CDC_DESCRIPTOR(Itf::CDC_0, 4, 0x80 | (Itf::CDC_0 + 1), 8, (Itf::CDC_0 + 2), 0x80 | (Itf::CDC_0 + 2), 64),
};
enum
static const uint8_t STRING_DESC_LANGUAGE[] = { 0x09, 0x04 };
static const uint8_t STRING_MANUFACTURER[] = "Wired Opposite";
static const uint8_t STRING_PRODUCT[] = "OGX-Mini";
static const uint8_t STRING_INTERFACE[] = "OGX-Mini CDC";
static const uint8_t *DESC_STRING[] =
{
STRID_LANGID = 0,
STRID_MANUFACTURER,
STRID_PRODUCT,
STRID_SERIAL,
STRING_DESC_LANGUAGE,
STRING_MANUFACTURER,
STRING_PRODUCT,
nullptr, //Serial
STRING_INTERFACE
};
static const char *STRING_DESCRIPTORS[] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
NULL, // 3: Serials will use unique ID if possible
"TinyUSB CDC", // 4: CDC Interface
};
static uint16_t _desc_str[32 + 1];
}; // namespace CDCDesc
#endif // _CDC_DEV_DESCRIPTORS_H_

View File

@@ -75,6 +75,11 @@ namespace DInput
uint8_t r1_axis;
uint8_t l2_axis;
uint8_t r2_axis;
InReport()
{
std::memset(this, 0, sizeof(InReport));
}
};
#pragma pack(pop)
static_assert(sizeof(InReport) == 19, "DInput::InReport is misaligned");

View File

@@ -10,7 +10,7 @@
namespace PS3
{
static constexpr uint8_t MAGIC_BYTES[8] = { 0x21, 0x26, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
static constexpr uint8_t JOYSTICK_MID = 0x80;
static constexpr uint8_t JOYSTICK_MID = 0x7F;
static constexpr uint16_t SIXAXIS_MID = 0xFF01;
namespace ReportID
@@ -94,22 +94,19 @@ namespace PS3
struct InReport
{
uint8_t report_id;
uint8_t reserved0;
uint8_t unk0;
uint8_t buttons[3];
uint8_t reserved1;
uint8_t unk1;
uint8_t joystick_lx;
uint8_t joystick_ly;
uint8_t joystick_rx;
uint8_t joystick_ry;
uint8_t reserved2[2];
uint8_t unk2[2];
uint8_t move_power_status;
uint8_t reserved3;
uint8_t unk3;
uint8_t up_axis;
uint8_t right_axis;
@@ -126,7 +123,7 @@ namespace PS3
uint8_t cross_axis;
uint8_t square_axis;
uint8_t reserved4[3];
uint8_t unk4[3];
uint8_t plugged;
uint8_t power_status;
@@ -137,8 +134,7 @@ namespace PS3
uint16_t acceler_x;
uint16_t acceler_y;
uint16_t acceler_z;
uint16_t velocity_z;
uint16_t gyro_z;
InReport()
{
@@ -151,44 +147,50 @@ namespace PS3
plugged = PlugState::PLUGGED;
power_status = PowerState::FULL;
rumble_status = RumbleState::WIRED_RUMBLE;
acceler_x = acceler_y = acceler_z = velocity_z = SIXAXIS_MID;
acceler_x = acceler_y = acceler_z = gyro_z = SIXAXIS_MID;
}
};
static_assert(sizeof(InReport) == 49, "PS3::InReport size mismatch");
struct LEDs {
uint8_t time_enabled; /* the total time the led is active (0xff means forever) */
uint8_t duty_length; /* how long a cycle is in deciseconds (0 means "really fast") */
uint8_t enabled;
uint8_t duty_off; /* % of duty_length the led is off (0xff means 100%) */
uint8_t duty_on; /* % of duty_length the led is on (0xff mean 100%) */
};
static_assert(sizeof(LEDs) == 5, "PS3::LEDs size mismatch");
struct Rumble {
uint8_t reserved;
uint8_t right_duration; /* Right motor duration (0xff means forever) */
uint8_t right_motor_on; /* Right (small) motor on/off, only supports values of 0 or 1 (off/on) */
uint8_t left_duration; /* Left motor duration (0xff means forever) */
uint8_t left_motor_force; /* left (large) motor, supports force values from 0 to 255 */
};
static_assert(sizeof(Rumble) == 5, "PS3::Rumble size mismatch");
struct OutReport
{
struct Rumble rumble;
uint8_t padding[4];
uint8_t leds_bitmap; /* bitmap of enabled LEDs: LED_1 = 0x02, LED_2 = 0x04, ... */
struct LEDs led[4]; /* LEDx at (4 - x) */
struct LEDs reserved; /* LED5, not actually soldered */
//uint8_t report_id;
uint8_t reserved0;
struct Rumble
{
uint8_t right_duration; /* Right motor duration (0xff means forever) */
uint8_t right_motor_on; /* Right (small) motor on/off, only supports values of 0 or 1 (off/on) */
uint8_t left_duration; /* Left motor duration (0xff means forever) */
uint8_t left_motor_force; /* left (large) motor, supports force values from 0 to 255 */
} rumble;
uint8_t reserved1[4];
uint8_t leds_bitmap; /* bitmap of enabled LEDs: LED_1 = 0x02, LED_2 = 0x04, ... */
struct LEDs
{
uint8_t time_enabled; /* the total time the led is active (0xff means forever) */
uint8_t duty_length; /* how long a cycle is in deciseconds (0 means "really fast") */
uint8_t enabled;
uint8_t duty_off; /* % of duty_length the led is off (0xff means 100%) */
uint8_t duty_on; /* % of duty_length the led is on (0xff mean 100%) */
} leds[4]; /* LEDx at (4 - x) */
struct LEDs unused; /* LED5, not actually soldered */
uint8_t reserved2[13];
OutReport()
{
std::memcpy(this, DEFAULT_OUT_REPORT, sizeof(OutReport));
std::memset(this, 0, sizeof(OutReport));
std::memcpy(this, DEFAULT_OUT_REPORT, sizeof(DEFAULT_OUT_REPORT));
}
};
static_assert(sizeof(OutReport) == 35, "PS3::OutReport size mismatch");
static_assert(sizeof(OutReport) == sizeof(DEFAULT_OUT_REPORT));
static_assert(sizeof(OutReport) == 48, "PS3::OutReport size mismatch");
static_assert(sizeof(OutReport) >= sizeof(DEFAULT_OUT_REPORT));
static constexpr uint8_t DEFAULT_BT_INFO_HEADER[] =
{
0xFF, 0xFF,
0x00, 0x20, 0x40, 0xCE, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
struct BTInfo
{
@@ -200,20 +202,19 @@ namespace PS3
BTInfo()
{
std::memset(this, 0, sizeof(BTInfo));
std::memset(reserved0, 0xFF, sizeof(reserved0));
uint8_t addr[] = { 0x00, 0x20, 0x40, 0xCE, 0x00, 0x00, 0x00 };
std::memcpy(device_address, addr, sizeof(addr));
std::memcpy(device_address, DEFAULT_BT_INFO_HEADER, sizeof(DEFAULT_BT_INFO_HEADER));
for (uint8_t addr = 0; addr < 3; addr++)
{
device_address[4 + addr] = static_cast<uint8_t>(get_rand_32() % 0xFF);
device_address[4 + addr] = static_cast<uint8_t>(get_rand_32() % 0xff);
}
for (uint8_t addr = 0; addr < 6; addr++)
{
host_address[1 + addr] = static_cast<uint8_t>(get_rand_32() % 0xFF);
host_address[1 + addr] = static_cast<uint8_t>(get_rand_32() % 0xff);
}
}
};
static_assert(sizeof(BTInfo) == 17, "PS3::BTInfo size mismatch");
static_assert(sizeof(BTInfo) >= sizeof(DEFAULT_BT_INFO_HEADER));
#pragma pack(pop)
static const uint8_t STRING_LANGUAGE[] = { 0x09, 0x04 };
@@ -327,128 +328,10 @@ namespace PS3
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
0xC0, // End Collection
// 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
// 0x09, 0x04, // Usage (Joystick)
// 0xA1, 0x01, // Collection (Application)
// 0xA1, 0x02, // Collection (Logical)
// 0x85, 0x01, // Report ID (1)
// 0x75, 0x08, // Report Size (8)
// 0x95, 0x01, // Report Count (1)
// 0x15, 0x00, // Logical Minimum (0)
// 0x26, 0xFF, 0x00, // Logical Maximum (255)
// 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
// 0x75, 0x01, // Report Size (1)
// 0x95, 0x13, // Report Count (19)
// 0x15, 0x00, // Logical Minimum (0)
// 0x25, 0x01, // Logical Maximum (1)
// 0x35, 0x00, // Physical Minimum (0)
// 0x45, 0x01, // Physical Maximum (1)
// 0x05, 0x09, // Usage Page (Button)
// 0x19, 0x01, // Usage Minimum (0x01)
// 0x29, 0x13, // Usage Maximum (0x13)
// 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
// 0x75, 0x01, // Report Size (1)
// 0x95, 0x0D, // Report Count (13)
// 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
// 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
// 0x15, 0x00, // Logical Minimum (0)
// 0x26, 0xFF, 0x00, // Logical Maximum (255)
// 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
// 0x09, 0x01, // Usage (Pointer)
// 0xA1, 0x00, // Collection (Physical)
// 0x75, 0x08, // Report Size (8)
// 0x95, 0x04, // Report Count (4)
// 0x35, 0x00, // Physical Minimum (0)
// 0x46, 0xFF, 0x00, // Physical Maximum (255)
// 0x09, 0x30, // Usage (X)
// 0x09, 0x31, // Usage (Y)
// 0x09, 0x32, // Usage (Z)
// 0x09, 0x35, // Usage (Rz)
// 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
// 0xC0, // End Collection
// 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
// 0x75, 0x08, // Report Size (8)
// 0x95, 0x27, // Report Count (39)
// 0x09, 0x01, // Usage (Pointer)
// 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
// 0x75, 0x08, // Report Size (8)
// 0x95, 0x30, // Report Count (48)
// 0x09, 0x01, // Usage (Pointer)
// 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
// 0x75, 0x08, // Report Size (8)
// 0x95, 0x30, // Report Count (48)
// 0x09, 0x01, // Usage (Pointer)
// 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
// 0xC0, // End Collection
// 0xA1, 0x02, // Collection (Logical)
// 0x85, 0x02, // Report ID (2)
// 0x75, 0x08, // Report Size (8)
// 0x95, 0x30, // Report Count (48)
// 0x09, 0x01, // Usage (Pointer)
// 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
// 0xC0, // End Collection
// 0xA1, 0x02, // Collection (Logical)
// 0x85, 0xEE, // Report ID (-18)
// 0x75, 0x08, // Report Size (8)
// 0x95, 0x30, // Report Count (48)
// 0x09, 0x01, // Usage (Pointer)
// 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
// 0xC0, // End Collection
// 0xA1, 0x02, // Collection (Logical)
// 0x85, 0xEF, // Report ID (-17)
// 0x75, 0x08, // Report Size (8)
// 0x95, 0x30, // Report Count (48)
// 0x09, 0x01, // Usage (Pointer)
// 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
// 0xC0, // End Collection
// 0xC0, // End Collection
};
// #define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN)
static const uint8_t CONFIGURATION_DESCRIPTORS[] =
{
// 0x09, // bLength
// 0x02, // bDescriptorType (Configuration)
// 0x29, 0x00, // wTotalLength 41
// 0x01, // bNumInterfaces 1
// 0x01, // bConfigurationValue
// 0x00, // iConfiguration (String Index)
// 0x80, // bmAttributes
// 0xFA, // bMaxPower 500mA
// 0x09, // bLength
// 0x04, // bDescriptorType (Interface)
// 0x00, // bInterfaceNumber 0
// 0x00, // bAlternateSetting
// 0x02, // bNumEndpoints 2
// 0x03, // bInterfaceClass
// 0x00, // bInterfaceSubClass
// 0x00, // bInterfaceProtocol
// 0x00, // iInterface (String Index)
// 0x09, // bLength
// 0x21, // bDescriptorType (HID)
// 0x11, 0x01, // bcdHID 1.11
// 0x00, // bCountryCode
// 0x01, // bNumDescriptors
// 0x22, // bDescriptorType[0] (HID)
// 0x94, 0x00, // wDescriptorLength[0] 148
// 0x07, // bLength
// 0x05, // bDescriptorType (Endpoint)
// 0x02, // bEndpointAddress (OUT/H2D)
// 0x03, // bmAttributes (Interrupt)
// 0x40, 0x00, // wMaxPacketSize 64
// 0x0A, // bInterval 10 (unit depends on device speed)
// 0x07, // bLength
// 0x05, // bDescriptorType (Endpoint)
// 0x81, // bEndpointAddress (IN/D2H)
// 0x03, // bmAttributes (Interrupt)
// 0x40, 0x00, // wMaxPacketSize 64
// 0x0A, // bInterval 10 (unit depends on device speed)
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0x29, 0x00, // wTotalLength 41
@@ -490,6 +373,68 @@ namespace PS3
0x40, 0x00, // wMaxPacketSize 64
0x01, // bInterval 1 (unit depends on device speed)
};
static constexpr uint8_t OUTPUT_0x01[] =
{
0x01, 0x04, 0x00, 0x0b, 0x0c, 0x01, 0x02, 0x18,
0x18, 0x18, 0x18, 0x09, 0x0a, 0x10, 0x11, 0x12,
0x13, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02,
0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x04, 0x04,
0x04, 0x04, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02,
0x07, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// calibration data
static constexpr uint8_t OUTPUT_0xEF[] =
{
0xef, 0x04, 0x00, 0x0b, 0x03, 0x01, 0xa0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff,
0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
};
// unknown
static constexpr uint8_t OUTPUT_0xF5[] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // host address - must match 0xf2
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// unknown
static constexpr uint8_t OUTPUT_0xF7[] =
{
0x02, 0x01, 0xf8, 0x02, 0xe2, 0x01, 0x05, 0xff,
0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// unknown
static constexpr uint8_t OUTPUT_0xF8[] =
{
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
} // namespace PS3
#endif // _PS3_DESCRIPTORS_H_

View File

@@ -7,9 +7,13 @@
namespace PS5
{
static constexpr uint8_t DPAD_MASK = 0x0F;
static constexpr size_t IN_REPORT_CMP_SIZE = 12;
static constexpr uint8_t JOYSTICK_MID = 0x80;
static constexpr uint8_t OUT_REPORT_ID = 5;
namespace OutReportID
{
static constexpr uint8_t CONTROL = 0x02;
static constexpr uint8_t RUMBLE = 0x05;
};
namespace Buttons0
{
@@ -68,30 +72,34 @@ namespace PS5
uint16_t gyro[3]; // Gyroscope data for x, y, z axes
uint16_t accel[3]; // Accelerometer data for x, y, z axes
uint32_t sensor_timestamp; // Timestamp for sensor data
uint8_t reserved2;
uint8_t reserved0;
// Touchpad
struct dualsense_touch_point {
uint8_t counter : 7; // Incremented every time a finger touches the touchpad
uint8_t touching : 1; // Indicates if a finger is currently touching the touchpad
uint16_t x : 12; // X coordinate of the touchpoint
uint16_t y : 12; // Y coordinate of the touchpoint
struct Touchpad
{
uint32_t counter : 7; // Incremented every time a finger touches the touchpad
uint32_t touching : 1; // Indicates if a finger is currently touching the touchpad
uint32_t x : 12; // X coordinate of the touchpoint
uint32_t y : 12; // Y coordinate of the touchpoint
} points[2]; // Array of touchpoints (up to 2)
// uint32_t touchpad[2];
uint8_t reserved3[12];
uint8_t reserved1[12];
uint8_t status; // ?
uint8_t reserved4[10];
uint8_t reserved2[10];
InReport()
{
std::memset(this, 0, sizeof(InReport));
}
};
// static_assert(sizeof(InReport) == 52, "PS5::InReport is not correct size");
static_assert(sizeof(InReport) == 60, "PS5::InReport is not correct size");
struct OutReport
{
uint8_t report_id;
uint8_t valid_flag0;
uint8_t valid_flag1;
uint8_t control_flag[2];
/* For DualShock 4 compatibility mode. */
uint8_t motor_right;
@@ -120,14 +128,19 @@ namespace PS5
uint8_t audio_flags2; /* 3 first bits: speaker pre-gain */
/* LEDs and lightbar */
uint8_t valid_flag2;
uint8_t led_control_flag;
uint8_t reserved3[2];
uint8_t lightbar_setup;
uint8_t pulse_option;
uint8_t led_brightness;
uint8_t player_leds;
uint8_t player_number;
uint8_t lightbar_red;
uint8_t lightbar_green;
uint8_t lightbar_blue;
OutReport()
{
std::memset(this, 0, sizeof(OutReport));
}
};
static_assert(sizeof(OutReport) == 48);
#pragma pack(pop)

View File

@@ -1,7 +1,7 @@
#ifndef _XINPUT_DESCRIPTORS_H_
#define _XINPUT_DESCRIPTORS_H_
#include <stdint.h>
#include <cstdint>
#include <cstring>
namespace XInput
@@ -133,6 +133,11 @@ namespace XInput
uint8_t reserved[6];
uint8_t chatpad_status;
uint8_t chatpad[3];
InReportWireless()
{
std::memset(this, 0, sizeof(InReportWireless));
}
};
static_assert(sizeof(InReportWireless) == 28, "XInput::InReportWireless is not the correct size");

View File

@@ -99,15 +99,12 @@ namespace XboxOG
.bDeviceSubClass = 0x00,
.bDeviceProtocol = 0x00,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = 0x045E,
.idProduct = 0x0289,
.bcdDevice = 0x0121,
.iManufacturer = 0x00,
.iProduct = 0x00,
.iSerialNumber = 0x00,
.bNumConfigurations = 0x01
};
@@ -184,8 +181,6 @@ namespace XboxOG
{
static constexpr uint16_t AIMING_MID = 32768;
static constexpr uint16_t BUTTONS2_TOGGLE_MID = 0xFFFC;
static constexpr int16_t DEFAULT_DEADZONE = 7500;
static constexpr uint16_t DEFAULT_SENSE = 400;
namespace Buttons0
{

View File

@@ -5,6 +5,7 @@
#include <atomic>
#include <limits>
#include <cstring>
#include <array>
#include <pico/mutex.h>
#include "Scale.h"
@@ -38,16 +39,16 @@ public:
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;
static constexpr uint8_t ANALOG_OFF_UP = 0;
static constexpr uint8_t ANALOG_OFF_DOWN = 1;
static constexpr uint8_t ANALOG_OFF_LEFT = 2;
static constexpr uint8_t ANALOG_OFF_RIGHT = 3;
static constexpr uint8_t ANALOG_OFF_A = 4;
static constexpr uint8_t ANALOG_OFF_B = 5;
static constexpr uint8_t ANALOG_OFF_X = 6;
static constexpr uint8_t ANALOG_OFF_Y = 7;
static constexpr uint8_t ANALOG_OFF_LB = 8;
static constexpr uint8_t ANALOG_OFF_RB = 9;
//Mappings used by host to set buttons
@@ -97,7 +98,7 @@ public:
int16_t joystick_ly;
int16_t joystick_rx;
int16_t joystick_ry;
uint8_t chatpad[3];
// uint8_t chatpad[3];
uint8_t analog[10];
PadIn()
@@ -116,15 +117,20 @@ public:
std::memset(this, 0, sizeof(PadOut));
}
};
using ChatpadIn = std::array<uint8_t, 3>;
#pragma pack(pop)
Gamepad()
{
mutex_init(&pad_in_mutex_);
mutex_init(&pad_out_mutex_);
mutex_init(&chatpad_in_mutex_);
reset_pad_in();
reset_pad_out();
setup_deadzones(profile_);
reset_chatpad_in();
setup_deadzones();
};
~Gamepad() = default;
@@ -132,42 +138,70 @@ public:
//Get
inline bool new_pad_in() const { return new_pad_in_.load(); }
inline bool new_pad_out() const { return new_pad_out_.load(); }
//True if both host and device have enabled analog
inline bool analog_enabled() const { return analog_enabled_.load(std::memory_order_relaxed); }
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_);
}
mutex_enter_blocking(&pad_in_mutex_);
pad_in = pad_in_;
new_pad_in_.store(false);
mutex_exit(&pad_in_mutex_);
return pad_in;
}
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;
}
inline ChatpadIn get_chatpad_in()
{
ChatpadIn chatpad_in;
mutex_enter_blocking(&chatpad_in_mutex_);
chatpad_in = chatpad_in_;
mutex_exit(&chatpad_in_mutex_);
return chatpad_in;
}
//Set
void set_analog_enabled(bool value)
void set_analog_device(bool value)
{
analog_enabled_.store(value);
analog_device_.store(value);
if (analog_host_.load() && analog_device_.load() && profile_.analog_enabled)
{
analog_enabled_.store(true);
}
}
void set_analog_host(bool value)
{
analog_host_.store(value);
if (analog_host_.load() && analog_device_.load() && profile_.analog_enabled)
{
analog_enabled_.store(true);
}
}
void set_profile(const UserProfile& user_profile)
{
profile_ = user_profile;
setup_mappings(profile_);
setup_deadzones(profile_);
setup_mappings();
setup_deadzones();
}
inline void set_pad_in(PadIn pad_in)
@@ -180,26 +214,32 @@ public:
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_);
}
mutex_enter_blocking(&pad_in_mutex_);
pad_in_ = pad_in;
new_pad_in_.store(true);
mutex_exit(&pad_in_mutex_);
}
inline void set_pad_out(PadOut pad_out)
inline void set_pad_out(const PadOut& pad_out)
{
mutex_enter_blocking(&pad_out_mutex_);
pad_out_ = pad_out;
mutex_exit(&pad_out_mutex_);
new_pad_out_.store(true);
mutex_exit(&pad_out_mutex_);
}
inline void set_chatpad_in(const ChatpadIn& chatpad_in)
{
mutex_enter_blocking(&chatpad_in_mutex_);
chatpad_in_ = chatpad_in;
mutex_exit(&chatpad_in_mutex_);
}
inline void reset_pad_in()
{
mutex_enter_blocking(&pad_in_mutex_);
std::memset(&pad_in_, 0, sizeof(pad_in_));
std::memset(reinterpret_cast<void*>(&pad_in_), 0, sizeof(pad_in_));
mutex_exit(&pad_in_mutex_);
new_pad_in_.store(true);
}
@@ -207,21 +247,33 @@ public:
inline void reset_pad_out()
{
mutex_enter_blocking(&pad_out_mutex_);
std::memset(&pad_out_, 0, sizeof(pad_out_));
mutex_exit(&pad_out_mutex_);
std::memset(reinterpret_cast<void*>(&pad_out_), 0, sizeof(pad_out_));
new_pad_out_.store(true);
mutex_exit(&pad_out_mutex_);
}
inline void reset_chatpad_in()
{
mutex_enter_blocking(&chatpad_in_mutex_);
chatpad_in_.fill(0);
mutex_exit(&chatpad_in_mutex_);
}
private:
mutex_t pad_in_mutex_;
mutex_t pad_out_mutex_;
mutex_t chatpad_in_mutex_;
PadOut pad_out_;
PadIn pad_in_;
ChatpadIn chatpad_in_;
std::atomic<bool> new_pad_in_{false};
std::atomic<bool> new_pad_out_{false};
std::atomic<bool> analog_enabled_{false};
std::atomic<bool> analog_host_{false};
std::atomic<bool> analog_device_{false};
UserProfile profile_;
@@ -235,44 +287,44 @@ private:
int16_t joystick_r_pos{0};
} dz_;
void setup_mappings(const UserProfile& profile)
void setup_mappings()
{
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_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_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;
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 setup_deadzones(const UserProfile& profile) //Deadzones in the profile are 0-255 (0-100%)
void setup_deadzones() //Deadzones in the profile are 0-255 (0-100%)
{
dz_.trigger_l = profile_.dz_trigger_l;
dz_.trigger_r = profile_.dz_trigger_r;

View File

@@ -12,16 +12,16 @@
class I2CDriver
{
public:
virtual ~I2CDriver() = default;
virtual ~I2CDriver() {};
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;
virtual void notify_xbox360w_connected(uint8_t idx) {};
virtual void notify_xbox360w_disconnected(uint8_t idx) {};
protected:
enum class PacketID : uint8_t { UNKNOWN = 0, PAD, STATUS, ENABLE, DISABLE };
enum class PacketID : uint8_t { UNKNOWN = 0, PAD, STATUS, ENABLE, DISABLE, REBOOT };
enum class SlaveStatus : uint8_t { NC = 0, NOT_READY, READY, RESP_OK };
#pragma pack(push, 1)
@@ -38,7 +38,7 @@ protected:
packet_id = static_cast<uint8_t>(PacketID::PAD);
}
};
static_assert(sizeof(PacketIn) == 28, "I2CDriver::PacketIn is misaligned");
static_assert(sizeof(PacketIn) == 28, "I2CDriver::PacketIn is misaligned");
struct PacketOut
{
@@ -53,7 +53,7 @@ static_assert(sizeof(PacketIn) == 28, "I2CDriver::PacketIn is misaligned");
packet_id = static_cast<uint8_t>(PacketID::PAD);
}
};
static_assert(sizeof(PacketOut) == 4, "I2CDriver::PacketOut is misaligned");
static_assert(sizeof(PacketOut) == 4, "I2CDriver::PacketOut is misaligned");
struct PacketStatus
{
@@ -68,7 +68,7 @@ static_assert(sizeof(PacketOut) == 4, "I2CDriver::PacketOut is misaligned");
status = static_cast<uint8_t>(SlaveStatus::NC);
}
};
static_assert(sizeof(PacketStatus) == 3, "I2CDriver::PacketStatus is misaligned");
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)));

View File

@@ -23,7 +23,7 @@ public:
return instance;
}
bool initialize_driver() //Gamepad idx 0 for slave to update on interrupt
bool initialize_driver()
{
uint8_t i2c_address = get_i2c_address();
if (i2c_address == 0xFF)

View File

@@ -1,8 +1,14 @@
#include <cstring>
#include "TaskQueue/TaskQueue.h"
#include "OGXMini/OGXMini.h"
#include "I2CDriver/4Channel/I2CMaster.h"
I2CMaster::~I2CMaster()
{
TaskQueue::Core0::cancel_delayed_task(tid_update_slave_);
}
void I2CMaster::initialize(uint8_t address)
{
i2c_init(I2C_PORT, I2C_BAUDRATE);
@@ -21,11 +27,12 @@ void I2CMaster::initialize(uint8_t address)
}
tid_update_slave_ = TaskQueue::Core0::get_new_task_id();
TaskQueue::Core0::queue_delayed_task(tid_update_slave_, 1000, true, [this]
TaskQueue::Core0::queue_delayed_task(tid_update_slave_, 2000, true, [this]
{
for (auto& slave : slaves_)
{
update_slave_status(slave);
check_slave_status(slave);
sleep_us(10);
}
});
@@ -33,26 +40,17 @@ void I2CMaster::initialize(uint8_t address)
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))
if (slave.status != SlaveStatus::READY || !slave_detected(slave.address))
{
continue;
}
if (slave.status == SlaveStatus::READY)
if (send_packet_in(slave, gamepads[i + 1]))
{
if (send_packet_in(slave, gamepads[i + 1]))
{
get_packet_out(slave, gamepads[i + 1]);
}
get_packet_out(slave, gamepads[i + 1]);
}
sleep_us(100);
@@ -69,8 +67,18 @@ void I2CMaster::notify_tuh_mounted(HostDriver::Type host_type)
void I2CMaster::notify_tuh_unmounted(HostDriver::Type host_type)
{
i2c_enabled_.store(false);
notify_deinit_.store(true);
if (host_type == HostDriver::Type::XBOX360W)
{
i2c_enabled_.store(false);
TaskQueue::Core0::queue_task([this]()
{
for (auto& slave : slaves_)
{
notify_disable(slave);
}
});
}
}
void I2CMaster::notify_xbox360w_connected(uint8_t idx)
@@ -80,6 +88,11 @@ void I2CMaster::notify_xbox360w_connected(uint8_t idx)
return;
}
slaves_[idx - 1].enabled.store(true);
TaskQueue::Core0::queue_task([this, idx]()
{
notify_enable(slaves_[idx - 1].address);
});
}
void I2CMaster::notify_xbox360w_disconnected(uint8_t idx)
@@ -89,6 +102,11 @@ void I2CMaster::notify_xbox360w_disconnected(uint8_t idx)
return;
}
slaves_[idx - 1].enabled.store(false);
TaskQueue::Core0::queue_task([this, idx]()
{
notify_disable(slaves_[idx - 1]);
});
}
bool I2CMaster::slave_detected(uint8_t address)
@@ -98,53 +116,70 @@ bool I2CMaster::slave_detected(uint8_t address)
return (result >= 0);
}
void I2CMaster::update_slave_status(Slave& slave)
void I2CMaster::check_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))
if (slave.enabled.load())
{
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;
slave.status = get_slave_status(slave.address);
}
slave.status = SlaveStatus::NOT_READY;
}
//Tell slave if it's enabled or not
bool I2CMaster::update_slave_enabled(uint8_t address, bool enabled)
I2CMaster::SlaveStatus I2CMaster::get_slave_status(uint8_t address)
{
PacketStatus status_packet;
status_packet.packet_id = enabled ? static_cast<uint8_t>(PacketID::ENABLE) : static_cast<uint8_t>(PacketID::DISABLE);
status_packet.packet_id = static_cast<uint8_t>(PacketID::STATUS);
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 static_cast<SlaveStatus>(status_packet.status);
}
return SlaveStatus::NC;
}
I2CMaster::SlaveStatus I2CMaster::notify_enable(uint8_t address)
{
PacketStatus status_packet;
status_packet.packet_id = static_cast<uint8_t>(PacketID::ENABLE);
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);
}
return SlaveStatus::NC;
}
bool I2CMaster::notify_disable(Slave& slave)
{
if (slave_detected(slave.address) && slave.enabled.load())
{
int retries = 6;
bool success = false;
while (!success && retries--)
{
PacketStatus status_packet;
status_packet.packet_id = static_cast<uint8_t>(PacketID::DISABLE);
int 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);
success = (static_cast<SlaveStatus>(status_packet.status) == SlaveStatus::RESP_OK);
}
sleep_ms(1);
}
return success;
}
return false;
}
@@ -153,11 +188,10 @@ 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;
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));
}
@@ -173,20 +207,4 @@ bool I2CMaster::get_packet_out(Slave& slave, Gamepad& gamepad)
gamepad.set_pad_out(packet_out.pad_out);
return true;
}
void I2CMaster::notify_tud_deinit()
{
for (auto& slave : slaves_)
{
if (slave.status != SlaveStatus::NC && slave_detected(slave.address) && slave.enabled.load())
{
int retries = 0;
while (!update_slave_enabled(slave.address, false) && retries < 6)
{
sleep_ms(1);
++retries;
}
}
}
}

View File

@@ -5,7 +5,6 @@
#include <atomic>
#include <array>
#include <pico/time.h>
#include <hardware/gpio.h>
#include <hardware/i2c.h>
@@ -17,7 +16,6 @@ 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;
@@ -36,22 +34,23 @@ private:
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::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);
void check_slave_status(Slave& slave);
bool notify_disable(Slave& slave);
SlaveStatus notify_enable(uint8_t address);
// bool send_packet_status(uint8_t address, PacketID packet_id);
SlaveStatus get_slave_status(uint8_t address);
bool send_packet_in(Slave& slave, Gamepad& gamepad);
bool get_packet_out(Slave& slave, Gamepad& gamepad);
void notify_tud_deinit();
};
#endif // I2C_MASTER_4CH_H

View File

@@ -1,7 +1,7 @@
#include <cstring>
#include <array>
#include "Board/board_api.h"
#include "USBHost/HostManager.h"
#include "OGXMini/OGXMini.h"
#include "I2CDriver/4Channel/I2CSlave.h"
@@ -40,10 +40,15 @@ void I2CSlave::process(Gamepad (&gamepads)[MAX_GAMEPADS])
{
return;
}
//Don't want to hang up the i2c bus by doing this in the slave handler
if (packet_in_.packet_id == static_cast<uint8_t>(PacketID::PAD))
{
gamepads[0].set_pad_in(packet_in_.pad_in);
if (new_packet_in_)
{
new_packet_in_ = false;
gamepads[0].set_pad_in(packet_in_.pad_in);
}
if (gamepads[0].new_pad_out())
{
packet_out_.pad_out = gamepads[0].get_pad_out();
@@ -114,34 +119,38 @@ void I2CSlave::slave_handler(i2c_inst_t *i2c, i2c_slave_event_t event)
{
case PacketID::PAD:
this_instance_->packet_in_ = *reinterpret_cast<PacketIn*>(buffer_in.data());
this_instance_->new_packet_in_ = true;
*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);
// if something is mounted by tuh, signal that we're not talking to the master
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);
}
OGXMini::update_tud_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);
OGXMini::update_tud_status(false);
}
break;
default:
break;
}
@@ -155,6 +164,5 @@ void I2CSlave::slave_handler(i2c_inst_t *i2c, i2c_slave_event_t event)
default:
break;
}
}

View File

@@ -4,7 +4,6 @@
#include <cstdint>
#include <atomic>
#include <cstring>
#include <pico/time.h>
#include <hardware/gpio.h>
#include <hardware/i2c.h>
#include <pico/i2c_slave.h>
@@ -16,18 +15,19 @@
class I2CSlave : public I2CDriver
{
public:
~I2CSlave() = default;
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_;
bool new_packet_in_{false};
std::atomic<bool> i2c_disabled_{false};
static PacketID get_packet_id(uint8_t* buffer_in);
static void slave_handler(i2c_inst_t *i2c, i2c_slave_event_t event);

View File

@@ -0,0 +1,187 @@
#include <array>
#include <cstring>
#include <pico/i2c_slave.h>
#include <hardware/gpio.h>
#include <hardware/i2c.h>
#include "Gamepad.h"
#include "board_config.h"
#include "Board/board_api.h"
#include "I2CDriver/ESP32/I2CDriver.h"
#include "TaskQueue/TaskQueue.h"
namespace I2CDriver {
//May expand commands in the future
enum class PacketID : uint8_t { UNKNOWN = 0, SET_PAD, GET_PAD };
#pragma pack(push, 1)
struct PacketIn
{
uint8_t packet_len;
uint8_t packet_id;
uint8_t index;
uint8_t gp_data[sizeof(Gamepad::PadIn) - sizeof(Gamepad::PadIn::analog) - sizeof(Gamepad::PadIn::chatpad)];
PacketIn()
{
std::memset(this, 0, sizeof(PacketIn));
packet_len = sizeof(PacketIn);
packet_id = static_cast<uint8_t>(PacketID::SET_PAD);
}
};
static_assert(sizeof(PacketIn) == 16, "i2c_driver_esp::PacketIn size mismatch");
struct PacketOut
{
uint8_t packet_len;
uint8_t packet_id;
uint8_t index;
Gamepad::PadOut pad_out;
uint8_t reserved[3];
PacketOut()
{
std::memset(this, 0, sizeof(PacketOut));
packet_len = sizeof(PacketOut);
packet_id = static_cast<uint8_t>(PacketID::GET_PAD);
}
};
static_assert(sizeof(PacketOut) == 8, "i2c_driver_esp::PacketOut size mismatch");
#pragma pack(pop)
static constexpr size_t MAX_BUFFER_SIZE = std::max(sizeof(PacketOut), sizeof(PacketIn));
static constexpr uint8_t I2C_ADDR = 0x01;
Gamepad* gamepads_[MAX_GAMEPADS];
inline void process_in_packet(PacketIn* packet_in)
{
Gamepad::PadIn gp_in;
std::memcpy(&gp_in, packet_in->gp_data, sizeof(packet_in->gp_data));
//This is a bandaid since the ESP32 doesn't have access to user profiles atm
//Will update this once I write a BLE server for interfacing with the webapp
Gamepad* gamepad = gamepads_[packet_in->index];
Gamepad::PadIn mapped_gp_in;
if (gp_in.dpad & Gamepad::DPAD_UP) mapped_gp_in.dpad |= gamepad->MAP_DPAD_UP;
if (gp_in.dpad & Gamepad::DPAD_DOWN) mapped_gp_in.dpad |= gamepad->MAP_DPAD_DOWN;
if (gp_in.dpad & Gamepad::DPAD_LEFT) mapped_gp_in.dpad |= gamepad->MAP_DPAD_LEFT;
if (gp_in.dpad & Gamepad::DPAD_RIGHT) mapped_gp_in.dpad |= gamepad->MAP_DPAD_RIGHT;
if (gp_in.buttons & Gamepad::BUTTON_START) mapped_gp_in.buttons |= gamepad->MAP_BUTTON_START;
if (gp_in.buttons & Gamepad::BUTTON_BACK) mapped_gp_in.buttons |= gamepad->MAP_BUTTON_BACK;
if (gp_in.buttons & Gamepad::BUTTON_L3) mapped_gp_in.buttons |= gamepad->MAP_BUTTON_L3;
if (gp_in.buttons & Gamepad::BUTTON_R3) mapped_gp_in.buttons |= gamepad->MAP_BUTTON_R3;
if (gp_in.buttons & Gamepad::BUTTON_LB) mapped_gp_in.buttons |= gamepad->MAP_BUTTON_LB;
if (gp_in.buttons & Gamepad::BUTTON_RB) mapped_gp_in.buttons |= gamepad->MAP_BUTTON_RB;
if (gp_in.buttons & Gamepad::BUTTON_SYS) mapped_gp_in.buttons |= gamepad->MAP_BUTTON_SYS;
if (gp_in.buttons & Gamepad::BUTTON_A) mapped_gp_in.buttons |= gamepad->MAP_BUTTON_A;
if (gp_in.buttons & Gamepad::BUTTON_B) mapped_gp_in.buttons |= gamepad->MAP_BUTTON_B;
if (gp_in.buttons & Gamepad::BUTTON_X) mapped_gp_in.buttons |= gamepad->MAP_BUTTON_X;
if (gp_in.buttons & Gamepad::BUTTON_Y) mapped_gp_in.buttons |= gamepad->MAP_BUTTON_Y;
mapped_gp_in.trigger_l = gp_in.trigger_l;
mapped_gp_in.trigger_r = gp_in.trigger_r;
mapped_gp_in.joystick_lx = gp_in.joystick_lx;
mapped_gp_in.joystick_ly = gp_in.joystick_ly;
mapped_gp_in.joystick_rx = gp_in.joystick_rx;
mapped_gp_in.joystick_ry = gp_in.joystick_ry;
gamepad->set_pad_in(mapped_gp_in);
}
inline void fill_out_report(uint8_t index, PacketOut* report_out)
{
if (index >= MAX_GAMEPADS)
{
return;
}
report_out->packet_len = sizeof(PacketOut);
report_out->packet_id = static_cast<uint8_t>(PacketID::GET_PAD);
report_out->index = index;
report_out->pad_out = gamepads_[index]->get_pad_out();
}
PacketID get_packet_id(uint8_t* buffer_in)
{
switch (static_cast<PacketID>(buffer_in[1]))
{
case PacketID::SET_PAD:
if (buffer_in[0] == sizeof(PacketIn))
{
return PacketID::SET_PAD;
}
break;
//Unused ATM
// case PacketID::GET_PAD:
// if (buffer_in[0] == sizeof(PacketOut))
// {
// return PacketID::GET_PAD;
// }
// break;
default:
break;
}
return PacketID::UNKNOWN;
}
static inline void slave_handler(i2c_inst_t *i2c, i2c_slave_event_t event)
{
static int count = 0;
static std::array<uint8_t, MAX_BUFFER_SIZE> buffer_in{0};
static std::array<uint8_t, MAX_BUFFER_SIZE> buffer_out{0};
switch (event)
{
case I2C_SLAVE_RECEIVE: // master has written
if (count < sizeof(PacketIn))
{
buffer_in.data()[count] = i2c_read_byte_raw(i2c);
++count;
}
break;
case I2C_SLAVE_FINISH: // master signalled Stop / Restart
if (get_packet_id(buffer_in.data()) == PacketID::SET_PAD)
{
process_in_packet(reinterpret_cast<PacketIn*>(buffer_in.data()));
}
count = 0;
break;
case I2C_SLAVE_REQUEST: // master requesting data
fill_out_report(reinterpret_cast<PacketIn*>(buffer_in.data())->index, reinterpret_cast<PacketOut*>(buffer_out.data()));
i2c_write_raw_blocking(i2c, buffer_out.data(), buffer_out.data()[0]);
buffer_in.fill(0);
break;
default:
break;
}
}
void initialize(Gamepad (&gamepads)[MAX_GAMEPADS])
{
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
{
gamepads_[i] = &gamepads[i];
}
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, I2C_ADDR, &slave_handler);
}
} // namespace i2c_driver_esp32

View File

@@ -5,10 +5,9 @@
#include "Gamepad.h"
namespace i2c_driver_esp32
namespace I2CDriver
{
void initialize(std::array<Gamepad, MAX_GAMEPADS>& gamepad);
// bool pad_connected();
void initialize(Gamepad (&gamepads)[MAX_GAMEPADS]);
}
#endif // _I2CDRIVER_ESP_H_

View File

@@ -1,627 +0,0 @@
// #include <cstdint>
// #include <array>
// #include <cstring>
// #include <atomic>
// #include <pico/i2c_slave.h>
// #include <pico/time.h>
// #include <hardware/gpio.h>
// #include <hardware/i2c.h>
// #include "board_config.h"
// #include "OGXMini/OGXMini.h"
// #include "I2CDriver/i2c_driver_4ch.h"
// namespace i2c {
// 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)));
// driver driver_;
// namespace i2c_master
// {
// 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;
// };
// Master master_;
// bool slave_detected(uint8_t address);
// bool send_in_report(Master::Slave& slave);
// bool get_out_report(Master::Slave& slave);
// bool update_slave_enabled(uint8_t address, bool connected);
// void notify_tud_deinit();
// void update_slave_status(Master::Slave& slave);
// void notify_tuh_mounted(HostDriver::Type host_type);
// void notify_tuh_unmounted(HostDriver::Type host_type);
// void notify_xbox360w_connected(uint8_t idx);
// void notify_xbox360w_disconnected(uint8_t idx);
// bool is_active();
// void process();
// void init(Gamepad (&gamepads)[MAX_GAMEPADS]);
// }
// namespace i2c_slave
// {
// struct Slave
// {
// uint8_t address{0xFF};
// Gamepad* gamepad{nullptr};
// std::atomic<bool> i2c_enabled{false};
// std::atomic<bool> tuh_enabled{false};
// };
// Slave slave_;
// void process_in_report(ReportIn* report_in);
// void fill_out_report(ReportOut* report_out);
// ReportID get_report_id(uint8_t* buffer_in);
// void slave_handler(i2c_inst_t *i2c, i2c_slave_event_t event);
// bool is_active();
// void notify_tuh_mounted();
// void notify_tuh_unmounted();
// bool is_active();
// void process() {}
// void init(uint8_t address, Gamepad& gamepad);
// }
// namespace i2c_master {
// bool is_active()
// {
// return master_.enabled.load();
// }
// bool 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 notify_tuh_mounted(HostDriver::Type host_type)
// {
// if (host_type == HostDriver::Type::XBOX360W)
// {
// master_.enabled.store(true);
// }
// }
// void notify_tuh_unmounted(HostDriver::Type host_type)
// {
// master_.enabled.store(false);
// }
// void notify_xbox360w_connected(uint8_t idx)
// {
// if (idx < 1 || idx >= MAX_GAMEPADS)
// {
// return;
// }
// master_.slaves[idx - 1].enabled.store(true);
// }
// void notify_xbox360w_disconnected(uint8_t idx)
// {
// if (idx < 1 || idx >= MAX_GAMEPADS)
// {
// return;
// }
// master_.slaves[idx - 1].enabled.store(false);
// // bool any_connected = false;
// // for (auto& slave : master_.slaves)
// // {
// // if (slave.enabled.load())
// // {
// // any_connected = true;
// // break;
// // }
// // }
// // if (!any_connected)
// // {
// // master_.enabled.store(false);
// // }
// }
// bool send_in_report(Master::Slave& slave)
// {
// static ReportIn report_in = ReportIn();
// Gamepad::PadIn pad_in = slave.gamepad->get_pad_in();
// std::memcpy(report_in.pad_in, &pad_in, sizeof(ReportIn::pad_in));
// int count = i2c_write_blocking(I2C_PORT, slave.address, reinterpret_cast<uint8_t*>(&report_in), sizeof(report_in), false);
// return (count == sizeof(ReportIn));
// }
// bool get_out_report(Master::Slave& slave)
// {
// static ReportOut report_out = ReportOut();
// int count = i2c_read_blocking(I2C_PORT, slave.address, reinterpret_cast<uint8_t*>(&report_out), sizeof(ReportOut), false);
// if (count != sizeof(ReportOut))
// {
// return false;
// }
// Gamepad::PadOut pad_out;
// std::memcpy(&pad_out, report_out.pad_out, sizeof(ReportOut::pad_out));
// return true;
// }
// bool update_slave_enabled(uint8_t address, bool connected)
// {
// ReportStatus report;
// report.report_id = connected ? static_cast<uint8_t>(ReportID::CONNECT) : static_cast<uint8_t>(ReportID::DISCONNECT);
// int count = i2c_write_blocking(I2C_PORT, address, reinterpret_cast<uint8_t*>(&report), sizeof(ReportStatus), false);
// if (count == sizeof(ReportStatus))
// {
// count = i2c_read_blocking(I2C_PORT, address, reinterpret_cast<uint8_t*>(&report), sizeof(ReportStatus), false);
// return (static_cast<SlaveStatus>(report.status) == SlaveStatus::RESP_OK);
// }
// return false;
// }
// void notify_tud_deinit()
// {
// for (auto& slave : master_.slaves)
// {
// if (slave.status != SlaveStatus::NC)
// {
// int retries = 0;
// while (!update_slave_enabled(slave.address, false) && retries < 6)
// {
// sleep_ms(1);
// ++retries;
// }
// }
// }
// }
// void update_slave_status(Master::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)
// {
// ReportStatus report = ReportStatus();
// int count = 0;
// report.report_id = static_cast<uint8_t>(ReportID::STATUS);
// count = i2c_write_blocking(I2C_PORT, slave.address, reinterpret_cast<uint8_t*>(&report), sizeof(ReportStatus), false);
// if (count == sizeof(ReportStatus))
// {
// count = i2c_read_blocking(I2C_PORT, slave.address, reinterpret_cast<uint8_t*>(&report), sizeof(ReportStatus), false);
// slave.status = (count == sizeof(ReportStatus)) ? static_cast<SlaveStatus>(report.status) : SlaveStatus::NC;
// }
// else
// {
// slave.status = SlaveStatus::NOT_READY;
// }
// }
// else
// {
// slave.status = SlaveStatus::NOT_READY;
// }
// }
// void process()
// {
// for (auto& slave : master_.slaves)
// {
// if ((time_us_32() / 1000) - slave.last_update > 1000)
// {
// update_slave_status(slave);
// slave.last_update = time_us_32() / 1000;
// }
// sleep_us(100);
// }
// if (!master_.enabled.load())
// {
// return;
// }
// for (auto& slave : master_.slaves)
// {
// if (slave.status == SlaveStatus::READY)
// {
// if (send_in_report(slave))
// {
// get_out_report(slave);
// }
// sleep_us(100);
// }
// }
// }
// void init(Gamepad (&gamepads)[MAX_GAMEPADS])
// {
// for (uint8_t i = 0; i < master_.slaves.size(); ++i)
// {
// master_.slaves[i].address = i + 1;
// master_.slaves[i].gamepad = &gamepads[i + 1];
// }
// }
// } // namespace i2c_master
// namespace i2c_slave {
// bool is_active()
// {
// return slave_.i2c_enabled.load();
// }
// void notify_tuh_mounted()
// {
// slave_.tuh_enabled.store(true);
// }
// void notify_tuh_unmounted()
// {
// slave_.tuh_enabled.store(false);
// }
// void process_in_report(ReportIn* report_in)
// {
// Gamepad& gamepad = *slave_.gamepad;
// Gamepad::PadIn pad_in;
// std::memcpy(&pad_in, report_in->pad_in, sizeof(ReportIn::pad_in));
// gamepad.set_pad_in(pad_in);
// }
// void fill_out_report(ReportOut* report_out)
// {
// Gamepad& gamepad = *slave_.gamepad;
// Gamepad::PadOut pad_out = gamepad.get_pad_out();
// report_out->report_len = sizeof(ReportOut);
// report_out->report_id = static_cast<uint8_t>(ReportID::PAD);
// std::memcpy(report_out->pad_out, &pad_out, sizeof(ReportOut::pad_out));
// }
// ReportID get_report_id(uint8_t* buffer_in)
// {
// switch (static_cast<ReportID>(buffer_in[1]))
// {
// case ReportID::PAD:
// if (buffer_in[0] == sizeof(ReportIn))
// {
// return ReportID::PAD;
// }
// break;
// case ReportID::DISCONNECT:
// if (buffer_in[0] == sizeof(ReportStatus))
// {
// return ReportID::DISCONNECT;
// }
// break;
// case ReportID::CONNECT:
// if (buffer_in[0] == sizeof(ReportStatus))
// {
// return ReportID::CONNECT;
// }
// break;
// case ReportID::STATUS:
// if (buffer_in[0] == sizeof(ReportStatus))
// {
// return ReportID::STATUS;
// }
// break;
// default:
// break;
// }
// return ReportID::UNKNOWN;
// }
// void slave_handler(i2c_inst_t *i2c, i2c_slave_event_t event)
// {
// static int count = 0;
// static std::array<uint8_t, MAX_BUFFER_SIZE> buffer_in{0};
// static std::array<uint8_t, MAX_BUFFER_SIZE> buffer_out{0};
// switch (event)
// {
// case I2C_SLAVE_RECEIVE: // master has written
// if (count < MAX_BUFFER_SIZE)
// {
// buffer_in.data()[count] = i2c_read_byte_raw(i2c);
// ++count;
// }
// 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 request
// // Every write has an associated read
// switch (get_report_id(buffer_in.data()))
// {
// case ReportID::PAD:
// process_in_report(reinterpret_cast<ReportIn*>(buffer_in.data()));
// fill_out_report(reinterpret_cast<ReportOut*>(buffer_out.data()));
// break;
// case ReportID::STATUS:
// buffer_out.data()[0] = sizeof(ReportStatus);
// buffer_out.data()[1] = static_cast<uint8_t>(ReportID::STATUS);
// // if something is mounted by tuh, signal to not send gamepad data
// buffer_out.data()[2] = slave_.tuh_enabled.load() ? static_cast<uint8_t>(SlaveStatus::NOT_READY) : static_cast<uint8_t>(SlaveStatus::READY);
// break;
// case ReportID::CONNECT:
// slave_.i2c_enabled.store(true);
// buffer_out.data()[0] = sizeof(ReportStatus);
// buffer_out.data()[1] = static_cast<uint8_t>(ReportID::STATUS);
// buffer_out.data()[2] = static_cast<uint8_t>(SlaveStatus::RESP_OK);
// break;
// case ReportID::DISCONNECT:
// slave_.i2c_enabled.store(false);
// buffer_out.data()[0] = sizeof(ReportStatus);
// buffer_out.data()[1] = static_cast<uint8_t>(ReportID::STATUS);
// buffer_out.data()[2] = static_cast<uint8_t>(SlaveStatus::RESP_OK);
// 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;
// }
// }
// void init(uint8_t address, Gamepad& gamepad)
// {
// slave_.address = address;
// slave_.gamepad = &gamepad;
// i2c_slave_init(I2C_PORT, slave_.address, &slave_handler);
// }
// } // namespace i2c_slave
// Mode mode_{Mode::MASTER};
// uint8_t get_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; //Master
// }
// 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;
// }
// //Public methods
// //Call before core1 starts
// void initialize(Gamepad (&gamepads)[MAX_GAMEPADS])
// {
// uint8_t address = get_address();
// if (address == 0xFF)
// {
// return;
// }
// 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);
// if (address < 1)
// {
// mode_ = Mode::MASTER;
// driver_.process = i2c_master::process;
// driver_.is_active = i2c_master::is_active;
// driver_.notify_tud_deinit = i2c_master::notify_tud_deinit;
// driver_.notify_tuh_mounted = i2c_master::notify_tuh_mounted;
// driver_.notify_tuh_unmounted = i2c_master::notify_tuh_unmounted;
// driver_.notify_xbox360w_connected = i2c_master::notify_xbox360w_connected;
// driver_.notify_xbox360w_disconnected = i2c_master::notify_xbox360w_disconnected;
// i2c_master::init(gamepads);
// }
// else
// {
// mode_ = Mode::SLAVE;
// driver_.process = i2c_slave::is_active;
// driver_.is_active = i2c_slave::is_active;
// driver_.notify_tud_deinit = i2c_slave::notify_tuh_unmounted;
// driver_.notify_tuh_mounted = i2c_slave::notify_tuh_mounted;
// driver_.notify_tuh_unmounted = i2c_slave::notify_tuh_unmounted;
// driver_.notify_xbox360w_connected = nullptr;
// i2c_slave::init(address, gamepads[0]);
// }
// }
// void process()
// {
// switch (mode_)
// {
// case Mode::MASTER:
// i2c_master::process();
// break;
// case Mode::SLAVE:
// return;
// }
// }
// bool is_active()
// {
// switch (mode_)
// {
// case Mode::MASTER:
// return i2c_master::is_active();
// case Mode::SLAVE:
// return i2c_slave::is_active();
// }
// return false;
// }
// //Called from core1
// void notify_tuh_mounted(HostDriver::Type host_type)
// {
// switch (mode_)
// {
// case Mode::MASTER:
// i2c_master::notify_tuh_mounted(host_type);
// break;
// case Mode::SLAVE:
// i2c_slave::notify_tuh_mounted();
// break;
// }
// }
// //Called from core1
// void notify_tuh_unmounted(HostDriver::Type host_type)
// {
// switch (mode_)
// {
// case Mode::MASTER:
// i2c_master::notify_tuh_unmounted(host_type);
// break;
// case Mode::SLAVE:
// i2c_slave::notify_tuh_unmounted();
// break;
// }
// }
// //Called from core1
// void notify_xbox360w_connected(uint8_t idx)
// {
// switch (mode_)
// {
// case Mode::MASTER:
// i2c_master::notify_xbox360w_connected(idx);
// break;
// case Mode::SLAVE:
// return;
// }
// }
// //Called from core1
// void notify_xbox360w_disconnected(uint8_t idx)
// {
// switch (mode_)
// {
// case Mode::MASTER:
// i2c_master::notify_xbox360w_disconnected(idx);
// break;
// case Mode::SLAVE:
// return;
// }
// }
// void notify_tud_deinit()
// {
// switch (mode_)
// {
// case Mode::MASTER:
// i2c_master::notify_tud_deinit();
// break;
// case Mode::SLAVE:
// return;
// }
// }
// } // namespace I2CDriver

View File

@@ -1,145 +0,0 @@
// #ifndef _I2C_DRIVER_H_
// #define _I2C_DRIVER_H_
// #include <cstdint>
// #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
// // {
// // void initialize(Gamepad (&gamepads)[MAX_GAMEPADS]);
// // 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 process();
// // // bool is_active();
// // // void notify_tud_deinit();
// // // void notify_tuh_mounted(HostDriver::Type host_type = HostDriver::Type::UNKNOWN);
// // // void notify_tuh_unmounted(HostDriver::Type host_type = HostDriver::Type::UNKNOWN);
// // // void notify_xbox360w_connected(uint8_t idx);
// // // void notify_xbox360w_disconnected(uint8_t idx);
// // }
// class I2CDriver4Ch
// {
// public:
// I2CDriver4Ch& get_instance()
// {
// static I2CDriver4Ch instance;
// return instance;
// }
// I2CDriver4Ch(const I2CDriver4Ch&) = delete;
// I2CDriver4Ch& operator=(const I2CDriver4Ch&) = delete;
// void initialize(Gamepad (&gamepads)[MAX_GAMEPADS]);
// private:
// I2CDriver4Ch() = default;
// ~I2CDriver4Ch() = default;
// I2CDriver4Ch(const I2CDriver4Ch&) = delete;
// I2CDriver4Ch& operator=(const I2CDriver4Ch&) = delete;
// enum class Mode { MASTER = 0, SLAVE };
// enum class ReportID : uint8_t { UNKNOWN = 0, PAD, STATUS, CONNECT, DISCONNECT };
// enum class SlaveStatus : uint8_t { NC = 0, NOT_READY, READY, RESP_OK };
// #pragma pack(push, 1)
// struct ReportIn
// {
// uint8_t report_len;
// uint8_t report_id;
// uint8_t pad_in[sizeof(Gamepad::PadIn) - sizeof(Gamepad::PadIn::analog)];
// ReportIn()
// {
// std::memset(this, 0, sizeof(ReportIn));
// report_len = sizeof(ReportIn);
// report_id = static_cast<uint8_t>(ReportID::PAD);
// }
// };
// static_assert(sizeof(ReportIn) == 18, "I2CDriver::ReportIn size mismatch");
// struct ReportOut
// {
// uint8_t report_len;
// uint8_t report_id;
// uint8_t pad_out[sizeof(Gamepad::PadOut)];
// ReportOut()
// {
// std::memset(this, 0, sizeof(ReportOut));
// report_len = sizeof(ReportOut);
// report_id = static_cast<uint8_t>(ReportID::PAD);
// }
// };
// static_assert(sizeof(ReportOut) == 4, "I2CDriver::ReportOut size mismatch");
// struct ReportStatus
// {
// uint8_t report_len;
// uint8_t report_id;
// uint8_t status;
// ReportStatus()
// {
// report_len = sizeof(ReportStatus);
// report_id = static_cast<uint8_t>(ReportID::STATUS);
// status = static_cast<uint8_t>(SlaveStatus::NC);
// }
// };
// static_assert(sizeof(ReportStatus) == 3, "I2CDriver::ReportStatus size mismatch");
// #pragma pack(pop)
// static constexpr size_t MAX_BUFFER_SIZE = std::max(sizeof(ReportStatus), std::max(sizeof(ReportIn), sizeof(ReportOut)));
// struct Master
// {
// std::atomic<bool> enabled{false};
// struct Slave
// {
// uint8_t address{0xFF};
// Gamepad* gamepad{nullptr};
// SlaveStatus status{SlaveStatus::NC};
// std::atomic<bool> enabled{false};
// uint32_t last_update{0};
// };
// std::array<Slave, MAX_GAMEPADS - 1> slaves;
// };
// struct Slave
// {
// uint8_t address{0xFF};
// Gamepad* gamepad{nullptr};
// std::atomic<bool> i2c_enabled{false};
// std::atomic<bool> tuh_enabled{false};
// };
// Slave slave_;
// static Gamepad* gamepads_[MAX_GAMEPADS];
// };
// #endif // _I2C_DRIVER_H_

View File

@@ -1,177 +0,0 @@
#include <array>
#include <cstring>
#include <pico/i2c_slave.h>
#include <hardware/gpio.h>
#include <hardware/i2c.h>
#include "Gamepad.h"
#include "board_config.h"
#include "Board/board_api.h"
#include "I2CDriver/i2c_driver_esp32.h"
namespace i2c_driver_esp32 {
//May expand commands in the future
enum class ReportID : uint8_t { UNKNOWN = 0, SET_PAD, GET_PAD };
#pragma pack(push, 1)
struct ReportIn
{
uint8_t report_len;
uint8_t report_id;
uint8_t index;
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;
ReportIn()
{
std::memset(this, 0, sizeof(ReportIn));
report_len = sizeof(ReportIn);
report_id = static_cast<uint8_t>(ReportID::SET_PAD);
}
};
static_assert(sizeof(ReportIn) == 16, "i2c_driver_esp::ReportIn size mismatch");
struct ReportOut
{
uint8_t report_len;
uint8_t report_id;
uint8_t index;
uint8_t rumble_l;
uint8_t rumble_r;
ReportOut()
{
std::memset(this, 0, sizeof(ReportOut));
report_len = sizeof(ReportOut);
report_id = static_cast<uint8_t>(ReportID::GET_PAD);
}
};
static_assert(sizeof(ReportOut) == 5, "i2c_driver_esp::ReportOut size mismatch");
#pragma pack(pop)
static constexpr size_t MAX_BUFFER_SIZE = std::max(sizeof(ReportOut), sizeof(ReportIn));
static constexpr uint8_t I2C_ADDR = 0x01;
std::array<Gamepad*, MAX_GAMEPADS> gamepads_{nullptr};
inline void process_in_report(ReportIn* report_in)
{
if (report_in->index >= MAX_GAMEPADS)
{
return;
}
Gamepad* gamepad = gamepads_[report_in->index];
gamepad->set_buttons(report_in->buttons);
gamepad->set_dpad(report_in->dpad);
gamepad->set_trigger_l(report_in->trigger_l);
gamepad->set_trigger_r(report_in->trigger_r);
gamepad->set_joystick_lx_int10(static_cast<int32_t>(report_in->joystick_lx));
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)
{
if (index >= MAX_GAMEPADS)
{
return;
}
Gamepad* gamepad = gamepads_[index];
report_out->report_len = sizeof(ReportOut);
report_out->report_id = static_cast<uint8_t>(ReportID::GET_PAD);
report_out->rumble_l = gamepad->get_rumble_l().uint8();
report_out->rumble_r = gamepad->get_rumble_r().uint8();
}
ReportID get_report_id(uint8_t* buffer_in)
{
switch (static_cast<ReportID>(buffer_in[1]))
{
case ReportID::SET_PAD:
if (buffer_in[0] == sizeof(ReportIn))
{
return ReportID::SET_PAD;
}
break;
//Unused ATM
// case ReportID::GET_PAD:
// if (buffer_in[0] == sizeof(ReportOut))
// {
// return ReportID::GET_PAD;
// }
// break;
default:
break;
}
return ReportID::UNKNOWN;
}
static inline void slave_handler(i2c_inst_t *i2c, i2c_slave_event_t event)
{
static int count = 0;
static std::array<uint8_t, MAX_BUFFER_SIZE> buffer_in{0};
static std::array<uint8_t, MAX_BUFFER_SIZE> buffer_out{0};
switch (event)
{
case I2C_SLAVE_RECEIVE: // master has written
if (count < MAX_BUFFER_SIZE)
{
buffer_in.data()[count] = i2c_read_byte_raw(i2c);
++count;
}
break;
case I2C_SLAVE_FINISH: // master signalled Stop / Restart
if (get_report_id(buffer_in.data()) == ReportID::SET_PAD)
{
process_in_report(reinterpret_cast<ReportIn*>(buffer_in.data()));
}
count = 0;
break;
case I2C_SLAVE_REQUEST: // master requesting data
fill_out_report(reinterpret_cast<ReportIn*>(buffer_in.data())->index, reinterpret_cast<ReportOut*>(buffer_out.data()));
i2c_write_raw_blocking(i2c, buffer_out.data(), buffer_out.data()[0]);
buffer_in.fill(0);
break;
default:
break;
}
}
void initialize(std::array<Gamepad, MAX_GAMEPADS>& gamepad)
{
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
{
gamepads_[i] = &gamepad[i];
}
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, I2C_ADDR, &slave_handler);
}
} // namespace i2c_driver_esp32

View File

@@ -0,0 +1,55 @@
#ifndef _OGXM_DEBUG_H_
#define _OGXM_DEBUG_H_
#include "board_config.h"
#if defined(OGXM_DEBUG)
#include <cstdint>
#include <string>
#include <sstream>
#include <iomanip>
#include <pico/mutex.h>
#include <hardware/uart.h>
namespace OGXMini {
//Don't use this directly, use the OGXM_LOG macro
static inline void log(const std::string& message)
{
static mutex_t log_mutex;
if (!mutex_is_initialized(&log_mutex))
{
mutex_init(&log_mutex);
}
mutex_enter_blocking(&log_mutex);
uart_puts(DEBUG_UART_PORT, message.c_str());
mutex_exit(&log_mutex);
}
//Don't use this directly, use the OGXM_LOG macro
static inline void log_hex(const uint8_t* data, size_t size)
{
std::ostringstream hex_stream;
hex_stream << std::hex << std::setfill('0');
for (uint16_t i = 0; i < size; ++i)
{
hex_stream << std::setw(2) << static_cast<int>(data[i]) << " ";
}
log(hex_stream.str());
}
} // namespace OGXMini
#endif // defined(OGXM_DEBUG)
#if defined(OGXM_DEBUG)
#define OGXM_LOG OGXMini::log
#define OGXM_LOG_HEX OGXMini::log_hex
#else
#define OGXM_LOG(...)
#define OGXM_LOG_HEX(...)
#endif // OGXM_DEBUG
#endif // _OGXM_DEBUG_H_

View File

@@ -7,8 +7,6 @@
namespace OGXMini
{
enum class TUDStatus { INIT, DEINIT, NOCHANGE };
static constexpr int32_t FEEDBACK_DELAY_MS = 150;
static constexpr int32_t TUD_CHECK_DELAY_MS = 500;

View File

@@ -18,28 +18,7 @@
namespace OGXMini {
Gamepad gamepads_[MAX_GAMEPADS];
//Called by tusb host or i2c driver so we know to connect or disconnect usb
void update_tud_status(bool host_mounted)
{
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);
}
}
std::atomic<bool> tud_inited_{false};
void core1_task()
{
@@ -64,31 +43,34 @@ void core1_task()
}
}
void run_program()
//Called by tusb host or i2c driver so we know to connect or disconnect usb
void update_tud_status(bool host_mounted)
{
UserSettings user_settings;
user_settings.initialize_flash();
board_api::set_led(host_mounted);
board_init();
board_api::init_gpio();
board_api::set_led(false);
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
if (!host_mounted && tud_inited_.load())
{
gamepads_[i].set_profile(user_settings.get_profile_by_index(i));
TaskQueue::Core0::queue_task([]()
{
tud_disconnect();
sleep_ms(300);
multicore_reset_core1();
sleep_ms(300);
board_api::reboot();
});
}
else if (!tud_inited_.load())
{
TaskQueue::Core0::queue_task([]()
{
tud_init(BOARD_TUD_RHPORT);
});
}
}
DeviceManager& device_manager = DeviceManager::get_instance();
device_manager.initialize_driver(user_settings.get_current_driver());
I2CManager& i2c_manager = I2CManager::get_instance();
i2c_manager.initialize_driver();
multicore_reset_core1();
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]
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]))
@@ -97,9 +79,31 @@ void run_program()
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();
void run_program()
{
UserSettings user_settings;
user_settings.initialize_flash();
board_api::init_board();
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
{
gamepads_[i].set_profile(user_settings.get_profile_by_index(i));
}
DeviceManager::get_instance().initialize_driver(user_settings.get_current_driver(), gamepads_);
I2CManager::get_instance().initialize_driver();
multicore_reset_core1();
multicore_launch_core1(core1_task);
uint32_t tid_gp_check = TaskQueue::Core0::get_new_task_id();
set_gp_check_timer(tid_gp_check, user_settings);
DeviceDriver* device_driver = DeviceManager::get_instance().get_driver();
I2CDriver* i2c_driver = I2CManager::get_instance().get_driver();
//Wait for something to call tud_init
while (!tud_inited())
@@ -108,11 +112,15 @@ void run_program()
sleep_ms(10);
}
tud_inited_.store(true);
while (true)
{
TaskQueue::Core0::process_tasks();
i2c_driver->process(gamepads_);
device_driver->process(0, gamepads_[0]);
tud_task();
sleep_us(100);
}

View File

@@ -1,11 +1,7 @@
#include "board_config.h"
#if OGXM_BOARD == W_ESP32
#include <array>
#include <pico/stdlib.h>
#include <pico/multicore.h>
#include <hardware/gpio.h>
#include <hardware/sync.h>
#include "tusb.h"
#include "bsp/board_api.h"
@@ -13,36 +9,48 @@
#include "USBDevice/DeviceManager.h"
#include "Board/board_api.h"
#include "OGXMini/OGXMini.h"
#include "I2CDriver/i2c_driver_esp32.h"
#include "I2CDriver/ESP32/I2CDriver.h"
#include "Gamepad.h"
#include "TaskQueue/TaskQueue.h"
namespace OGXMini {
std::array<Gamepad, MAX_GAMEPADS> gamepads_;
static Gamepad gamepads_[MAX_GAMEPADS];
//Not using this for ESP32 currently
void update_tud_status(bool host_mounted) { }
void core1_task()
{
I2CDriver::initialize(gamepads_);
while (true)
{
tight_loop_contents();
}
}
void run_esp32_uart_bridge()
{
DeviceManager& device_manager = DeviceManager::get_instance();
device_manager.initialize_driver(DeviceDriver::Type::UART_BRIDGE);
device_manager.initialize_driver(DeviceDriver::Type::UART_BRIDGE, gamepads_);
board_api::enter_esp32_prog_mode();
device_manager.get_driver()->process(0, gamepads_.front()); //Runs UART Bridge task
device_manager.get_driver()->process(0, gamepads_[0]); //Runs UART Bridge task, doesn't return
}
void core1_task()
void set_gp_check_timer(uint32_t task_id, UserSettings& user_settings)
{
i2c_driver_esp32::initialize(gamepads_);
while (true)
TaskQueue::Core0::queue_delayed_task(task_id, UserSettings::GP_CHECK_DELAY_MS, true, [&user_settings]
{
__wfi();
}
}
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;
//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()
@@ -50,56 +58,44 @@ void run_program()
UserSettings user_settings;
user_settings.initialize_flash();
board_api::init_gpio();
board_api::init_board();
if (board_api::uart_bridge_mode())
{
run_esp32_uart_bridge();
return;
}
// else if (!user_settings.verify_firmware_version())
// {
// user_settings.write_firmware_version();
// }
board_init();
for (uint8_t i = 0; i < gamepads_.size(); ++i)
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
{
gamepads_[i].set_profile(user_settings.get_profile_by_index(i));
}
DeviceManager& device_manager = DeviceManager::get_instance();
device_manager.initialize_driver(user_settings.get_current_driver());
DeviceManager::get_instance().initialize_driver(user_settings.get_current_driver(), gamepads_);
multicore_reset_core1();
multicore_launch_core1(core1_task);
board_api::reset_esp32();
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);
uint32_t tid_gp_check = TaskQueue::Core0::get_new_task_id();
set_gp_check_timer(tid_gp_check, user_settings);
DeviceDriver* device_driver = device_manager.get_driver();
DeviceDriver* device_driver = DeviceManager::get_instance().get_driver();
tud_init(BOARD_TUD_RHPORT);
while (true)
{
for (uint8_t i = 0; i < gamepads_.size(); ++i)
TaskQueue::Core0::process_tasks();
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());
}
}
}

View File

@@ -1,11 +1,7 @@
#include "board_config.h"
#if (OGXM_BOARD == PI_PICOW)
#include <pico/stdlib.h>
#include <hardware/sync.h>
#include <pico/multicore.h>
#include <hardware/gpio.h>
#include <hardware/clocks.h>
#include <pico/cyw43_arch.h>
#include "tusb.h"
@@ -15,57 +11,63 @@
#include "Board/board_api.h"
#include "Bluepad32/Bluepad32.h"
#include "OGXMini/OGXMini.h"
#include "Gamepad.h"
#include "TaskQueue/TaskQueue.h"
namespace OGXMini {
Gamepad gamepads_[MAX_GAMEPADS];
//Not using this for Pico W currently
void update_tud_status(bool host_mounted) { }
void core1_task()
{
if (cyw43_arch_init() != 0)
{
{
return;
}
//Doesn't return, don't do anything with core1 unless it's executing within the BTStack loop
bluepad32::run_task(gamepads_);
}
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]);
return true;
}
void run_program()
{
UserSettings user_settings;
user_settings.initialize_flash();
board_init();
board_api::init_gpio();
board_api::init_board();
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
{
gamepads_[i].set_profile(user_settings.get_profile_by_index(i));
}
DeviceManager& device_manager = DeviceManager::get_instance();
device_manager.initialize_driver(user_settings.get_current_driver());
DeviceManager::get_instance().initialize_driver(user_settings.get_current_driver(), gamepads_);
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);
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();
DeviceDriver* device_driver = DeviceManager::get_instance().get_driver();
tud_init(BOARD_TUD_RHPORT);
while (true)
{
TaskQueue::Core0::process_tasks();
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
{
device_driver->process(i, gamepads_[i]);
@@ -73,12 +75,6 @@ void run_program()
}
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());
}
}
}

View File

@@ -1,11 +1,7 @@
#include "board_config.h"
#if (OGXM_BOARD == ADA_FEATHER) || (OGXM_BOARD == RP_ZERO) || (OGXM_BOARD == PI_PICO)
#if (OGXM_BOARD == ADA_FEATHER) || (OGXM_BOARD == RP_ZERO) || (OGXM_BOARD == PI_PICO) || (OGXM_BOARD == PI_PICO2)
#include <array>
#include <atomic>
#include <pico/multicore.h>
#include <hardware/gpio.h>
#include <hardware/clocks.h>
#include "tusb.h"
#include "bsp/board_api.h"
@@ -13,26 +9,15 @@
#include "USBHost/HostManager.h"
#include "USBDevice/DeviceManager.h"
#include "Board/board_api.h"
#include "OGXMini/OGXMini.h"
#include "TaskQueue/TaskQueue.h"
#include "Gamepad.h"
#include "Board/board_api.h"
namespace OGXMini {
std::atomic<TUDStatus> tud_status_ = TUDStatus::NOCHANGE;
Gamepad gamepads_[MAX_GAMEPADS];
void update_tuh_status(bool mounted)
{
tud_status_.store(mounted ? TUDStatus::INIT : TUDStatus::DEINIT);
board_api::set_led(mounted);
}
bool feedback_cb(repeating_timer_t* rt)
{
static_cast<HostManager*>(rt->user_data)->send_feedback();
return true;
}
std::atomic<bool> tud_inited_{false};
void core1_task()
{
@@ -44,49 +29,63 @@ 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);
while (true)
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_[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)
//Called by tusb host or i2c driver so we know to connect or disconnect usb
void update_tud_status(bool host_mounted)
{
UserSettings* user_settings = static_cast<UserSettings*>(rt->user_data);
if (user_settings->check_for_driver_change(gamepads_[0]))
board_api::set_led(host_mounted);
if (!host_mounted && tud_inited_.load())
{
user_settings->store_driver_type_safe(user_settings->get_current_driver());
return false;
TaskQueue::Core0::queue_task([]()
{
tud_disconnect();
sleep_ms(300);
multicore_reset_core1();
sleep_ms(300);
board_api::reboot();
});
}
return true;
else if (!tud_inited_.load())
{
TaskQueue::Core0::queue_task([]()
{
tud_init(BOARD_TUD_RHPORT);
});
}
}
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()
{
set_sys_clock_khz(250000, true);
UserSettings user_settings;
user_settings.initialize_flash();
board_init();
board_api::init_gpio();
board_api::set_led(false);
board_api::init_board();
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
{
@@ -94,52 +93,39 @@ void run_program()
}
DeviceManager& device_manager = DeviceManager::get_instance();
device_manager.initialize_driver(user_settings.get_current_driver());
device_manager.initialize_driver(user_settings.get_current_driver(), gamepads_);
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);
repeating_timer_t gp_check_timer;
add_repeating_timer_ms(UserSettings::GP_CHECK_DELAY_MS, gp_check_cb, &user_settings, &gp_check_timer);
uint32_t tid_gp_check = TaskQueue::Core0::get_new_task_id();
set_gp_check_timer(tid_gp_check, user_settings);
DeviceDriver* device_driver = device_manager.get_driver();
while (tud_status_.load() != TUDStatus::INIT)
// Wait for something to call update_tud_status()
while (!tud_inited())
{
sleep_ms(1);
TaskQueue::Core0::process_tasks();
sleep_ms(100);
}
tud_init(BOARD_TUD_RHPORT);
tud_inited_.store(true);
while (true)
{
switch(tud_status_.load())
{
case TUDStatus::DEINIT:
tud_disconnect();
sleep_ms(300);
multicore_reset_core1();
sleep_ms(300);
board_api::reboot();
break;
default:
break;
}
TaskQueue::Core0::process_tasks();
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
{
device_driver->process(i, gamepads_[i]);
tud_task();
}
tud_task();
sleep_us(100);
}
}
} // namespace OGXMini
#endif // (OGXM_BOARD == ADA_FEATHER) || (OGXM_BOARD == RP_ZERO) || (OGXM_BOARD == PI_PICO)
#endif // (OGXM_BOARD == ADA_FEATHER) || (OGXM_BOARD == RP_ZERO) || (OGXM_BOARD == PI_PICO) || (OGXM_BOARD == PI_PICO2)

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,10 @@
#include <cstdint>
#include <functional>
/* Queue tasks to be executed with process_tasks() */
#include "board_config.h"
/* Queue tasks to be executed with process_tasks() in the main loop on either core.
Don't use this on the core running BTStack, that is not safe. */
namespace TaskQueue
{
namespace Core0
@@ -16,6 +19,7 @@ namespace TaskQueue
void process_tasks();
}
#if OGXM_BOARD != PI_PICOW
namespace Core1
{
uint32_t get_new_task_id();
@@ -24,6 +28,7 @@ namespace TaskQueue
bool queue_task(const std::function<void()>& function);
void process_tasks();
}
#endif // OGXM_BOARD != PI_PICOW
} // namespace TaskQueue

View File

@@ -20,7 +20,7 @@ void DInputDevice::initialize()
{
for (auto& in_report : in_reports_)
{
std::memset(&in_report, 0, sizeof(DInput::InReport));
std::memset(reinterpret_cast<void*>(&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;
@@ -29,10 +29,9 @@ void DInputDevice::initialize()
}
class_driver_ = {
#if CFG_TUSB_DEBUG >= 2
.name = "HID",
#endif
.name = TUD_DRV_NAME("HID"),
.init = hidd_init,
.deinit = hidd_deinit,
.reset = hidd_reset,
.open = hidd_open,
.control_xfer_cb = DInputDevice::control_xfer_cb,
@@ -43,84 +42,84 @@ void DInputDevice::initialize()
void DInputDevice::process(const uint8_t idx, Gamepad& gamepad)
{
if (!gamepad.new_pad_in())
{
return;
}
Gamepad::PadIn gp_in = gamepad.get_pad_in();
DInput::InReport& in_report = in_reports_[idx];
switch (gp_in.dpad)
if (gamepad.new_pad_in())
{
case Gamepad::DPAD_UP:
in_report.dpad = DInput::DPad::UP;
break;
case Gamepad::DPAD_DOWN:
in_report.dpad = DInput::DPad::DOWN;
break;
case Gamepad::DPAD_LEFT:
in_report.dpad = DInput::DPad::LEFT;
break;
case Gamepad::DPAD_RIGHT:
in_report.dpad = DInput::DPad::RIGHT;
break;
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;
break;
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;
break;
default:
in_report.dpad = DInput::DPad::CENTER;
break;
Gamepad::PadIn gp_in = gamepad.get_pad_in();
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;
break;
case Gamepad::DPAD_LEFT:
in_report.dpad = DInput::DPad::LEFT;
break;
case Gamepad::DPAD_RIGHT:
in_report.dpad = DInput::DPad::RIGHT;
break;
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;
break;
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;
break;
default:
in_report.dpad = DInput::DPad::CENTER;
break;
}
std::memset(in_report.buttons, 0, sizeof(in_report.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 (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 = 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_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 = gp_in.analog[Gamepad::ANALOG_OFF_RB];
in_report.l1_axis = gp_in.analog[Gamepad::ANALOG_OFF_LB];
}
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 = gp_in.trigger_l;
in_report.r2_axis = gp_in.trigger_r;
}
std::memset(in_report.buttons, 0, sizeof(in_report.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 (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 = 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_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 = gp_in.analog[Gamepad::ANALOG_OFF_RB];
in_report.l1_axis = gp_in.analog[Gamepad::ANALOG_OFF_LB];
}
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 = gp_in.trigger_l;
in_report.r2_axis = gp_in.trigger_r;
if (tud_suspended())
{
tud_remote_wakeup();

View File

@@ -1,3 +1,5 @@
#include "class/cdc/cdc_device.h"
#include "bsp/board_api.h"
#include "USBDevice/DeviceDriver/DeviceDriver.h"
uint16_t* DeviceDriver::get_string_descriptor(const char* value, uint8_t index)

View File

@@ -9,6 +9,12 @@
#include "Gamepad.h"
#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
#define TUD_DRV_NAME(name) name
#else
#define TUD_DRV_NAME(name) NULL
#endif
class DeviceDriver
{
public:
@@ -28,7 +34,7 @@ public:
};
virtual void initialize() = 0;
virtual void process(const uint8_t idx, Gamepad& gamepad) = 0;
virtual void process(const uint8_t idx, Gamepad& gamepad) = 0;
virtual uint16_t get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t req_len) = 0;
virtual void set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t buffer_size) = 0;
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) = 0;

View File

@@ -1,4 +1,5 @@
#include <cstring>
#include <algorithm>
#include "USBDevice/DeviceDriver/PS3/PS3.h"
@@ -6,9 +7,7 @@ void PS3Device::initialize()
{
class_driver_ =
{
#if CFG_TUSB_DEBUG >= 2
.name = "PS3",
#endif
.name = TUD_DRV_NAME("PS3"),
.init = hidd_init,
.deinit = hidd_deinit,
.reset = hidd_reset,
@@ -17,25 +16,6 @@ void PS3Device::initialize()
.xfer_cb = hidd_xfer_cb,
.sof = NULL
};
in_report_ = PS3::InReport();
// bt_info_ =
// {
// .reserved0 = {0xFF,0xFF},
// .device_address = { 0x00, 0x20, 0x40, 0xCE, 0x00, 0x00, 0x00 },
// .host_address = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
// };
// for (uint8_t addr = 0; addr < 3; addr++)
// {
// bt_info_.device_address[4 + addr] = static_cast<uint8_t>(get_rand_32() % 0xFF);
// }
// for (uint8_t addr = 0; addr < 6; addr++)
// {
// bt_info_.host_address[1 + addr] = static_cast<uint8_t>(get_rand_32() % 0xFF);
// }
}
void PS3Device::process(const uint8_t idx, Gamepad& gamepad)
@@ -43,180 +23,117 @@ void PS3Device::process(const uint8_t idx, Gamepad& gamepad)
if (gamepad.new_pad_in())
{
Gamepad::PadIn gp_in = gamepad.get_pad_in();
std::memset(in_report_.buttons, 0, sizeof(in_report_.buttons));
report_in_ = PS3::InReport();
switch (gp_in.dpad)
{
case Gamepad::DPAD_UP:
in_report_.buttons[0] = PS3::Buttons0::DPAD_UP;
report_in_.buttons[0] = PS3::Buttons0::DPAD_UP;
break;
case Gamepad::DPAD_DOWN:
in_report_.buttons[0] = PS3::Buttons0::DPAD_DOWN;
report_in_.buttons[0] = PS3::Buttons0::DPAD_DOWN;
break;
case Gamepad::DPAD_LEFT:
in_report_.buttons[0] = PS3::Buttons0::DPAD_LEFT;
report_in_.buttons[0] = PS3::Buttons0::DPAD_LEFT;
break;
case Gamepad::DPAD_RIGHT:
in_report_.buttons[0] = PS3::Buttons0::DPAD_RIGHT;
report_in_.buttons[0] = PS3::Buttons0::DPAD_RIGHT;
break;
case Gamepad::DPAD_UP_LEFT:
in_report_.buttons[0] = PS3::Buttons0::DPAD_UP | PS3::Buttons0::DPAD_LEFT;
report_in_.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;
report_in_.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;
report_in_.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;
report_in_.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.buttons & Gamepad::BUTTON_X) report_in_.buttons[1] |= PS3::Buttons1::SQUARE;
if (gp_in.buttons & Gamepad::BUTTON_A) report_in_.buttons[1] |= PS3::Buttons1::CROSS;
if (gp_in.buttons & Gamepad::BUTTON_Y) report_in_.buttons[1] |= PS3::Buttons1::TRIANGLE;
if (gp_in.buttons & Gamepad::BUTTON_B) report_in_.buttons[1] |= PS3::Buttons1::CIRCLE;
if (gp_in.buttons & Gamepad::BUTTON_LB) report_in_.buttons[1] |= PS3::Buttons1::L1;
if (gp_in.buttons & Gamepad::BUTTON_RB) report_in_.buttons[1] |= PS3::Buttons1::R1;
if (gp_in.buttons & Gamepad::BUTTON_BACK) report_in_.buttons[0] |= PS3::Buttons0::SELECT;
if (gp_in.buttons & Gamepad::BUTTON_START) report_in_.buttons[0] |= PS3::Buttons0::START;
if (gp_in.buttons & Gamepad::BUTTON_L3) report_in_.buttons[0] |= PS3::Buttons0::L3;
if (gp_in.buttons & Gamepad::BUTTON_R3) report_in_.buttons[0] |= PS3::Buttons0::R3;
if (gp_in.buttons & Gamepad::BUTTON_SYS) report_in_.buttons[2] |= PS3::Buttons2::PS;
if (gp_in.buttons & Gamepad::BUTTON_MISC) report_in_.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;
if (gp_in.trigger_l) report_in_.buttons[1] |= PS3::Buttons1::L2;
if (gp_in.trigger_r) report_in_.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);
report_in_.joystick_lx = Scale::int16_to_uint8(gp_in.joystick_lx);
report_in_.joystick_ly = Scale::int16_to_uint8(gp_in.joystick_ly);
report_in_.joystick_rx = Scale::int16_to_uint8(gp_in.joystick_rx);
report_in_.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];
report_in_.up_axis = gp_in.analog[Gamepad::ANALOG_OFF_UP];
report_in_.down_axis = gp_in.analog[Gamepad::ANALOG_OFF_DOWN];
report_in_.right_axis = gp_in.analog[Gamepad::ANALOG_OFF_RIGHT];
report_in_.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];
report_in_.triangle_axis = gp_in.analog[Gamepad::ANALOG_OFF_Y];
report_in_.circle_axis = gp_in.analog[Gamepad::ANALOG_OFF_B];
report_in_.cross_axis = gp_in.analog[Gamepad::ANALOG_OFF_A];
report_in_.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];
report_in_.r1_axis = gp_in.analog[Gamepad::ANALOG_OFF_RB];
report_in_.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;
report_in_.up_axis = (gp_in.dpad & Gamepad::DPAD_UP) ? 0xFF : 0;
report_in_.down_axis = (gp_in.dpad & Gamepad::DPAD_DOWN) ? 0xFF : 0;
report_in_.right_axis = (gp_in.dpad & Gamepad::DPAD_RIGHT) ? 0xFF : 0;
report_in_.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;
report_in_.triangle_axis = (gp_in.buttons & Gamepad::BUTTON_Y) ? 0xFF : 0;
report_in_.circle_axis = (gp_in.buttons & Gamepad::BUTTON_X) ? 0xFF : 0;
report_in_.cross_axis = (gp_in.buttons & Gamepad::BUTTON_B) ? 0xFF : 0;
report_in_.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));
report_in_.r1_axis = (gp_in.buttons & Gamepad::BUTTON_RB) ? 0xFF : 0;
report_in_.l1_axis = (gp_in.buttons & Gamepad::BUTTON_LB) ? 0xFF : 0;
}
}
if (new_out_report_)
if (tud_suspended())
{
tud_remote_wakeup();
}
if (tud_hid_ready())
{
//PS3 seems to start using stale data if a report isn't sent every frame
tud_hid_report(0, reinterpret_cast<uint8_t*>(&report_in_), sizeof(PS3::InReport));
}
if (new_report_out_)
{
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;
gp_out.rumble_l = report_out_.rumble.left_motor_force;
gp_out.rumble_r = report_out_.rumble.right_motor_on ? UINT_8::MAX : 0;
gamepad.set_pad_out(gp_out);
new_out_report_ = false;
new_report_out_ = false;
}
}
static constexpr uint8_t output_ps3_0x01[] =
{
0x01, 0x04, 0x00, 0x0b, 0x0c, 0x01, 0x02, 0x18,
0x18, 0x18, 0x18, 0x09, 0x0a, 0x10, 0x11, 0x12,
0x13, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02,
0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x04, 0x04,
0x04, 0x04, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02,
0x07, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// calibration data
static constexpr uint8_t output_ps3_0xef[] =
{
0xef, 0x04, 0x00, 0x0b, 0x03, 0x01, 0xa0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff,
0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
};
// unknown
static constexpr uint8_t output_ps3_0xf5[] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // host address - must match 0xf2
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// unknown
static constexpr uint8_t output_ps3_0xf7[] =
{
0x02, 0x01, 0xf8, 0x02, 0xe2, 0x01, 0x05, 0xff,
0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// unknown
static constexpr uint8_t output_ps3_0xf8[] =
{
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/* Based on: https://github.com/OpenStickCommunity/GP2040-CE/blob/main/src/drivers/ps3/PS3Driver.cpp */
uint16_t PS3Device::get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
{
if (report_type == HID_REPORT_TYPE_INPUT)
{
std::memcpy(buffer, &in_report_, sizeof(PS3::InReport));
std::memcpy(buffer, &report_in_, sizeof(PS3::InReport));
return sizeof(PS3::InReport);
}
else if (report_type == HID_REPORT_TYPE_FEATURE)
@@ -228,43 +145,37 @@ uint16_t PS3Device::get_report_cb(uint8_t itf, uint8_t report_id, hid_report_typ
{
case PS3::ReportID::FEATURE_01:
resp_len = reqlen;
std::memcpy(buffer, output_ps3_0x01, resp_len);
std::memcpy(buffer, PS3::OUTPUT_0x01, resp_len);
return resp_len;
case PS3::ReportID::FEATURE_EF:
resp_len = reqlen;
std::memcpy(buffer, output_ps3_0xef, resp_len);
std::memcpy(buffer, PS3::OUTPUT_0xEF, resp_len);
buffer[6] = ef_byte_;
return resp_len;
case PS3::ReportID::GET_PAIRING_INFO:
resp_len = reqlen;
std::memcpy(buffer, &bt_info_, resp_len);
return resp_len;
case PS3::ReportID::FEATURE_F5:
resp_len = reqlen;
std::memcpy(buffer, output_ps3_0xf5, resp_len);
std::memcpy(buffer, PS3::OUTPUT_0xF5, resp_len);
for (ctr = 0; ctr < 6; ctr++)
{
buffer[1 + ctr] = bt_info_.host_address[ctr];
buffer[1+ctr] = bt_info_.host_address[ctr];
}
return resp_len;
case PS3::ReportID::FEATURE_F7:
resp_len = reqlen;
std::memcpy(buffer, output_ps3_0xf7, resp_len);
std::memcpy(buffer, PS3::OUTPUT_0xF7, resp_len);
return resp_len;
case PS3::ReportID::FEATURE_F8:
resp_len = reqlen;
std::memcpy(buffer, output_ps3_0xf8, resp_len);
std::memcpy(buffer, PS3::OUTPUT_0xF8, resp_len);
buffer[6] = ef_byte_;
return resp_len;
}
}
return -1;
return 0;
}
void PS3Device::set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize)
@@ -278,7 +189,7 @@ void PS3Device::set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t
break;
}
}
else if (report_type == HID_REPORT_TYPE_OUTPUT )
else if (report_type == HID_REPORT_TYPE_OUTPUT)
{
// DS3 command
uint8_t const *buf = buffer;
@@ -288,12 +199,11 @@ void PS3Device::set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t
bufsize = bufsize - 1;
buf = &buffer[1];
}
switch(report_id)
{
case PS3::ReportID::FEATURE_01:
std::memcpy(&out_report_, buf, std::min(bufsize, static_cast<uint16_t>(sizeof(PS3::OutReport))));
new_out_report_ = true;
new_report_out_ = true;
std::memcpy(&report_out_, buf, std::min(bufsize, static_cast<uint16_t>(sizeof(PS3::OutReport))));
break;
}
}

View File

@@ -22,11 +22,11 @@ public:
const uint8_t* get_descriptor_device_qualifier_cb() override;
private:
PS3::InReport in_report_;
PS3::OutReport out_report_;
PS3::InReport report_in_;
PS3::OutReport report_out_;
PS3::BTInfo bt_info_;
uint8_t ef_byte_;
bool new_out_report_{false};
bool new_report_out_{false};
};
#endif // _PS3_DEVICE_H_

View File

@@ -6,10 +6,9 @@ void PSClassicDevice::initialize()
{
class_driver_ =
{
#if CFG_TUSB_DEBUG >= 2
.name = "PSClassic",
#endif
.name = TUD_DRV_NAME("PSClassic"),
.init = hidd_init,
.deinit = hidd_deinit,
.reset = hidd_reset,
.open = hidd_open,
.control_xfer_cb = hidd_control_xfer_cb,
@@ -20,98 +19,96 @@ void PSClassicDevice::initialize()
void PSClassicDevice::process(const uint8_t idx, Gamepad& gamepad)
{
if (!gamepad.new_pad_in())
if (gamepad.new_pad_in())
{
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:
in_report_.buttons = PSClassic::Buttons::DOWN;
break;
case Gamepad::DPAD_LEFT:
in_report_.buttons = PSClassic::Buttons::LEFT;
break;
case Gamepad::DPAD_RIGHT:
in_report_.buttons = PSClassic::Buttons::RIGHT;
break;
case Gamepad::DPAD_UP_LEFT:
in_report_.buttons = PSClassic::Buttons::UP_LEFT;
break;
case Gamepad::DPAD_UP_RIGHT:
in_report_.buttons = PSClassic::Buttons::UP_RIGHT;
break;
case Gamepad::DPAD_DOWN_LEFT:
in_report_.buttons = PSClassic::Buttons::DOWN_LEFT;
break;
case Gamepad::DPAD_DOWN_RIGHT:
in_report_.buttons = PSClassic::Buttons::DOWN_RIGHT;
break;
default:
in_report_.buttons = PSClassic::Buttons::CENTER;
break;
}
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:
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))
{
if (meets_neg_45_threshold(joy_ly, joy_ry))
{
in_report_.buttons = PSClassic::Buttons::DOWN_RIGHT;
}
else if (meets_pos_45_threshold(joy_ly, joy_ry))
{
in_report_.buttons = PSClassic::Buttons::UP_RIGHT;
}
else
{
in_report_.buttons = PSClassic::Buttons::RIGHT;
}
}
else if (meets_neg_threshold(joy_lx, joy_rx))
{
if (meets_neg_45_threshold(joy_ly, joy_ry))
{
in_report_.buttons = PSClassic::Buttons::DOWN_LEFT;
}
else if (meets_pos_45_threshold(joy_ly, joy_ry))
{
in_report_.buttons = PSClassic::Buttons::UP_LEFT;
}
else
{
in_report_.buttons = PSClassic::Buttons::LEFT;
}
}
else if (meets_neg_threshold(joy_ly, joy_ry))
{
in_report_.buttons = PSClassic::Buttons::DOWN;
break;
case Gamepad::DPAD_LEFT:
in_report_.buttons = PSClassic::Buttons::LEFT;
break;
case Gamepad::DPAD_RIGHT:
in_report_.buttons = PSClassic::Buttons::RIGHT;
break;
case Gamepad::DPAD_UP_LEFT:
in_report_.buttons = PSClassic::Buttons::UP_LEFT;
break;
case Gamepad::DPAD_UP_RIGHT:
in_report_.buttons = PSClassic::Buttons::UP_RIGHT;
break;
case Gamepad::DPAD_DOWN_LEFT:
in_report_.buttons = PSClassic::Buttons::DOWN_LEFT;
break;
case Gamepad::DPAD_DOWN_RIGHT:
in_report_.buttons = PSClassic::Buttons::DOWN_RIGHT;
break;
default:
in_report_.buttons = PSClassic::Buttons::CENTER;
break;
}
}
else if (meets_pos_threshold(joy_ly, joy_ry))
{
in_report_.buttons = PSClassic::Buttons::UP;
}
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))
{
if (meets_neg_45_threshold(joy_ly, joy_ry))
{
in_report_.buttons = PSClassic::Buttons::DOWN_RIGHT;
}
else if (meets_pos_45_threshold(joy_ly, joy_ry))
{
in_report_.buttons = PSClassic::Buttons::UP_RIGHT;
}
else
{
in_report_.buttons = PSClassic::Buttons::RIGHT;
}
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 (gp_in.trigger_l) in_report_.buttons |= PSClassic::Buttons::L2;
if (gp_in.trigger_r) in_report_.buttons |= PSClassic::Buttons::R2;
}
else if (meets_neg_threshold(joy_lx, joy_rx))
{
if (meets_neg_45_threshold(joy_ly, joy_ry))
{
in_report_.buttons = PSClassic::Buttons::DOWN_LEFT;
}
else if (meets_pos_45_threshold(joy_ly, joy_ry))
{
in_report_.buttons = PSClassic::Buttons::UP_LEFT;
}
else
{
in_report_.buttons = PSClassic::Buttons::LEFT;
}
}
else if (meets_neg_threshold(joy_ly, joy_ry))
{
in_report_.buttons = PSClassic::Buttons::DOWN;
}
else if (meets_pos_threshold(joy_ly, joy_ry))
{
in_report_.buttons = PSClassic::Buttons::UP;
}
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 (gp_in.trigger_l) in_report_.buttons |= PSClassic::Buttons::L2;
if (gp_in.trigger_r) in_report_.buttons |= PSClassic::Buttons::R2;
if (tud_suspended())
{

View File

@@ -6,10 +6,9 @@ void SwitchDevice::initialize()
{
class_driver_ =
{
#if CFG_TUSB_DEBUG >= 2
.name = "SWITCH",
#endif
.name = TUD_DRV_NAME("SWITCH"),
.init = hidd_init,
.deinit = hidd_deinit,
.reset = hidd_reset,
.open = hidd_open,
.control_xfer_cb = hidd_control_xfer_cb,
@@ -22,68 +21,67 @@ void SwitchDevice::initialize()
void SwitchDevice::process(const uint8_t idx, Gamepad& gamepad)
{
if (!gamepad.new_pad_in())
{
return;
}
Gamepad::PadIn gp_in = gamepad.get_pad_in();
SwitchWired::InReport& in_report = in_report_[idx];
switch (gp_in.dpad)
if (gamepad.new_pad_in())
{
case Gamepad::DPAD_UP:
in_report.dpad = SwitchWired::DPad::UP;
break;
case Gamepad::DPAD_DOWN:
in_report.dpad = SwitchWired::DPad::DOWN;
break;
case Gamepad::DPAD_LEFT:
in_report.dpad = SwitchWired::DPad::LEFT;
break;
case Gamepad::DPAD_RIGHT:
in_report.dpad = SwitchWired::DPad::RIGHT;
break;
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;
break;
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;
break;
default:
in_report.dpad = SwitchWired::DPad::CENTER;
break;
Gamepad::PadIn gp_in = gamepad.get_pad_in();
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;
break;
case Gamepad::DPAD_LEFT:
in_report.dpad = SwitchWired::DPad::LEFT;
break;
case Gamepad::DPAD_RIGHT:
in_report.dpad = SwitchWired::DPad::RIGHT;
break;
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;
break;
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;
break;
default:
in_report.dpad = SwitchWired::DPad::CENTER;
break;
}
in_report.buttons = 0;
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 (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 = 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.buttons = 0;
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 (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 = 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();

View File

@@ -1,33 +1,37 @@
#include "class/cdc/cdc_device.h"
#include "bsp/board_api.h"
#include "Descriptors/CDCDev.h"
#include "USBDevice/DeviceDriver/UARTBridge/UARTBridge.h"
#include "USBDevice/DeviceDriver/UARTBridge/uart_bridge/uart_bridge.h"
void UARTBridgeDevice::initialize()
{
class_driver_ = {
#if CFG_TUSB_DEBUG >= 2
.name = "UART",
#endif
.init = cdcd_init,
.reset = cdcd_reset,
.open = cdcd_open,
.control_xfer_cb = cdcd_control_xfer_cb,
.xfer_cb = cdcd_xfer_cb,
.sof = NULL
};
class_driver_ =
{
.name = TUD_DRV_NAME("UART_BRIDGE"),
.init = cdcd_init,
.deinit = cdcd_deinit,
.reset = cdcd_reset,
.open = cdcd_open,
.control_xfer_cb = cdcd_control_xfer_cb,
.xfer_cb = cdcd_xfer_cb,
.sof = NULL
};
}
void UARTBridgeDevice::process(const uint8_t idx, Gamepad& gamepad)
{
if (!uart_initialized_)
if (!task_running_)
{
uart_initialized_ = true;
task_running_ = true;
uart_bridge_run();
}
}
uint16_t UARTBridgeDevice::get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
{
return sizeof(buffer);
return reqlen;
}
void UARTBridgeDevice::set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize)
@@ -42,12 +46,47 @@ bool UARTBridgeDevice::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tus
const uint16_t * UARTBridgeDevice::get_descriptor_string_cb(uint8_t index, uint16_t langid)
{
return uart_bridge_descriptor_string_cb(index, langid);
static uint16_t desc_str[32 + 1];
size_t char_count = 0;
switch(index)
{
case 0:
std::memcpy(&desc_str[1], CDCDesc::DESC_STRING[0], 2);
char_count = 1;
break;
case 3:
char_count = board_usb_get_serial(&desc_str[1], 32);
break;
default:
if (index >= sizeof(CDCDesc::DESC_STRING) / sizeof(CDCDesc::DESC_STRING[0]))
{
return nullptr;
}
const char *str = reinterpret_cast<const char *>(CDCDesc::DESC_STRING[index]);
char_count = std::strlen(str);
const size_t max_count = sizeof(desc_str) / sizeof(desc_str[0]) - 1;
if (char_count > max_count)
{
char_count = max_count;
}
for (size_t i = 0; i < char_count; i++)
{
desc_str[1 + i] = str[i];
}
break;
}
desc_str[0] = static_cast<uint16_t>((TUSB_DESC_STRING << 8) | (2 * char_count + 2));
return desc_str;
}
const uint8_t * UARTBridgeDevice::get_descriptor_device_cb()
{
return uart_bridge_descriptor_device_cb();
return reinterpret_cast<const uint8_t*>(&CDCDesc::DESC_DEVICE);
}
const uint8_t * UARTBridgeDevice::get_hid_descriptor_report_cb(uint8_t itf)
@@ -57,7 +96,7 @@ const uint8_t * UARTBridgeDevice::get_hid_descriptor_report_cb(uint8_t itf)
const uint8_t * UARTBridgeDevice::get_descriptor_configuration_cb(uint8_t index)
{
return uart_bridge_descriptor_configuration_cb(index);
return CDCDesc::DESC_CONFIG;
}
const uint8_t * UARTBridgeDevice::get_descriptor_device_qualifier_cb()

View File

@@ -20,7 +20,7 @@ public:
const uint8_t* get_descriptor_device_qualifier_cb() override;
private:
bool uart_initialized_ = false;
bool task_running_ = false;
};
#endif // _UART_BRIDGE_DEVICE_H_

View File

@@ -13,6 +13,7 @@
#include <hardware/structs/sio.h>
#include <hardware/uart.h>
#include <hardware/flash.h>
#include <hardware/clocks.h>
#include <pico/multicore.h>
#include <pico/stdlib.h>
#include <string.h>
@@ -302,13 +303,10 @@ void core1_entry(void)
}
}
void usbd_serial_init(void);
int uart_bridge_run(void)
{
set_sys_clock_khz(125000, false);
usbd_serial_init();
tud_init(BOARD_TUD_RHPORT);
multicore_reset_core1();
@@ -328,129 +326,4 @@ int uart_bridge_run(void)
}
return 0;
}
#define DESC_STR_MAX 20
#define USBD_VID 0x2E8A /* Raspberry Pi */
#define USBD_PID 0x000A /* Raspberry Pi Pico SDK CDC */
#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + (TUD_CDC_DESC_LEN * CFG_TUD_CDC))
#define USBD_MAX_POWER_MA 500
enum
{
USBD_ITF_CDC_0_1 = 0,
USBD_ITF_CDC_0_2,
#if CFG_TUD_CDC > 1
USBD_ITF_CDC_1_1,
USBD_ITF_CDC_1_2,
#endif
USBD_ITF_MAX,
};
#define USBD_CDC_0_EP_CMD 0x81
#define USBD_CDC_1_EP_CMD 0x83
#define USBD_CDC_0_EP_OUT 0x01
#define USBD_CDC_1_EP_OUT 0x03
#define USBD_CDC_0_EP_IN 0x82
#define USBD_CDC_1_EP_IN 0x84
#define USBD_CDC_CMD_MAX_SIZE 8
#define USBD_CDC_IN_OUT_MAX_SIZE 64
#define USBD_STR_0 0x00
#define USBD_STR_MANUF 0x01
#define USBD_STR_PRODUCT 0x02
#define USBD_STR_SERIAL 0x03
#define USBD_STR_SERIAL_LEN 17
#define USBD_STR_CDC 0x04
static const tusb_desc_device_t usbd_desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = USBD_VID,
.idProduct = USBD_PID,
.bcdDevice = 0x0100,
.iManufacturer = USBD_STR_MANUF,
.iProduct = USBD_STR_PRODUCT,
.iSerialNumber = USBD_STR_SERIAL,
.bNumConfigurations = 1,
};
static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = {
TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_0, USBD_DESC_LEN,
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA),
TUD_CDC_DESCRIPTOR(USBD_ITF_CDC_0_1, USBD_STR_CDC, USBD_CDC_0_EP_CMD,
USBD_CDC_CMD_MAX_SIZE, USBD_CDC_0_EP_OUT, USBD_CDC_0_EP_IN,
USBD_CDC_IN_OUT_MAX_SIZE),
#if CFG_TUD_CDC > 1
TUD_CDC_DESCRIPTOR(USBD_ITF_CDC_1_1, USBD_STR_CDC, USBD_CDC_1_EP_CMD,
USBD_CDC_CMD_MAX_SIZE, USBD_CDC_1_EP_OUT, USBD_CDC_1_EP_IN,
USBD_CDC_IN_OUT_MAX_SIZE),
#endif
};
static char usbd_serial[USBD_STR_SERIAL_LEN] = "000000000000";
static const char *const usbd_desc_str[] = {
[USBD_STR_MANUF] = "Raspberry Pi",
[USBD_STR_PRODUCT] = "Pico",
[USBD_STR_SERIAL] = usbd_serial,
[USBD_STR_CDC] = "Board CDC",
};
const uint8_t *uart_bridge_descriptor_device_cb(void)
{
return (const uint8_t *) &usbd_desc_device;
}
const uint8_t *uart_bridge_descriptor_configuration_cb(uint8_t index)
{
return usbd_desc_cfg;
}
const uint16_t *uart_bridge_descriptor_string_cb(uint8_t index, uint16_t langid)
{
static uint16_t desc_str[DESC_STR_MAX];
uint8_t len;
if (index == 0) {
desc_str[1] = 0x0409;
len = 1;
} else {
const char *str;
char serial[USBD_STR_SERIAL_LEN];
if (index >= sizeof(usbd_desc_str) / sizeof(usbd_desc_str[0]))
return NULL;
str = usbd_desc_str[index];
for (len = 0; len < DESC_STR_MAX - 1 && str[len]; ++len)
desc_str[1 + len] = str[len];
}
desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * len + 2);
return desc_str;
}
void usbd_serial_init(void)
{
uint8_t id[8];
flash_get_unique_id(id);
snprintf(usbd_serial, USBD_STR_SERIAL_LEN, "%02X%02X%02X%02X%02X%02X%02X%02X",
id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7]);
}

View File

@@ -6,9 +6,9 @@ extern "C" {
#endif
int uart_bridge_run(void);
const uint8_t *uart_bridge_descriptor_device_cb(void);
const uint8_t *uart_bridge_descriptor_configuration_cb(uint8_t index);
const uint16_t *uart_bridge_descriptor_string_cb(uint8_t index, uint16_t langid);
// const uint8_t *uart_bridge_descriptor_device_cb(void);
// const uint8_t *uart_bridge_descriptor_configuration_cb(uint8_t index);
// const uint16_t *uart_bridge_descriptor_string_cb(uint8_t index, uint16_t langid);
#ifdef __cplusplus
}

View File

@@ -8,10 +8,9 @@ void WebAppDevice::initialize()
{
class_driver_ =
{
#if CFG_TUSB_DEBUG >= 2
.name = "WEBAPP",
#endif
.name = TUD_DRV_NAME("WEBAPP"),
.init = cdcd_init,
.deinit = cdcd_deinit,
.reset = cdcd_reset,
.open = cdcd_open,
.control_xfer_cb = cdcd_control_xfer_cb,
@@ -36,7 +35,7 @@ void WebAppDevice::process(const uint8_t idx, Gamepad& gamepad)
switch (in_report_.report_id)
{
case ReportID::INIT_READ:
in_report_.input_mode = static_cast<uint8_t>(driver_type_);
in_report_.input_mode = static_cast<uint8_t>(user_settings_.get_current_driver());
in_report_.player_idx = 0;
in_report_.report_id = ReportID::RESP_OK;
in_report_.max_gamepads = MAX_GAMEPADS;
@@ -49,7 +48,7 @@ void WebAppDevice::process(const uint8_t idx, Gamepad& gamepad)
break;
case ReportID::READ_PROFILE:
in_report_.input_mode = static_cast<uint8_t>(driver_type_);
in_report_.input_mode = static_cast<uint8_t>(user_settings_.get_current_driver());
in_report_.profile = user_settings_.get_profile_by_id(in_report_.profile.id);
in_report_.report_id = ReportID::RESP_OK;
@@ -58,7 +57,7 @@ void WebAppDevice::process(const uint8_t idx, Gamepad& gamepad)
break;
case ReportID::WRITE_PROFILE:
if (in_report_.input_mode != static_cast<uint8_t>(driver_type_) && in_report_.input_mode != 0)
if (user_settings_.valid_mode(static_cast<DeviceDriver::Type>(in_report_.input_mode)))
{
success = user_settings_.store_profile_and_driver_type_safe(static_cast<DeviceDriver::Type>(in_report_.input_mode), in_report_.player_idx, in_report_.profile);
}
@@ -93,50 +92,47 @@ bool WebAppDevice::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_co
const uint16_t * WebAppDevice::get_descriptor_string_cb(uint8_t index, uint16_t langid)
{
size_t chr_count;
static uint16_t desc_str[32 + 1];
size_t char_count = 0;
switch ( index )
{
case CDCDesc::STRID_LANGID:
std::memcpy(&CDCDesc::_desc_str[1], CDCDesc::STRING_DESCRIPTORS[0], 2);
chr_count = 1;
break;
switch(index)
{
case 0:
std::memcpy(&desc_str[1], CDCDesc::DESC_STRING[0], 2);
char_count = 1;
break;
case CDCDesc::STRID_SERIAL:
chr_count = board_usb_get_serial(CDCDesc::_desc_str + 1, 32);
break;
case 3:
char_count = board_usb_get_serial(&desc_str[1], 32);
break;
default:
if ( !(index < sizeof(CDCDesc::STRING_DESCRIPTORS) / sizeof(CDCDesc::STRING_DESCRIPTORS[0])) )
default:
if (index >= sizeof(CDCDesc::DESC_STRING) / sizeof(CDCDesc::DESC_STRING[0]))
{
return NULL;
return nullptr;
}
const char *str = reinterpret_cast<const char *>(CDCDesc::DESC_STRING[index]);
char_count = std::strlen(str);
const size_t max_count = sizeof(desc_str) / sizeof(desc_str[0]) - 1;
if (char_count > max_count)
{
char_count = max_count;
}
const char *str = CDCDesc::STRING_DESCRIPTORS[index];
chr_count = strlen(str);
size_t const max_count = sizeof(CDCDesc::_desc_str) / sizeof(CDCDesc::_desc_str[0]) - 1;
if ( chr_count > max_count )
for (size_t i = 0; i < char_count; i++)
{
chr_count = max_count;
desc_str[1 + i] = str[i];
}
break;
}
for ( size_t i = 0; i < chr_count; i++ )
{
CDCDesc::_desc_str[1 + i] = str[i];
}
break;
}
CDCDesc::_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return CDCDesc::_desc_str;
desc_str[0] = static_cast<uint16_t>((TUSB_DESC_STRING << 8) | (2 * char_count + 2));
return desc_str;
}
const uint8_t * WebAppDevice::get_descriptor_device_cb()
{
return reinterpret_cast<const uint8_t*>(&CDCDesc::DEVICE_DESCRIPTORS);
return reinterpret_cast<const uint8_t*>(&CDCDesc::DESC_DEVICE);
}
const uint8_t * WebAppDevice::get_hid_descriptor_report_cb(uint8_t itf)
@@ -146,7 +142,7 @@ const uint8_t * WebAppDevice::get_hid_descriptor_report_cb(uint8_t itf)
const uint8_t * WebAppDevice::get_descriptor_configuration_cb(uint8_t index)
{
return CDCDesc::CONFIGURATION_DESCRIPTORS;
return CDCDesc::DESC_CONFIG;
}
const uint8_t * WebAppDevice::get_descriptor_device_qualifier_cb()

View File

@@ -1,8 +1,6 @@
#ifndef _XINPUT_DEVICE_H_
#define _XINPUT_DEVICE_H_
#include <pico/time.h>
#include "USBDevice/DeviceDriver/DeviceDriver.h"
#include "Descriptors/XInput.h"
@@ -23,8 +21,6 @@ public:
private:
XInput::InReport in_report_;
XInput::OutReport out_report_;
XInput::InReport prev_in_report_;
XInput::OutReport prev_out_report_;
};
#endif // _XINPUT_DEVICE_H_

View File

@@ -29,6 +29,12 @@ static void init(void)
std::memset(out_buffer_, 0, ENDPOINT_SIZE);
}
static bool deinit(void)
{
init();
return true;
}
static void reset(uint8_t rhport)
{
init();
@@ -84,10 +90,13 @@ const usbd_class_driver_t* class_driver()
{
static const usbd_class_driver_t tud_class_driver_ =
{
#if CFG_TUSB_DEBUG >= 2
#if CFG_TUSB_DEBUG >= 2
.name = "XINPUT",
#endif
#else
.name = NULL,
#endif
.init = init,
.deinit = deinit,
.reset = reset,
.open = open,
.control_xfer_cb = control_xfer_cb,

View File

@@ -1,10 +1,10 @@
#include <cstring>
#include <vector>
#include "pico/time.h"
#include <pico/time.h>
#include "Descriptors/XInput.h"
#include "USBDevice/DeviceDriver/XboxOG/tud_xid/tud_xid.h"
#include "USBDevice/DeviceDriver/XboxOG/XboxOG_SB.h"
#include "OGXMini/Debug.h"
static constexpr std::array<XboxOGSBDevice::ButtonMap, 9> GP_MAP =
{{
@@ -82,118 +82,55 @@ void XboxOGSBDevice::initialize()
in_report_.bLength = sizeof(XboxOG::SB::InReport);
in_report_.gearLever = XboxOG::SB::Gear::N;
std::memcpy(&prev_in_report_, &in_report_, sizeof(XboxOG::SB::InReport));
prev_in_report_ = in_report_;
}
void XboxOGSBDevice::process(const uint8_t idx, Gamepad& gamepad)
{
if (gamepad.new_pad_in())
Gamepad::PadIn gp_in = gamepad.get_pad_in();
Gamepad::ChatpadIn gp_in_chatpad = gamepad.get_chatpad_in();
in_report_.dButtons[0] = 0;
in_report_.dButtons[1] = 0;
in_report_.dButtons[2] &= XboxOG::SB::BUTTONS2_TOGGLE_MID;
for (const auto& map : GP_MAP)
{
Gamepad::PadIn gp_in = gamepad.get_pad_in();
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();
for (const auto& map : GP_MAP)
if (gp_in.buttons & map.gp_mask)
{
if (gp_in.buttons & map.gp_mask)
in_report_.dButtons[map.button_offset] |= map.sb_mask;
}
}
for (const auto& map : CHATPAD_MAP)
{
if (chatpad_pressed(gp_in_chatpad, map.gp_mask))
{
in_report_.dButtons[map.button_offset] |= map.sb_mask;
}
}
static std::array<bool, CHATPAD_TOGGLE_MAP.size() + 1> toggle_pressed{false};
for (uint8_t i = 0; i < CHATPAD_TOGGLE_MAP.size(); i++)
{
if (chatpad_pressed(gp_in_chatpad, CHATPAD_TOGGLE_MAP[i].gp_mask))
{
if (!toggle_pressed[i])
{
in_report_.dButtons[map.button_offset] |= map.sb_mask;
in_report_.dButtons[CHATPAD_TOGGLE_MAP[i].button_offset] ^= CHATPAD_TOGGLE_MAP[i].sb_mask;
toggle_pressed[i] = true;
}
}
// Gamepad::Chatpad gp_chatpad = gamepad.get_chatpad();
for (const auto& map : CHATPAD_MAP)
else
{
if (chatpad_pressed(gp_in.chatpad, map.gp_mask))
{
in_report_.dButtons[map.button_offset] |= map.sb_mask;
}
toggle_pressed[i] = false;
}
}
for (const auto& map : CHATPAD_TOGGLE_MAP)
{
if (chatpad_pressed(gp_in.chatpad, map.gp_mask))
{
in_report_.dButtons[map.button_offset] |= map.sb_mask;
}
}
if (gp_in.buttons & Gamepad::BUTTON_X)
{
if (out_report_.Chaff_Extinguisher & 0x0F)
{
in_report_.dButtons[1] |= XboxOG::SB::Buttons1::EXTINGUISHER;
}
if (out_report_.Comm1_MagazineChange & 0x0F)
{
in_report_.dButtons[1] |= XboxOG::SB::Buttons1::WEAPONCONMAGAZINE;
}
if (out_report_.Washing_LineColorChange & 0xF0)
{
in_report_.dButtons[1] |= XboxOG::SB::Buttons1::WASHING;
}
}
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_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_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_in.dpad & Gamepad::DPAD_UP || gp_in.dpad & Gamepad::DPAD_RIGHT)
{
in_report_.tunerDial += (prev_in_report_.tunerDial < 15) ? 1 : -15;
}
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_in.chatpad, XInput::Chatpad::CODE_ORANGE))
{
for (const auto& map : CHATPAD_MAP_ALT2)
{
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_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_in.dpad & Gamepad::DPAD_LEFT) && !(gp_in.dpad & Gamepad::DPAD_RIGHT))
{
if (gp_in.dpad & Gamepad::DPAD_UP)
{
in_report_.gearLever += (prev_in_report_.gearLever < XboxOG::SB::Gear::G5) ? 1 : 0;
}
if (gp_in.dpad & Gamepad::DPAD_DOWN)
{
in_report_.gearLever -= (prev_in_report_.gearLever > XboxOG::SB::Gear::R) ? 1 : 0;
}
}
}
if (chatpad_pressed(gp_in.chatpad, XInput::Chatpad::CODE_SHIFT))
if (chatpad_pressed(gp_in_chatpad, XInput::Chatpad::CODE_SHIFT))
{
if (!toggle_pressed.back())
{
if (in_report_.dButtons[2] & XboxOG::SB::BUTTONS2_TOGGLE_MID)
{
@@ -203,108 +140,193 @@ void XboxOGSBDevice::process(const uint8_t idx, Gamepad& gamepad)
{
in_report_.dButtons[2] |= XboxOG::SB::BUTTONS2_TOGGLE_MID;
}
toggle_pressed.back() = true;
}
}
else
{
toggle_pressed.back() = false;
}
if (gp_in.buttons & Gamepad::BUTTON_X)
{
if (out_report_.Chaff_Extinguisher & 0x0F)
{
in_report_.dButtons[1] |= XboxOG::SB::Buttons1::EXTINGUISHER;
}
if (out_report_.Comm1_MagazineChange & 0x0F)
{
in_report_.dButtons[1] |= XboxOG::SB::Buttons1::WEAPONCONMAGAZINE;
}
if (out_report_.Washing_LineColorChange & 0xF0)
{
in_report_.dButtons[1] |= XboxOG::SB::Buttons1::WASHING;
}
}
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_in_chatpad, map.gp_mask))
{
in_report_.dButtons[map.button_offset] |= map.sb_mask;
}
}
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 = Scale::invert_joy(gp_in.joystick_lx);
in_report_.sightChangeY = gp_in.joystick_ly;
int32_t axis_value = static_cast<int32_t>(Scale::invert_joy(gp_in.joystick_rx));
if (axis_value > XboxOG::SB::DEFAULT_DEADZONE)
if (gp_in.dpad & Gamepad::DPAD_UP && dpad_reset_)
{
vmouse_x_ += axis_value / sensitivity_;
in_report_.tunerDial = (in_report_.tunerDial + 1) % 16;
dpad_reset_ = false;
}
else if (gp_in.dpad & Gamepad::DPAD_DOWN && dpad_reset_)
{
in_report_.tunerDial = (in_report_.tunerDial + 15) % 16;
dpad_reset_ = false;
}
else if (!(gp_in.dpad & Gamepad::DPAD_DOWN) && !(gp_in.dpad & Gamepad::DPAD_UP))
{
dpad_reset_ = true;
}
}
else if (chatpad_pressed(gp_in_chatpad, XInput::Chatpad::CODE_ORANGE))
{
for (const auto& map : CHATPAD_MAP_ALT2)
{
if (chatpad_pressed(gp_in_chatpad, map.gp_mask))
{
in_report_.dButtons[map.button_offset] |= map.sb_mask;
}
}
axis_value = static_cast<int32_t>(Scale::invert_joy(gp_in.joystick_ry));
// if (!(gp_in.dpad & Gamepad::DPAD_LEFT) && !(gp_in.dpad & Gamepad::DPAD_RIGHT))
// {
if (gp_in.dpad & Gamepad::DPAD_UP && dpad_reset_)
{
if (in_report_.gearLever < XboxOG::SB::Gear::G5)
{
in_report_.gearLever++;
}
dpad_reset_ = false;
}
else if (gp_in.dpad & Gamepad::DPAD_DOWN && dpad_reset_)
{
if (in_report_.gearLever > XboxOG::SB::Gear::R)
{
in_report_.gearLever--;
}
dpad_reset_ = false;
}
else if (!(gp_in.dpad & Gamepad::DPAD_DOWN) && !(gp_in.dpad & Gamepad::DPAD_UP))
{
dpad_reset_ = true;
}
// }
}
else
{
dpad_reset_ = true;
}
if (axis_value > XboxOG::SB::DEFAULT_DEADZONE)
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) ? INT_16::MIN :
(gp_in.dpad & Gamepad::DPAD_RIGHT) ? INT_16::MAX : 0;
in_report_.sightChangeX = gp_in.joystick_lx;
in_report_.sightChangeY = gp_in.joystick_ly;
int32_t axis_value_x = static_cast<int32_t>(gp_in.joystick_rx);
if (std::abs(axis_value_x) > DEFAULT_DEADZONE)
{
vmouse_x_ += axis_value_x / sensitivity_;
}
int32_t axis_value_y = static_cast<int32_t>(Scale::invert_joy(gp_in.joystick_ry));
if (std::abs(axis_value_y) > DEFAULT_DEADZONE)
{
vmouse_y_ -= axis_value_y / sensitivity_;
}
if (vmouse_x_ < 0) vmouse_x_ = 0;
if (vmouse_x_ > UINT_16::MAX) vmouse_x_ = UINT_16::MAX;
if (vmouse_y_ > UINT_16::MAX) vmouse_y_ = UINT_16::MAX;
if (vmouse_y_ < 0) vmouse_y_ = 0;
if (gp_in.buttons & Gamepad::BUTTON_L3)
{
if ((time_us_32() / 1000) - aim_reset_timer_ > 500)
{
vmouse_y_ -= axis_value / sensitivity_;
vmouse_x_ = XboxOG::SB::AIMING_MID;
vmouse_y_ = XboxOG::SB::AIMING_MID;
}
}
else
{
aim_reset_timer_ = time_us_32() / 1000;
}
in_report_.aimingX = static_cast<uint16_t>(vmouse_x_);
in_report_.aimingY = static_cast<uint16_t>(vmouse_y_);
if (tud_suspended())
{
tud_remote_wakeup();
}
if (tud_xid::send_report_ready(0) &&
std::memcmp(&prev_in_report_, &in_report_, sizeof(XboxOG::SB::InReport)) &&
tud_xid::send_report(0, reinterpret_cast<uint8_t*>(&in_report_), sizeof(XboxOG::SB::InReport)))
{
std::memcpy(&prev_in_report_, &in_report_, sizeof(XboxOG::SB::InReport));
}
if (chatpad_pressed(gp_in_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 (vmouse_x_ < 0) vmouse_x_ = 0;
if (vmouse_x_ > UINT16_MAX) vmouse_x_ = UINT16_MAX;
if (vmouse_y_ > UINT16_MAX) vmouse_y_ = UINT16_MAX;
if (vmouse_y_ < 0) vmouse_y_ = 0;
if (gp_in.buttons & Gamepad::BUTTON_L3)
if (new_sense != 0)
{
if ((time_us_32() / 1000) - aim_reset_timer_ > 500)
{
vmouse_x_ = XboxOG::SB::AIMING_MID;
vmouse_y_ = XboxOG::SB::AIMING_MID;
}
}
else
{
aim_reset_timer_ = time_us_32() / 1000;
}
in_report_.aimingX = static_cast<uint16_t>(vmouse_x_);
in_report_.aimingY = static_cast<uint16_t>(vmouse_y_);
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::SB::InReport));
}
if (chatpad_pressed(gp_in.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 (new_sense != 0 && new_sense != sensitivity_)
{
sensitivity_ = new_sense;
}
sensitivity_ = new_sense;
}
}

View File

@@ -30,22 +30,27 @@ public:
const uint8_t* get_descriptor_device_qualifier_cb() override;
private:
static constexpr int16_t DEFAULT_DEADZONE = 7500;
static constexpr uint16_t DEFAULT_SENSE = 400;
int32_t vmouse_x_ = XboxOG::SB::AIMING_MID;
int32_t vmouse_y_ = XboxOG::SB::AIMING_MID;
uint16_t sensitivity_ = XboxOG::SB::DEFAULT_SENSE;
uint16_t sensitivity_ = DEFAULT_SENSE;
uint32_t aim_reset_timer_ = 0;
bool dpad_reset_ = true;
XboxOG::SB::InReport in_report_;
XboxOG::SB::InReport prev_in_report_;
XboxOG::SB::OutReport out_report_;
static inline bool chatpad_pressed(const uint8_t* chatpad_array, const uint16_t keycode)
static inline bool chatpad_pressed(const Gamepad::ChatpadIn& chatpad, const uint16_t keycode)
{
if (std::accumulate(chatpad_array, chatpad_array + 3, 0) == 0)
if (std::accumulate(std::begin(chatpad), std::end(chatpad), 0) == 0)
{
return false;
}
else if (keycode < 17 && (chatpad_array[0] & keycode))
else if (keycode < 17 && (chatpad[0] & keycode))
{
return true;
}
@@ -53,11 +58,11 @@ private:
{
return false;
}
else if (chatpad_array[1] == keycode)
else if (chatpad[1] == keycode)
{
return true;
}
else if (chatpad_array[2] == keycode)
else if (chatpad[2] == keycode)
{
return true;
}

View File

@@ -609,6 +609,12 @@ static void xid_init()
}
}
static bool xid_deinit()
{
xid_init();
return true;
}
static void xid_reset(uint8_t rhport)
{
xid_init();
@@ -834,8 +840,11 @@ 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,

View File

@@ -16,45 +16,57 @@
#include "USBDevice/DeviceDriver/UARTBridge/UARTBridge.h"
#endif // defined(CONFIG_EN_UART_BRIDGE)
void DeviceManager::initialize_driver(DeviceDriver::Type driver_type)
void DeviceManager::initialize_driver(DeviceDriver::Type driver_type, Gamepad(&gamepads)[MAX_GAMEPADS])
{
bool has_analog = false; //TODO: Put gamepad setup in the drivers themselves
switch (driver_type)
{
case DeviceDriver::Type::DINPUT:
device_driver_ = new DInputDevice();
has_analog = true;
device_driver_ = std::make_unique<DInputDevice>();
break;
case DeviceDriver::Type::PS3:
device_driver_ = new PS3Device();
has_analog = true;
device_driver_ = std::make_unique<PS3Device>();
break;
case DeviceDriver::Type::PSCLASSIC:
device_driver_ = new PSClassicDevice();
device_driver_ = std::make_unique<PSClassicDevice>();
break;
case DeviceDriver::Type::SWITCH:
device_driver_ = new SwitchDevice();
device_driver_ = std::make_unique<SwitchDevice>();
break;
case DeviceDriver::Type::XINPUT:
device_driver_ = new XInputDevice();
device_driver_ = std::make_unique<XInputDevice>();
break;
case DeviceDriver::Type::XBOXOG:
device_driver_ = new XboxOGDevice();
has_analog = true;
device_driver_ = std::make_unique<XboxOGDevice>();
break;
case DeviceDriver::Type::XBOXOG_SB:
device_driver_ = new XboxOGSBDevice();
device_driver_ = std::make_unique<XboxOGSBDevice>();
break;
case DeviceDriver::Type::XBOXOG_XR:
device_driver_ = new XboxOGXRDevice();
device_driver_ = std::make_unique<XboxOGXRDevice>();
break;
case DeviceDriver::Type::WEBAPP:
device_driver_ = new WebAppDevice();
device_driver_ = std::make_unique<WebAppDevice>();
break;
#if defined(CONFIG_EN_UART_BRIDGE)
case DeviceDriver::Type::UART_BRIDGE:
device_driver_ = new UARTBridgeDevice();
device_driver_ = std::make_unique<UARTBridgeDevice>();
break;
#endif //defined(CONFIG_EN_UART_BRIDGE)
default:
return;
}
if (has_analog)
{
for (size_t i = 0; i < MAX_GAMEPADS; ++i)
{
gamepads[i].set_analog_device(true);
}
}
device_driver_->initialize();
}

View File

@@ -1,8 +1,10 @@
#ifndef _DEVICE_MANAGER_H_
#define _DEVICE_MANAGER_H_
#include <cstdint>
#include <memory>
#include "Gamepad.h"
#include "USBDevice/DeviceDriver/DeviceDriver.h"
class DeviceManager
@@ -18,14 +20,15 @@ public:
}
//Must be called before any other method
void initialize_driver(DeviceDriver::Type driver_type);
void initialize_driver(DeviceDriver::Type driver_type, Gamepad(&gamepads)[MAX_GAMEPADS]);
DeviceDriver* get_driver() { return device_driver_; }
DeviceDriver* get_driver() { return device_driver_.get(); }
private:
DeviceManager() {}
~DeviceManager() { delete device_driver_; }
DeviceDriver* device_driver_{nullptr};
DeviceManager() = default;
~DeviceManager() = default;
std::unique_ptr<DeviceDriver> device_driver_{nullptr};
};
#endif // _DEVICE_MANAGER_H_

View File

@@ -1,3 +1,27 @@
/*
MIT License
Copyright (c) 2024 o0zz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "USBHost/HIDParser/HIDJoystick.h"
#include "USBHost/HIDParser/HIDUtils.h"
#include <cstring>

View File

@@ -1,3 +1,27 @@
/*
MIT License
Copyright (c) 2024 o0zz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "USBHost/HIDParser/HIDReportDescriptor.h"
#include <memory>
#include <vector>

View File

@@ -1,3 +1,27 @@
/*
MIT License
Copyright (c) 2024 o0zz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "USBHost/HIDParser/HIDReportDescriptor.h"
#include "USBHost/HIDParser/HIDReportDescriptorElements.h"
#include "USBHost/HIDParser/HIDReportDescriptorUsages.h"

View File

@@ -1,3 +1,27 @@
/*
MIT License
Copyright (c) 2024 o0zz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <stdint.h>

View File

@@ -1,3 +1,27 @@
/*
MIT License
Copyright (c) 2024 o0zz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "USBHost/HIDParser/HIDReportDescriptorElements.h"
#include <cstring>

View File

@@ -1,3 +1,27 @@
/*
MIT License
Copyright (c) 2024 o0zz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <memory>
#include <vector>

View File

@@ -1,3 +1,27 @@
/*
MIT License
Copyright (c) 2024 o0zz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "USBHost/HIDParser/HIDReportDescriptorUsages.h"
#include <iostream>
#include <vector>

View File

@@ -1,3 +1,27 @@
/*
MIT License
Copyright (c) 2024 o0zz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include "USBHost/HIDParser/HIDReportDescriptorElements.h"
#include <vector>

View File

@@ -1,3 +1,27 @@
/*
MIT License
Copyright (c) 2024 o0zz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "USBHost/HIDParser/HIDUtils.h"
uint32_t HIDUtils::readBitsLE(uint8_t *buffer, uint32_t bitOffset, uint32_t bitLength) {

View File

@@ -1,3 +1,27 @@
/*
MIT License
Copyright (c) 2024 o0zz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <stdint.h>

View File

@@ -7,7 +7,7 @@
void DInputHost::initialize(Gamepad& gamepad, uint8_t address, uint8_t instance, const uint8_t* report_desc, uint16_t desc_len)
{
gamepad.set_analog_enabled(true);
gamepad.set_analog_host(true);
tuh_hid_receive_report(address, instance);
}

View File

@@ -39,6 +39,9 @@ public:
virtual void process_report(Gamepad& gamepad, uint8_t address, uint8_t instance, const uint8_t* report, uint16_t len) = 0;
virtual bool send_feedback(Gamepad& gamepad, uint8_t address, uint8_t instance) = 0;
virtual void connect_cb(Gamepad& gamepad, uint8_t address, uint8_t instance) {}; //Wireless specific
virtual void disconnect_cb(Gamepad& gamepad, uint8_t address, uint8_t instance) {}; //Wireless specific
protected:
const uint8_t idx_;

View File

@@ -16,12 +16,14 @@ const tusb_control_request_t PS3Host::RUMBLE_REQUEST =
void PS3Host::initialize(Gamepad& gamepad, uint8_t address, uint8_t instance, const uint8_t* report_desc, uint16_t desc_len)
{
gamepad.set_analog_enabled(true);
gamepad.set_analog_host(true);
std::memcpy(&out_report_, PS3::DEFAULT_OUT_REPORT, std::min(sizeof(PS3::OutReport), sizeof(PS3::DEFAULT_OUT_REPORT)));
std::memcpy(reinterpret_cast<uint8_t*>(&out_report_),
PS3::DEFAULT_OUT_REPORT,
std::min(sizeof(PS3::OutReport), sizeof(PS3::DEFAULT_OUT_REPORT)));
out_report_.leds_bitmap = 0x1 << (idx_ + 1);
out_report_.led[idx_].time_enabled = 0xFF;
out_report_.leds[idx_].time_enabled = 0xFF;
init_state_.out_report = &out_report_;
init_state_.dev_addr = address;
@@ -154,12 +156,13 @@ 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
//Spamming set_report doesn't work, limit the rate
if (init_state_.reports_enabled &&
current_ms - last_rumble_ms >= 300)
{
Gamepad::PadOut gp_out = gamepad.get_pad_out();
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;

View File

@@ -7,21 +7,35 @@
void PS5Host::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_));
out_report_.report_id = PS5::OUT_REPORT_ID;
out_report_.valid_flag0 = 0x02;
out_report_.valid_flag1 = 0x02;
out_report_.valid_flag2 = 0x04;
out_report_.report_id = PS5::OutReportID::CONTROL;
out_report_.control_flag[0] = 2;
out_report_.control_flag[1] = 2;
out_report_.led_control_flag = 0x01 | 0x02;
out_report_.pulse_option = 1;
out_report_.led_brightness = 0xFF;
out_report_.player_number = idx_ + 1;
out_report_.lightbar_blue = 0xFF;
while (!tuh_hid_send_report(address, instance, 0, &out_report_, sizeof(PS5::OutReport)))
{
tuh_task();
}
out_report_ = PS5::OutReport();
out_report_.report_id = PS5::OutReportID::RUMBLE;
out_report_.control_flag[0] = 2;
out_report_.control_flag[1] = 2;
out_report_.led_control_flag = 0x04;
tuh_hid_receive_report(address, instance);
}
void PS5Host::process_report(Gamepad& gamepad, uint8_t address, uint8_t instance, const uint8_t* report, uint16_t len)
{
in_report_ = *reinterpret_cast<const PS5::InReport*>(report);
in_report_.seq_number = 0;
const PS5::InReport* in_report = reinterpret_cast<const PS5::InReport*>(report);
if (std::memcmp(&prev_in_report_, &in_report_, PS5::IN_REPORT_CMP_SIZE) == 0)
if (std::memcmp(&prev_in_report_.joystick_lx, &in_report->joystick_lx, sizeof(uint8_t) * 6) == 0 &&
std::memcmp(prev_in_report_.buttons, in_report->buttons, sizeof(in_report->buttons)) == 0)
{
tuh_hid_receive_report(address, instance);
return;
@@ -29,7 +43,7 @@ void PS5Host::process_report(Gamepad& gamepad, uint8_t address, uint8_t instance
Gamepad::PadIn gp_in;
switch (in_report_.buttons[0] & PS5::DPAD_MASK)
switch (in_report->buttons[0] & PS5::DPAD_MASK)
{
case PS5::Buttons0::DPAD_UP:
gp_in.dpad |= gamepad.MAP_DPAD_UP;
@@ -59,31 +73,31 @@ void PS5Host::process_report(Gamepad& gamepad, uint8_t address, uint8_t instance
break;
}
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;
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;
gp_in.trigger_l = in_report_.trigger_l;
gp_in.trigger_r = in_report_.trigger_r;
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);
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);
std::memcpy(&prev_in_report_, in_report, sizeof(PS5::InReport));
}
bool PS5Host::send_feedback(Gamepad& gamepad, uint8_t address, uint8_t instance)

View File

@@ -17,7 +17,6 @@ public:
bool send_feedback(Gamepad& gamepad, uint8_t address, uint8_t instance) override;
private:
PS5::InReport in_report_{};
PS5::InReport prev_in_report_{};
PS5::OutReport out_report_{};
};

View File

@@ -5,36 +5,48 @@
#include "host/usbh.h"
#include "TaskQueue/TaskQueue.h"
#include "USBHost/HostDriver/XInput/tuh_xinput/tuh_xinput.h"
#include "USBHost/HostDriver/XInput/Xbox360W.h"
#include "OGXMini/Debug.h"
Xbox360WHost::~Xbox360WHost()
{
TaskQueue::Core1::cancel_delayed_task(timer_info_.task_id);
TaskQueue::Core1::cancel_delayed_task(tid_chatpad_keepalive_);
}
void Xbox360WHost::initialize(Gamepad& gamepad, uint8_t address, uint8_t instance, const uint8_t* report_desc, uint16_t desc_len)
{
std::memset(&prev_in_report_, 0, sizeof(XInput::InReportWireless));
timer_info_.address = address;
timer_info_.instance = instance;
timer_info_.led_quadrant = idx_ + 1;
timer_info_.task_id = TaskQueue::Core1::get_new_task_id();
//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);
}
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);
if (std::memcmp(&prev_in_report_, in_report, std::min(static_cast<size_t>(len), sizeof(XInput::InReportWireless))) == 0)
if (in_report->command[1] & 2)
{
if (in_report->chatpad_status == 0x00)
{
Gamepad::ChatpadIn gp_in_chatpad;
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_in(gp_in_chatpad);
}
else if (in_report->chatpad_status == 0xF0 && in_report->chatpad[0] == 0x03)
{
tuh_xinput::xbox360_chatpad_init(address, instance);
}
tuh_xinput::receive_report(address, instance);
return;
}
if (!(in_report->command[1] & 1) ||
!(in_report->report_size == 0x13) ||
std::memcmp(&prev_in_report_, in_report, std::min(static_cast<size_t>(len), sizeof(XInput::InReportWireless))) == 0)
{
tuh_xinput::receive_report(address, instance);
return;
@@ -67,21 +79,39 @@ void Xbox360WHost::process_report(Gamepad& gamepad, uint8_t address, uint8_t ins
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_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_pad_in(gp_in);
tuh_xinput::receive_report(address, instance);
std::memcpy(&prev_in_report_, in_report, sizeof(XInput::InReportWireless));
prev_in_report_ = *in_report;
}
bool Xbox360WHost::send_feedback(Gamepad& gamepad, uint8_t address, uint8_t instance)
{
Gamepad::PadOut gp_out = gamepad.get_pad_out();
return tuh_xinput::set_rumble(address, instance, gp_out.rumble_l, gp_out.rumble_r, false);
}
void Xbox360WHost::connect_cb(Gamepad& gamepad, uint8_t address, uint8_t instance)
{
tid_chatpad_keepalive_ = TaskQueue::Core1::get_new_task_id();
//Might not be ready for leds yet, needs delay
TaskQueue::Core1::queue_delayed_task(TaskQueue::Core1::get_new_task_id(), 1000, false,
[address, instance, this]
{
tuh_xinput::set_led(address, instance, idx_ + 1, false);
tuh_xinput::xbox360_chatpad_init(address, instance);
TaskQueue::Core1::queue_delayed_task(tid_chatpad_keepalive_, tuh_xinput::KEEPALIVE_MS, true,
[address, instance]
{
OGXM_LOG("XInput Chatpad Keepalive\r\n");
tuh_xinput::xbox360_chatpad_keepalive(address, instance);
});
});
}
void Xbox360WHost::disconnect_cb(Gamepad& gamepad, uint8_t address, uint8_t instance)
{
TaskQueue::Core1::cancel_delayed_task(tid_chatpad_keepalive_);
}

View File

@@ -3,7 +3,6 @@
#include <cstdint>
#include "TaskQueue/TaskQueue.h"
#include "Descriptors/XInput.h"
#include "USBHost/HostDriver/HostDriver.h"
@@ -19,19 +18,12 @@ public:
void process_report(Gamepad& gamepad, uint8_t address, uint8_t instance, const uint8_t* report, uint16_t len) override;
bool send_feedback(Gamepad& gamepad, uint8_t address, uint8_t instance) override;
void connect_cb(Gamepad& gamepad, uint8_t address, uint8_t instance) override;
void disconnect_cb(Gamepad& gamepad, uint8_t address, uint8_t instance) override;
private:
struct TimerInfo
{
uint8_t address;
uint8_t instance;
uint8_t led_quadrant;
uint32_t task_id;
};
TimerInfo timer_info_;
uint32_t tid_chatpad_keepalive_{0};
XInput::InReportWireless prev_in_report_;
static bool timer_cb(struct repeating_timer *t);
};
#endif // _XBOX360_WIRELESS_HOST_H_

View File

@@ -7,7 +7,7 @@
void XboxOGHost::initialize(Gamepad& gamepad, uint8_t address, uint8_t instance, const uint8_t* report_desc, uint16_t desc_len)
{
gamepad.set_analog_enabled(true);
gamepad.set_analog_host(true);
std::memset(&prev_in_report_, 0, sizeof(XboxOG::GP::InReport));
tuh_xinput::receive_report(address, instance);
}

View File

@@ -72,8 +72,8 @@ namespace tuh_xinput
uint8_t ep_in{0xFF};
uint8_t ep_out{0xFF};
uint8_t ep_in_size{0xFF};
uint8_t ep_out_size{0xFF};
uint16_t ep_in_size{0xFF};
uint16_t ep_out_size{0xFF};
std::array<uint8_t, ENDPOINT_SIZE> ep_in_buffer{0};
std::array<uint8_t, ENDPOINT_SIZE> ep_out_buffer{0};
@@ -82,10 +82,14 @@ namespace tuh_xinput
// API
const usbh_class_driver_t* class_driver();
bool send_report(uint8_t address, uint8_t instance, const uint8_t* report, uint16_t len);
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);
//Wireless only atm
void xbox360_chatpad_init(uint8_t address, uint8_t instance);
bool xbox360_chatpad_keepalive(uint8_t address, uint8_t instance);
// User implemented callbacks

View File

@@ -77,10 +77,10 @@ namespace tuh_xinput
static constexpr tusb_control_request_t INIT_5 = { .bmRequestType = 0x40, .bRequest = 0xA1, .wValue = 0x0000, .wIndex = 0xE416, .wLength = 2 };
static constexpr tusb_control_request_t INIT_6 = { .bmRequestType = 0xC0, .bRequest = 0xA1, .wValue = 0x0000, .wIndex = 0xE416, .wLength = 2 };
//wValue in xbox360_wired_chatpad_command can be replaced with CHATPAD_CMD constants for different functions
static constexpr tusb_control_request_t CMD = { .bmRequestType = 0x41, .bRequest = 0x00, .wValue = 0x0000, .wIndex = 0x0002, .wLength = 0 };
static constexpr tusb_control_request_t CMD = { .bmRequestType = 0x41, .bRequest = 0x00, .wValue = 0x0000, .wIndex = 0x0002, .wLength = 0 };
static constexpr tusb_control_request_t KEEPALIVE_1 = { .bmRequestType = 0x41, .bRequest = 0x00, .wValue = 0x001F, .wIndex = 0x0002, .wLength = 0 };
static constexpr tusb_control_request_t KEEPALIVE_2 = { .bmRequestType = 0x41, .bRequest = 0x00, .wValue = 0x001E, .wIndex = 0x0002, .wLength = 0 };
static constexpr tusb_control_request_t LEDS_1B = { .bmRequestType = 0x41, .bRequest = 0x00, .wValue = 0x001B, .wIndex = 0x0002, .wLength = 0 };
static constexpr tusb_control_request_t LEDS_1B = { .bmRequestType = 0x41, .bRequest = 0x00, .wValue = 0x001B, .wIndex = 0x0002, .wLength = 0 };
}
}

View File

@@ -1,3 +1,383 @@
#ifndef _HOST_MANAGER_H_
#define _HOST_MANAGER_H_
#include <cstdint>
#include <memory>
#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"
#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];
}
}
//XInput doesn't need report_desc or desc_len
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 || instance >= MAX_INTERFACES)
{
return false;
}
//Check if this device is already mounted
uint8_t dev_idx = get_device_slot(address);
//If not, find a free device slot
if (dev_idx == INVALID_IDX && ((dev_idx = find_free_device_slot()) == INVALID_IDX))
{
return false;
}
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::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;
}
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& device_slot : device_slots_)
{
if (device_slot.address == address &&
device_slot.interfaces[instance].driver &&
device_slot.interfaces[instance].gamepad)
{
device_slot.interfaces[instance].driver->process_report(*device_slot.interfaces[instance].gamepad, address, instance, report, len);
}
}
}
inline void connect_cb(DriverClass driver_class, uint8_t address, uint8_t instance)
{
for (auto& device_slot : device_slots_)
{
if (device_slot.address == address &&
device_slot.interfaces[instance].driver &&
device_slot.interfaces[instance].gamepad)
{
device_slot.interfaces[instance].driver->connect_cb(*device_slot.interfaces[instance].gamepad, address, instance);
}
}
}
inline void disconnect_cb(DriverClass driver_class, uint8_t address, uint8_t instance)
{
for (auto& device_slot : device_slots_)
{
if (device_slot.address == address &&
device_slot.interfaces[instance].driver &&
device_slot.interfaces[instance].gamepad)
{
device_slot.interfaces[instance].driver->disconnect_cb(*device_slot.interfaces[instance].gamepad, address, instance);
}
}
}
//Call on a timer
inline void send_feedback()
{
for (auto& device_slot : device_slots_)
{
if (device_slot.address == INVALID_IDX)
{
continue;
}
for (uint8_t i = 0; i < MAX_INTERFACES; ++i)
{
if (device_slot.interfaces[i].driver != nullptr && device_slot.interfaces[i].gamepad->new_pad_out())
{
device_slot.interfaces[i].driver->send_feedback(*device_slot.interfaces[i].gamepad, device_slot.address, i);
tuh_task();
}
}
}
}
void deinit_driver(DriverClass driver_class, uint8_t address, uint8_t instance)
{
for (auto& device_slot : device_slots_)
{
if (device_slot.address == address)
{
TU_LOG2("Deinit driver\r\n");
device_slot.reset();
TU_LOG2("Driver deinitialized\r\n");
}
}
}
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& device_slot : device_slots_)
{
if (device_slot.address == address && instance < MAX_INTERFACES)
{
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 Interface
{
std::unique_ptr<HostDriver> driver{nullptr};
Gamepad* gamepad{nullptr};
uint8_t gamepad_idx{INVALID_IDX};
};
struct Device
{
uint8_t address{INVALID_IDX};
Interface interfaces[MAX_INTERFACES];
void reset()
{
address = INVALID_IDX;
for (auto& interface : interfaces)
{
interface.driver.reset();
interface.gamepad_idx = INVALID_IDX;
interface.gamepad = nullptr;
}
}
};
Device device_slots_[MAX_GAMEPADS];
Gamepad* gamepads_[MAX_GAMEPADS];
HostManager() {}
inline uint8_t find_free_device_slot()
{
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
{
if (device_slots_[i].address == INVALID_IDX)
{
return i;
}
}
return INVALID_IDX;
}
inline uint8_t find_free_gamepad()
{
uint8_t count = 0;
for (auto& device_slot : device_slots_)
{
for (auto& interface : device_slot.interfaces)
{
if (interface.gamepad_idx != INVALID_IDX)
{
++count;
}
}
}
return (count < MAX_GAMEPADS) ? count : INVALID_IDX;
}
inline uint8_t get_device_slot(uint8_t address)
{
if (address > MAX_GAMEPADS)
{
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;
// }
// }
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;
}
inline HostDriver* get_driver_by_gamepad(uint8_t gamepad_idx)
{
for (const auto& device_slot : device_slots_)
{
for (const auto& interface : device_slot.interfaces)
{
if (interface.gamepad_idx == gamepad_idx)
{
return interface.driver.get();
}
}
}
return nullptr;
}
};
#endif // _HOST_MANAGER_H_
// #ifndef _HOST_MANAGER_H_
// #define _HOST_MANAGER_H_
@@ -361,368 +741,4 @@
// }
// };
// #endif // _HOST_MANAGER_H_
#ifndef _HOST_MANAGER_H_
#define _HOST_MANAGER_H_
#include <cstdint>
#include <memory>
#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"
#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 || instance >= MAX_INTERFACES)
{
return false;
}
// DriverClass driver_class = determine_driver_class(driver_type);
uint8_t dev_idx = get_device_slot(address);
//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;
}
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::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;
}
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& device_slot : device_slots_)
{
if (device_slot.address == address &&
device_slot.interfaces[instance].driver &&
device_slot.interfaces[instance].gamepad)
{
device_slot.interfaces[instance].driver->process_report(*device_slot.interfaces[instance].gamepad, address, instance, report, len);
}
}
}
//Call on a timer
inline void send_feedback()
{
for (auto& device_slot : device_slots_)
{
if (device_slot.address == INVALID_IDX)
{
continue;
}
for (uint8_t i = 0; i < MAX_INTERFACES; ++i)
{
if (device_slot.interfaces[i].driver != nullptr && device_slot.interfaces[i].gamepad->new_pad_out())
{
device_slot.interfaces[i].driver->send_feedback(*device_slot.interfaces[i].gamepad, device_slot.address, i);
tuh_task();
}
}
}
}
void deinit_driver(DriverClass driver_class, uint8_t address, uint8_t instance)
{
for (auto& device_slot : device_slots_)
{
if (device_slot.address == address)
{
TU_LOG2("Deinit driver\r\n");
device_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& device_slot : device_slots_)
{
if (device_slot.address == address && instance < MAX_INTERFACES)
{
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 Interface
{
std::unique_ptr<HostDriver> driver{nullptr};
Gamepad* gamepad{nullptr};
uint8_t gamepad_idx{INVALID_IDX};
};
struct Device
{
uint8_t address{INVALID_IDX};
Interface interfaces[MAX_INTERFACES];
void reset()
{
address = INVALID_IDX;
for (auto& interface : interfaces)
{
interface.driver.reset();
interface.gamepad_idx = INVALID_IDX;
interface.gamepad = nullptr;
}
}
};
Device device_slots_[MAX_GAMEPADS];
Gamepad* gamepads_[MAX_GAMEPADS];
HostManager()
{
// 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 (device_slots_[i].address == INVALID_IDX)
{
return i;
}
}
return INVALID_IDX;
}
inline uint8_t find_free_gamepad()
{
uint8_t count = 0;
for (auto& device_slot : device_slots_)
{
for (auto& interface : device_slot.interfaces)
{
if (interface.gamepad_idx != INVALID_IDX)
{
++count;
}
}
}
return (count < MAX_GAMEPADS) ? count : INVALID_IDX;
}
inline uint8_t get_device_slot(uint8_t address)
{
if (address > MAX_GAMEPADS)
{
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;
// }
// }
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;
}
/* 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;
// }
}
};
#endif // _HOST_MANAGER_H_
// #endif // _HOST_MANAGER_H_

View File

@@ -9,7 +9,6 @@
#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/4Channel/I2CManager.h"
@@ -36,7 +35,7 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
I2CManager::get_instance().get_driver()->notify_tuh_mounted();
#endif //defined(CONFIG_EN_4CH)
OGXMini::update_tuh_status(true);
OGXMini::update_tud_status(true);
}
}
@@ -47,11 +46,11 @@ void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
if (!host_manager.any_mounted())
{
// #if defined(CONFIG_EN_4CH)
// I2CManager::get_instance().get_driver()->notify_tuh_unmounted();
// #endif //defined(CONFIG_EN_4CH)
#if defined(CONFIG_EN_4CH)
I2CManager::get_instance().get_driver()->notify_tuh_unmounted();
#endif //defined(CONFIG_EN_4CH)
OGXMini::update_tuh_status(false);
OGXMini::update_tud_status(false);
}
}
@@ -69,11 +68,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)
// I2CManager::get_instance().get_driver()->notify_tuh_mounted(host_type);
// #endif //defined(CONFIG_EN_4CH)
OGXMini::update_tuh_status(true);
#if defined(CONFIG_EN_4CH)
I2CManager::get_instance().get_driver()->notify_tuh_mounted(host_type);
#endif //defined(CONFIG_EN_4CH)
OGXMini::update_tud_status(true);
}
}
@@ -84,11 +83,11 @@ void tuh_xinput::unmount_cb(uint8_t dev_addr, uint8_t instance, const tuh_xinput
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)
#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);
OGXMini::update_tud_status(false);
}
}
@@ -99,16 +98,20 @@ void tuh_xinput::report_received_cb(uint8_t dev_addr, uint8_t instance, const ui
void tuh_xinput::xbox360w_connect_cb(uint8_t dev_addr, uint8_t instance)
{
// #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)
#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)
HostManager::get_instance().connect_cb(HostManager::DriverClass::XINPUT, dev_addr, instance);
}
void tuh_xinput::xbox360w_disconnect_cb(uint8_t dev_addr, uint8_t instance)
{
// #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)
#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)
HostManager::get_instance().disconnect_cb(HostManager::DriverClass::XINPUT, dev_addr, instance);
}

View File

@@ -35,14 +35,14 @@ UserProfile::UserProfile()
analog_enabled = 1;
analog_off_up = 0;
analog_off_down = 1;
analog_off_left = 2;
analog_off_right = 3;
analog_off_a = 4;
analog_off_b = 5;
analog_off_x = 6;
analog_off_y = 7;
analog_off_lb = 8;
analog_off_rb = 9;
analog_off_up = Gamepad::ANALOG_OFF_UP;
analog_off_down = Gamepad::ANALOG_OFF_DOWN;
analog_off_left = Gamepad::ANALOG_OFF_LEFT;
analog_off_right = Gamepad::ANALOG_OFF_RIGHT;
analog_off_a = Gamepad::ANALOG_OFF_A;
analog_off_b = Gamepad::ANALOG_OFF_B;
analog_off_x = Gamepad::ANALOG_OFF_X;
analog_off_y = Gamepad::ANALOG_OFF_Y;
analog_off_lb = Gamepad::ANALOG_OFF_LB;
analog_off_rb = Gamepad::ANALOG_OFF_RB;
}

View File

@@ -33,25 +33,31 @@ static constexpr DeviceDriver::Type VALID_DRIVER_TYPES[] =
#if defined(CONFIG_EN_4CH)
DeviceDriver::Type::XBOXOG,
DeviceDriver::Type::XBOXOG_SB,
DeviceDriver::Type::XBOXOG_XR,
DeviceDriver::Type::XINPUT,
DeviceDriver::Type::PS3,
DeviceDriver::Type::PSCLASSIC,
DeviceDriver::Type::WEBAPP,
#if defined(XREMOTE_ROM_AVAILABLE)
DeviceDriver::Type::XBOXOG_XR,
#endif
#elif MAX_GAMEPADS > 1
DeviceDriver::Type::DINPUT,
DeviceDriver::Type::SWITCH,
DeviceDriver::Type::WEBAPP,
#else
#else // MAX_GAMEPADS == 1
DeviceDriver::Type::XBOXOG,
DeviceDriver::Type::XBOXOG_SB,
DeviceDriver::Type::XBOXOG_XR,
// DeviceDriver::Type::DINPUT,
DeviceDriver::Type::DINPUT,
DeviceDriver::Type::SWITCH,
DeviceDriver::Type::WEBAPP,
DeviceDriver::Type::PS3,
DeviceDriver::Type::PSCLASSIC,
DeviceDriver::Type::XINPUT,
#if defined(XREMOTE_ROM_AVAILABLE)
DeviceDriver::Type::XBOXOG_XR,
#endif
#endif
};
@@ -59,14 +65,14 @@ static constexpr DeviceDriver::Type VALID_DRIVER_TYPES[] =
struct ComboMap { uint32_t combo; DeviceDriver::Type driver; };
static constexpr std::array<ComboMap, 9> BUTTON_COMBO_MAP =
{{
{ ButtonCombo::XBOXOG, DeviceDriver::Type::XBOXOG },
{ ButtonCombo::XBOXOG, DeviceDriver::Type::XBOXOG },
{ ButtonCombo::XBOXOG_SB, DeviceDriver::Type::XBOXOG_SB },
{ ButtonCombo::XBOXOG_XR, DeviceDriver::Type::XBOXOG_XR },
{ ButtonCombo::WEBAPP, DeviceDriver::Type::WEBAPP },
{ ButtonCombo::DINPUT, DeviceDriver::Type::DINPUT },
{ ButtonCombo::SWITCH, DeviceDriver::Type::SWITCH },
{ ButtonCombo::XINPUT, DeviceDriver::Type::XINPUT },
{ ButtonCombo::PS3, DeviceDriver::Type::PS3 },
{ ButtonCombo::WEBAPP, DeviceDriver::Type::WEBAPP },
{ ButtonCombo::DINPUT, DeviceDriver::Type::DINPUT },
{ ButtonCombo::SWITCH, DeviceDriver::Type::SWITCH },
{ ButtonCombo::XINPUT, DeviceDriver::Type::XINPUT },
{ ButtonCombo::PS3, DeviceDriver::Type::PS3 },
{ ButtonCombo::PSCLASSIC, DeviceDriver::Type::PSCLASSIC }
}};
@@ -166,8 +172,6 @@ bool UserSettings::write_firmware_version_safe()
DeviceDriver::Type UserSettings::get_current_driver()
{
return DeviceDriver::Type::XINPUT;
if (current_driver_ != DeviceDriver::Type::NONE)
{
return current_driver_;
@@ -431,4 +435,16 @@ UserProfile UserSettings::get_profile_by_id(const uint8_t profile_id)
DeviceDriver::Type UserSettings::get_default_driver()
{
return VALID_DRIVER_TYPES[0];
}
bool UserSettings::valid_mode(DeviceDriver::Type mode)
{
for (const auto& driver : VALID_DRIVER_TYPES)
{
if (mode == driver)
{
return true;
}
}
return false;
}

View File

@@ -26,6 +26,8 @@ public:
bool verify_firmware_version();
bool write_firmware_version_safe();
bool valid_mode(DeviceDriver::Type mode);
DeviceDriver::Type get_current_driver();
bool check_for_driver_change(Gamepad& gamepad);

View File

@@ -1,8 +1,9 @@
#ifndef _BOARD_CONFIG_H_
#define _BOARD_CONFIG_H_
/* OGXM_BOARD and MAX_GAMEPADS are both defined as Cmake configure args,
add args -DOGXM_BOARD=PI_PICO and -DMAX_GAMEPADS=1 (or = whatever option you want).
/* 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
@@ -13,7 +14,7 @@
#define EXTERNAL_4CH 6
#define W_ESP32 7
#define SYSCLOCK_HZ 250000
#define SYSCLOCK_KHZ 240000
#ifndef MAX_GAMEPADS
#define MAX_GAMEPADS 1
@@ -31,7 +32,7 @@
#define LED_INDICATOR_PIN 13
#define VCC_EN_PIN 18
#elif OGXM_BOARD == PI_PICO
#elif OGXM_BOARD == PI_PICO || OGXM_BOARD == PI_PICO2
#define PIO_USB_DP_PIN 0 // DM = 1
#define LED_INDICATOR_PIN 25
@@ -62,6 +63,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 MODE_SEL_PIN 21
#define ESP_PROG_PIN 20 // ESP32 IO0
#define ESP_RST_PIN 8 // ESP32 EN
@@ -73,10 +75,6 @@
#endif // OGXM_BOARD
#if defined(UART0_TX_PIN)
#define UART0_RX_PIN (UART0_TX_PIN + 1)
#endif // defined(UART0_TX_PIN)
#if defined(I2C_SDA_PIN)
#define I2C_BAUDRATE 400 * 1000
#define I2C_SCL_PIN (I2C_SDA_PIN + 1)
@@ -97,19 +95,23 @@
#if defined(CONFIG_EN_USB_HOST)
#define PIO_USB_CONFIG { \
PIO_USB_DP_PIN, \
PIO_USB_TX_DEFAULT, \
PIO_SM_USB_TX_DEFAULT, \
PIO_USB_DMA_TX_DEFAULT, \
PIO_USB_RX_DEFAULT, \
PIO_SM_USB_RX_DEFAULT, \
PIO_SM_USB_EOP_DEFAULT, \
NULL, \
PIO_USB_DEBUG_PIN_NONE, \
PIO_USB_DEBUG_PIN_NONE, \
false, \
PIO_USB_PINOUT_DPDM \
}
PIO_USB_DP_PIN, \
PIO_USB_TX_DEFAULT, \
PIO_SM_USB_TX_DEFAULT, \
PIO_USB_DMA_TX_DEFAULT, \
PIO_USB_RX_DEFAULT, \
PIO_SM_USB_RX_DEFAULT, \
PIO_SM_USB_EOP_DEFAULT, \
NULL, \
PIO_USB_DEBUG_PIN_NONE, \
PIO_USB_DEBUG_PIN_NONE, \
false, \
PIO_USB_PINOUT_DPDM \
}
#endif // PIO_USB_DP_PIN
#if defined(OGXM_DEBUG)
#define DEBUG_UART_PORT __CONCAT(uart,PICO_DEFAULT_UART)
#endif // defined(OGXM_DEBUG)
#endif // _BOARD_CONFIG_H_

View File

@@ -6,8 +6,5 @@
int main()
{
if (set_sys_clock_hz(SYSCLOCK_HZ*1000, true))
{
OGXMini::run_program();
}
OGXMini::run_program();
}

View File

@@ -130,27 +130,24 @@
// Enable host stack with pio-usb if Pico-PIO-USB library is available
#define CFG_TUH_ENABLED 1
#define CFG_TUH_RPI_PIO_USB 1
// #define PICO_DEFAULT_PIO_USB_DP_PIN PIO_USB_DP_PIN
#define TUH_OPT_RHPORT 1
// Size of buffer to hold descriptors and other data used for enumeration
#define CFG_TUH_ENUMERATION_BUFSIZE 512
#define CFG_TUH_HUB 0
#define CFG_TUH_HUB 1
#define CFG_TUH_CDC 0
#if defined(CONFIG_EN_4CH)
#define CFG_TUH_HID 0
#define CFG_TUH_HID 1
#else
#define CFG_TUH_HID MAX_GAMEPADS
#endif
#define CFG_TUH_MSC 0
#define CFG_TUH_VENDOR 0
#define CFG_TUH_XINPUT 4
#define CFG_TUH_XINPUT_WIRED_CHATPAD_EN 0
#define CFG_TUH_XINPUT MAX_GAMEPADS
// max device support (excluding hub device)
#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1) // hub typically has 4 ports

View File

@@ -40,25 +40,4 @@ function(apply_lib_patches EXTERNAL_DIR)
else ()
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")
# 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
# )
# if (TUSB_PATCH_RESULT EQUAL 0)
# message(STATUS "tinyusb patch applied successfully.")
# elseif (TUSB_PATCH_ERROR MATCHES "patch does not apply")
# message(STATUS "tinyusb patch already applied.")
# else ()
# message(FATAL_ERROR "Failed to apply tinyusb patch: ${TUSB_PATCH_ERROR}")
# endif ()
endfunction()

View File

@@ -1,25 +0,0 @@
diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h
index 9681c704b..ad055105e 100644
--- a/src/class/hid/hid_host.h
+++ b/src/class/hid/hid_host.h
@@ -28,6 +28,7 @@
#define _TUSB_HID_HOST_H_
#include "hid.h"
+#include "host/usbh.h"
#ifdef __cplusplus
extern "C" {
diff --git a/src/host/usbh.c b/src/host/usbh.c
index a2994cde7..052f17d1c 100644
--- a/src/host/usbh.c
+++ b/src/host/usbh.c
@@ -176,7 +176,7 @@ static usbh_class_driver_t const usbh_class_drivers[] = {
},
#endif
- #if CFG_TUH_HID
+ #if CFG_TUH_HID_NO
{
.name = DRIVER_NAME("HID"),
.init = hidh_init,

Some files were not shown because too many files have changed in this diff Show More