add blueretro support via i2c
This commit is contained in:
20
.vscode/c_cpp_properties.json
vendored
Normal file
20
.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Pico",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/Firmware/external/pico-sdk/**"
|
||||
],
|
||||
"forcedInclude": [
|
||||
"${workspaceFolder}/Firmware/external/pico-sdk/src/common/pico_base_headers/include/pico.h",
|
||||
"${workspaceFolder}/Firmware/RP2040/build/generated/pico_base/pico/config_autogen.h"
|
||||
],
|
||||
"defines": [],
|
||||
"compileCommands": "${workspaceFolder}/Firmware/RP2040/build/compile_commands.json",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "c++14",
|
||||
"intelliSenseMode": "linux-gcc-arm"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
64
.vscode/settings.json
vendored
Normal file
64
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
|
||||
"cmake.sourceDirectory": "${workspaceFolder}/Firmware/RP2040",
|
||||
"cmake.buildDirectory": "${workspaceFolder}/Firmware/RP2040/build",
|
||||
"cmake.configureArgs": [
|
||||
"-DOGXM_BOARD=EXTERNAL_4CH_I2C",
|
||||
"-DMAX_GAMEPADS=4"
|
||||
],
|
||||
"files.associations": {
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"cctype": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"list": "cpp",
|
||||
"string": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"new": "cpp",
|
||||
"numbers": "cpp",
|
||||
"ostream": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"xmemory": "cpp",
|
||||
"xtr1common": "cpp",
|
||||
"xutility": "cpp"
|
||||
},
|
||||
}
|
||||
Submodule Firmware/ESP32_Blueretro updated: 30f2e837e8...bb98a87da7
76
Firmware/RP2040/.vscode/settings.json
vendored
76
Firmware/RP2040/.vscode/settings.json
vendored
@@ -2,82 +2,12 @@
|
||||
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
|
||||
|
||||
"cmake.configureArgs": [
|
||||
"-DOGXM_BOARD=ADA_FEATHER",
|
||||
"-DOGXM_BOARD=ESP32_BLUERETRO_I2C",
|
||||
// "-DOGXM_RETAIL=TRUE",
|
||||
"-DMAX_GAMEPADS=1"
|
||||
],
|
||||
|
||||
"files.associations": {
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"any": "cpp",
|
||||
"bit": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"bitset": "cpp",
|
||||
"cctype": "cpp",
|
||||
"charconv": "cpp",
|
||||
"chrono": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"codecvt": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp",
|
||||
"csignal": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cuchar": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"forward_list": "cpp",
|
||||
"list": "cpp",
|
||||
"map": "cpp",
|
||||
"set": "cpp",
|
||||
"string": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"regex": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"format": "cpp",
|
||||
"fstream": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"new": "cpp",
|
||||
"numbers": "cpp",
|
||||
"ostream": "cpp",
|
||||
"ranges": "cpp",
|
||||
"semaphore": "cpp",
|
||||
"span": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"thread": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"valarray": "cpp",
|
||||
"variant": "cpp"
|
||||
|
||||
}
|
||||
}
|
||||
@@ -35,19 +35,21 @@ apply_lib_patches(${EXTERNAL_DIR})
|
||||
set(SOURCES_BOARD
|
||||
${SRC}/main.cpp
|
||||
|
||||
${SRC}/OGXMini/OGXMini_Standard.cpp
|
||||
${SRC}/OGXMini/OGXMini_4Channel.cpp
|
||||
${SRC}/OGXMini/OGXMini_PicoW.cpp
|
||||
${SRC}/OGXMini/OGXMini_ESP32.cpp
|
||||
${SRC}/OGXMini/OGXMini.cpp
|
||||
${SRC}/OGXMini/Board/Standard.cpp
|
||||
${SRC}/OGXMini/Board/PicoW.cpp
|
||||
${SRC}/OGXMini/Board/Four_Channel_I2C.cpp
|
||||
${SRC}/OGXMini/Board/ESP32_Bluepad32_I2C.cpp
|
||||
${SRC}/OGXMini/Board/ESP32_Blueretro_I2C.cpp
|
||||
|
||||
${SRC}/TaskQueue/TaskQueue.cpp
|
||||
|
||||
${SRC}/Board/ogxm_log.cpp
|
||||
${SRC}/Board/esp32_api.cpp
|
||||
${SRC}/Board/board_api.cpp
|
||||
${SRC}/Board/board_api_private/board_api_led.cpp
|
||||
${SRC}/Board/board_api_private/board_api_rgb.cpp
|
||||
${SRC}/Board/board_api_private/board_api_bt.cpp
|
||||
${SRC}/Board/board_api_private/board_api_esp32.cpp
|
||||
${SRC}/Board/board_api_private/board_api_usbh.cpp
|
||||
|
||||
${SRC}/UserSettings/UserSettings.cpp
|
||||
@@ -102,48 +104,67 @@ set(FLASH_SIZE_MB 2)
|
||||
set(PICO_BOARD none)
|
||||
|
||||
if (OGXM_BOARD STREQUAL "PI_PICO")
|
||||
add_compile_definitions(CONFIG_OGXM_BOARD_PI_PICO=1)
|
||||
set(EN_USB_HOST TRUE)
|
||||
|
||||
elseif (OGXM_BOARD STREQUAL "PI_PICO2")
|
||||
add_compile_definitions(CONFIG_OGXM_BOARD_PI_PICO2=1)
|
||||
set(EN_USB_HOST TRUE)
|
||||
set(PICO_PLATFORM rp2350)
|
||||
set(FLASH_SIZE_MB 4)
|
||||
|
||||
elseif(OGXM_BOARD STREQUAL "PI_PICOW")
|
||||
add_compile_definitions(CONFIG_OGXM_BOARD_PI_PICOW=1)
|
||||
set(EN_BLUETOOTH TRUE)
|
||||
set(PICO_BOARD pico_w)
|
||||
|
||||
elseif(OGXM_BOARD STREQUAL "PI_PICO2W")
|
||||
add_compile_definitions(CONFIG_OGXM_BOARD_PI_PICO2W=1)
|
||||
set(EN_BLUETOOTH TRUE)
|
||||
set(PICO_BOARD pico2_w)
|
||||
set(PICO_PLATFORM rp2350)
|
||||
set(FLASH_SIZE_MB 4)
|
||||
|
||||
elseif(OGXM_BOARD STREQUAL "ADA_FEATHER")
|
||||
elseif(OGXM_BOARD STREQUAL "ADAFRUIT_FEATHER")
|
||||
add_compile_definitions(CONFIG_OGXM_BOARD_ADAFRUIT_FEATHER=1)
|
||||
set(EN_USB_HOST TRUE)
|
||||
set(EN_RGB TRUE)
|
||||
set(FLASH_SIZE_MB 8)
|
||||
|
||||
elseif(OGXM_BOARD STREQUAL "RP_ZERO")
|
||||
elseif(OGXM_BOARD STREQUAL "RP2040_ZERO")
|
||||
add_compile_definitions(CONFIG_OGXM_BOARD_RP2040_ZERO=1)
|
||||
set(EN_USB_HOST TRUE)
|
||||
set(EN_RGB TRUE)
|
||||
|
||||
elseif(OGXM_BOARD STREQUAL "INTERNAL_4CH")
|
||||
set(EN_USB_HOST TRUE)
|
||||
set(EN_4CH TRUE)
|
||||
# elseif(OGXM_BOARD STREQUAL "INTERNAL_4CH")
|
||||
# set(EN_USB_HOST TRUE)
|
||||
# set(EN_4CH TRUE)
|
||||
|
||||
elseif(OGXM_BOARD STREQUAL "EXTERNAL_4CH")
|
||||
elseif(OGXM_BOARD STREQUAL "EXTERNAL_4CH_I2C")
|
||||
add_compile_definitions(CONFIG_OGXM_BOARD_EXTERNAL_4CH=1)
|
||||
set(EN_USB_HOST TRUE)
|
||||
set(EN_4CH TRUE)
|
||||
set(EN_RGB TRUE)
|
||||
|
||||
elseif(OGXM_BOARD STREQUAL "PICO_ESP32")
|
||||
elseif(OGXM_BOARD STREQUAL "ESP32_BLUEPAD32_I2C")
|
||||
add_compile_definitions(CONFIG_OGXM_BOARD_ESP32_BLUEPAD32_I2C=1)
|
||||
set(EN_ESP32 TRUE)
|
||||
set(EN_UART_BRIDGE TRUE)
|
||||
|
||||
if(OGXM_RETAIL STREQUAL "TRUE")
|
||||
message(STATUS "Retail mode enabled.")
|
||||
add_definitions(-DOGXM_ESP32_RETAIL)
|
||||
add_compile_definitions(OGXM_RETAIL=1)
|
||||
endif()
|
||||
|
||||
elseif(OGXM_BOARD STREQUAL "ESP32_BLUERETRO_I2C")
|
||||
add_compile_definitions(CONFIG_OGXM_BOARD_ESP32_BLUERETRO_I2C=1)
|
||||
set(EN_ESP32 TRUE)
|
||||
set(EN_BLUERETRO_I2C TRUE)
|
||||
set(EN_UART_BRIDGE TRUE)
|
||||
|
||||
if(OGXM_RETAIL STREQUAL "TRUE")
|
||||
message(STATUS "Retail mode enabled.")
|
||||
add_compile_definitions(OGXM_RETAIL=1)
|
||||
endif()
|
||||
|
||||
else()
|
||||
@@ -225,10 +246,10 @@ endif()
|
||||
if(EN_4CH)
|
||||
add_compile_definitions(CONFIG_EN_4CH=1)
|
||||
message(STATUS "4CH enabled.")
|
||||
list(APPEND SOURCES_BOARD
|
||||
${SRC}/I2CDriver/4Channel/I2CMaster.cpp
|
||||
${SRC}/I2CDriver/4Channel/I2CSlave.cpp
|
||||
)
|
||||
# list(APPEND SOURCES_BOARD
|
||||
# ${SRC}/I2CDriver/4Channel/I2CMaster.cpp
|
||||
# ${SRC}/I2CDriver/4Channel/I2CSlave.cpp
|
||||
# )
|
||||
list(APPEND LIBS_BOARD
|
||||
hardware_i2c
|
||||
pico_i2c_slave
|
||||
@@ -238,12 +259,15 @@ endif()
|
||||
if(EN_ESP32)
|
||||
add_compile_definitions(CONFIG_EN_ESP32=1)
|
||||
message(STATUS "ESP32 enabled.")
|
||||
list(APPEND SOURCES_BOARD
|
||||
${SRC}/I2CDriver/ESP32/I2CDriver.cpp
|
||||
)
|
||||
if (EN_BLUERETRO_I2C)
|
||||
# Nothing
|
||||
else()
|
||||
list(APPEND LIBS_BOARD
|
||||
pico_i2c_slave
|
||||
)
|
||||
endif()
|
||||
list(APPEND LIBS_BOARD
|
||||
hardware_i2c
|
||||
pico_i2c_slave
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -14,8 +14,7 @@ namespace BLEServer {
|
||||
|
||||
static constexpr uint16_t PACKET_LEN_MAX = 20;
|
||||
|
||||
namespace Handle
|
||||
{
|
||||
namespace Handle {
|
||||
static constexpr uint16_t FW_VERSION = ATT_CHARACTERISTIC_12345678_1234_1234_1234_123456789020_01_VALUE_HANDLE;
|
||||
static constexpr uint16_t FW_NAME = ATT_CHARACTERISTIC_12345678_1234_1234_1234_123456789021_01_VALUE_HANDLE;
|
||||
|
||||
@@ -28,22 +27,19 @@ namespace Handle
|
||||
static constexpr uint16_t GAMEPAD = ATT_CHARACTERISTIC_12345678_1234_1234_1234_123456789050_01_VALUE_HANDLE;
|
||||
}
|
||||
|
||||
namespace ADV
|
||||
{
|
||||
namespace ADV {
|
||||
// Flags general discoverable, BR/EDR not supported
|
||||
static const uint8_t FLAGS[] = { 0x02, 0x01, 0x06 };
|
||||
static const uint8_t NAME_TYPE = 0x09;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct Data
|
||||
{
|
||||
struct Data {
|
||||
uint8_t flags[sizeof(FLAGS)];
|
||||
uint8_t name_len;
|
||||
uint8_t name_type;
|
||||
uint8_t name[sizeof(FIRMWARE_NAME) - 1];
|
||||
|
||||
Data()
|
||||
{
|
||||
Data() {
|
||||
std::memcpy(flags, FLAGS, sizeof(flags));
|
||||
name_len = sizeof(FIRMWARE_NAME);
|
||||
name_type = NAME_TYPE;
|
||||
@@ -56,8 +52,7 @@ namespace ADV
|
||||
}
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct SetupPacket
|
||||
{
|
||||
struct SetupPacket {
|
||||
DeviceDriverType device_type{DeviceDriverType::NONE};
|
||||
uint8_t max_gamepads{MAX_GAMEPADS};
|
||||
uint8_t player_idx{0};
|
||||
@@ -66,43 +61,35 @@ struct SetupPacket
|
||||
static_assert(sizeof(SetupPacket) == 4, "BLEServer::SetupPacket struct size mismatch");
|
||||
#pragma pack(pop)
|
||||
|
||||
class ProfileReader
|
||||
{
|
||||
class ProfileReader {
|
||||
public:
|
||||
ProfileReader() = default;
|
||||
~ProfileReader() = default;
|
||||
|
||||
void set_setup_packet(const SetupPacket& setup_packet)
|
||||
{
|
||||
void set_setup_packet(const SetupPacket& setup_packet) {
|
||||
setup_packet_ = setup_packet;
|
||||
current_offset_ = 0;
|
||||
}
|
||||
const SetupPacket& get_setup_packet() const
|
||||
{
|
||||
|
||||
const SetupPacket& get_setup_packet() const {
|
||||
return setup_packet_;
|
||||
}
|
||||
uint16_t get_xfer_len()
|
||||
{
|
||||
|
||||
uint16_t get_xfer_len() {
|
||||
return static_cast<uint16_t>(std::min(static_cast<size_t>(PACKET_LEN_MAX), sizeof(UserProfile) - current_offset_));
|
||||
}
|
||||
uint16_t get_profile_data(uint8_t* buffer, uint16_t buffer_len)
|
||||
{
|
||||
|
||||
uint16_t get_profile_data(uint8_t* buffer, uint16_t buffer_len) {
|
||||
size_t copy_len = get_xfer_len();
|
||||
if (!buffer || buffer_len < copy_len)
|
||||
{
|
||||
if (!buffer || buffer_len < copy_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (current_offset_ == 0 && !set_profile())
|
||||
{
|
||||
if (current_offset_ == 0 && !set_profile()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::memcpy(buffer, reinterpret_cast<uint8_t*>(&profile_) + current_offset_, copy_len);
|
||||
|
||||
current_offset_ += copy_len;
|
||||
if (current_offset_ >= sizeof(UserProfile))
|
||||
{
|
||||
if (current_offset_ >= sizeof(UserProfile)) {
|
||||
current_offset_ = 0;
|
||||
}
|
||||
return copy_len;
|
||||
@@ -113,20 +100,14 @@ private:
|
||||
UserProfile profile_;
|
||||
size_t current_offset_ = 0;
|
||||
|
||||
bool set_profile()
|
||||
{
|
||||
if (setup_packet_.profile_id == 0xFF)
|
||||
{
|
||||
if (setup_packet_.player_idx >= UserSettings::MAX_PROFILES)
|
||||
{
|
||||
bool set_profile() {
|
||||
if (setup_packet_.profile_id == 0xFF) {
|
||||
if (setup_packet_.player_idx >= UserSettings::MAX_PROFILES) {
|
||||
return false;
|
||||
}
|
||||
profile_ = UserSettings::get_instance().get_profile_by_index(setup_packet_.player_idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (setup_packet_.profile_id > UserSettings::MAX_PROFILES)
|
||||
{
|
||||
} else {
|
||||
if (setup_packet_.profile_id > UserSettings::MAX_PROFILES) {
|
||||
return false;
|
||||
}
|
||||
profile_ = UserSettings::get_instance().get_profile_by_id(setup_packet_.profile_id);
|
||||
@@ -141,24 +122,22 @@ public:
|
||||
ProfileWriter() = default;
|
||||
~ProfileWriter() = default;
|
||||
|
||||
void set_setup_packet(const SetupPacket& setup_packet)
|
||||
{
|
||||
void set_setup_packet(const SetupPacket& setup_packet) {
|
||||
setup_packet_ = setup_packet;
|
||||
current_offset_ = 0;
|
||||
}
|
||||
const SetupPacket& get_setup_packet() const
|
||||
{
|
||||
|
||||
const SetupPacket& get_setup_packet() const {
|
||||
return setup_packet_;
|
||||
}
|
||||
uint16_t get_xfer_len()
|
||||
{
|
||||
|
||||
uint16_t get_xfer_len() {
|
||||
return static_cast<uint16_t>(std::min(static_cast<size_t>(PACKET_LEN_MAX), sizeof(UserProfile) - current_offset_));
|
||||
}
|
||||
size_t set_profile_data(const uint8_t* buffer, uint16_t buffer_len)
|
||||
{
|
||||
|
||||
size_t set_profile_data(const uint8_t* buffer, uint16_t buffer_len) {
|
||||
size_t copy_len = get_xfer_len();
|
||||
if (!buffer || buffer_len < copy_len)
|
||||
{
|
||||
if (!buffer || buffer_len < copy_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -167,25 +146,21 @@ public:
|
||||
current_offset_ += copy_len;
|
||||
size_t ret = current_offset_;
|
||||
|
||||
if (current_offset_ >= sizeof(UserProfile))
|
||||
{
|
||||
if (current_offset_ >= sizeof(UserProfile)) {
|
||||
current_offset_ = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
bool commit_profile()
|
||||
{
|
||||
|
||||
bool commit_profile() {
|
||||
bool success = false;
|
||||
if (setup_packet_.device_type != DeviceDriverType::NONE)
|
||||
{
|
||||
if (setup_packet_.device_type != DeviceDriverType::NONE) {
|
||||
success = TaskQueue::Core0::queue_delayed_task(TaskQueue::Core0::get_new_task_id(), 1000, false,
|
||||
[driver_type = setup_packet_.device_type, profile = profile_, index = setup_packet_.player_idx]
|
||||
{
|
||||
UserSettings::get_instance().store_profile_and_driver_type(driver_type, index, profile);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
success = TaskQueue::Core0::queue_delayed_task(TaskQueue::Core0::get_new_task_id(), 1000, false,
|
||||
[index = setup_packet_.player_idx, profile = profile_]
|
||||
{
|
||||
@@ -205,24 +180,20 @@ std::array<Gamepad*, MAX_GAMEPADS> gamepads_;
|
||||
ProfileReader profile_reader_;
|
||||
ProfileWriter profile_writer_;
|
||||
|
||||
static int verify_write(const uint16_t buffer_size, const uint16_t expected_size)
|
||||
{
|
||||
if (buffer_size != expected_size)
|
||||
{
|
||||
static int verify_write(const uint16_t buffer_size, const uint16_t expected_size) {
|
||||
if (buffer_size != expected_size) {
|
||||
return ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void disconnect_client_cb(btstack_timer_source_t *ts)
|
||||
{
|
||||
static void disconnect_client_cb(btstack_timer_source_t *ts) {
|
||||
hci_con_handle_t connection_handle = *static_cast<hci_con_handle_t*>(ts->context);
|
||||
hci_send_cmd(&hci_disconnect, connection_handle);
|
||||
delete static_cast<hci_con_handle_t*>(ts->context);
|
||||
}
|
||||
|
||||
static void queue_disconnect(hci_con_handle_t connection_handle, uint32_t dealy_ms)
|
||||
{
|
||||
static void queue_disconnect(hci_con_handle_t connection_handle, uint32_t dealy_ms) {
|
||||
static btstack_timer_source_t disconnect_timer;
|
||||
|
||||
hci_con_handle_t* connection_handle_ptr = new hci_con_handle_t(connection_handle);
|
||||
@@ -238,33 +209,28 @@ static uint16_t att_read_callback( hci_con_handle_t connection_handle,
|
||||
uint16_t att_handle,
|
||||
uint16_t offset,
|
||||
uint8_t *buffer,
|
||||
uint16_t buffer_size)
|
||||
{
|
||||
uint16_t buffer_size) {
|
||||
std::string fw_version;
|
||||
std::string fw_name;
|
||||
Gamepad::PadIn pad_in;
|
||||
|
||||
switch (att_handle)
|
||||
{
|
||||
switch (att_handle) {
|
||||
case Handle::FW_VERSION:
|
||||
fw_version = FIRMWARE_VERSION;
|
||||
if (buffer)
|
||||
{
|
||||
if (buffer) {
|
||||
std::memcpy(buffer, reinterpret_cast<const uint8_t*>(fw_version.c_str()), fw_version.size());
|
||||
}
|
||||
return static_cast<uint16_t>(fw_version.size());
|
||||
|
||||
case Handle::FW_NAME:
|
||||
fw_name = FIRMWARE_NAME;
|
||||
if (buffer)
|
||||
{
|
||||
if (buffer) {
|
||||
std::memcpy(buffer, reinterpret_cast<const uint8_t*>(fw_name.c_str()), fw_name.size());;
|
||||
}
|
||||
return static_cast<uint16_t>(fw_name.size());
|
||||
|
||||
case Handle::GET_SETUP:
|
||||
if (buffer)
|
||||
{
|
||||
if (buffer) {
|
||||
buffer[0] = static_cast<uint8_t>(UserSettings::get_instance().get_current_driver());
|
||||
buffer[1] = MAX_GAMEPADS;
|
||||
buffer[2] = 0;
|
||||
@@ -273,15 +239,13 @@ static uint16_t att_read_callback( hci_con_handle_t connection_handle,
|
||||
return static_cast<uint16_t>(sizeof(SetupPacket));
|
||||
|
||||
case Handle::PROFILE:
|
||||
if (buffer)
|
||||
{
|
||||
if (buffer) {
|
||||
return profile_reader_.get_profile_data(buffer, buffer_size);
|
||||
}
|
||||
return profile_reader_.get_xfer_len();
|
||||
|
||||
case Handle::GAMEPAD:
|
||||
if (buffer)
|
||||
{
|
||||
if (buffer) {
|
||||
pad_in = gamepads_.front()->get_pad_in();
|
||||
std::memcpy(buffer, &pad_in, sizeof(Gamepad::PadIn));
|
||||
}
|
||||
@@ -298,35 +262,29 @@ static int att_write_callback( hci_con_handle_t connection_handle,
|
||||
uint16_t transaction_mode,
|
||||
uint16_t offset,
|
||||
uint8_t *buffer,
|
||||
uint16_t buffer_size)
|
||||
{
|
||||
uint16_t buffer_size) {
|
||||
int ret = 0;
|
||||
|
||||
switch (att_handle)
|
||||
{
|
||||
switch (att_handle) {
|
||||
case Handle::SETUP_READ:
|
||||
if ((ret = verify_write(buffer_size, sizeof(SetupPacket))) != 0)
|
||||
{
|
||||
if ((ret = verify_write(buffer_size, sizeof(SetupPacket))) != 0) {
|
||||
break;
|
||||
}
|
||||
profile_reader_.set_setup_packet(*reinterpret_cast<SetupPacket*>(buffer));
|
||||
break;
|
||||
|
||||
case Handle::SETUP_WRITE:
|
||||
if ((ret = verify_write(buffer_size, sizeof(SetupPacket))) != 0)
|
||||
{
|
||||
if ((ret = verify_write(buffer_size, sizeof(SetupPacket))) != 0) {
|
||||
break;
|
||||
}
|
||||
profile_writer_.set_setup_packet(*reinterpret_cast<SetupPacket*>(buffer));
|
||||
break;
|
||||
|
||||
case Handle::PROFILE:
|
||||
if ((ret = verify_write(buffer_size, profile_writer_.get_xfer_len())) != 0)
|
||||
{
|
||||
if ((ret = verify_write(buffer_size, profile_writer_.get_xfer_len())) != 0) {
|
||||
break;
|
||||
}
|
||||
if (profile_writer_.set_profile_data(buffer, buffer_size) == sizeof(UserProfile))
|
||||
{
|
||||
if (profile_writer_.set_profile_data(buffer, buffer_size) == sizeof(UserProfile)) {
|
||||
queue_disconnect(connection_handle, 500);
|
||||
profile_writer_.commit_profile();
|
||||
}
|
||||
@@ -338,10 +296,8 @@ static int att_write_callback( hci_con_handle_t connection_handle,
|
||||
return ret;
|
||||
}
|
||||
|
||||
void init_server(Gamepad(&gamepads)[MAX_GAMEPADS])
|
||||
{
|
||||
for (uint8_t i = 0; i < MAX_GAMEPADS; i++)
|
||||
{
|
||||
void init_server(Gamepad(&gamepads)[MAX_GAMEPADS]) {
|
||||
for (uint8_t i = 0; i < MAX_GAMEPADS; i++) {
|
||||
gamepads_[i] = &gamepads[i];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
#ifndef BLE_SERVER_H
|
||||
#define BLE_SERVER_H
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "Gamepad/Gamepad.h"
|
||||
|
||||
namespace BLEServer
|
||||
{
|
||||
namespace BLEServer {
|
||||
void init_server(Gamepad(&gamepads)[MAX_GAMEPADS]);
|
||||
}
|
||||
|
||||
#endif // BLE_SERVER_H
|
||||
@@ -23,8 +23,7 @@ namespace bluepad32 {
|
||||
static constexpr uint32_t FEEDBACK_TIME_MS = 250;
|
||||
static constexpr uint32_t LED_CHECK_TIME_MS = 500;
|
||||
|
||||
struct BTDevice
|
||||
{
|
||||
struct BTDevice {
|
||||
bool connected{false};
|
||||
Gamepad* gamepad{nullptr};
|
||||
};
|
||||
@@ -123,78 +122,61 @@ static 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)
|
||||
{
|
||||
static void init_complete_cb(void) {
|
||||
uni_bt_enable_new_connections_unsafe(true);
|
||||
|
||||
uni_bt_del_keys_unsafe();
|
||||
|
||||
// uni_bt_del_keys_unsafe();
|
||||
uni_property_dump_all();
|
||||
}
|
||||
|
||||
static uni_error_t device_discovered_cb(bd_addr_t addr, const char* name, uint16_t cod, uint8_t rssi)
|
||||
{
|
||||
if (!((cod & UNI_BT_COD_MINOR_MASK) & UNI_BT_COD_MINOR_GAMEPAD))
|
||||
{
|
||||
static uni_error_t device_discovered_cb(bd_addr_t addr, const char* name, uint16_t cod, uint8_t rssi) {
|
||||
if (!((cod & UNI_BT_COD_MINOR_MASK) & UNI_BT_COD_MINOR_GAMEPAD)) {
|
||||
return UNI_ERROR_IGNORE_DEVICE;
|
||||
}
|
||||
return UNI_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static void device_connected_cb(uni_hid_device_t* device)
|
||||
{
|
||||
|
||||
static void device_connected_cb(uni_hid_device_t* device) {
|
||||
}
|
||||
|
||||
static void device_disconnected_cb(uni_hid_device_t* device)
|
||||
{
|
||||
static void device_disconnected_cb(uni_hid_device_t* device) {
|
||||
int idx = uni_hid_device_get_idx_for_instance(device);
|
||||
if (idx >= MAX_GAMEPADS || idx < 0)
|
||||
{
|
||||
if (idx >= MAX_GAMEPADS || idx < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
bt_devices_[idx].connected = false;
|
||||
bt_devices_[idx].gamepad->reset_pad_in();
|
||||
|
||||
if (!led_timer_set_ && !any_connected())
|
||||
{
|
||||
if (!led_timer_set_ && !any_connected()) {
|
||||
led_timer_set_ = true;
|
||||
led_timer_.process = check_led_cb;
|
||||
led_timer_.context = nullptr;
|
||||
btstack_run_loop_set_timer(&led_timer_, LED_CHECK_TIME_MS);
|
||||
btstack_run_loop_add_timer(&led_timer_);
|
||||
}
|
||||
if (feedback_timer_set_ && !any_connected())
|
||||
{
|
||||
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)
|
||||
{
|
||||
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_GAMEPADS || idx < 0)
|
||||
{
|
||||
if (idx >= MAX_GAMEPADS || idx < 0) {
|
||||
return UNI_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bt_devices_[idx].connected = true;
|
||||
|
||||
if (led_timer_set_)
|
||||
{
|
||||
if (led_timer_set_) {
|
||||
led_timer_set_ = false;
|
||||
btstack_run_loop_remove_timer(&led_timer_);
|
||||
board_api::set_led(true);
|
||||
}
|
||||
if (!feedback_timer_set_)
|
||||
{
|
||||
if (!feedback_timer_set_) {
|
||||
feedback_timer_set_ = true;
|
||||
feedback_timer_.process = send_feedback_cb;
|
||||
feedback_timer_.context = nullptr;
|
||||
@@ -204,17 +186,14 @@ static uni_error_t device_ready_cb(uni_hid_device_t* device)
|
||||
return UNI_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static void oob_event_cb(uni_platform_oob_event_t event, void* data)
|
||||
{
|
||||
static void oob_event_cb(uni_platform_oob_event_t event, void* data) {
|
||||
return;
|
||||
}
|
||||
|
||||
static void controller_data_cb(uni_hid_device_t* device, uni_controller_t* controller)
|
||||
{
|
||||
static void controller_data_cb(uni_hid_device_t* device, uni_controller_t* controller) {
|
||||
static uni_gamepad_t prev_uni_gp[MAX_GAMEPADS] = {};
|
||||
|
||||
if (controller->klass != UNI_CONTROLLER_CLASS_GAMEPAD)
|
||||
{
|
||||
if (controller->klass != UNI_CONTROLLER_CLASS_GAMEPAD){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
#ifndef _BLUEPAD_32_H_
|
||||
#define _BLUEPAD_32_H_
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
|
||||
#include "Gamepad/Gamepad.h"
|
||||
#include "board_config.h"
|
||||
#include "Board/Config.h"
|
||||
|
||||
/* NOTE: Everything bluepad32/uni needs to be wrapped
|
||||
and kept away from tinyusb due to naming conflicts */
|
||||
|
||||
namespace bluepad32
|
||||
{
|
||||
namespace bluepad32 {
|
||||
void run_task(Gamepad(&gamepads)[MAX_GAMEPADS]);
|
||||
}
|
||||
|
||||
#endif // _BLUEPAD_32_H_
|
||||
129
Firmware/RP2040/src/Board/Config.h
Normal file
129
Firmware/RP2040/src/Board/Config.h
Normal file
@@ -0,0 +1,129 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#define PI_PICO 0
|
||||
#define RP2040_ZERO 1
|
||||
#define ADAFRUIT_FEATHER 2
|
||||
#define PI_PICOW 3
|
||||
#define ESP32_BLUEPAD32_I2C 4
|
||||
#define ESP32_BLUERETRO_I2C 5
|
||||
#define EXTERNAL_4CH_I2C 6
|
||||
#define INTERNAL_4CH_I2C 7
|
||||
#define BOARDS_COUNT 8
|
||||
|
||||
#define SYSCLOCK_KHZ 240000
|
||||
|
||||
#ifndef MAX_GAMEPADS
|
||||
#define MAX_GAMEPADS 1
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_OGXM_BOARD_PI_PICO) || defined(CONFIG_OGXM_BOARD_PI_PICO2)
|
||||
#define OGXM_BOARD PI_PICO
|
||||
#define PIO_USB_DP_PIN 0 // DM = 1
|
||||
#define LED_INDICATOR_PIN 25
|
||||
|
||||
#elif defined(CONFIG_OGXM_BOARD_PI_PICOW) || defined(CONFIG_OGXM_BOARD_PI_PICO2W)
|
||||
#define OGXM_BOARD PI_PICOW
|
||||
|
||||
#elif defined(CONFIG_OGXM_BOARD_RP2040_ZERO)
|
||||
#define OGXM_BOARD RP2040_ZERO
|
||||
#define RGB_PXL_PIN 16
|
||||
#define PIO_USB_DP_PIN 10 // DM = 11
|
||||
#define LED_INDICATOR_PIN 14
|
||||
|
||||
#elif defined(CONFIG_OGXM_BOARD_ADAFRUIT_FEATHER)
|
||||
#define OGXM_BOARD ADAFRUIT_FEATHER
|
||||
#define RGB_PWR_PIN 20
|
||||
#define RGB_PXL_PIN 21
|
||||
|
||||
#define PIO_USB_DP_PIN 16 // DM = 17
|
||||
#define LED_INDICATOR_PIN 13
|
||||
#define VCC_EN_PIN 18
|
||||
|
||||
#elif defined(CONFIG_OGXM_BOARD_INTERNAL_4CH)
|
||||
#define OGXM_BOARD INTERNAL_4CH_I2C
|
||||
#define PIO_USB_DP_PIN 16 // DM = 17
|
||||
#define FOUR_CH_ENABLED 1
|
||||
#define I2C_SDA_PIN 10
|
||||
#define I2C_SCL_PIN 11
|
||||
#define SLAVE_ADDR_PIN_1 20
|
||||
#define SLAVE_ADDR_PIN_2 21
|
||||
|
||||
#elif defined(CONFIG_OGXM_BOARD_EXTERNAL_4CH)
|
||||
#define OGXM_BOARD EXTERNAL_4CH_I2C
|
||||
#define RGB_PXL_PIN 16
|
||||
#define FOUR_CH_ENABLED 1
|
||||
#define PIO_USB_DP_PIN 10 // DM = 11
|
||||
#define I2C_SDA_PIN 6
|
||||
#define I2C_SCL_PIN 7
|
||||
#define SLAVE_ADDR_PIN_1 13
|
||||
#define SLAVE_ADDR_PIN_2 14
|
||||
|
||||
#elif defined(CONFIG_OGXM_BOARD_ESP32_BLUEPAD32_I2C)
|
||||
#define OGXM_BOARD ESP32_BLUEPAD32_I2C
|
||||
#define I2C_SDA_PIN 18
|
||||
#define I2C_SCL_PIN 19
|
||||
#define UART0_TX_PIN 16
|
||||
#define UART0_RX_PIN 17
|
||||
#define MODE_SEL_PIN 21
|
||||
#define ESP_PROG_PIN 20 // ESP32 IO0
|
||||
#define ESP_RST_PIN 8 // ESP32 EN
|
||||
|
||||
#if MAX_GAMEPADS > 1
|
||||
#undef MAX_GAMEPADS
|
||||
#define MAX_GAMEPADS 1
|
||||
#endif
|
||||
|
||||
#elif defined(CONFIG_OGXM_BOARD_ESP32_BLUERETRO_I2C)
|
||||
#define OGXM_BOARD ESP32_BLUERETRO_I2C
|
||||
#define I2C_SDA_PIN 18
|
||||
#define I2C_SCL_PIN 19
|
||||
#define UART0_TX_PIN 16
|
||||
#define UART0_RX_PIN 17
|
||||
#define MODE_SEL_PIN 21
|
||||
#define ESP_PROG_PIN 20 // ESP32 IO0
|
||||
#define ESP_RST_PIN 8 // ESP32 EN
|
||||
|
||||
#if MAX_GAMEPADS > 1
|
||||
#undef MAX_GAMEPADS
|
||||
#define MAX_GAMEPADS 1
|
||||
#endif
|
||||
|
||||
#else
|
||||
#error "Invalid OGXMini board selected"
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_OGXM_DEBUG)
|
||||
//Pins and port are defined in CMakeLists.txt
|
||||
#define DEBUG_UART_PORT __CONCAT(uart,PICO_DEFAULT_UART)
|
||||
#endif // defined(CONFIG_OGXM_DEBUG)
|
||||
|
||||
#if defined(I2C_SDA_PIN)
|
||||
#define I2C_BAUDRATE 400 * 1000
|
||||
#define I2C_PORT ((I2C_SDA_PIN == 2 ) || \
|
||||
(I2C_SDA_PIN == 6 ) || \
|
||||
(I2C_SDA_PIN == 10) || \
|
||||
(I2C_SDA_PIN == 14) || \
|
||||
(I2C_SDA_PIN == 18) || \
|
||||
(I2C_SDA_PIN == 26)) ? i2c1 : i2c0
|
||||
#endif // defined(I2C_SDA_PIN)
|
||||
|
||||
#if defined(PIO_USB_DP_PIN)
|
||||
#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 \
|
||||
}
|
||||
#endif // defined(PIO_USB_DP_PIN)
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include "tusb.h"
|
||||
|
||||
#include "board_config.h"
|
||||
#include "Board/Config.h"
|
||||
#include "Board/board_api.h"
|
||||
#include "Board/ogxm_log.h"
|
||||
#include "Board/board_api_private/board_api_private.h"
|
||||
@@ -15,50 +15,15 @@ namespace board_api {
|
||||
|
||||
mutex_t gpio_mutex_;
|
||||
|
||||
bool esp32::uart_bridge_mode()
|
||||
{
|
||||
bool ret = false;
|
||||
if (board_api_esp32::uart_bridge_mode)
|
||||
{
|
||||
mutex_enter_blocking(&gpio_mutex_);
|
||||
ret = board_api_esp32::uart_bridge_mode();
|
||||
mutex_exit(&gpio_mutex_);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void esp32::enter_programming_mode()
|
||||
{
|
||||
if (board_api_esp32::enter_programming_mode)
|
||||
{
|
||||
mutex_enter_blocking(&gpio_mutex_);
|
||||
board_api_esp32::enter_programming_mode();
|
||||
mutex_exit(&gpio_mutex_);
|
||||
}
|
||||
}
|
||||
|
||||
void esp32::reset()
|
||||
{
|
||||
if (board_api_esp32::reset)
|
||||
{
|
||||
mutex_enter_blocking(&gpio_mutex_);
|
||||
board_api_esp32::reset();
|
||||
mutex_exit(&gpio_mutex_);
|
||||
}
|
||||
}
|
||||
|
||||
bool usb::host_connected()
|
||||
{
|
||||
if (board_api_usbh::host_connected)
|
||||
{
|
||||
bool usb::host_connected() {
|
||||
if (board_api_usbh::host_connected) {
|
||||
return board_api_usbh::host_connected();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//Only call this from core0
|
||||
void usb::disconnect_all()
|
||||
{
|
||||
void usb::disconnect_all() {
|
||||
OGXM_LOG("Disconnecting USB and resetting Core1\n");
|
||||
|
||||
TaskQueue::suspend_delayed_tasks();
|
||||
@@ -69,28 +34,23 @@ void usb::disconnect_all()
|
||||
}
|
||||
|
||||
// If using PicoW, only use this method from the core running btstack and after you've called init_bluetooth
|
||||
void set_led(bool state)
|
||||
{
|
||||
void set_led(bool state) {
|
||||
mutex_enter_blocking(&gpio_mutex_);
|
||||
|
||||
if (board_api_led::set_led)
|
||||
{
|
||||
if (board_api_led::set_led) {
|
||||
board_api_led::set_led(state);
|
||||
}
|
||||
if (board_api_bt::set_led)
|
||||
{
|
||||
if (board_api_bt::set_led) {
|
||||
board_api_bt::set_led(state);
|
||||
}
|
||||
if (board_api_rgb::set_led)
|
||||
{
|
||||
if (board_api_rgb::set_led) {
|
||||
board_api_rgb::set_led(state ? 0x00 : 0xFF, state ? 0xFF : 0x00, 0x00);
|
||||
}
|
||||
|
||||
mutex_exit(&gpio_mutex_);
|
||||
}
|
||||
|
||||
void reboot()
|
||||
{
|
||||
void reboot() {
|
||||
#define AIRCR_REG (*((volatile uint32_t *)(0xE000ED0C)))
|
||||
#define AIRCR_SYSRESETREQ (1 << 2)
|
||||
#define AIRCR_VECTKEY (0x5FA << 16)
|
||||
@@ -101,62 +61,46 @@ void reboot()
|
||||
while(1);
|
||||
}
|
||||
|
||||
uint32_t ms_since_boot()
|
||||
{
|
||||
uint32_t ms_since_boot() {
|
||||
return to_ms_since_boot(get_absolute_time());
|
||||
}
|
||||
|
||||
//Call after board is initialized
|
||||
void init_bluetooth()
|
||||
{
|
||||
if (board_api_bt::init)
|
||||
{
|
||||
void init_bluetooth() {
|
||||
if (board_api_bt::init) {
|
||||
board_api_bt::init();
|
||||
}
|
||||
}
|
||||
|
||||
//Call on core0 before any other method
|
||||
void init_board()
|
||||
{
|
||||
if (!set_sys_clock_khz(SYSCLOCK_KHZ, true))
|
||||
{
|
||||
if (!set_sys_clock_khz((SYSCLOCK_KHZ / 2), true))
|
||||
{
|
||||
void init_board() {
|
||||
if (!set_sys_clock_khz(SYSCLOCK_KHZ, true)) {
|
||||
if (!set_sys_clock_khz((SYSCLOCK_KHZ / 2), true)) {
|
||||
panic("Failed to set sys clock");
|
||||
}
|
||||
}
|
||||
|
||||
stdio_init_all();
|
||||
|
||||
if (!mutex_is_initialized(&gpio_mutex_))
|
||||
{
|
||||
if (!mutex_is_initialized(&gpio_mutex_)) {
|
||||
mutex_init(&gpio_mutex_);
|
||||
mutex_enter_blocking(&gpio_mutex_);
|
||||
|
||||
if (ogxm_log::init)
|
||||
{
|
||||
if (ogxm_log::init) {
|
||||
ogxm_log::init();
|
||||
}
|
||||
if (board_api_led::init)
|
||||
{
|
||||
if (board_api_led::init) {
|
||||
board_api_led::init();
|
||||
}
|
||||
if (board_api_rgb::init)
|
||||
{
|
||||
if (board_api_rgb::init) {
|
||||
board_api_rgb::init();
|
||||
}
|
||||
if (board_api_esp32::init)
|
||||
{
|
||||
board_api_esp32::init();
|
||||
}
|
||||
if (board_api_usbh::init)
|
||||
{
|
||||
if (board_api_usbh::init) {
|
||||
board_api_usbh::init();
|
||||
}
|
||||
|
||||
mutex_exit(&gpio_mutex_);
|
||||
}
|
||||
|
||||
OGXM_LOG("Board initialized\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -4,26 +4,17 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace board_api
|
||||
{
|
||||
namespace board_api {
|
||||
void init_board();
|
||||
void init_bluetooth();
|
||||
void reboot();
|
||||
void set_led(bool state);
|
||||
uint32_t ms_since_boot();
|
||||
|
||||
namespace usb
|
||||
{
|
||||
namespace usb {
|
||||
bool host_connected();
|
||||
void disconnect_all();
|
||||
}
|
||||
|
||||
namespace esp32
|
||||
{
|
||||
bool uart_bridge_mode();
|
||||
void reset();
|
||||
void enter_programming_mode();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // _OGXM_BOARD_API_H_
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "board_config.h"
|
||||
#include "Board/Config.h"
|
||||
#if defined(CONFIG_EN_BLUETOOTH)
|
||||
|
||||
#include <atomic>
|
||||
@@ -14,22 +14,16 @@ namespace board_api_bt {
|
||||
|
||||
std::atomic<bool> inited{false};
|
||||
|
||||
void init()
|
||||
{
|
||||
if (cyw43_arch_init() != 0)
|
||||
{
|
||||
void init() {
|
||||
if (cyw43_arch_init() != 0) {
|
||||
panic("CYW43 init failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
inited.store(true);
|
||||
}
|
||||
}
|
||||
|
||||
void set_led(bool state)
|
||||
{
|
||||
if (!inited.load())
|
||||
{
|
||||
void set_led(bool state) {
|
||||
if (!inited.load()) {
|
||||
return;
|
||||
}
|
||||
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, state ? 1 : 0);
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
#include "board_config.h"
|
||||
#include "Board/Config.h"
|
||||
#if defined(LED_INDICATOR_PIN)
|
||||
|
||||
#include <hardware/gpio.h>
|
||||
|
||||
namespace board_api_led {
|
||||
|
||||
void init()
|
||||
{
|
||||
void init() {
|
||||
gpio_init(LED_INDICATOR_PIN);
|
||||
gpio_set_dir(LED_INDICATOR_PIN, GPIO_OUT);
|
||||
gpio_put(LED_INDICATOR_PIN, 0);
|
||||
}
|
||||
|
||||
void set_led(bool state)
|
||||
{
|
||||
void set_led(bool state) {
|
||||
gpio_put(LED_INDICATOR_PIN, state ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,34 +6,22 @@
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
namespace board_api_bt
|
||||
{
|
||||
namespace board_api_bt {
|
||||
void init() __attribute__((weak));
|
||||
void set_led(bool state) __attribute__((weak));
|
||||
}
|
||||
|
||||
namespace board_api_led
|
||||
{
|
||||
namespace board_api_led {
|
||||
void init() __attribute__((weak));
|
||||
void set_led(bool state) __attribute__((weak));
|
||||
}
|
||||
|
||||
namespace board_api_rgb
|
||||
{
|
||||
namespace board_api_rgb {
|
||||
void init() __attribute__((weak));
|
||||
void set_led(uint8_t r, uint8_t g, uint8_t b) __attribute__((weak));
|
||||
}
|
||||
|
||||
namespace board_api_esp32
|
||||
{
|
||||
void init() __attribute__((weak));
|
||||
bool uart_bridge_mode() __attribute__((weak));
|
||||
void reset() __attribute__((weak));
|
||||
void enter_programming_mode() __attribute__((weak));
|
||||
}
|
||||
|
||||
namespace board_api_usbh
|
||||
{
|
||||
namespace board_api_usbh {
|
||||
void init() __attribute__((weak));
|
||||
bool host_connected() __attribute__((weak));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "board_config.h"
|
||||
#include "Board/Config.h"
|
||||
#if defined(CONFIG_EN_RGB)
|
||||
|
||||
#include <hardware/gpio.h>
|
||||
@@ -8,14 +8,12 @@
|
||||
|
||||
namespace board_api_rgb {
|
||||
|
||||
WS2812& get_ws2812()
|
||||
{
|
||||
WS2812& get_ws2812() {
|
||||
static WS2812 ws2812 = WS2812(RGB_PXL_PIN, 1, pio1, 0, WS2812::FORMAT_GRB);
|
||||
return ws2812;
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
void init() {
|
||||
#if defined(RGB_PWR_PIN)
|
||||
gpio_init(RGB_PWR_PIN);
|
||||
gpio_set_dir(RGB_PWR_PIN, GPIO_OUT);
|
||||
@@ -25,8 +23,7 @@ void init()
|
||||
set_led(0xFF, 0, 0);
|
||||
}
|
||||
|
||||
void set_led(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
void set_led(uint8_t r, uint8_t g, uint8_t b) {
|
||||
get_ws2812().setPixelColor(0, WS2812::RGB(r, g, b));
|
||||
get_ws2812().show();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "board_config.h"
|
||||
#include "Board/Config.h"
|
||||
#if defined(CONFIG_EN_USB_HOST)
|
||||
|
||||
#include <atomic>
|
||||
@@ -10,22 +10,17 @@ namespace board_api_usbh {
|
||||
|
||||
std::atomic<bool> host_connected_ = false;
|
||||
|
||||
void host_pin_isr(uint gpio, uint32_t events)
|
||||
{
|
||||
void host_pin_isr(uint gpio, uint32_t events) {
|
||||
gpio_set_irq_enabled(PIO_USB_DP_PIN, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false);
|
||||
gpio_set_irq_enabled(PIO_USB_DP_PIN + 1, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false);
|
||||
|
||||
if (gpio == PIO_USB_DP_PIN || gpio == PIO_USB_DP_PIN + 1)
|
||||
{
|
||||
if (gpio == PIO_USB_DP_PIN || gpio == PIO_USB_DP_PIN + 1) {
|
||||
uint32_t dp_state = gpio_get(PIO_USB_DP_PIN);
|
||||
uint32_t dm_state = gpio_get(PIO_USB_DP_PIN + 1);
|
||||
|
||||
if (dp_state || dm_state)
|
||||
{
|
||||
if (dp_state || dm_state) {
|
||||
host_connected_.store(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
host_connected_.store(false);
|
||||
gpio_set_irq_enabled(PIO_USB_DP_PIN, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true);
|
||||
gpio_set_irq_enabled(PIO_USB_DP_PIN + 1, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true);
|
||||
@@ -33,13 +28,11 @@ void host_pin_isr(uint gpio, uint32_t events)
|
||||
}
|
||||
}
|
||||
|
||||
bool host_connected()
|
||||
{
|
||||
bool host_connected() {
|
||||
return host_connected_.load();
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
void init() {
|
||||
#if defined(VCC_EN_PIN)
|
||||
gpio_init(VCC_EN_PIN);
|
||||
gpio_set_dir(VCC_EN_PIN, GPIO_OUT);
|
||||
@@ -54,12 +47,9 @@ void init()
|
||||
gpio_set_dir(PIO_USB_DP_PIN + 1, GPIO_IN);
|
||||
gpio_pull_down(PIO_USB_DP_PIN + 1);
|
||||
|
||||
if (gpio_get(PIO_USB_DP_PIN) || gpio_get(PIO_USB_DP_PIN + 1))
|
||||
{
|
||||
if (gpio_get(PIO_USB_DP_PIN) || gpio_get(PIO_USB_DP_PIN + 1)) {
|
||||
host_connected_.store(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
gpio_set_irq_enabled_with_callback(PIO_USB_DP_PIN, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &host_pin_isr);
|
||||
gpio_set_irq_enabled_with_callback(PIO_USB_DP_PIN + 1, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &host_pin_isr);
|
||||
}
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
#include "board_config.h"
|
||||
#include "Board/Config.h"
|
||||
#if defined(CONFIG_EN_ESP32)
|
||||
|
||||
#include <pico/stdlib.h>
|
||||
#include <hardware/gpio.h>
|
||||
|
||||
#include "Board/board_api_private/board_api_private.h"
|
||||
#include "Board/esp32_api.h"
|
||||
|
||||
namespace board_api_esp32 {
|
||||
|
||||
bool uart_bridge_mode()
|
||||
bool esp32_api::uart_bridge_mode()
|
||||
{
|
||||
gpio_pull_up(MODE_SEL_PIN);
|
||||
return (gpio_get(MODE_SEL_PIN) == 0);
|
||||
}
|
||||
|
||||
void reset()
|
||||
void esp32_api::reset()
|
||||
{
|
||||
gpio_put(ESP_RST_PIN, 0);
|
||||
sleep_ms(500);
|
||||
@@ -22,7 +20,7 @@ void reset()
|
||||
sleep_ms(250);
|
||||
}
|
||||
|
||||
void enter_programming_mode()
|
||||
void esp32_api::enter_programming_mode()
|
||||
{
|
||||
gpio_put(ESP_PROG_PIN, 1);
|
||||
sleep_ms(250);
|
||||
@@ -34,7 +32,7 @@ void enter_programming_mode()
|
||||
gpio_put(ESP_PROG_PIN, 1);
|
||||
}
|
||||
|
||||
void init()
|
||||
void esp32_api::init()
|
||||
{
|
||||
gpio_init(ESP_PROG_PIN);
|
||||
gpio_set_dir(ESP_PROG_PIN, GPIO_OUT);
|
||||
@@ -49,6 +47,4 @@ void init()
|
||||
gpio_pull_up(MODE_SEL_PIN);
|
||||
}
|
||||
|
||||
} // namespace board_api_esp32
|
||||
|
||||
#endif // defined(CONFIG_EN_ESP32)
|
||||
13
Firmware/RP2040/src/Board/esp32_api.h
Normal file
13
Firmware/RP2040/src/Board/esp32_api.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "Board/Config.h"
|
||||
#if defined(CONFIG_EN_ESP32)
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace esp32_api {
|
||||
bool uart_bridge_mode();
|
||||
void reset();
|
||||
void enter_programming_mode();
|
||||
void init();
|
||||
} // namespace board_api_esp32
|
||||
|
||||
#endif // defined(CONFIG_EN_ESP32)
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "board_config.h"
|
||||
#if defined(OGXM_DEBUG)
|
||||
#include "Board/Config.h"
|
||||
#if defined(CONFIG_OGXM_DEBUG)
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
@@ -13,10 +13,8 @@
|
||||
#include "USBDevice/DeviceDriver/DeviceDriverTypes.h"
|
||||
#include "Board/ogxm_log.h"
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, DeviceDriverType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
std::ostream& operator<<(std::ostream& os, DeviceDriverType type) {
|
||||
switch (type) {
|
||||
case DeviceDriverType::NONE: os << "NONE"; break;
|
||||
case DeviceDriverType::XBOXOG: os << "XBOXOG"; break;
|
||||
case DeviceDriverType::XBOXOG_SB: os << "XBOXOG_SB"; break;
|
||||
@@ -35,19 +33,16 @@ std::ostream& operator<<(std::ostream& os, DeviceDriverType type)
|
||||
|
||||
namespace ogxm_log {
|
||||
|
||||
void init()
|
||||
{
|
||||
void init() {
|
||||
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);
|
||||
}
|
||||
|
||||
void log(const std::string& message)
|
||||
{
|
||||
void log(const std::string& message) {
|
||||
static mutex_t log_mutex;
|
||||
|
||||
if (!mutex_is_initialized(&log_mutex))
|
||||
{
|
||||
if (!mutex_is_initialized(&log_mutex)) {
|
||||
mutex_init(&log_mutex);
|
||||
}
|
||||
|
||||
@@ -60,8 +55,7 @@ void log(const std::string& message)
|
||||
mutex_exit(&log_mutex);
|
||||
}
|
||||
|
||||
void log(const char* fmt, ...)
|
||||
{
|
||||
void log(const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
@@ -75,16 +69,13 @@ void log(const char* fmt, ...)
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void log_hex(const uint8_t* data, size_t size)
|
||||
{
|
||||
void log_hex(const uint8_t* data, size_t size) {
|
||||
std::ostringstream hex_stream;
|
||||
hex_stream << std::hex << std::setfill('0');
|
||||
int count = 0;
|
||||
for (uint16_t i = 0; i < size; ++i)
|
||||
{
|
||||
for (uint16_t i = 0; i < size; ++i) {
|
||||
hex_stream << std::setw(2) << static_cast<int>(data[i]) << " ";
|
||||
if (++count == 16)
|
||||
{
|
||||
if (++count == 16) {
|
||||
hex_stream << "\n";
|
||||
count = 0;
|
||||
}
|
||||
@@ -95,4 +86,4 @@ void log_hex(const uint8_t* data, size_t size)
|
||||
|
||||
} // namespace ogxm_log
|
||||
|
||||
#endif // defined(OGXM_DEBUG)
|
||||
#endif // defined(CONFIG_OGXM_DEBUG)
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "board_config.h"
|
||||
#if defined(OGXM_DEBUG)
|
||||
#include "Board/Config.h"
|
||||
#if defined(CONFIG_OGXM_DEBUG)
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
@@ -15,22 +15,17 @@
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, DeviceDriverType type);
|
||||
|
||||
namespace ogxm_log
|
||||
{
|
||||
namespace ogxm_log {
|
||||
void init() __attribute__((weak));
|
||||
|
||||
//Don't use this directly, use the OGXM_LOG macro
|
||||
void log(const std::string& message);
|
||||
|
||||
//Don't use this directly, use the OGXM_LOG macro
|
||||
void log(const char* fmt, ...);
|
||||
|
||||
//Don't use this directly, use the OGXM_LOG_HEX macro
|
||||
void log_hex(const uint8_t* data, size_t size);
|
||||
|
||||
template <typename T>
|
||||
std::string to_string(const T& value)
|
||||
{
|
||||
std::string to_string(const T& value) {
|
||||
std::ostringstream stream;
|
||||
stream << value;
|
||||
return stream.str();
|
||||
@@ -43,10 +38,9 @@ namespace ogxm_log
|
||||
#define OGXM_ASSERT_MSG(x, msg) if (!(x)) { OGXM_LOG("Assertion failed: " #x " " msg); while(1); }
|
||||
#define OGXM_TO_STRING ogxm_log::to_string
|
||||
|
||||
#else // OGXM_DEBUG
|
||||
#else // CONFIG_OGXM_DEBUG
|
||||
|
||||
namespace ogxm_log
|
||||
{
|
||||
namespace ogxm_log {
|
||||
void init() __attribute__((weak));
|
||||
}
|
||||
|
||||
@@ -56,6 +50,6 @@ namespace ogxm_log
|
||||
#define OGXM_ASSERT_MSG(x, msg)
|
||||
#define OGXM_TO_STRING(x)
|
||||
|
||||
#endif // OGXM_DEBUG
|
||||
#endif // CONFIG_OGXM_DEBUG
|
||||
|
||||
#endif // BOARD_API_LOG_H
|
||||
@@ -1,12 +1,11 @@
|
||||
#ifndef _DINPUT_DESCRIPTORS_H_
|
||||
#define _DINPUT_DESCRIPTORS_H_
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#include "tusb.h"
|
||||
|
||||
#include "board_config.h"
|
||||
#include "Board/Config.h"
|
||||
|
||||
namespace DInput
|
||||
{
|
||||
@@ -228,8 +227,7 @@ namespace DInput
|
||||
// 0x0A, // bInterval 10 (unit depends on device speed)
|
||||
// };
|
||||
|
||||
enum Itf
|
||||
{
|
||||
enum Itf {
|
||||
NUM_HID1 = 0,
|
||||
#if MAX_GAMEPADS > 1
|
||||
NUM_HID2,
|
||||
@@ -298,5 +296,3 @@ namespace DInput
|
||||
};
|
||||
|
||||
}; // namespace DInput
|
||||
|
||||
#endif // _DINPUT_DESCRIPTORS_H_
|
||||
@@ -96,16 +96,15 @@ public:
|
||||
#pragma pack(push, 1)
|
||||
struct PadIn
|
||||
{
|
||||
uint8_t dpad;
|
||||
uint8_t dpad;
|
||||
uint16_t buttons;
|
||||
uint8_t trigger_l;
|
||||
uint8_t trigger_r;
|
||||
int16_t joystick_lx;
|
||||
int16_t joystick_ly;
|
||||
int16_t joystick_rx;
|
||||
int16_t joystick_ry;
|
||||
// uint8_t chatpad[3];
|
||||
uint8_t analog[10];
|
||||
uint8_t trigger_l;
|
||||
uint8_t trigger_r;
|
||||
int16_t joystick_lx;
|
||||
int16_t joystick_ly;
|
||||
int16_t joystick_rx;
|
||||
int16_t joystick_ry;
|
||||
uint8_t analog[10];
|
||||
|
||||
PadIn()
|
||||
{
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
#ifndef I2C_DRIVER_4CH_H
|
||||
#define I2C_DRIVER_4CH_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
|
||||
#include "board_config.h"
|
||||
#include "Gamepad.h"
|
||||
#include "USBHost/HostDriver/HostDriverTypes.h"
|
||||
|
||||
//Run on core0
|
||||
class I2CDriver
|
||||
{
|
||||
public:
|
||||
virtual ~I2CDriver() {};
|
||||
virtual void initialize(uint8_t address) = 0;
|
||||
virtual void process(Gamepad (&gamepads)[MAX_GAMEPADS]) = 0;
|
||||
virtual void notify_tuh(bool mounted, HostDriverType host_type = HostDriverType::UNKNOWN) = 0;
|
||||
virtual void notify_xbox360w(bool connected, uint8_t idx) {};
|
||||
|
||||
protected:
|
||||
enum class PacketID : uint8_t { UNKNOWN = 0, PAD, COMMAND };
|
||||
enum class Command : uint8_t { UNKNOWN = 0, STATUS, DISABLE };
|
||||
enum class Status : uint8_t { UNKNOWN = 0, NC, ERROR, OK, READY, NOT_READY };
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct PacketIn
|
||||
{
|
||||
uint8_t packet_len{sizeof(PacketIn)};
|
||||
PacketID packet_id{PacketID::PAD};
|
||||
Gamepad::PadIn pad_in{Gamepad::PadIn()};
|
||||
Gamepad::ChatpadIn chatpad_in{0};
|
||||
std::array<uint8_t, 4> reserved{0};
|
||||
};
|
||||
static_assert(sizeof(PacketIn) == 32, "I2CDriver::PacketIn is misaligned");
|
||||
static_assert((sizeof(PacketIn) % 8) == 0, "I2CDriver::PacketIn is not a multiple of 8");
|
||||
|
||||
struct PacketOut
|
||||
{
|
||||
uint8_t packet_len{sizeof(PacketOut)};
|
||||
PacketID packet_id{PacketID::PAD};
|
||||
Gamepad::PadOut pad_out{Gamepad::PadOut()};
|
||||
std::array<uint8_t, 4> reserved{0};
|
||||
};
|
||||
static_assert(sizeof(PacketOut) == 8, "I2CDriver::PacketOut is misaligned");
|
||||
|
||||
struct PacketCMD
|
||||
{
|
||||
uint8_t packet_len{sizeof(PacketCMD)};
|
||||
PacketID packet_id{PacketID::COMMAND};
|
||||
Command command{Command::UNKNOWN};
|
||||
Status status{Status::UNKNOWN};
|
||||
std::array<uint8_t, 4> reserved{0};
|
||||
};
|
||||
static_assert(sizeof(PacketCMD) == 8, "I2CDriver::PacketCMD is misaligned");
|
||||
#pragma pack(pop)
|
||||
|
||||
static constexpr size_t MAX_PACKET_SIZE = sizeof(PacketIn);
|
||||
};
|
||||
|
||||
#endif // I2C_DRIVER_4CH_H
|
||||
@@ -1,92 +0,0 @@
|
||||
#ifndef I2C_4CH_MANAGER_H
|
||||
#define I2C_4CH_MANAGER_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <hardware/gpio.h>
|
||||
|
||||
#include "board_config.h"
|
||||
#include "Gamepad/Gamepad.h"
|
||||
#include "I2CDriver/4Channel/I2CMaster.h"
|
||||
#include "I2CDriver/4Channel/I2CSlave.h"
|
||||
#include "I2CDriver/4Channel/I2CDriver.h"
|
||||
|
||||
class I2CManager
|
||||
{
|
||||
public:
|
||||
I2CManager(const I2CManager&) = delete;
|
||||
I2CManager& operator=(const I2CManager&) = delete;
|
||||
|
||||
static I2CManager& get_instance()
|
||||
{
|
||||
static I2CManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
bool initialize_driver()
|
||||
{
|
||||
uint8_t i2c_address = get_i2c_address();
|
||||
if (i2c_address == 0xFF)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (i2c_address < 1)
|
||||
{
|
||||
is_master_.store(true);
|
||||
driver_ = std::make_unique<I2CMaster>();
|
||||
}
|
||||
else
|
||||
{
|
||||
driver_ = std::make_unique<I2CSlave>();
|
||||
}
|
||||
driver_->initialize(i2c_address);
|
||||
return true;
|
||||
}
|
||||
|
||||
I2CDriver* get_driver()
|
||||
{
|
||||
return driver_.get();
|
||||
}
|
||||
|
||||
bool is_master()
|
||||
{
|
||||
return is_master_.load();
|
||||
}
|
||||
|
||||
private:
|
||||
I2CManager() {};
|
||||
~I2CManager() {};
|
||||
|
||||
std::unique_ptr<I2CDriver> driver_{nullptr};
|
||||
std::atomic<bool> is_master_{false};
|
||||
|
||||
uint8_t get_i2c_address()
|
||||
{
|
||||
gpio_init(SLAVE_ADDR_PIN_1);
|
||||
gpio_init(SLAVE_ADDR_PIN_2);
|
||||
gpio_pull_up(SLAVE_ADDR_PIN_1);
|
||||
gpio_pull_up(SLAVE_ADDR_PIN_2);
|
||||
|
||||
if (gpio_get(SLAVE_ADDR_PIN_1) == 1 && gpio_get(SLAVE_ADDR_PIN_2) == 1)
|
||||
{
|
||||
return 0x00;
|
||||
}
|
||||
else if (gpio_get(SLAVE_ADDR_PIN_1) == 1 && gpio_get(SLAVE_ADDR_PIN_2) == 0)
|
||||
{
|
||||
return 0x01;
|
||||
}
|
||||
else if (gpio_get(SLAVE_ADDR_PIN_1) == 0 && gpio_get(SLAVE_ADDR_PIN_2) == 1)
|
||||
{
|
||||
return 0x02;
|
||||
}
|
||||
else if (gpio_get(SLAVE_ADDR_PIN_1) == 0 && gpio_get(SLAVE_ADDR_PIN_2) == 0)
|
||||
{
|
||||
return 0x03;
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // I2C_4CH_MANAGER_H
|
||||
@@ -1,146 +0,0 @@
|
||||
#include <cstring>
|
||||
#include <hardware/gpio.h>
|
||||
|
||||
#include "TaskQueue/TaskQueue.h"
|
||||
#include "I2CDriver/4Channel/I2CMaster.h"
|
||||
|
||||
void I2CMaster::initialize(uint8_t address)
|
||||
{
|
||||
i2c_init(I2C_PORT, I2C_BAUDRATE);
|
||||
|
||||
gpio_init(I2C_SDA_PIN);
|
||||
gpio_set_function(I2C_SDA_PIN, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(I2C_SDA_PIN);
|
||||
|
||||
gpio_init(I2C_SCL_PIN);
|
||||
gpio_set_function(I2C_SCL_PIN, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(I2C_SCL_PIN);
|
||||
|
||||
for (uint8_t i = 0; i < NUM_SLAVES; ++i)
|
||||
{
|
||||
slaves_[i].address = address + i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void I2CMaster::process(Gamepad (&gamepads)[MAX_GAMEPADS])
|
||||
{
|
||||
for (uint8_t i = 0; i < NUM_SLAVES; ++i)
|
||||
{
|
||||
Slave& slave = slaves_[i];
|
||||
|
||||
if (!slave.enabled.load() || !slave_detected(slave.address))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
PacketCMD packet_cmd;
|
||||
packet_cmd.packet_id = PacketID::COMMAND;
|
||||
packet_cmd.command = Command::STATUS;
|
||||
|
||||
if (!write_blocking(slave.address, &packet_cmd, sizeof(PacketCMD)) ||
|
||||
!read_blocking(slave.address, &packet_cmd, sizeof(PacketCMD)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (packet_cmd.status == Status::READY)
|
||||
{
|
||||
Gamepad& gamepad = gamepads[i + 1];
|
||||
PacketIn packet_in;
|
||||
packet_in.pad_in = gamepad.get_pad_in();
|
||||
packet_in.chatpad_in = gamepad.get_chatpad_in();
|
||||
|
||||
if (write_blocking(slave.address, &packet_in, sizeof(PacketIn)))
|
||||
{
|
||||
PacketOut packet_out;
|
||||
if (read_blocking(slave.address, &packet_out, sizeof(PacketOut)))
|
||||
{
|
||||
gamepad.set_pad_out(packet_out.pad_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sleep_us(100);
|
||||
}
|
||||
}
|
||||
|
||||
void I2CMaster::notify_tuh(bool mounted, HostDriverType host_type)
|
||||
{
|
||||
if (host_type != HostDriverType::XBOX360W)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
i2c_enabled_.store(mounted);
|
||||
|
||||
if (!mounted)
|
||||
{
|
||||
//Called from core1 so queue on core0
|
||||
TaskQueue::Core0::queue_task(
|
||||
[this]()
|
||||
{
|
||||
for (auto& slave : slaves_)
|
||||
{
|
||||
notify_disable(slave.address);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void I2CMaster::notify_xbox360w(bool connected, uint8_t idx)
|
||||
{
|
||||
if (idx < 1 || idx >= MAX_GAMEPADS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
slaves_[idx - 1].enabled.store(connected);
|
||||
|
||||
if (!connected)
|
||||
{
|
||||
//Called from core1 so queue on core0
|
||||
TaskQueue::Core0::queue_task(
|
||||
[this]()
|
||||
{
|
||||
for (auto& slave : slaves_)
|
||||
{
|
||||
notify_disable(slave.address);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool I2CMaster::slave_detected(uint8_t address)
|
||||
{
|
||||
uint8_t dummy_data = 0;
|
||||
int result = i2c_write_timeout_us(I2C_PORT, address, &dummy_data, 0, false, 1000);
|
||||
return (result >= 0);
|
||||
}
|
||||
|
||||
void I2CMaster::notify_disable(uint8_t address)
|
||||
{
|
||||
if (!slave_detected(address))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int retries = 10;
|
||||
|
||||
while (retries--)
|
||||
{
|
||||
PacketCMD packet_cmd;
|
||||
packet_cmd.packet_id = PacketID::COMMAND;
|
||||
packet_cmd.command = Command::DISABLE;
|
||||
if (write_blocking(address, &packet_cmd, sizeof(PacketCMD)))
|
||||
{
|
||||
if (read_blocking(address, &packet_cmd, sizeof(PacketCMD)))
|
||||
{
|
||||
if (packet_cmd.status == Status::OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
sleep_ms(1);
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
#ifndef I2C_MASTER_4CH_H
|
||||
#define I2C_MASTER_4CH_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <atomic>
|
||||
#include <array>
|
||||
#include <hardware/i2c.h>
|
||||
|
||||
#include "board_config.h"
|
||||
#include "Gamepad/Gamepad.h"
|
||||
#include "I2CDriver/4Channel/I2CDriver.h"
|
||||
|
||||
class I2CMaster : public I2CDriver
|
||||
{
|
||||
public:
|
||||
~I2CMaster() = default;
|
||||
void initialize(uint8_t address) override;
|
||||
void process(Gamepad (&gamepads)[MAX_GAMEPADS]) override;
|
||||
void notify_tuh(bool mounted, HostDriverType host_type) override;
|
||||
void notify_xbox360w(bool connected, uint8_t idx) override;
|
||||
|
||||
private:
|
||||
struct Slave
|
||||
{
|
||||
uint8_t address{0xFF};
|
||||
Status status{Status::NC};
|
||||
std::atomic<bool> enabled{false};
|
||||
};
|
||||
|
||||
static constexpr size_t NUM_SLAVES = MAX_GAMEPADS - 1;
|
||||
static_assert(NUM_SLAVES > 0, "I2CMaster::NUM_SLAVES must be greater than 0 to use I2C");
|
||||
|
||||
std::atomic<bool> i2c_enabled_{false};
|
||||
std::array<Slave, NUM_SLAVES> slaves_;
|
||||
|
||||
void notify_disable(uint8_t address);
|
||||
|
||||
static bool slave_detected(uint8_t address);
|
||||
|
||||
static inline bool read_blocking(uint8_t address, void* buffer, size_t len)
|
||||
{
|
||||
return (i2c_read_blocking(I2C_PORT, address, reinterpret_cast<uint8_t*>(buffer), len, false) == static_cast<int>(len));
|
||||
}
|
||||
static inline bool write_blocking(uint8_t address, void* buffer, size_t len)
|
||||
{
|
||||
return (i2c_write_blocking(I2C_PORT, address, reinterpret_cast<uint8_t*>(buffer), len, false) == static_cast<int>(len));
|
||||
}
|
||||
};
|
||||
|
||||
#endif // I2C_MASTER_4CH_H
|
||||
@@ -1,152 +0,0 @@
|
||||
#include <cstring>
|
||||
#include <array>
|
||||
#include <hardware/gpio.h>
|
||||
|
||||
#include "OGXMini/OGXMini.h"
|
||||
#include "I2CDriver/4Channel/I2CSlave.h"
|
||||
#include "TaskQueue/TaskQueue.h"
|
||||
|
||||
I2CSlave* I2CSlave::instance_ = nullptr;
|
||||
|
||||
void I2CSlave::initialize(uint8_t address)
|
||||
{
|
||||
instance_ = this;
|
||||
|
||||
i2c_init(I2C_PORT, I2C_BAUDRATE);
|
||||
|
||||
gpio_init(I2C_SDA_PIN);
|
||||
gpio_set_function(I2C_SDA_PIN, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(I2C_SDA_PIN);
|
||||
|
||||
gpio_init(I2C_SCL_PIN);
|
||||
gpio_set_function(I2C_SCL_PIN, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(I2C_SCL_PIN);
|
||||
|
||||
i2c_slave_init(I2C_PORT, address, &slave_handler);
|
||||
}
|
||||
|
||||
void I2CSlave::notify_tuh(bool mounted, HostDriverType host_type)
|
||||
{
|
||||
tuh_mounted_.store(mounted);
|
||||
}
|
||||
|
||||
void I2CSlave::process(Gamepad (&gamepads)[MAX_GAMEPADS])
|
||||
{
|
||||
if (tuh_mounted_.load())
|
||||
{
|
||||
return;
|
||||
}
|
||||
//Don't want to hang up the i2c bus by doing this in the slave handler
|
||||
if (new_pad_in_.load())
|
||||
{
|
||||
new_pad_in_.store(false);
|
||||
gamepads[0].set_pad_in(packet_in_.pad_in);
|
||||
gamepads[0].set_chatpad_in(packet_in_.chatpad_in);
|
||||
}
|
||||
|
||||
if (gamepads[0].new_pad_out())
|
||||
{
|
||||
packet_out_.pad_out = gamepads[0].get_pad_out();
|
||||
}
|
||||
}
|
||||
|
||||
I2CSlave::PacketID I2CSlave::get_packet_id(uint8_t* buffer_in)
|
||||
{
|
||||
switch (static_cast<PacketID>(buffer_in[1]))
|
||||
{
|
||||
case PacketID::PAD:
|
||||
if (buffer_in[0] == sizeof(PacketIn))
|
||||
{
|
||||
return PacketID::PAD;
|
||||
}
|
||||
break;
|
||||
|
||||
case PacketID::COMMAND:
|
||||
if (buffer_in[0] == sizeof(PacketCMD))
|
||||
{
|
||||
return PacketID::COMMAND;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return PacketID::UNKNOWN;
|
||||
}
|
||||
|
||||
void I2CSlave::slave_handler(i2c_inst_t *i2c, i2c_slave_event_t event)
|
||||
{
|
||||
static size_t count = 0;
|
||||
static bool enabled = false;
|
||||
static uint8_t buffer_in[MAX_PACKET_SIZE];
|
||||
static uint8_t buffer_out[MAX_PACKET_SIZE];
|
||||
|
||||
PacketIn *packet_in_p = reinterpret_cast<PacketIn*>(buffer_in);
|
||||
PacketOut *packet_out_p = reinterpret_cast<PacketOut*>(buffer_out);
|
||||
PacketCMD *packet_cmd_in_p = reinterpret_cast<PacketCMD*>(buffer_in);
|
||||
PacketCMD *packet_cmd_out_p = reinterpret_cast<PacketCMD*>(buffer_out);
|
||||
|
||||
switch (event)
|
||||
{
|
||||
case I2C_SLAVE_RECEIVE: // master has written
|
||||
if (count < MAX_PACKET_SIZE)
|
||||
{
|
||||
buffer_in[count] = i2c_read_byte_raw(i2c);
|
||||
++count;
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_SLAVE_FINISH:
|
||||
// Each master write has an ID indicating the type of data to send back on the next read request
|
||||
// Every write has an associated read
|
||||
switch (get_packet_id(buffer_in))
|
||||
{
|
||||
case PacketID::PAD:
|
||||
instance_->packet_in_ = *packet_in_p;
|
||||
*packet_out_p = instance_->packet_out_;
|
||||
instance_->new_pad_in_.store(true);
|
||||
break;
|
||||
|
||||
case PacketID::COMMAND:
|
||||
switch (packet_cmd_in_p->command)
|
||||
{
|
||||
case Command::DISABLE:
|
||||
packet_cmd_out_p->packet_len = sizeof(PacketCMD);
|
||||
packet_cmd_out_p->packet_id = PacketID::COMMAND;
|
||||
packet_cmd_out_p->command = Command::DISABLE;
|
||||
packet_cmd_out_p->status = Status::OK;
|
||||
if (!instance_->tuh_mounted_.load())
|
||||
{
|
||||
OGXMini::host_mounted(false);
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::STATUS:
|
||||
packet_cmd_out_p->packet_len = sizeof(PacketCMD);
|
||||
packet_cmd_out_p->packet_id = PacketID::COMMAND;
|
||||
packet_cmd_out_p->command = Command::STATUS;
|
||||
packet_cmd_out_p->status = instance_->tuh_mounted_.load() ? Status::NOT_READY : Status::READY;
|
||||
if (!instance_->tuh_mounted_.load() && !enabled)
|
||||
{
|
||||
enabled = true;
|
||||
OGXMini::host_mounted(true);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
count = 0;
|
||||
std::memset(buffer_in, 0, sizeof(buffer_in));
|
||||
break;
|
||||
|
||||
case I2C_SLAVE_REQUEST:
|
||||
i2c_write_raw_blocking(i2c, buffer_out, buffer_out[0]);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
#ifndef I2C_SLAVE_4CH_H
|
||||
#define I2C_SLAVE_4CH_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
#include <hardware/i2c.h>
|
||||
#include <pico/i2c_slave.h>
|
||||
|
||||
#include "board_config.h"
|
||||
#include "Gamepad/Gamepad.h"
|
||||
#include "I2CDriver/4Channel/I2CDriver.h"
|
||||
|
||||
class I2CSlave : public I2CDriver
|
||||
{
|
||||
public:
|
||||
~I2CSlave() = default;
|
||||
void initialize(uint8_t address) override;
|
||||
void process(Gamepad (&gamepads)[MAX_GAMEPADS]) override;
|
||||
void notify_tuh(bool mounted, HostDriverType host_type) override;
|
||||
|
||||
private:
|
||||
static I2CSlave* instance_;
|
||||
|
||||
PacketIn packet_in_;
|
||||
PacketOut packet_out_;
|
||||
std::atomic<bool> new_pad_in_{false};
|
||||
std::atomic<bool> tuh_mounted_{false};
|
||||
|
||||
static PacketID get_packet_id(uint8_t* buffer_in);
|
||||
static void slave_handler(i2c_inst_t *i2c, i2c_slave_event_t event);
|
||||
};
|
||||
|
||||
#endif // I2C_SLAVE_4CH_H
|
||||
@@ -1,146 +0,0 @@
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <pico/i2c_slave.h>
|
||||
#include <hardware/gpio.h>
|
||||
#include <hardware/i2c.h>
|
||||
|
||||
#include "board_config.h"
|
||||
#include "Board/board_api.h"
|
||||
#include "I2CDriver/ESP32/I2CDriver.h"
|
||||
#include "UserSettings/UserSettings.h"
|
||||
#include "TaskQueue/TaskQueue.h"
|
||||
#include "Board/ogxm_log.h"
|
||||
|
||||
namespace I2CDriver {
|
||||
|
||||
enum class PacketID : uint8_t { UNKNOWN = 0, SET_PAD, GET_PAD, SET_DRIVER };
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct PacketIn
|
||||
{
|
||||
uint8_t packet_len{sizeof(PacketIn)};
|
||||
PacketID packet_id{PacketID::SET_PAD};
|
||||
uint8_t index{0};
|
||||
DeviceDriverType device_type{DeviceDriverType::NONE};
|
||||
Gamepad::PadIn pad_in{Gamepad::PadIn()};
|
||||
std::array<uint8_t, 5> reserved{0};
|
||||
};
|
||||
static_assert(sizeof(PacketIn) == 32, "i2c_driver_esp::PacketIn size mismatch");
|
||||
|
||||
struct PacketOut
|
||||
{
|
||||
uint8_t packet_len{sizeof(PacketOut)};
|
||||
PacketID packet_id{PacketID::GET_PAD};
|
||||
uint8_t index{0};
|
||||
Gamepad::PadOut pad_out{Gamepad::PadOut()};
|
||||
std::array<uint8_t, 3> reserved{0};
|
||||
};
|
||||
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];
|
||||
|
||||
static inline void slave_handler(i2c_inst_t *i2c, i2c_slave_event_t event)
|
||||
{
|
||||
static size_t count = 0;
|
||||
static PacketIn packet_in;
|
||||
static PacketOut packet_out;
|
||||
static DeviceDriverType current_device_type = UserSettings::get_instance().get_current_driver();
|
||||
|
||||
switch (event)
|
||||
{
|
||||
case I2C_SLAVE_RECEIVE:
|
||||
if (count < sizeof(PacketIn))
|
||||
{
|
||||
reinterpret_cast<uint8_t*>(&packet_in)[count] = i2c_read_byte_raw(i2c);
|
||||
++count;
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_SLAVE_FINISH:
|
||||
if (count == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
switch (packet_in.packet_id)
|
||||
{
|
||||
case PacketID::SET_PAD:
|
||||
if (packet_in.index < MAX_GAMEPADS)
|
||||
{
|
||||
gamepads_[packet_in.index]->set_pad_in(packet_in.pad_in);
|
||||
}
|
||||
break;
|
||||
|
||||
case PacketID::SET_DRIVER:
|
||||
if (packet_in.device_type != DeviceDriverType::NONE &&
|
||||
packet_in.device_type != current_device_type)
|
||||
{
|
||||
OGXM_LOG("I2C: Driver change detected.\n");
|
||||
|
||||
//Any writes to flash should be done on Core0
|
||||
TaskQueue::Core0::queue_delayed_task(TaskQueue::Core0::get_new_task_id(), 1000, false,
|
||||
[new_device_type = packet_in.device_type]
|
||||
{
|
||||
UserSettings::get_instance().store_driver_type(new_device_type);
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
count = 0;
|
||||
break;
|
||||
|
||||
case I2C_SLAVE_REQUEST:
|
||||
if (packet_in.index < MAX_GAMEPADS)
|
||||
{
|
||||
packet_out.index = packet_in.index;
|
||||
packet_out.pad_out = gamepads_[packet_in.index]->get_pad_out();
|
||||
}
|
||||
// switch (packet_in.packet_id)
|
||||
// {
|
||||
// case PacketID::SET_PAD:
|
||||
|
||||
i2c_write_raw_blocking(i2c, reinterpret_cast<const uint8_t*>(&packet_out), packet_out.packet_len);
|
||||
// break;
|
||||
|
||||
// default:
|
||||
// i2c_write_raw_blocking(i2c, reinterpret_cast<const uint8_t*>(&packet_out), 1);
|
||||
// break;
|
||||
// }
|
||||
|
||||
// packet_in = PacketIn();
|
||||
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);
|
||||
|
||||
OGXM_LOG("I2C Driver initialized\n");
|
||||
}
|
||||
|
||||
} // namespace i2c_driver_esp32
|
||||
@@ -1,13 +0,0 @@
|
||||
#ifndef _I2CDRIVER_ESP_H_
|
||||
#define _I2CDRIVER_ESP_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "Gamepad/Gamepad.h"
|
||||
|
||||
namespace I2CDriver
|
||||
{
|
||||
void initialize(Gamepad (&gamepads)[MAX_GAMEPADS]);
|
||||
}
|
||||
|
||||
#endif // _I2CDRIVER_ESP_H_
|
||||
201
Firmware/RP2040/src/OGXMini/Board/ESP32_Bluepad32_I2C.cpp
Normal file
201
Firmware/RP2040/src/OGXMini/Board/ESP32_Bluepad32_I2C.cpp
Normal file
@@ -0,0 +1,201 @@
|
||||
#include "Board/Config.h"
|
||||
#include "OGXMini/Board/ESP32_Bluepad32_I2C.h"
|
||||
#if (OGXM_BOARD == ESP32_BLUEPAD32_I2C)
|
||||
|
||||
#include <cstring>
|
||||
#include <pico/multicore.h>
|
||||
#include <pico/i2c_slave.h>
|
||||
#include <hardware/gpio.h>
|
||||
#include <hardware/i2c.h>
|
||||
|
||||
#include "tusb.h"
|
||||
#include "bsp/board_api.h"
|
||||
|
||||
#include "USBDevice/DeviceManager.h"
|
||||
#include "UserSettings/UserSettings.h"
|
||||
#include "Board/board_api.h"
|
||||
#include "Board/esp32_api.h"
|
||||
#include "Gamepad/Gamepad.h"
|
||||
#include "TaskQueue/TaskQueue.h"
|
||||
|
||||
enum class PacketID : uint8_t {
|
||||
UNKNOWN = 0,
|
||||
SET_PAD,
|
||||
GET_PAD,
|
||||
SET_DRIVER
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct PacketIn {
|
||||
uint8_t packet_len{sizeof(PacketIn)};
|
||||
PacketID packet_id{PacketID::SET_PAD};
|
||||
uint8_t index{0};
|
||||
DeviceDriverType device_type{DeviceDriverType::NONE};
|
||||
Gamepad::PadIn pad_in{Gamepad::PadIn()};
|
||||
uint8_t reserved[5]{0};
|
||||
};
|
||||
static_assert(sizeof(PacketIn) == 32, "i2c_driver_esp::PacketIn size mismatch");
|
||||
|
||||
struct PacketOut {
|
||||
uint8_t packet_len{sizeof(PacketOut)};
|
||||
PacketID packet_id{PacketID::GET_PAD};
|
||||
uint8_t index{0};
|
||||
Gamepad::PadOut pad_out{Gamepad::PadOut()};
|
||||
uint8_t reserved[3]{0};
|
||||
};
|
||||
static_assert(sizeof(PacketOut) == 8, "i2c_driver_esp::PacketOut size mismatch");
|
||||
#pragma pack(pop)
|
||||
|
||||
constexpr size_t MAX_BUFFER_SIZE = std::max(sizeof(PacketOut), sizeof(PacketIn));
|
||||
constexpr uint8_t I2C_ADDR = 0x01;
|
||||
|
||||
static Gamepad _gamepads[MAX_GAMEPADS];
|
||||
static bool _uart_bridge_mode = false;
|
||||
|
||||
static inline void slave_handler(i2c_inst_t *i2c, i2c_slave_event_t event) {
|
||||
static size_t count = 0;
|
||||
static PacketIn packet_in;
|
||||
static PacketOut packet_out;
|
||||
static DeviceDriverType current_device_type =
|
||||
UserSettings::get_instance().get_current_driver();
|
||||
|
||||
switch (event) {
|
||||
case I2C_SLAVE_RECEIVE:
|
||||
if (count < sizeof(PacketIn)) {
|
||||
reinterpret_cast<uint8_t*>(&packet_in)[count] = i2c_read_byte_raw(i2c);
|
||||
++count;
|
||||
}
|
||||
break;
|
||||
case I2C_SLAVE_FINISH:
|
||||
if (count == 0) {
|
||||
break;
|
||||
}
|
||||
switch (packet_in.packet_id) {
|
||||
case PacketID::SET_PAD:
|
||||
if (packet_in.index < MAX_GAMEPADS) {
|
||||
_gamepads[packet_in.index].set_pad_in(packet_in.pad_in);
|
||||
}
|
||||
break;
|
||||
case PacketID::SET_DRIVER:
|
||||
if (packet_in.device_type != DeviceDriverType::NONE &&
|
||||
packet_in.device_type != current_device_type) {
|
||||
OGXM_LOG("I2C: Driver change detected.\n");
|
||||
//Any writes to flash should be done on Core0
|
||||
TaskQueue::Core0::queue_delayed_task(
|
||||
TaskQueue::Core0::get_new_task_id(), 1000, false,
|
||||
[new_device_type = packet_in.device_type] {
|
||||
UserSettings::get_instance().store_driver_type(new_device_type);
|
||||
}
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
count = 0;
|
||||
break;
|
||||
case I2C_SLAVE_REQUEST:
|
||||
if (packet_in.index < MAX_GAMEPADS) {
|
||||
packet_out.index = packet_in.index;
|
||||
packet_out.pad_out = _gamepads[packet_in.index].get_pad_out();
|
||||
}
|
||||
i2c_write_raw_blocking( i2c,
|
||||
reinterpret_cast<const uint8_t*>(&packet_out),
|
||||
packet_out.packet_len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void core1_task() {
|
||||
i2c_init(I2C_PORT, I2C_BAUDRATE);
|
||||
|
||||
gpio_init(I2C_SDA_PIN);
|
||||
gpio_init(I2C_SCL_PIN);
|
||||
gpio_set_function(I2C_SDA_PIN, GPIO_FUNC_I2C);
|
||||
gpio_set_function(I2C_SCL_PIN, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(I2C_SDA_PIN);
|
||||
gpio_pull_up(I2C_SCL_PIN);
|
||||
|
||||
i2c_slave_init(I2C_PORT, I2C_ADDR, &slave_handler);
|
||||
|
||||
OGXM_LOG("I2C Driver initialized\n");
|
||||
|
||||
while (true) {
|
||||
tight_loop_contents();
|
||||
}
|
||||
}
|
||||
|
||||
void run_uart_bridge() {
|
||||
esp32_api::enter_programming_mode();
|
||||
|
||||
OGXM_LOG("Entering UART Bridge mode\n");
|
||||
|
||||
//Runs UART Bridge task, doesn't return unless programming is complete
|
||||
DeviceManager::get_instance().get_driver()->process(0, _gamepads[0]);
|
||||
|
||||
OGXM_LOG("Exiting UART Bridge mode\n");
|
||||
|
||||
board_api::usb::disconnect_all();
|
||||
UserSettings::get_instance().write_datetime();
|
||||
board_api::reboot();
|
||||
}
|
||||
|
||||
bool update_needed(UserSettings& user_settings) {
|
||||
#if defined(OGXM_RETAIL)
|
||||
return !user_settings.verify_datetime();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void esp32_bp32_i2c::initialize() {
|
||||
board_api::init_board();
|
||||
esp32_api::init();
|
||||
|
||||
UserSettings& user_settings = UserSettings::get_instance();
|
||||
user_settings.initialize_flash();
|
||||
|
||||
//MODE_SEL_PIN is used to determine if UART bridge should be run
|
||||
_uart_bridge_mode =
|
||||
(esp32_api::uart_bridge_mode() || update_needed(user_settings));
|
||||
|
||||
DeviceDriverType driver_type =
|
||||
_uart_bridge_mode ?
|
||||
DeviceDriverType::UART_BRIDGE : user_settings.get_current_driver();
|
||||
|
||||
DeviceManager::get_instance().initialize_driver(driver_type, _gamepads);
|
||||
}
|
||||
|
||||
void esp32_bp32_i2c::run() {
|
||||
if (_uart_bridge_mode) {
|
||||
run_uart_bridge();
|
||||
return;
|
||||
}
|
||||
|
||||
multicore_reset_core1();
|
||||
multicore_launch_core1(core1_task);
|
||||
|
||||
esp32_api::reset();
|
||||
|
||||
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]);
|
||||
tud_task();
|
||||
}
|
||||
sleep_ms(1);
|
||||
}
|
||||
}
|
||||
|
||||
// #else // OGXM_BOARD == ESP32_BLUEPAD32_I2C
|
||||
|
||||
// void esp32_bp32_i2c::initialize() {}
|
||||
// void esp32_bp32_i2c::run() {}
|
||||
|
||||
#endif // OGXM_BOARD == ESP32_BLUEPAD32_I2C
|
||||
8
Firmware/RP2040/src/OGXMini/Board/ESP32_Bluepad32_I2C.h
Normal file
8
Firmware/RP2040/src/OGXMini/Board/ESP32_Bluepad32_I2C.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace esp32_bp32_i2c {
|
||||
void initialize();
|
||||
void run();
|
||||
} // namespace esp32_bp32_i2c
|
||||
200
Firmware/RP2040/src/OGXMini/Board/ESP32_Blueretro_I2C.cpp
Normal file
200
Firmware/RP2040/src/OGXMini/Board/ESP32_Blueretro_I2C.cpp
Normal file
@@ -0,0 +1,200 @@
|
||||
#include "Board/Config.h"
|
||||
#include "OGXMini/Board/ESP32_Blueretro_I2C.h"
|
||||
#if (OGXM_BOARD == ESP32_BLUERETRO_I2C)
|
||||
|
||||
#include <pico/multicore.h>
|
||||
#include <hardware/gpio.h>
|
||||
#include <hardware/i2c.h>
|
||||
|
||||
#include "tusb.h"
|
||||
#include "bsp/board_api.h"
|
||||
|
||||
#include "UserSettings/UserSettings.h"
|
||||
#include "USBDevice/DeviceManager.h"
|
||||
#include "Board/board_api.h"
|
||||
#include "Board/esp32_api.h"
|
||||
#include "Gamepad/Gamepad.h"
|
||||
#include "TaskQueue/TaskQueue.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct PacketIn {
|
||||
uint8_t len{sizeof(PacketIn)};
|
||||
uint8_t index{0};
|
||||
DeviceDriverType device_type{DeviceDriverType::NONE};
|
||||
uint8_t gp_data[13]{0};
|
||||
};
|
||||
static_assert(sizeof(PacketIn) == 16, "i2c_driver_esp::PacketIn size mismatch");
|
||||
|
||||
struct PacketOut {
|
||||
uint8_t len{sizeof(PacketOut)};
|
||||
uint8_t rumble_l{0};
|
||||
uint8_t rumble_r{0};
|
||||
uint8_t reserved[5]{0};
|
||||
};
|
||||
static_assert(sizeof(PacketOut) == 8, "i2c_driver_esp::PacketOut size mismatch");
|
||||
#pragma pack(pop)
|
||||
|
||||
constexpr uint8_t SLAVE_ADDR = 0x50;
|
||||
constexpr uint32_t FEEDBACK_DELAY_MS = 250;
|
||||
|
||||
static Gamepad _gamepads[MAX_GAMEPADS];
|
||||
static bool _uart_bridge_mode = false;
|
||||
|
||||
static void core1_task() {
|
||||
i2c_init(I2C_PORT, I2C_BAUDRATE);
|
||||
|
||||
gpio_set_function(I2C_SCL_PIN, GPIO_FUNC_I2C);
|
||||
gpio_set_function(I2C_SDA_PIN, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(I2C_SCL_PIN);
|
||||
gpio_pull_up(I2C_SDA_PIN);
|
||||
|
||||
bool slave_ready = false;
|
||||
PacketIn packet_in;
|
||||
PacketOut packet_out;
|
||||
Gamepad::PadIn pad_in;
|
||||
Gamepad& gamepad = _gamepads[0];
|
||||
uint32_t tid = TaskQueue::Core1::get_new_task_id();
|
||||
|
||||
sleep_ms(500); // Wait for ESP32 to start
|
||||
|
||||
TaskQueue::Core1::queue_delayed_task(tid, FEEDBACK_DELAY_MS, true,
|
||||
[&packet_out, &gamepad, &slave_ready] {
|
||||
if (!slave_ready) { // Check if slave present
|
||||
uint8_t addr = SLAVE_ADDR;
|
||||
int result = i2c_read_blocking(I2C_PORT, SLAVE_ADDR, &addr, 1, false);
|
||||
slave_ready = (result == 1);
|
||||
|
||||
} else { // Update rumble
|
||||
Gamepad::PadOut pad_out = gamepad.get_pad_out();
|
||||
packet_out.rumble_l = pad_out.rumble_l;
|
||||
packet_out.rumble_r = pad_out.rumble_r;
|
||||
int result = i2c_write_blocking(I2C_PORT, SLAVE_ADDR,
|
||||
reinterpret_cast<const uint8_t*>(&packet_out),
|
||||
sizeof(PacketOut), false);
|
||||
|
||||
if (result != sizeof(PacketOut)) {
|
||||
OGXM_LOG("I2C write failed\n");
|
||||
} else {
|
||||
OGXM_LOG("I2C sent rumble, L: %02X, R: %02X\n",
|
||||
packet_out.rumble_l, packet_out.rumble_r);
|
||||
sleep_ms(1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
OGXM_LOG("I2C Driver initialized\n");
|
||||
|
||||
//Wait for slave to be detected
|
||||
while (!slave_ready) {
|
||||
TaskQueue::Core1::process_tasks();
|
||||
sleep_ms(100);
|
||||
}
|
||||
|
||||
OGXM_LOG("I2C Slave ready\n");
|
||||
|
||||
while (true) {
|
||||
TaskQueue::Core1::process_tasks();
|
||||
int result = i2c_read_blocking( I2C_PORT, SLAVE_ADDR,
|
||||
reinterpret_cast<uint8_t*>(&packet_in),
|
||||
sizeof(PacketIn), false);
|
||||
|
||||
if (result == sizeof(PacketIn)) {
|
||||
std::memcpy(reinterpret_cast<uint8_t*>(&pad_in),
|
||||
packet_in.gp_data,
|
||||
sizeof(packet_in.gp_data));
|
||||
gamepad.set_pad_in(pad_in);
|
||||
|
||||
} else {
|
||||
OGXM_LOG("I2C read failed\n");
|
||||
return;
|
||||
}
|
||||
sleep_ms(1);
|
||||
}
|
||||
}
|
||||
|
||||
void set_gp_check_timer(uint32_t task_id) {
|
||||
UserSettings& user_settings = UserSettings::get_instance();
|
||||
|
||||
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])) {
|
||||
OGXM_LOG("Driver change detected, storing new driver.\n");
|
||||
//This will store the new mode and reboot the pico
|
||||
user_settings.store_driver_type(user_settings.get_current_driver());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void run_uart_bridge() {
|
||||
esp32_api::enter_programming_mode();
|
||||
|
||||
OGXM_LOG("Entering UART Bridge mode\n");
|
||||
|
||||
//Runs UART Bridge task, doesn't return unless programming is complete
|
||||
DeviceManager::get_instance().get_driver()->process(0, _gamepads[0]);
|
||||
|
||||
OGXM_LOG("Exiting UART Bridge mode\n");
|
||||
|
||||
board_api::usb::disconnect_all();
|
||||
UserSettings::get_instance().write_datetime();
|
||||
board_api::reboot();
|
||||
}
|
||||
|
||||
bool update_needed(UserSettings& user_settings) {
|
||||
#if defined(OGXM_RETAIL)
|
||||
return !user_settings.verify_datetime();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void esp32_br_i2c::initialize() {
|
||||
board_api::init_board();
|
||||
esp32_api::init();
|
||||
|
||||
UserSettings& user_settings = UserSettings::get_instance();
|
||||
user_settings.initialize_flash();
|
||||
|
||||
//MODE_SEL_PIN is used to determine if UART bridge should be run
|
||||
_uart_bridge_mode =
|
||||
(esp32_api::uart_bridge_mode() || update_needed(user_settings));
|
||||
|
||||
DeviceDriverType driver_type =
|
||||
_uart_bridge_mode ?
|
||||
DeviceDriverType::UART_BRIDGE : user_settings.get_current_driver();
|
||||
|
||||
DeviceManager::get_instance().initialize_driver(driver_type, _gamepads);
|
||||
}
|
||||
|
||||
void esp32_br_i2c::run() {
|
||||
if (_uart_bridge_mode) {
|
||||
run_uart_bridge();
|
||||
return;
|
||||
}
|
||||
|
||||
esp32_api::reset();
|
||||
|
||||
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);
|
||||
|
||||
DeviceDriver* device_driver = DeviceManager::get_instance().get_driver();
|
||||
|
||||
tud_init(BOARD_TUD_RHPORT);
|
||||
|
||||
while (true) {
|
||||
TaskQueue::Core0::process_tasks();
|
||||
device_driver->process(0, _gamepads[0]);
|
||||
tud_task();
|
||||
sleep_ms(1);
|
||||
}
|
||||
}
|
||||
|
||||
// #else // OGXM_BOARD == ESP32_BLUERETRO_I2C
|
||||
|
||||
// void esp32_br_i2c::initialize() {}
|
||||
// void esp32_br_i2c::run() {}
|
||||
|
||||
#endif // OGXM_BOARD == ESP32_BLUERETRO_I2C
|
||||
8
Firmware/RP2040/src/OGXMini/Board/ESP32_Blueretro_I2C.h
Normal file
8
Firmware/RP2040/src/OGXMini/Board/ESP32_Blueretro_I2C.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace esp32_br_i2c {
|
||||
void initialize();
|
||||
void run();
|
||||
} // namespace esp32_br_i2c
|
||||
470
Firmware/RP2040/src/OGXMini/Board/Four_Channel_I2C.cpp
Normal file
470
Firmware/RP2040/src/OGXMini/Board/Four_Channel_I2C.cpp
Normal file
@@ -0,0 +1,470 @@
|
||||
#include "Board/Config.h"
|
||||
#include "OGXMini/Board/Four_Channel_I2C.h"
|
||||
#if ((OGXM_BOARD == INTERNAL_4CH_I2C) || (OGXM_BOARD == EXTERNAL_4CH_I2C))
|
||||
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
#include <pico/multicore.h>
|
||||
#include <hardware/gpio.h>
|
||||
#include <hardware/i2c.h>
|
||||
#include <pico/i2c_slave.h>
|
||||
|
||||
#include "tusb.h"
|
||||
#include "bsp/board_api.h"
|
||||
#include "pio_usb.h"
|
||||
|
||||
#include "USBDevice/DeviceManager.h"
|
||||
#include "USBHost/HostManager.h"
|
||||
#include "Board/board_api.h"
|
||||
#include "Board/ogxm_log.h"
|
||||
#include "UserSettings/UserSettings.h"
|
||||
#include "Gamepad/Gamepad.h"
|
||||
#include "TaskQueue/TaskQueue.h"
|
||||
|
||||
constexpr uint32_t FEEDBACK_DELAY_MS = 250;
|
||||
|
||||
Gamepad _gamepads[MAX_GAMEPADS];
|
||||
|
||||
namespace I2C {
|
||||
enum class Role {
|
||||
SLAVE = 0,
|
||||
MASTER
|
||||
};
|
||||
enum class PacketID : uint8_t {
|
||||
UNKNOWN = 0,
|
||||
PAD,
|
||||
COMMAND
|
||||
};
|
||||
enum class Command : uint8_t {
|
||||
UNKNOWN = 0,
|
||||
STATUS,
|
||||
DISABLE
|
||||
};
|
||||
enum class Status : uint8_t {
|
||||
UNKNOWN = 0,
|
||||
NC,
|
||||
ERROR,
|
||||
OK,
|
||||
READY,
|
||||
NOT_READY
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct PacketIn {
|
||||
uint8_t packet_len{sizeof(PacketIn)};
|
||||
PacketID packet_id{PacketID::PAD};
|
||||
Gamepad::PadIn pad_in{Gamepad::PadIn()};
|
||||
Gamepad::ChatpadIn chatpad_in{0};
|
||||
uint8_t reserved[4]{0};
|
||||
};
|
||||
static_assert(sizeof(PacketIn) == 32, "I2CDriver::PacketIn is misaligned");
|
||||
|
||||
struct PacketOut {
|
||||
uint8_t packet_len{sizeof(PacketOut)};
|
||||
PacketID packet_id{PacketID::PAD};
|
||||
Gamepad::PadOut pad_out{Gamepad::PadOut()};
|
||||
uint8_t reserved[4]{0};
|
||||
};
|
||||
static_assert(sizeof(PacketOut) == 8, "I2CDriver::PacketOut is misaligned");
|
||||
|
||||
struct PacketCMD {
|
||||
uint8_t packet_len{sizeof(PacketCMD)};
|
||||
PacketID packet_id{PacketID::COMMAND};
|
||||
Command command{Command::UNKNOWN};
|
||||
Status status{Status::UNKNOWN};
|
||||
uint8_t reserved[4]{0};
|
||||
};
|
||||
static_assert(sizeof(PacketCMD) == 8, "I2CDriver::PacketCMD is misaligned");
|
||||
#pragma pack(pop)
|
||||
|
||||
constexpr size_t MAX_PACKET_SIZE = sizeof(PacketIn);
|
||||
|
||||
static Role _i2c_role = Role::SLAVE;
|
||||
|
||||
namespace Slave {
|
||||
static inline PacketID get_packet_id(uint8_t* buffer_in) {
|
||||
switch (static_cast<PacketID>(buffer_in[1])) {
|
||||
case PacketID::PAD:
|
||||
if (buffer_in[0] == sizeof(PacketIn)) {
|
||||
return PacketID::PAD;
|
||||
}
|
||||
break;
|
||||
case PacketID::COMMAND:
|
||||
if (buffer_in[0] == sizeof(PacketCMD)) {
|
||||
return PacketID::COMMAND;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return PacketID::UNKNOWN;
|
||||
}
|
||||
|
||||
static void slave_handler(i2c_inst_t *i2c, i2c_slave_event_t event) {
|
||||
static size_t count = 0;
|
||||
static bool enabled = false;
|
||||
static uint8_t buffer_in[MAX_PACKET_SIZE];
|
||||
static uint8_t buffer_out[MAX_PACKET_SIZE];
|
||||
|
||||
PacketIn *packet_in_p = reinterpret_cast<PacketIn*>(buffer_in);
|
||||
PacketOut *packet_out_p = reinterpret_cast<PacketOut*>(buffer_out);
|
||||
PacketCMD *packet_cmd_in_p = reinterpret_cast<PacketCMD*>(buffer_in);
|
||||
PacketCMD *packet_cmd_out_p = reinterpret_cast<PacketCMD*>(buffer_out);
|
||||
|
||||
switch (event) {
|
||||
case I2C_SLAVE_RECEIVE: // master has written
|
||||
if (count < MAX_PACKET_SIZE) {
|
||||
buffer_in[count] = i2c_read_byte_raw(i2c);
|
||||
++count;
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_SLAVE_FINISH:
|
||||
// Each master write has an ID indicating the type of data to send back on the next read request
|
||||
// Every write has an associated read
|
||||
switch (get_packet_id(buffer_in)) {
|
||||
case PacketID::PAD:
|
||||
// instance_->packet_in_ = *packet_in_p;
|
||||
// *packet_out_p = instance_->packet_out_;
|
||||
// instance_->new_pad_in_.store(true);
|
||||
_gamepads[0].set_pad_in(packet_in_p->pad_in);
|
||||
if (_gamepads[0].new_pad_out()) {
|
||||
packet_out_p->pad_out = _gamepads[0].get_pad_out();
|
||||
}
|
||||
break;
|
||||
|
||||
case PacketID::COMMAND:
|
||||
switch (packet_cmd_in_p->command) {
|
||||
case Command::DISABLE:
|
||||
packet_cmd_out_p->packet_len = sizeof(PacketCMD);
|
||||
packet_cmd_out_p->packet_id = PacketID::COMMAND;
|
||||
packet_cmd_out_p->command = Command::DISABLE;
|
||||
packet_cmd_out_p->status = Status::OK;
|
||||
|
||||
if (!tuh_mounted(BOARD_TUH_RHPORT)) {
|
||||
four_ch_i2c::host_mounted(false);
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::STATUS:
|
||||
packet_cmd_out_p->packet_len = sizeof(PacketCMD);
|
||||
packet_cmd_out_p->packet_id = PacketID::COMMAND;
|
||||
packet_cmd_out_p->command = Command::STATUS;
|
||||
packet_cmd_out_p->status =
|
||||
tuh_mounted(BOARD_TUH_RHPORT) ? Status::NOT_READY : Status::READY;
|
||||
|
||||
if (!tuh_mounted(BOARD_TUH_RHPORT) && !enabled) {
|
||||
enabled = true;
|
||||
four_ch_i2c::host_mounted(true);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
count = 0;
|
||||
std::memset(buffer_in, 0, sizeof(buffer_in));
|
||||
break;
|
||||
|
||||
case I2C_SLAVE_REQUEST:
|
||||
i2c_write_raw_blocking(i2c, buffer_out, buffer_out[0]);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // namespace Slave
|
||||
|
||||
namespace Master {
|
||||
struct Slave {
|
||||
uint8_t address{0xFF};
|
||||
Status status{Status::NC};
|
||||
bool enabled{false};
|
||||
};
|
||||
|
||||
static constexpr size_t NUM_SLAVES = MAX_GAMEPADS - 1;
|
||||
static_assert(NUM_SLAVES > 0, "I2CMaster::NUM_SLAVES must be greater than 0 to use I2C");
|
||||
|
||||
std::array<Slave, NUM_SLAVES> _slaves;
|
||||
|
||||
static inline bool read_blocking(uint8_t address, void* buffer, size_t len) {
|
||||
return (i2c_read_blocking( I2C_PORT, address, reinterpret_cast<uint8_t*>(buffer),
|
||||
len, false) == static_cast<int>(len));
|
||||
}
|
||||
|
||||
static inline bool write_blocking(uint8_t address, void* buffer, size_t len) {
|
||||
return (i2c_write_blocking( I2C_PORT, address, reinterpret_cast<uint8_t*>(buffer),
|
||||
len, false) == static_cast<int>(len));
|
||||
}
|
||||
|
||||
static inline bool slave_detected(uint8_t address) {
|
||||
uint8_t dummy = 0;
|
||||
int result = i2c_write_timeout_us(I2C_PORT, address, &dummy, 0, false, 1000);
|
||||
return (result >= 0);
|
||||
}
|
||||
|
||||
static void notify_disable(uint8_t address) {
|
||||
if (!slave_detected(address)) {
|
||||
return;
|
||||
}
|
||||
int retries = 10;
|
||||
|
||||
while (retries--) {
|
||||
PacketCMD packet_cmd;
|
||||
packet_cmd.packet_id = PacketID::COMMAND;
|
||||
packet_cmd.command = Command::DISABLE;
|
||||
|
||||
if (write_blocking(address, &packet_cmd, sizeof(PacketCMD))) {
|
||||
if (read_blocking(address, &packet_cmd, sizeof(PacketCMD))) {
|
||||
if (packet_cmd.status == Status::OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
sleep_ms(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void process() {
|
||||
for (uint8_t i = 0; i < NUM_SLAVES; ++i) {
|
||||
Slave& slave = _slaves[i];
|
||||
|
||||
if (!slave.enabled || !slave_detected(slave.address)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PacketCMD packet_cmd;
|
||||
packet_cmd.packet_id = PacketID::COMMAND;
|
||||
packet_cmd.command = Command::STATUS;
|
||||
|
||||
if (!write_blocking(slave.address, &packet_cmd, sizeof(PacketCMD)) ||
|
||||
!read_blocking(slave.address, &packet_cmd, sizeof(PacketCMD))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (packet_cmd.status == Status::READY) {
|
||||
Gamepad& gamepad = _gamepads[i + 1];
|
||||
PacketIn packet_in;
|
||||
packet_in.pad_in = gamepad.get_pad_in();
|
||||
packet_in.chatpad_in = gamepad.get_chatpad_in();
|
||||
|
||||
if (write_blocking(slave.address, &packet_in, sizeof(PacketIn))) {
|
||||
PacketOut packet_out;
|
||||
if (read_blocking(slave.address, &packet_out, sizeof(PacketOut))) {
|
||||
gamepad.set_pad_out(packet_out.pad_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
sleep_ms(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void xbox360w_connect(bool connected, uint8_t idx) {
|
||||
if (idx < 1 || idx >= MAX_GAMEPADS) {
|
||||
return;
|
||||
}
|
||||
// This function can be called from core1
|
||||
// so queue on core0 (i2c thread)
|
||||
TaskQueue::Core0::queue_task(
|
||||
[&slave = _slaves[idx - 1], connected]() {
|
||||
slave.enabled = connected;
|
||||
if (!connected) {
|
||||
notify_disable(slave.address);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void tuh_connect(bool connected, HostDriverType host_type) {
|
||||
if (host_type != HostDriverType::XBOX360W) {
|
||||
return;
|
||||
}
|
||||
if (!connected) {
|
||||
//Called from core1 so queue on core0
|
||||
TaskQueue::Core0::queue_task(
|
||||
[]() {
|
||||
for (auto& slave : _slaves) {
|
||||
slave.enabled = false;
|
||||
notify_disable(slave.address);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} // namespace Master
|
||||
|
||||
Role role() {
|
||||
return _i2c_role;
|
||||
}
|
||||
|
||||
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) && gpio_get(SLAVE_ADDR_PIN_2)) {
|
||||
return 0x00;
|
||||
}
|
||||
else if (gpio_get(SLAVE_ADDR_PIN_1) && !gpio_get(SLAVE_ADDR_PIN_2)) {
|
||||
return 0x01;
|
||||
}
|
||||
else if (!gpio_get(SLAVE_ADDR_PIN_1) && gpio_get(SLAVE_ADDR_PIN_2)) {
|
||||
return 0x02;
|
||||
}
|
||||
else if (!gpio_get(SLAVE_ADDR_PIN_1) && !gpio_get(SLAVE_ADDR_PIN_2)) {
|
||||
return 0x03;
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void initialize() {
|
||||
uint8_t i2c_address = get_address();
|
||||
_i2c_role = (i2c_address == 0xFF) ? Role::MASTER : _i2c_role = Role::SLAVE;
|
||||
|
||||
i2c_init(I2C_PORT, I2C_BAUDRATE);
|
||||
|
||||
gpio_init(I2C_SDA_PIN);
|
||||
gpio_init(I2C_SCL_PIN);
|
||||
gpio_set_function(I2C_SDA_PIN, GPIO_FUNC_I2C);
|
||||
gpio_set_function(I2C_SCL_PIN, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(I2C_SDA_PIN);
|
||||
gpio_pull_up(I2C_SCL_PIN);
|
||||
|
||||
if (_i2c_role == Role::SLAVE) {
|
||||
i2c_slave_init(I2C_PORT, i2c_address, &Slave::slave_handler);
|
||||
}
|
||||
}
|
||||
} // namespace I2C
|
||||
|
||||
void core1_task() {
|
||||
HostManager& host_manager = HostManager::get_instance();
|
||||
host_manager.initialize(_gamepads);
|
||||
|
||||
//Pico-PIO-USB will not reliably detect a hot plug on some boards,
|
||||
//so monitor pins and init host stack after connection
|
||||
while(!board_api::usb::host_connected()) {
|
||||
sleep_ms(100);
|
||||
}
|
||||
|
||||
pio_usb_configuration_t pio_cfg = PIO_USB_CONFIG;
|
||||
tuh_configure(BOARD_TUH_RHPORT, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, &pio_cfg);
|
||||
|
||||
tuh_init(BOARD_TUH_RHPORT);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
void set_gp_check_timer(uint32_t task_id) {
|
||||
UserSettings& user_settings = UserSettings::get_instance();
|
||||
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(user_settings.get_current_driver());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void four_ch_i2c::wireless_connected(bool connected, uint8_t idx) {
|
||||
if (I2C::role() == I2C::Role::MASTER) {
|
||||
I2C::Master::xbox360w_connect(connected, idx);
|
||||
}
|
||||
}
|
||||
|
||||
void four_ch_i2c::host_mounted(bool mounted) {
|
||||
static std::atomic<bool> tud_is_inited = false;
|
||||
|
||||
board_api::set_led(mounted);
|
||||
|
||||
if (!mounted && tud_is_inited.load()) {
|
||||
TaskQueue::Core0::queue_task([]() {
|
||||
OGXM_LOG("Disconnecting USB and rebooting.\n");
|
||||
board_api::usb::disconnect_all();
|
||||
board_api::reboot();
|
||||
});
|
||||
} else if (!tud_is_inited.load() && mounted) {
|
||||
TaskQueue::Core0::queue_task([]() {
|
||||
OGXM_LOG("Initializing USB device stack.\n");
|
||||
tud_init(BOARD_TUD_RHPORT);
|
||||
tud_is_inited.store(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void four_ch_i2c::host_mounted_w_type(bool mounted, HostDriverType host_type) {
|
||||
host_mounted(mounted);
|
||||
if (I2C::role() == I2C::Role::MASTER) {
|
||||
I2C::Master::tuh_connect(mounted, host_type);
|
||||
}
|
||||
}
|
||||
|
||||
void four_ch_i2c::initialize() {
|
||||
UserSettings& user_settings = UserSettings::get_instance();
|
||||
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);
|
||||
}
|
||||
|
||||
void four_ch_i2c::run() {
|
||||
I2C::initialize();
|
||||
|
||||
multicore_reset_core1();
|
||||
multicore_launch_core1(core1_task);
|
||||
|
||||
//Wait for something to call tud_init
|
||||
while (!tud_inited()) {
|
||||
TaskQueue::Core0::process_tasks();
|
||||
sleep_ms(100);
|
||||
}
|
||||
|
||||
uint32_t tid_gp_check = TaskQueue::Core0::get_new_task_id();
|
||||
set_gp_check_timer(tid_gp_check);
|
||||
|
||||
DeviceDriver* device_driver = DeviceManager::get_instance().get_driver();
|
||||
|
||||
if (I2C::role() == I2C::Role::MASTER) {
|
||||
while (true) {
|
||||
TaskQueue::Core0::process_tasks();
|
||||
I2C::Master::process();
|
||||
device_driver->process(0, _gamepads[0]);
|
||||
tud_task();
|
||||
sleep_ms(1);
|
||||
}
|
||||
} else {
|
||||
while (true) {
|
||||
TaskQueue::Core0::process_tasks();
|
||||
device_driver->process(0, _gamepads[0]);
|
||||
tud_task();
|
||||
sleep_ms(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #else // OGXM_BOARD == INTERNAL_4CH_I2C || OGXM_BOARD == EXTERNAL_4CH_I2C
|
||||
|
||||
// void four_ch_i2c::initialize() {}
|
||||
// void four_ch_i2c::run() {}
|
||||
// void four_ch_i2c::host_mounted_w_type(bool mounted, HostDriverType host_type) {}
|
||||
// void four_ch_i2c::host_mounted(bool mounted) {}
|
||||
// void four_ch_i2c::wireless_connected(bool connected, uint8_t idx) {}
|
||||
|
||||
#endif // OGXM_BOARD == INTERNAL_4CH || OGXM_BOARD == EXTERNAL_4CH
|
||||
13
Firmware/RP2040/src/OGXMini/Board/Four_Channel_I2C.h
Normal file
13
Firmware/RP2040/src/OGXMini/Board/Four_Channel_I2C.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "USBHost/HostDriver/HostDriverTypes.h"
|
||||
|
||||
namespace four_ch_i2c {
|
||||
void initialize();
|
||||
void run();
|
||||
void host_mounted_w_type(bool mounted, HostDriverType host_type);
|
||||
void host_mounted(bool mounted);
|
||||
void wireless_connected(bool connected, uint8_t idx);
|
||||
} // namespace ext_4ch_i2c
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "board_config.h"
|
||||
#if (OGXM_BOARD == PI_PICOW) || (OGXM_BOARD == PI_PICO2W)
|
||||
#include "Board/Config.h"
|
||||
#include "OGXMini/Board/PicoW.h"
|
||||
#if (OGXM_BOARD == PI_PICOW)
|
||||
|
||||
#include <hardware/clocks.h>
|
||||
#include <pico/multicore.h>
|
||||
@@ -8,80 +9,73 @@
|
||||
#include "bsp/board_api.h"
|
||||
|
||||
#include "USBDevice/DeviceManager.h"
|
||||
#include "UserSettings/UserSettings.h"
|
||||
#include "Board/board_api.h"
|
||||
#include "Bluepad32/Bluepad32.h"
|
||||
#include "OGXMini/OGXMini.h"
|
||||
#include "BLEServer/BLEServer.h"
|
||||
#include "Gamepad/Gamepad.h"
|
||||
#include "TaskQueue/TaskQueue.h"
|
||||
|
||||
namespace OGXMini {
|
||||
Gamepad _gamepads[MAX_GAMEPADS];
|
||||
|
||||
Gamepad gamepads_[MAX_GAMEPADS];
|
||||
|
||||
//Not using this for Pico W currently
|
||||
void host_mounted(bool host_mounted) { }
|
||||
|
||||
void core1_task()
|
||||
{
|
||||
void core1_task() {
|
||||
board_api::init_bluetooth();
|
||||
board_api::set_led(true);
|
||||
BLEServer::init_server(gamepads_);
|
||||
bluepad32::run_task(gamepads_);
|
||||
BLEServer::init_server(_gamepads);
|
||||
bluepad32::run_task(_gamepads);
|
||||
}
|
||||
|
||||
void set_gp_check_timer(uint32_t task_id, UserSettings& user_settings)
|
||||
{
|
||||
TaskQueue::Core0::queue_delayed_task(task_id, UserSettings::GP_CHECK_DELAY_MS, true, [&user_settings]
|
||||
{
|
||||
void set_gp_check_timer(uint32_t task_id) {
|
||||
UserSettings& user_settings = UserSettings::get_instance();
|
||||
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]))
|
||||
{
|
||||
if (user_settings.check_for_driver_change(_gamepads[0])) {
|
||||
//This will store the new mode and reboot the pico
|
||||
user_settings.store_driver_type(user_settings.get_current_driver());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void run_program()
|
||||
{
|
||||
void pico_w::initialize() {
|
||||
board_api::init_board();
|
||||
|
||||
UserSettings& user_settings = UserSettings::get_instance();
|
||||
user_settings.initialize_flash();
|
||||
|
||||
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
|
||||
{
|
||||
gamepads_[i].set_profile(user_settings.get_profile_by_index(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(), gamepads_);
|
||||
device_manager.initialize_driver(user_settings.get_current_driver(), _gamepads);
|
||||
}
|
||||
|
||||
void pico_w::run() {
|
||||
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);
|
||||
set_gp_check_timer(tid_gp_check);
|
||||
|
||||
DeviceDriver* device_driver = device_manager.get_driver();
|
||||
DeviceDriver* device_driver = DeviceManager::get_instance().get_driver();
|
||||
|
||||
tud_init(BOARD_TUD_RHPORT);
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (true) {
|
||||
TaskQueue::Core0::process_tasks();
|
||||
|
||||
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
|
||||
{
|
||||
device_driver->process(i, gamepads_[i]);
|
||||
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i) {
|
||||
device_driver->process(i, _gamepads[i]);
|
||||
tud_task();
|
||||
}
|
||||
|
||||
sleep_us(100);
|
||||
sleep_ms(1);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OGXMini
|
||||
// #else // (OGXM_BOARD == PI_PICOW)
|
||||
|
||||
// void pico_w::initialize() {}
|
||||
// void pico_w::run() {}
|
||||
|
||||
#endif // (OGXM_BOARD == PI_PICOW)
|
||||
8
Firmware/RP2040/src/OGXMini/Board/PicoW.h
Normal file
8
Firmware/RP2040/src/OGXMini/Board/PicoW.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace pico_w {
|
||||
void initialize();
|
||||
void run();
|
||||
} // namespace pico_w
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "board_config.h"
|
||||
#if (OGXM_BOARD == ADA_FEATHER) || (OGXM_BOARD == RP_ZERO) || (OGXM_BOARD == PI_PICO) || (OGXM_BOARD == PI_PICO2)
|
||||
#include "Board/Config.h"
|
||||
#include "OGXMini/Board/Standard.h"
|
||||
#if ((OGXM_BOARD == PI_PICO) || (OGXM_BOARD == RP2040_ZERO) || (OGXM_BOARD == ADAFRUIT_FEATHER))
|
||||
|
||||
#include <pico/multicore.h>
|
||||
|
||||
@@ -9,50 +10,22 @@
|
||||
|
||||
#include "USBHost/HostManager.h"
|
||||
#include "USBDevice/DeviceManager.h"
|
||||
#include "OGXMini/OGXMini.h"
|
||||
#include "TaskQueue/TaskQueue.h"
|
||||
#include "Gamepad/Gamepad.h"
|
||||
#include "Board/board_api.h"
|
||||
#include "Board/ogxm_log.h"
|
||||
|
||||
namespace OGXMini {
|
||||
constexpr uint32_t FEEDBACK_DELAY_MS = 200;
|
||||
|
||||
Gamepad gamepads_[MAX_GAMEPADS];
|
||||
Gamepad _gamepads[MAX_GAMEPADS];
|
||||
|
||||
//Called by tusb host so we know to connect or disconnect usb
|
||||
void host_mounted(bool host_mounted)
|
||||
{
|
||||
static std::atomic<bool> tud_is_inited = false;
|
||||
|
||||
board_api::set_led(host_mounted);
|
||||
|
||||
if (!host_mounted && tud_is_inited.load())
|
||||
{
|
||||
TaskQueue::Core0::queue_task([]()
|
||||
{
|
||||
OGXM_LOG("USB disconnected, rebooting.\n");
|
||||
board_api::usb::disconnect_all();
|
||||
board_api::reboot();
|
||||
});
|
||||
}
|
||||
else if (!tud_is_inited.load())
|
||||
{
|
||||
TaskQueue::Core0::queue_task([]()
|
||||
{
|
||||
tud_init(BOARD_TUD_RHPORT);
|
||||
tud_is_inited.store(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void core1_task()
|
||||
{
|
||||
void core1_task() {
|
||||
HostManager& host_manager = HostManager::get_instance();
|
||||
host_manager.initialize(gamepads_);
|
||||
host_manager.initialize(_gamepads);
|
||||
|
||||
//Pico-PIO-USB will not reliably detect a hot plug on some boards, monitor and init host stack after connection
|
||||
while(!board_api::usb::host_connected())
|
||||
{
|
||||
//Pico-PIO-USB will not reliably detect a hot plug on some boards,
|
||||
//monitor and init host stack after connection
|
||||
while(!board_api::usb::host_connected()) {
|
||||
sleep_ms(100);
|
||||
}
|
||||
|
||||
@@ -62,25 +35,24 @@ void core1_task()
|
||||
tuh_init(BOARD_TUH_RHPORT);
|
||||
|
||||
uint32_t tid_feedback = TaskQueue::Core1::get_new_task_id();
|
||||
TaskQueue::Core1::queue_delayed_task(tid_feedback, FEEDBACK_DELAY_MS, true, [&host_manager]
|
||||
{
|
||||
TaskQueue::Core1::queue_delayed_task(tid_feedback, FEEDBACK_DELAY_MS, true,
|
||||
[&host_manager] {
|
||||
host_manager.send_feedback();
|
||||
});
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (true) {
|
||||
TaskQueue::Core1::process_tasks();
|
||||
tuh_task();
|
||||
}
|
||||
}
|
||||
|
||||
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]
|
||||
{
|
||||
void set_gp_check_timer(uint32_t task_id) {
|
||||
UserSettings& user_settings = UserSettings::get_instance();
|
||||
|
||||
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]))
|
||||
{
|
||||
if (user_settings.check_for_driver_change(_gamepads[0])) {
|
||||
OGXM_LOG("Driver change detected, storing new driver.\n");
|
||||
//This will store the new mode and reboot the pico
|
||||
user_settings.store_driver_type(user_settings.get_current_driver());
|
||||
@@ -88,58 +60,75 @@ void set_gp_check_timer(uint32_t task_id, UserSettings& user_settings)
|
||||
});
|
||||
}
|
||||
|
||||
void run_program()
|
||||
{
|
||||
//Called by tusb host so we know to connect or disconnect usb
|
||||
void standard::host_mounted(bool host_mounted) {
|
||||
static std::atomic<bool> tud_is_inited = false;
|
||||
board_api::set_led(host_mounted);
|
||||
|
||||
if (!host_mounted && tud_is_inited.load()) {
|
||||
TaskQueue::Core0::queue_task([]() {
|
||||
OGXM_LOG("USB disconnected, rebooting.\n");
|
||||
board_api::usb::disconnect_all();
|
||||
board_api::reboot();
|
||||
});
|
||||
} else if (!tud_is_inited.load()) {
|
||||
TaskQueue::Core0::queue_task([]() {
|
||||
tud_init(BOARD_TUD_RHPORT);
|
||||
tud_is_inited.store(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void standard::initialize() {
|
||||
board_api::init_board();
|
||||
|
||||
UserSettings& user_settings = UserSettings::get_instance();
|
||||
user_settings.initialize_flash();
|
||||
|
||||
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
|
||||
{
|
||||
gamepads_[i].set_profile(user_settings.get_profile_by_index(i));
|
||||
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i) {
|
||||
_gamepads[i].set_profile(user_settings.get_profile_by_index(i));
|
||||
}
|
||||
|
||||
DeviceDriverType current_driver = user_settings.get_current_driver();
|
||||
DeviceManager& device_manager = DeviceManager::get_instance();
|
||||
device_manager.initialize_driver(current_driver, gamepads_);
|
||||
DeviceManager::get_instance().initialize_driver(user_settings.get_current_driver(), _gamepads);
|
||||
}
|
||||
|
||||
void standard::run() {
|
||||
multicore_reset_core1();
|
||||
multicore_launch_core1(core1_task);
|
||||
|
||||
if (current_driver != DeviceDriverType::WEBAPP)
|
||||
{
|
||||
DeviceDriverType current_driver = UserSettings::get_instance().get_current_driver();
|
||||
|
||||
if (current_driver != DeviceDriverType::WEBAPP) {
|
||||
// Wait for something to call host_mounted()
|
||||
while (!tud_inited())
|
||||
{
|
||||
while (!tud_inited()) {
|
||||
TaskQueue::Core0::process_tasks();
|
||||
sleep_ms(100);
|
||||
}
|
||||
}
|
||||
else //Connect immediately in WebApp mode
|
||||
{
|
||||
} else {
|
||||
//Connect immediately in WebApp mode
|
||||
host_mounted(true);
|
||||
}
|
||||
|
||||
uint32_t tid_gp_check = TaskQueue::Core0::get_new_task_id();
|
||||
set_gp_check_timer(tid_gp_check, user_settings);
|
||||
set_gp_check_timer(tid_gp_check);
|
||||
|
||||
DeviceDriver* device_driver = device_manager.get_driver();
|
||||
DeviceDriver* device_driver = DeviceManager::get_instance().get_driver();
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (true) {
|
||||
TaskQueue::Core0::process_tasks();
|
||||
|
||||
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
|
||||
{
|
||||
device_driver->process(i, gamepads_[i]);
|
||||
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i) {
|
||||
device_driver->process(i, _gamepads[i]);
|
||||
}
|
||||
|
||||
tud_task();
|
||||
sleep_us(100);
|
||||
sleep_ms(1);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OGXMini
|
||||
// #else // OGXM_BOARD == PI_PICO || OGXM_BOARD == RP2040_ZERO || OGXM_BOARD == ADAFRUIT_FEATHER
|
||||
|
||||
#endif // (OGXM_BOARD == ADA_FEATHER) || (OGXM_BOARD == RP_ZERO) || (OGXM_BOARD == PI_PICO) || (OGXM_BOARD == PI_PICO2)
|
||||
// void standard::host_mounted(bool host_mounted) {}
|
||||
// void standard::initialize() {}
|
||||
// void standard::run() {}
|
||||
|
||||
#endif // OGXM_BOARD == PI_PICO || OGXM_BOARD == RP2040_ZERO || OGXM_BOARD == ADAFRUIT_FEATHER
|
||||
9
Firmware/RP2040/src/OGXMini/Board/Standard.h
Normal file
9
Firmware/RP2040/src/OGXMini/Board/Standard.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace standard {
|
||||
void initialize();
|
||||
void run();
|
||||
void host_mounted(bool mounted);
|
||||
} // namespace standard
|
||||
103
Firmware/RP2040/src/OGXMini/OGXMini.cpp
Normal file
103
Firmware/RP2040/src/OGXMini/OGXMini.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
#include "Board/Config.h"
|
||||
#include "OGXMini/Board/Standard.h"
|
||||
#include "OGXMini/Board/PicoW.h"
|
||||
#include "OGXMini/Board/Four_Channel_I2C.h"
|
||||
#include "OGXMini/Board/ESP32_Blueretro_I2C.h"
|
||||
#include "OGXMini/Board/ESP32_Bluepad32_I2C.h"
|
||||
#include "OGXMini/OGXMini.h"
|
||||
|
||||
namespace OGXMini {
|
||||
typedef void (*InitFunc)();
|
||||
typedef void (*RunFunc)();
|
||||
typedef void (*HostMountedFunc)(bool mounted);
|
||||
typedef void (*HostMountedWTypeFunc)(bool mounted, HostDriverType host_type);
|
||||
typedef void (*WirelessConnectedFunc)(bool connected, uint8_t idx);
|
||||
|
||||
static constexpr InitFunc init_func[BOARDS_COUNT] = {
|
||||
standard::initialize, // PI_PICO
|
||||
standard::initialize, // RP2040_ZERO
|
||||
standard::initialize, // ADAFRUIT_FEATHER
|
||||
pico_w::initialize, // PI_PICOW
|
||||
esp32_bp32_i2c::initialize, // ESP32_BLUEPAD32_I2C
|
||||
esp32_br_i2c::initialize, // ESP32_BLUERETRO_I2C
|
||||
four_ch_i2c::initialize, // EXTERNAL_4CH_I2C
|
||||
four_ch_i2c::initialize, // INTERNAL_4CH_I2C
|
||||
};
|
||||
|
||||
static constexpr RunFunc run_func[BOARDS_COUNT] = {
|
||||
standard::run, // PI_PICO
|
||||
standard::run, // RP2040_ZERO
|
||||
standard::run, // ADAFRUIT_FEATHER
|
||||
pico_w::run, // PI_PICOW
|
||||
esp32_bp32_i2c::run, // ESP32_BLUEPAD32_I2C
|
||||
esp32_br_i2c::run, // ESP32_BLUERETRO_I2C
|
||||
four_ch_i2c::run, // EXTERNAL_4CH_I2C
|
||||
four_ch_i2c::run, // INTERNAL_4CH_I2C
|
||||
};
|
||||
|
||||
static constexpr HostMountedFunc host_mount_func[BOARDS_COUNT] = {
|
||||
standard::host_mounted, // PI_PICO
|
||||
standard::host_mounted, // RP2040_ZERO
|
||||
standard::host_mounted, // ADAFRUIT_FEATHER
|
||||
nullptr, // PI_PICOW
|
||||
nullptr, // ESP32_BLUEPAD32_I2C
|
||||
nullptr, // ESP32_BLUERETRO_I2C
|
||||
four_ch_i2c::host_mounted, // EXTERNAL_4CH_I2C
|
||||
four_ch_i2c::host_mounted, // INTERNAL_4CH_I2C
|
||||
};
|
||||
|
||||
static constexpr HostMountedWTypeFunc host_mount_w_type_func[BOARDS_COUNT] = {
|
||||
nullptr, // PI_PICO
|
||||
nullptr, // RP2040_ZERO
|
||||
nullptr, // ADAFRUIT_FEATHER
|
||||
nullptr, // PI_PICOW
|
||||
nullptr, // ESP32_BLUEPAD32_I2C
|
||||
nullptr, // ESP32_BLUERETRO_I2C
|
||||
four_ch_i2c::host_mounted_w_type, // EXTERNAL_4CH_I2C
|
||||
four_ch_i2c::host_mounted_w_type, // INTERNAL_4CH_I2C
|
||||
};
|
||||
|
||||
static constexpr WirelessConnectedFunc wl_conn_func[BOARDS_COUNT] = {
|
||||
nullptr, // PI_PICO
|
||||
nullptr, // RP2040_ZERO
|
||||
nullptr, // ADAFRUIT_FEATHER
|
||||
nullptr, // PI_PICOW
|
||||
nullptr, // ESP32_BLUEPAD32_I2C
|
||||
nullptr, // ESP32_BLUERETRO_I2C
|
||||
four_ch_i2c::wireless_connected, // EXTERNAL_4CH_I2C
|
||||
four_ch_i2c::wireless_connected, // INTERNAL_4CH_I2C
|
||||
};
|
||||
|
||||
void initialize() {
|
||||
if (init_func[OGXM_BOARD] != nullptr) {
|
||||
init_func[OGXM_BOARD]();
|
||||
}
|
||||
}
|
||||
|
||||
void run() {
|
||||
if (run_func[OGXM_BOARD] != nullptr) {
|
||||
run_func[OGXM_BOARD]();
|
||||
}
|
||||
}
|
||||
|
||||
void host_mounted(bool mounted, HostDriverType host_type) {
|
||||
if (host_mount_w_type_func[OGXM_BOARD] != nullptr) {
|
||||
host_mount_w_type_func[OGXM_BOARD](mounted, host_type);
|
||||
} else if (host_mount_func[OGXM_BOARD] != nullptr) {
|
||||
host_mount_func[OGXM_BOARD](mounted);
|
||||
}
|
||||
}
|
||||
|
||||
void host_mounted(bool mounted) {
|
||||
if (host_mount_func[OGXM_BOARD] != nullptr) {
|
||||
host_mount_func[OGXM_BOARD](mounted);
|
||||
}
|
||||
}
|
||||
|
||||
void wireless_connected(bool connected, uint8_t idx) {
|
||||
if (wl_conn_func[OGXM_BOARD] != nullptr) {
|
||||
wl_conn_func[OGXM_BOARD](connected, idx);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OGXMini
|
||||
@@ -1,18 +1,13 @@
|
||||
#ifndef _OGX_MINI_H_
|
||||
#define _OGX_MINI_H_
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "UserSettings/UserSettings.h"
|
||||
#include "USBHost/HostDriver/HostDriverTypes.h"
|
||||
|
||||
namespace OGXMini
|
||||
{
|
||||
static constexpr int32_t FEEDBACK_DELAY_MS = 150;
|
||||
static constexpr int32_t TUD_CHECK_DELAY_MS = 500;
|
||||
|
||||
void run_program();
|
||||
namespace OGXMini {
|
||||
void initialize();
|
||||
void run();
|
||||
void host_mounted(bool mounted, HostDriverType host_type);
|
||||
void host_mounted(bool mounted);
|
||||
|
||||
void wireless_connected(bool connected, uint8_t idx);
|
||||
} // namespace OGXMini
|
||||
|
||||
#endif // _OGX_MINI_H_
|
||||
@@ -1,141 +0,0 @@
|
||||
#include "board_config.h"
|
||||
#if OGXM_BOARD == INTERNAL_4CH || OGXM_BOARD == EXTERNAL_4CH
|
||||
|
||||
#include <pico/multicore.h>
|
||||
|
||||
#include "tusb.h"
|
||||
#include "bsp/board_api.h"
|
||||
#include "pio_usb.h"
|
||||
|
||||
#include "USBDevice/DeviceManager.h"
|
||||
#include "USBHost/HostManager.h"
|
||||
#include "Board/board_api.h"
|
||||
#include "Board/ogxm_log.h"
|
||||
#include "OGXMini/OGXMini.h"
|
||||
#include "I2CDriver/4Channel/I2CManager.h"
|
||||
#include "Gamepad.h"
|
||||
#include "TaskQueue/TaskQueue.h"
|
||||
|
||||
namespace OGXMini {
|
||||
|
||||
Gamepad gamepads_[MAX_GAMEPADS];
|
||||
|
||||
//Called by tusb host or i2c driver so we know to connect or disconnect usb
|
||||
void host_mounted(bool host_mounted)
|
||||
{
|
||||
static std::atomic<bool> tud_is_inited = false;
|
||||
|
||||
board_api::set_led(host_mounted);
|
||||
|
||||
if (!host_mounted && tud_is_inited.load())
|
||||
{
|
||||
TaskQueue::Core0::queue_task([]()
|
||||
{
|
||||
OGXM_LOG("Disconnecting USB and rebooting.\n");
|
||||
board_api::usb::disconnect_all();
|
||||
board_api::reboot();
|
||||
});
|
||||
}
|
||||
else if (!tud_is_inited.load() && host_mounted)
|
||||
{
|
||||
TaskQueue::Core0::queue_task([]()
|
||||
{
|
||||
OGXM_LOG("Initializing USB stack.\n");
|
||||
tud_init(BOARD_TUD_RHPORT);
|
||||
tud_is_inited.store(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void core1_task()
|
||||
{
|
||||
HostManager& host_manager = HostManager::get_instance();
|
||||
host_manager.initialize(gamepads_);
|
||||
|
||||
//Pico-PIO-USB will not reliably detect a hot plug on some boards, so monitor and init host stack after connection
|
||||
while(!board_api::usb::host_connected())
|
||||
{
|
||||
sleep_ms(100);
|
||||
}
|
||||
|
||||
pio_usb_configuration_t pio_cfg = PIO_USB_CONFIG;
|
||||
tuh_configure(BOARD_TUH_RHPORT, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, &pio_cfg);
|
||||
|
||||
tuh_init(BOARD_TUH_RHPORT);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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(user_settings.get_current_driver());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void run_program()
|
||||
{
|
||||
UserSettings& user_settings = UserSettings::get_instance();
|
||||
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& device_manager = DeviceManager::get_instance();
|
||||
device_manager.initialize_driver(user_settings.get_current_driver(), gamepads_);
|
||||
|
||||
I2CManager& i2c_manager = I2CManager::get_instance();
|
||||
i2c_manager.initialize_driver();
|
||||
|
||||
multicore_reset_core1();
|
||||
multicore_launch_core1(core1_task);
|
||||
|
||||
//Wait for something to call tud_init
|
||||
while (!tud_inited())
|
||||
{
|
||||
TaskQueue::Core0::process_tasks();
|
||||
sleep_ms(10);
|
||||
}
|
||||
|
||||
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();
|
||||
I2CDriver* i2c_driver = i2c_manager.get_driver();
|
||||
|
||||
while (true)
|
||||
{
|
||||
TaskQueue::Core0::process_tasks();
|
||||
|
||||
i2c_driver->process(gamepads_);
|
||||
device_driver->process(0, gamepads_[0]);
|
||||
|
||||
tud_task();
|
||||
sleep_us(100);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OGXMini
|
||||
|
||||
#endif // OGXM_BOARD == INTERNAL_4CH || OGXM_BOARD == EXTERNAL_4CH
|
||||
@@ -1,101 +0,0 @@
|
||||
#include "board_config.h"
|
||||
#if (OGXM_BOARD == PICO_ESP32)
|
||||
|
||||
#include <pico/multicore.h>
|
||||
|
||||
#include "tusb.h"
|
||||
#include "bsp/board_api.h"
|
||||
|
||||
#include "USBDevice/DeviceManager.h"
|
||||
#include "Board/board_api.h"
|
||||
#include "OGXMini/OGXMini.h"
|
||||
#include "I2CDriver/ESP32/I2CDriver.h"
|
||||
#include "Gamepad/Gamepad.h"
|
||||
#include "TaskQueue/TaskQueue.h"
|
||||
|
||||
namespace OGXMini {
|
||||
|
||||
static Gamepad gamepads_[MAX_GAMEPADS];
|
||||
|
||||
//Not using this for ESP32 currently
|
||||
void host_mounted(bool host_mounted) { }
|
||||
|
||||
void core1_task()
|
||||
{
|
||||
I2CDriver::initialize(gamepads_);
|
||||
|
||||
while (true)
|
||||
{
|
||||
tight_loop_contents();
|
||||
}
|
||||
}
|
||||
|
||||
void run_uart_bridge(UserSettings& user_settings)
|
||||
{
|
||||
DeviceManager& device_manager = DeviceManager::get_instance();
|
||||
device_manager.initialize_driver(DeviceDriverType::UART_BRIDGE, gamepads_);
|
||||
|
||||
board_api::esp32::enter_programming_mode();
|
||||
|
||||
OGXM_LOG("Entering UART Bridge mode\n");
|
||||
|
||||
device_manager.get_driver()->process(0, gamepads_[0]); //Runs UART Bridge task, doesn't return unless programming is complete
|
||||
|
||||
OGXM_LOG("Exiting UART Bridge mode\n");
|
||||
|
||||
board_api::usb::disconnect_all();
|
||||
user_settings.write_datetime();
|
||||
board_api::reboot();
|
||||
}
|
||||
|
||||
bool update_needed(UserSettings& user_settings)
|
||||
{
|
||||
#if defined(OGXM_ESP32_RETAIL)
|
||||
return !user_settings.verify_datetime();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void run_program()
|
||||
{
|
||||
board_api::init_board();
|
||||
|
||||
UserSettings& user_settings = UserSettings::get_instance();
|
||||
user_settings.initialize_flash();
|
||||
|
||||
//MODE_SEL_PIN is used to determine if UART bridge should be run
|
||||
if (board_api::esp32::uart_bridge_mode() || update_needed(user_settings))
|
||||
{
|
||||
run_uart_bridge(user_settings);
|
||||
return;
|
||||
}
|
||||
|
||||
DeviceManager& device_manager = DeviceManager::get_instance();
|
||||
device_manager.initialize_driver(user_settings.get_current_driver(), gamepads_);
|
||||
|
||||
multicore_reset_core1();
|
||||
multicore_launch_core1(core1_task);
|
||||
|
||||
// board_api::esp32::reset();
|
||||
|
||||
DeviceDriver* device_driver = device_manager.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]);
|
||||
tud_task();
|
||||
}
|
||||
|
||||
sleep_us(100);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OGXMini
|
||||
|
||||
#endif // OGXM_BOARD == W_ESP32
|
||||
@@ -3,7 +3,7 @@
|
||||
TaskQueue::TaskQueue(CoreNum core_num)
|
||||
{
|
||||
alarm_num_ = (core_num == CoreNum::Core0) ? 0 : 1;
|
||||
alarm_num_ += ((OGXM_BOARD == PI_PICOW) || (OGXM_BOARD == PI_PICO2W)) ? 1 : 0; //BTStack uses alarm 0
|
||||
alarm_num_ += (OGXM_BOARD == PI_PICOW) ? 1 : 0; //BTStack uses alarm 0
|
||||
|
||||
hw_set_bits(&timer_hw->inte, 1u << alarm_num_);
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <hardware/irq.h>
|
||||
#include <hardware/sync.h>
|
||||
|
||||
#include "board_config.h"
|
||||
#include "Board/Config.h"
|
||||
|
||||
class TaskQueue
|
||||
{
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#if (OGXM_BOARD != PI_PICOW) && (OGXM_BOARD != PI_PICO2W) //BTstack uses core1
|
||||
#if (OGXM_BOARD != PI_PICOW) //BTstack uses core1
|
||||
struct Core1
|
||||
{
|
||||
static inline uint32_t get_new_task_id()
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
|
||||
#include "board_config.h"
|
||||
#include "Board/Config.h"
|
||||
#include "USBDevice/DeviceDriver/DeviceDriver.h"
|
||||
#include "Descriptors/DInput.h"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "tusb.h"
|
||||
|
||||
#include "board_config.h"
|
||||
#include "Board/Config.h"
|
||||
#include "USBDevice/DeviceDriver/PSClassic/PSClassic.h"
|
||||
#include "USBDevice/DeviceDriver/XInput/XInput.h"
|
||||
#include "USBDevice/DeviceDriver/Switch/Switch.h"
|
||||
@@ -16,11 +16,12 @@
|
||||
#include "USBDevice/DeviceDriver/UARTBridge/UARTBridge.h"
|
||||
#endif // defined(CONFIG_EN_UART_BRIDGE)
|
||||
|
||||
void DeviceManager::initialize_driver(DeviceDriverType driver_type, Gamepad(&gamepads)[MAX_GAMEPADS])
|
||||
{
|
||||
bool has_analog = false; //TODO: Put gamepad setup in the drivers themselves
|
||||
switch (driver_type)
|
||||
{
|
||||
void DeviceManager::initialize_driver( DeviceDriverType driver_type,
|
||||
Gamepad(&gamepads)[MAX_GAMEPADS]) {
|
||||
//TODO: Put gamepad setup in the drivers themselves
|
||||
bool has_analog = false;
|
||||
|
||||
switch (driver_type) {
|
||||
case DeviceDriverType::DINPUT:
|
||||
has_analog = true;
|
||||
device_driver_ = std::make_unique<DInputDevice>();
|
||||
@@ -60,10 +61,8 @@ void DeviceManager::initialize_driver(DeviceDriverType driver_type, Gamepad(&gam
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_analog)
|
||||
{
|
||||
for (size_t i = 0; i < MAX_GAMEPADS; ++i)
|
||||
{
|
||||
if (has_analog) {
|
||||
for (size_t i = 0; i < MAX_GAMEPADS; ++i) {
|
||||
gamepads[i].set_analog_device(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,14 +7,12 @@
|
||||
#include "USBDevice/DeviceDriver/DeviceDriverTypes.h"
|
||||
#include "USBDevice/DeviceDriver/DeviceDriver.h"
|
||||
|
||||
class DeviceManager
|
||||
{
|
||||
class DeviceManager {
|
||||
public:
|
||||
DeviceManager(DeviceManager const&) = delete;
|
||||
void operator=(DeviceManager const&) = delete;
|
||||
|
||||
static DeviceManager& get_instance()
|
||||
{
|
||||
static DeviceManager& get_instance() {
|
||||
static DeviceManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <hardware/structs/usb.h>
|
||||
#include <hardware/resets.h>
|
||||
|
||||
#include "board_config.h"
|
||||
#include "Board/Config.h"
|
||||
#include "USBHost/HardwareIDs.h"
|
||||
#include "USBHost/HostDriver/XInput/tuh_xinput/tuh_xinput.h"
|
||||
#include "USBHost/HostDriver/HostDriver.h"
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include <cstdint>
|
||||
#include <atomic>
|
||||
#include <pico/stdlib.h>
|
||||
|
||||
#include "tusb.h"
|
||||
#include "host/usbh.h"
|
||||
@@ -10,108 +8,71 @@
|
||||
#include "USBHost/HostManager.h"
|
||||
#include "OGXMini/OGXMini.h"
|
||||
|
||||
#if defined(CONFIG_EN_4CH)
|
||||
#include "I2CDriver/4Channel/I2CManager.h"
|
||||
#endif
|
||||
|
||||
usbh_class_driver_t const* usbh_app_driver_get_cb(uint8_t* driver_count)
|
||||
{
|
||||
usbh_class_driver_t const* usbh_app_driver_get_cb(uint8_t* driver_count) {
|
||||
*driver_count = 1;
|
||||
return tuh_xinput::class_driver();
|
||||
}
|
||||
|
||||
//HID
|
||||
|
||||
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len)
|
||||
{
|
||||
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) {
|
||||
uint16_t vid, pid;
|
||||
tuh_vid_pid_get(dev_addr, &vid, &pid);
|
||||
|
||||
HostManager& host_manager = HostManager::get_instance();
|
||||
|
||||
if (host_manager.setup_driver(HostManager::get_type({ vid, pid }), dev_addr, instance, desc_report, desc_len))
|
||||
{
|
||||
#if defined(CONFIG_EN_4CH)
|
||||
I2CManager::get_instance().get_driver()->notify_tuh(true);
|
||||
#endif
|
||||
|
||||
if (host_manager.setup_driver(HostManager::get_type({ vid, pid }), dev_addr, instance, desc_report, desc_len)) {
|
||||
OGXMini::host_mounted(true);
|
||||
}
|
||||
}
|
||||
|
||||
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
|
||||
{
|
||||
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
|
||||
HostManager& host_manager = HostManager::get_instance();
|
||||
host_manager.deinit_driver(HostManager::DriverClass::HID, dev_addr, instance);
|
||||
|
||||
if (!host_manager.any_mounted())
|
||||
{
|
||||
#if defined(CONFIG_EN_4CH)
|
||||
I2CManager::get_instance().get_driver()->notify_tuh(false);
|
||||
#endif
|
||||
|
||||
if (!host_manager.any_mounted()) {
|
||||
OGXMini::host_mounted(false);
|
||||
}
|
||||
}
|
||||
|
||||
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
|
||||
{
|
||||
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {
|
||||
HostManager::get_instance().process_report(dev_addr, instance, report, len);
|
||||
}
|
||||
|
||||
//XINPUT
|
||||
|
||||
void tuh_xinput::mount_cb(uint8_t dev_addr, uint8_t instance, const tuh_xinput::Interface* interface)
|
||||
{
|
||||
void tuh_xinput::mount_cb(uint8_t dev_addr, uint8_t instance, const tuh_xinput::Interface* interface) {
|
||||
HostManager& host_manager = HostManager::get_instance();
|
||||
HostDriverType host_type = HostManager::get_type(interface->dev_type);
|
||||
|
||||
if (host_manager.setup_driver(host_type, dev_addr, instance))
|
||||
{
|
||||
#if defined(CONFIG_EN_4CH)
|
||||
I2CManager::get_instance().get_driver()->notify_tuh(true, host_type);
|
||||
#endif
|
||||
|
||||
OGXMini::host_mounted(true);
|
||||
if (host_manager.setup_driver(host_type, dev_addr, instance)) {
|
||||
OGXMini::host_mounted(true, host_type);
|
||||
}
|
||||
}
|
||||
|
||||
void tuh_xinput::unmount_cb(uint8_t dev_addr, uint8_t instance, const tuh_xinput::Interface* interface)
|
||||
{
|
||||
void tuh_xinput::unmount_cb(uint8_t dev_addr, uint8_t instance, const tuh_xinput::Interface* interface) {
|
||||
HostManager& host_manager = HostManager::get_instance();
|
||||
host_manager.deinit_driver(HostManager::DriverClass::XINPUT, dev_addr, instance);
|
||||
|
||||
if (!host_manager.any_mounted())
|
||||
{
|
||||
#if defined(CONFIG_EN_4CH)
|
||||
I2CManager::get_instance().get_driver()->notify_tuh(false, host_manager.get_type(interface->dev_type));
|
||||
#endif
|
||||
|
||||
if (!host_manager.any_mounted()) {
|
||||
OGXMini::host_mounted(false);
|
||||
}
|
||||
}
|
||||
|
||||
void tuh_xinput::report_received_cb(uint8_t dev_addr, uint8_t instance, const uint8_t* report, uint16_t len)
|
||||
{
|
||||
void tuh_xinput::report_received_cb(uint8_t dev_addr, uint8_t instance, const uint8_t* report, uint16_t len) {
|
||||
HostManager::get_instance().process_report(dev_addr, instance, report, len);
|
||||
}
|
||||
|
||||
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(true, idx);
|
||||
#endif
|
||||
|
||||
void tuh_xinput::xbox360w_connect_cb(uint8_t dev_addr, uint8_t instance) {
|
||||
uint8_t idx = HostManager::get_instance().get_gamepad_idx( HostManager::DriverClass::XINPUT,
|
||||
dev_addr, instance);
|
||||
OGXMini::wireless_connected(true, idx);
|
||||
HostManager::get_instance().connect_cb(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(false, idx);
|
||||
#endif
|
||||
|
||||
void tuh_xinput::xbox360w_disconnect_cb(uint8_t dev_addr, uint8_t instance) {
|
||||
uint8_t idx = HostManager::get_instance().get_gamepad_idx( HostManager::DriverClass::XINPUT,
|
||||
dev_addr, instance);
|
||||
OGXMini::wireless_connected(false, idx);
|
||||
HostManager::get_instance().disconnect_cb(dev_addr, instance);
|
||||
}
|
||||
@@ -13,8 +13,8 @@
|
||||
class NVSTool
|
||||
{
|
||||
public:
|
||||
static constexpr size_t KEY_LEN_MAX = 16; //Including null terminator
|
||||
static constexpr size_t VALUE_LEN_MAX = FLASH_PAGE_SIZE - KEY_LEN_MAX;
|
||||
static constexpr size_t KEY_LEN_MAX = 16; //Including null terminator
|
||||
static constexpr size_t VALUE_LEN_MAX = FLASH_PAGE_SIZE - KEY_LEN_MAX;
|
||||
static constexpr uint32_t MAX_ENTRIES = ((NVS_SECTORS * FLASH_SECTOR_SIZE) / FLASH_PAGE_SIZE) - 1;
|
||||
|
||||
static NVSTool& get_instance()
|
||||
|
||||
@@ -9,13 +9,11 @@
|
||||
#include "Board/board_api.h"
|
||||
#include "UserSettings/UserSettings.h"
|
||||
|
||||
static constexpr uint32_t BUTTON_COMBO(const uint16_t& buttons, const uint8_t& dpad = 0)
|
||||
{
|
||||
static constexpr uint32_t BUTTON_COMBO(const uint16_t& buttons, const uint8_t& dpad = 0) {
|
||||
return (static_cast<uint32_t>(buttons) << 16) | static_cast<uint32_t>(dpad);
|
||||
}
|
||||
|
||||
namespace ButtonCombo
|
||||
{
|
||||
namespace ButtonCombo {
|
||||
static constexpr uint32_t PS3 = BUTTON_COMBO(Gamepad::BUTTON_START, Gamepad::DPAD_LEFT);
|
||||
static constexpr uint32_t DINPUT = BUTTON_COMBO(Gamepad::BUTTON_START | Gamepad::BUTTON_RB, Gamepad::DPAD_LEFT);
|
||||
static constexpr uint32_t XINPUT = BUTTON_COMBO(Gamepad::BUTTON_START, Gamepad::DPAD_UP);
|
||||
@@ -27,8 +25,7 @@ namespace ButtonCombo
|
||||
static constexpr uint32_t WEBAPP = BUTTON_COMBO(Gamepad::BUTTON_START | Gamepad::BUTTON_LB | Gamepad::BUTTON_RB);
|
||||
};
|
||||
|
||||
static constexpr DeviceDriverType VALID_DRIVER_TYPES[] =
|
||||
{
|
||||
static constexpr DeviceDriverType VALID_DRIVER_TYPES[] = {
|
||||
#if defined(CONFIG_EN_4CH)
|
||||
DeviceDriverType::XBOXOG,
|
||||
DeviceDriverType::XBOXOG_SB,
|
||||
@@ -61,9 +58,12 @@ static constexpr DeviceDriverType VALID_DRIVER_TYPES[] =
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ComboMap { uint32_t combo; DeviceDriverType driver; };
|
||||
static constexpr std::array<ComboMap, 9> BUTTON_COMBO_MAP =
|
||||
{{
|
||||
struct ComboMap {
|
||||
uint32_t combo;
|
||||
DeviceDriverType driver;
|
||||
};
|
||||
|
||||
static constexpr std::array<ComboMap, 9> BUTTON_COMBO_MAP = {{
|
||||
{ ButtonCombo::XBOXOG, DeviceDriverType::XBOXOG },
|
||||
{ ButtonCombo::XBOXOG_SB, DeviceDriverType::XBOXOG_SB },
|
||||
{ ButtonCombo::XBOXOG_XR, DeviceDriverType::XBOXOG_XR },
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "board_config.h"
|
||||
#include "Board/Config.h"
|
||||
#include "USBDevice/DeviceDriver/DeviceDriverTypes.h"
|
||||
#include "UserSettings/UserProfile.h"
|
||||
#include "UserSettings/NVSTool.h"
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
#ifndef _OGXM_BOARD_CONFIG_H_
|
||||
#define _OGXM_BOARD_CONFIG_H_
|
||||
|
||||
/* Don't edit this file directly, instead use CMake to configure the board.
|
||||
Add args -DOGXM_BOARD=PI_PICO and -DMAX_GAMEPADS=1 (or = whatever option you want)
|
||||
to set the board and the number of gamepads.
|
||||
If you're setting MAX_GAMEPADS > 1 only D-Input, Switch, and WebApp device drivers will work. */
|
||||
|
||||
#define PI_PICO 1
|
||||
#define PI_PICO2 2
|
||||
#define PI_PICOW 3
|
||||
#define PI_PICO2W 4
|
||||
#define RP_ZERO 5
|
||||
#define ADA_FEATHER 6
|
||||
#define INTERNAL_4CH 7
|
||||
#define EXTERNAL_4CH 8
|
||||
#define PICO_ESP32 9
|
||||
|
||||
#define SYSCLOCK_KHZ 240000
|
||||
|
||||
#ifdef PICO_BOARD
|
||||
#define O_BOARD PICO_BOARD
|
||||
#endif
|
||||
|
||||
#ifndef MAX_GAMEPADS
|
||||
#define MAX_GAMEPADS 1
|
||||
#endif
|
||||
|
||||
#ifndef OGXM_BOARD
|
||||
#define OGXM_BOARD PI_PICO
|
||||
#endif
|
||||
|
||||
#if OGXM_BOARD == PI_PICO || OGXM_BOARD == PI_PICO2
|
||||
#define PIO_USB_DP_PIN 0 // DM = 1
|
||||
#define LED_INDICATOR_PIN 25
|
||||
|
||||
#elif OGXM_BOARD == PI_PICOW
|
||||
|
||||
#elif OGXM_BOARD == PI_PICO2W
|
||||
// #define LED_INDICATOR_PIN 0
|
||||
|
||||
#elif OGXM_BOARD == RP_ZERO
|
||||
#define RGB_PXL_PIN 16
|
||||
|
||||
#define PIO_USB_DP_PIN 10 // DM = 11
|
||||
#define LED_INDICATOR_PIN 14
|
||||
|
||||
#elif OGXM_BOARD == ADA_FEATHER
|
||||
#define RGB_PWR_PIN 20
|
||||
#define RGB_PXL_PIN 21
|
||||
|
||||
#define PIO_USB_DP_PIN 16 // DM = 17
|
||||
#define LED_INDICATOR_PIN 13
|
||||
#define VCC_EN_PIN 18
|
||||
|
||||
#elif OGXM_BOARD == INTERNAL_4CH
|
||||
#define PIO_USB_DP_PIN 16 // DM = 17
|
||||
#define FOUR_CH_ENABLED 1
|
||||
#define I2C_SDA_PIN 10 // SCL = 11
|
||||
#define SLAVE_ADDR_PIN_1 20
|
||||
#define SLAVE_ADDR_PIN_2 21
|
||||
|
||||
#elif OGXM_BOARD == EXTERNAL_4CH
|
||||
#define RGB_PXL_PIN 16
|
||||
#define FOUR_CH_ENABLED 1
|
||||
#define PIO_USB_DP_PIN 10 // DM = 11
|
||||
|
||||
#define I2C_SDA_PIN 6 // SCL = 7
|
||||
#define SLAVE_ADDR_PIN_1 13
|
||||
#define SLAVE_ADDR_PIN_2 14
|
||||
|
||||
#elif OGXM_BOARD == PICO_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
|
||||
|
||||
#if MAX_GAMEPADS > 1
|
||||
#undef MAX_GAMEPADS
|
||||
#define MAX_GAMEPADS 1
|
||||
#endif
|
||||
|
||||
#endif // OGXM_BOARD
|
||||
|
||||
#if defined(I2C_SDA_PIN)
|
||||
#define I2C_BAUDRATE 1000 * 1000
|
||||
#define I2C_SCL_PIN (I2C_SDA_PIN + 1)
|
||||
#define I2C_PORT ((I2C_SDA_PIN == 2 ) || \
|
||||
(I2C_SDA_PIN == 6 ) || \
|
||||
(I2C_SDA_PIN == 10) || \
|
||||
(I2C_SDA_PIN == 14) || \
|
||||
(I2C_SDA_PIN == 18) || \
|
||||
(I2C_SDA_PIN == 26)) ? i2c1 : i2c0
|
||||
#endif // defined(I2C_SDA_PIN)
|
||||
|
||||
#if defined(CONFIG_EN_4CH)
|
||||
#if MAX_GAMEPADS < 4
|
||||
#undef MAX_GAMEPADS
|
||||
#define MAX_GAMEPADS 4
|
||||
#endif
|
||||
#endif // FOUR_CH_ENABLED
|
||||
|
||||
#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 \
|
||||
}
|
||||
#endif // PIO_USB_DP_PIN
|
||||
|
||||
#if defined(OGXM_DEBUG)
|
||||
//Pins and port are defined in CMakeLists.txt
|
||||
#define DEBUG_UART_PORT __CONCAT(uart,PICO_DEFAULT_UART)
|
||||
#endif // defined(OGXM_DEBUG)
|
||||
|
||||
#endif // _OGXM_BOARD_CONFIG_H_
|
||||
@@ -1,10 +1,9 @@
|
||||
#include <cstdint>
|
||||
#include <hardware/clocks.h>
|
||||
|
||||
#include "OGXMini/OGXMini.h"
|
||||
#include "board_config.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
OGXMini::run_program();
|
||||
int main() {
|
||||
OGXMini::initialize();
|
||||
OGXMini::run();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef _SDK_CONFIG_H_
|
||||
#define _SDK_CONFIG_H_
|
||||
|
||||
#include "board_config.h"
|
||||
#include "Board/Config.h"
|
||||
|
||||
//
|
||||
// Emulate "menuconfig"
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#ifndef _TUSB_CONFIG_H_
|
||||
#define _TUSB_CONFIG_H_
|
||||
|
||||
#include "board_config.h"
|
||||
#include "Board/Config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -127,7 +127,10 @@
|
||||
|
||||
// Enable host stack with pio-usb if Pico-PIO-USB library is available
|
||||
#define CFG_TUH_ENABLED 1
|
||||
|
||||
#if defined(PIO_USB_CONFIG)
|
||||
#define CFG_TUH_RPI_PIO_USB 1
|
||||
#endif
|
||||
|
||||
#define TUH_OPT_RHPORT 1
|
||||
|
||||
|
||||
Reference in New Issue
Block a user