3 Commits

Author SHA1 Message Date
wiredopposite
b9038483ce update to tusb_gamepad lib 2024-05-01 22:13:43 -06:00
wiredopposite
e57de52cc4 new libs 2024-04-24 17:01:51 -06:00
wiredopposite
ee05f9516a use tusb_xinput fork 2024-04-24 16:58:05 -06:00
215 changed files with 4250 additions and 19604 deletions

212
.clang-format Normal file
View File

@@ -0,0 +1,212 @@
---
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveMacros: true
AlignConsecutiveAssignments: true
AlignConsecutiveBitFields: true
AlignConsecutiveDeclarations: true
AlignEscapedNewlines: Left
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: true
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 160
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: true
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^<.*\.h>'
Priority: 1
SortPriority: 0
CaseSensitive: false
- Regex: '^<.*'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 3
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '([-_](test|unittest))?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseLabels: true
IndentCaseBlocks: true
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentRequires: false
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
LambdaBodyIndentation: Signature
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PenaltyIndentedWhitespace: 0
PointerAlignment: Left
PPIndentWidth: -1
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- 'c++'
- 'C++'
CanonicalDelimiter: ''
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
- ParseTestProto
- ParsePartialTestProto
CanonicalDelimiter: pb
BasedOnStyle: google
ReferenceAlignment: Pointer
ReflowComments: true
ShortNamespaceLines: 1
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: true
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard: Auto
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseCRLF: false
UseTab: Never
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
...

17
.gitignore vendored
View File

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

25
.gitmodules vendored
View File

@@ -1,15 +1,12 @@
[submodule "Firmware/external/bluepad32"]
path = Firmware/external/bluepad32
url = https://github.com/ricardoquesada/bluepad32.git
[submodule "Firmware/external/tinyusb"]
path = Firmware/external/tinyusb
[submodule "lib/Pico-PIO-USB"]
path = lib/Pico-PIO-USB
url = https://github.com/sekigon-gonnoc/Pico-PIO-USB.git
[submodule "lib/tinyusb"]
path = lib/tinyusb
url = https://github.com/hathach/tinyusb.git
[submodule "Tools/dump-dvd-kit"]
path = Tools/dump-dvd-kit
url = https://github.com/XboxDev/dump-dvd-kit.git
[submodule "Firmware/external/Pico-PIO-USB"]
path = Firmware/external/Pico-PIO-USB
url = https://github.com/wiredopposite/Pico-PIO-USB.git
[submodule "WebApp"]
path = WebApp
url = https://github.com/wiredopposite/OGX-Mini-WebApp.git
[submodule "lib/tusb_gamepad"]
path = lib/tusb_gamepad
url = https://github.com/wiredopposite/tusb_gamepad.git
[submodule "lib/tusb_xinput"]
path = lib/tusb_xinput
url = https://github.com/wiredopposite/tusb_xinput.git

91
CMakeLists.txt Normal file
View File

@@ -0,0 +1,91 @@
cmake_minimum_required(VERSION 3.12)
set(CMAKE_BUILD_TYPE Release)
message("Build type: \"${CMAKE_BUILD_TYPE}\"")
set(NAME OGX-Mini)
set(PICO_BOARD none)
# Fixes that allow some MCH2022 badges with a slowly starting oscillator to boot properly
# add_compile_definitions(PICO_BOOT_STAGE2_CHOOSE_GENERIC_03H=1 PICO_XOSC_STARTUP_DELAY_MULTIPLIER=64)
# add_compile_options(-Wno-unused-parameter -Wno-unused-variable -Wno-missing-field-initializers -Wno-unused-function)
add_compile_options(-Wno-missing-field-initializers)
include($ENV{PICO_SDK_PATH}/pico_sdk_init.cmake)
project(${NAME} C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
if (PICO_SDK_VERSION_STRING VERSION_LESS "1.3.0")
message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.3.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")
endif()
set(ROOT ${CMAKE_CURRENT_LIST_DIR})
set(PICO_PIO_USB_PATH ${ROOT}/lib/Pico-PIO-USB)
set(PICO_TINYUSB_PATH ${ROOT}/lib/tinyusb)
set(TUSB_GAMEPAD_PATH ${ROOT}/lib/tusb_gamepad)
set(XINPUT_HOST_PATH ${ROOT}/lib/tusb_xinput)
pico_sdk_init()
# add_subdirectory(${ROOT}/lib)
add_subdirectory(${ROOT}/lib/CRC32 CRC32)
add_subdirectory(${XINPUT_HOST_PATH} xinput_host)
add_subdirectory(${PICO_PIO_USB_PATH})
add_subdirectory(${TUSB_GAMEPAD_PATH})
target_include_directories(tusb_gamepad PRIVATE ${ROOT}/src) # so tusb_gamepad can see tusb_config.h
set(SRC_DIR ${ROOT}/src)
file(GLOB_RECURSE SOURCES
${SRC_DIR}/main.cpp
${SRC_DIR}/input_mode.cpp
${SRC_DIR}/usbh/tusb_host_manager.cpp
${SRC_DIR}/usbh/tusb_host.cpp
${SRC_DIR}/usbh/n64usb/N64USB.cpp
${SRC_DIR}/usbh/ps3/Dualshock3.cpp
${SRC_DIR}/usbh/ps3/DInput.cpp
${SRC_DIR}/usbh/ps4/Dualshock4.cpp
${SRC_DIR}/usbh/ps5/Dualsense.cpp
${SRC_DIR}/usbh/psclassic/PSClassic.cpp
${SRC_DIR}/usbh/switch/SwitchPro.cpp
${SRC_DIR}/usbh/switch/SwitchWired.cpp
${SRC_DIR}/usbh/xinput/XInput.cpp
${SRC_DIR}/usbh/shared/hid_class_driver.c
${SRC_DIR}/usbh/shared/scaling.cpp
)
# Firmware
add_executable(${NAME} ${SOURCES})
target_include_directories(${NAME} PUBLIC
${ROOT}/src
${ROOT}/lib)
target_link_libraries(${NAME}
pico_stdlib
pico_unique_id
pico_multicore
hardware_watchdog
hardware_flash
hardware_sync
hardware_uart
hardware_pio
hardware_pwm
hardware_adc
hardware_i2c
tinyusb_device
tinyusb_board
tinyusb_host
tinyusb_pico_pio_usb
CRC32
cmsis_core
xinput_host
tusb_gamepad
)
pico_add_extra_outputs(${NAME})

View File

@@ -1,23 +0,0 @@
{
"configurations": [
{
"name": "ESP-IDF",
"compilerPath": "${default}",
"compileCommands": "${config:idf.buildPath}/compile_commands.json",
"includePath": [
"${config:idf.espIdfPath}/components/**",
"${config:idf.espIdfPathWin}/components/**",
"${workspaceFolder}/main/**"
],
"browse": {
"path": [
"${config:idf.espIdfPath}/components",
"${config:idf.espIdfPathWin}/components",
"${workspaceFolder}/main"
],
"limitSymbolsToIncludedHeaders": true
}
}
],
"version": 4
}

View File

@@ -1,106 +0,0 @@
{
"idf.adapterTargetName": "esp32",
"cmake.configureOnOpen": false,
"files.associations": {
"freertos.h": "c",
"stdint.h": "c",
"stdlib.h": "c",
"atomic": "cpp",
"array": "cpp",
"task.h": "c",
"bit": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"compare": "cpp",
"complex": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "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",
"netfwd": "cpp",
"numeric": "cpp",
"random": "cpp",
"ratio": "cpp",
"regex": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"future": "cpp",
"initializer_list": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"semaphore": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp",
"c_wrapper.h": "c",
"queue": "cpp",
"charconv": "cpp",
"format": "cpp",
"forward_list": "cpp",
"iomanip": "cpp",
"ios": "cpp",
"locale": "cpp",
"optional": "cpp",
"ranges": "cpp",
"span": "cpp",
"stack": "cpp",
"xfacet": "cpp",
"xhash": "cpp",
"xiosbase": "cpp",
"xlocale": "cpp",
"xlocbuf": "cpp",
"xlocinfo": "cpp",
"xlocmes": "cpp",
"xlocmon": "cpp",
"xlocnum": "cpp",
"xloctime": "cpp",
"xmemory": "cpp",
"xstring": "cpp",
"xtr1common": "cpp",
"xtree": "cpp",
"xutility": "cpp"
},
"idf.portWin": "COM26",
"idf.flashType": "UART",
"C_Cpp.intelliSenseEngine": "default",
"idf.espIdfPathWin": "C:\\Programming\\esp\\v5.1\\esp-idf",
"idf.toolsPathWin": "C:\\Programming\\.espressif"
}

View File

@@ -1,27 +0,0 @@
cmake_minimum_required(VERSION 3.5)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(EXTERNAL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../external)
include(${EXTERNAL_DIR}/init_submodules.cmake)
include(${EXTERNAL_DIR}/patch_libs.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/integrate_btstack.cmake)
init_git_submodules(${EXTERNAL_DIR})
apply_lib_patches(${EXTERNAL_DIR})
integrate_btstack(${EXTERNAL_DIR})
set(BLUEPAD32_ROOT ${EXTERNAL_DIR}/bluepad32/src/components/bluepad32)
if(NOT EXISTS ${BLUEPAD32_ROOT})
message(FATAL_ERROR "External directory not found: ${BLUEPAD32_ROOT}")
endif()
set(EXTRA_COMPONENT_DIRS
${BLUEPAD32_ROOT}/..
${CMAKE_CURRENT_SOURCE_DIR}/components
)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(OGX-Mini-ESP32)

View File

@@ -1,50 +0,0 @@
function(integrate_btstack EXTERNAL_DIR)
if(NOT EXISTS ${EXTERNAL_DIR})
message(FATAL_ERROR "External directory not found: ${EXTERNAL_DIR}")
else()
message(STATUS "External directory found: ${EXTERNAL_DIR}")
endif()
set(PROJECT_COMPONENTS ${CMAKE_CURRENT_LIST_DIR}/components)
set(BTSTACK_DIR ${EXTERNAL_DIR}/bluepad32/external/btstack)
set(PROJECT_BTSTACK ${PROJECT_COMPONENTS}/btstack)
if (NOT EXISTS ${PROJECT_COMPONENTS})
message(STATUS "Creating components folder at ${PROJECT_COMPONENTS}")
file(MAKE_DIRECTORY ${PROJECT_COMPONENTS})
endif()
if (NOT EXISTS ${BTSTACK_DIR})
message(FATAL_ERROR "Error: No BTstack folder at ${BTSTACK_DIR}")
endif()
if (NOT EXISTS ${PROJECT_BTSTACK})
find_package(Python3 COMPONENTS Interpreter REQUIRED)
if(Python3_Interpreter_FOUND)
message(STATUS "Python3 found: ${Python3_EXECUTABLE}")
message(STATUS "Python3 version: ${Python3_VERSION}")
else()
message(FATAL_ERROR "Python3 not found! Python is required to integrate BTStack with ESP-IDF")
endif()
set(BTSTACK_SCRIPT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/components/integrate_btstack.py)
message(STATUS "Integrating BTStack with project")
execute_process(
COMMAND ${Python3_EXECUTABLE} ${BTSTACK_SCRIPT_PATH} ${BTSTACK_DIR} ${PROJECT_COMPONENTS}
WORKING_DIRECTORY ${BTSTACK_SCRIPT_PATH}/..
RESULT_VARIABLE PYTHON_RESULT
OUTPUT_VARIABLE PYTHON_OUTPUT
ERROR_VARIABLE PYTHON_ERROR
)
if(PYTHON_RESULT EQUAL 0)
message(STATUS "BTStack integration successful:\n${PYTHON_OUTPUT}")
else()
message(FATAL_ERROR "BTStack integration failed:\n${PYTHON_ERROR}")
endif()
endif()
message(STATUS "BTstack setup complete")
endfunction()

View File

@@ -1,77 +0,0 @@
# This script copies BTstack ESP32 port files to this project's components folder, ESP-IDF freaks out otherwise
import os
import sys
import shutil
def main(btstack_root, components_dir):
PROJECT_COMPONENTS = os.path.abspath(components_dir)
BTSTACK_DIR = os.path.abspath(btstack_root)
BTSTACK_PORT_DIR = os.path.abspath(os.path.join(BTSTACK_DIR, 'port', 'esp32'))
if not os.path.exists(PROJECT_COMPONENTS):
print(f"Error: No components folder at {PROJECT_COMPONENTS}")
sys.exit(10)
if not os.path.exists(BTSTACK_DIR):
print(f"Error: No BTstack folder at {BTSTACK_DIR}")
sys.exit(10)
PROJECT_BTSTACK = os.path.join(PROJECT_COMPONENTS, "btstack")
if os.path.exists(PROJECT_BTSTACK):
print("Deleting old BTstack component %s" % PROJECT_BTSTACK)
shutil.rmtree(PROJECT_BTSTACK)
# create components/btstack
print("Creating BTstack component at %s" % PROJECT_COMPONENTS)
shutil.copytree(os.path.join(BTSTACK_PORT_DIR, 'components', 'btstack'), PROJECT_BTSTACK)
dirs_to_copy = [
'src',
'3rd-party/bluedroid',
'3rd-party/hxcmod-player',
'3rd-party/lwip/dhcp-server',
'3rd-party/lc3-google',
'3rd-party/md5',
'3rd-party/micro-ecc',
'3rd-party/yxml',
'platform/freertos',
'platform/lwip',
'tool'
]
for dir in dirs_to_copy:
print('- %s' % dir)
shutil.copytree(os.path.join(BTSTACK_PORT_DIR, '..', '..', dir), os.path.join(PROJECT_BTSTACK, dir))
# manually prepare platform/embedded
print('- platform/embedded')
platform_embedded_path = PROJECT_BTSTACK + '/platform/embedded'
os.makedirs(platform_embedded_path)
platform_embedded_files_to_copy = [
'hal_time_ms.h',
'hal_uart_dma.h',
'hci_dump_embedded_stdout.h',
'hci_dump_embedded_stdout.c',
]
for file in platform_embedded_files_to_copy:
shutil.copy(os.path.join(BTSTACK_PORT_DIR, '..', '..', 'platform', 'embedded', file), platform_embedded_path)
if __name__ == "__main__":
if len(sys.argv) < 3:
print("Usage: script.py <path_to_btstack> <path_to_project_components>")
sys.exit(1)
btstack_root = sys.argv[1]
project_components = sys.argv[2]
if not os.path.exists(btstack_root):
print(f"Error: Specified external directory does not exist: {btstack_root}")
sys.exit(2)
if not os.path.exists(project_components):
print(f"Error: Specified components directory does not exist: {project_components}")
sys.exit(3)
main(btstack_root, project_components)

View File

@@ -1,10 +0,0 @@
dependencies:
idf:
source:
type: idf
version: 5.1.5
direct_dependencies:
- idf
manifest_hash: ed38c883314ee552977d073f5c9d0e2ab9acc3248eefbeb203f3439de3e31b6e
target: esp32
version: 2.0.0

View File

@@ -1,338 +0,0 @@
#include <functional>
#include "btstack_port_esp32.h"
#include "btstack_run_loop.h"
#include "btstack_stdio_esp32.h"
#include "uni.h"
#include "sdkconfig.h"
#include "I2CDriver/I2CDriver.h"
#include "Board/board_api.h"
#include "Bluepad32/Gamepad.h"
#include "Bluepad32/Bluepad32.h"
namespace BP32 {
static constexpr uint8_t MAX_DEVICES = CONFIG_BLUEPAD32_MAX_DEVICES;
static constexpr uint32_t FEEDBACK_TIME_MS = 200;
static constexpr uint32_t LED_TIME_MS = 500;
I2CDriver i2c_driver_;
btstack_timer_source_t feedback_timer_;
std::atomic<bool> devs_conn_[MAX_DEVICES]{false};
static inline void send_feedback_cb(void* context)
{
I2CDriver::PacketOut packet_out = reinterpret_cast<std::atomic<I2CDriver::PacketOut>*>(context)->load();
uni_hid_device_t* bp_device = nullptr;
if (!(bp_device = uni_hid_device_get_instance_for_idx(packet_out.index)) ||
!uni_bt_conn_is_connected(&bp_device->conn) ||
!bp_device->report_parser.play_dual_rumble)
{
return;
}
if (packet_out.rumble_l || packet_out.rumble_r)
{
bp_device->report_parser.play_dual_rumble(
bp_device,
0,
FEEDBACK_TIME_MS,
packet_out.rumble_l,
packet_out.rumble_r
);
}
}
//This will have to be changed once full support for multiple devices is added
static inline void feedback_timer_cb(btstack_timer_source *ts)
{
static btstack_context_callback_registration_t cb_registration[MAX_DEVICES];
static std::atomic<I2CDriver::PacketOut> packets_out[MAX_DEVICES];
uni_hid_device_t* bp_device = nullptr;
for (uint8_t i = 0; i < MAX_DEVICES; ++i)
{
if (!(bp_device = uni_hid_device_get_instance_for_idx(i)) ||
!uni_bt_conn_is_connected(&bp_device->conn))
{
continue;
}
cb_registration[i].callback = send_feedback_cb;
cb_registration[i].context = reinterpret_cast<void*>(&packets_out[i]);
//Register a read on i2c thread, with callback to send feedback on btstack thread
i2c_driver_.i2c_read_blocking_safe( I2CDriver::MULTI_SLAVE ? i + 1 : 0x01,
[i](const I2CDriver::PacketOut& packet_out)
{
packets_out[i].store(packet_out);
btstack_run_loop_execute_on_main_thread(&cb_registration[i]);
});
}
btstack_run_loop_set_timer(ts, FEEDBACK_TIME_MS);
btstack_run_loop_add_timer(ts);
}
inline void check_led_cb(btstack_timer_source *ts)
{
static bool led_state = false;
led_state = !led_state;
if constexpr (board_api::NUM_LEDS == 1)
{
board_api::set_led(any_connected() ? 1 : (led_state ? 1 : 0));
}
else
{
for (uint8_t i = 0; i < board_api::NUM_LEDS; ++i)
{
board_api::set_led(i, devs_conn_[i].load() ? 1 : (led_state ? 1 : 0));
}
}
btstack_run_loop_set_timer(ts, LED_TIME_MS);
btstack_run_loop_add_timer(ts);
}
//BT Driver
static void init(int argc, const char** arg_V) {}
static void init_complete_cb(void)
{
uni_bt_enable_new_connections_unsafe(true);
// Based on runtime condition, you can delete or list the stored BT keys.
if (1)
{
uni_bt_del_keys_unsafe();
}
else
{
uni_bt_list_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))
{
return UNI_ERROR_IGNORE_DEVICE;
}
return UNI_ERROR_SUCCESS;
}
static void device_connected_cb(uni_hid_device_t* device)
{
#ifdef CONFIG_BLUEPAD32_USB_CONSOLE_ENABLE
logd("BP32", "Device connected, addr: %p, index: %i\n", device, uni_hid_device_get_idx_for_instance(device));
#endif
}
void device_disconnected_cb(uni_hid_device_t* device)
{
#ifdef CONFIG_BLUEPAD32_USB_CONSOLE_ENABLE
logd("BP32", "Device disconnected, addr: %p, index: %i\n", device, uni_hid_device_get_idx_for_instance(device));
#endif
int idx = uni_hid_device_get_idx_for_instance(device);
if (idx >= MAX_DEVICES || idx < 0)
{
return;
}
devs_conn_[idx].store(false);
if (!any_connected())
{
btstack_run_loop_remove_timer(&feedback_timer_);
}
I2CDriver::PacketIn packet_in = I2CDriver::PacketIn();
packet_in.index = static_cast<uint8_t>(idx);
i2c_driver_.i2c_write_blocking_safe(I2CDriver::MULTI_SLAVE ? packet_in.index + 1 : 0x01, packet_in);
}
static uni_error_t device_ready_cb(uni_hid_device_t* device)
{
int idx = uni_hid_device_get_idx_for_instance(device);
if (idx >= MAX_DEVICES || idx < 0)
{
return UNI_ERROR_IGNORE_DEVICE;
}
devs_conn_[idx].store(true);
feedback_timer_.process = feedback_timer_cb;
feedback_timer_.context = nullptr;
btstack_run_loop_set_timer(&feedback_timer_, FEEDBACK_TIME_MS);
btstack_run_loop_add_timer(&feedback_timer_);
return UNI_ERROR_SUCCESS;
}
static inline void controller_data_cb(uni_hid_device_t* device, uni_controller_t* controller)
{
static uni_gamepad_t prev_uni_gps[MAX_DEVICES]{0};
if (controller->klass != UNI_CONTROLLER_CLASS_GAMEPAD)
{
return;
}
uni_gamepad_t *uni_gp = &controller->gamepad;
int idx = uni_hid_device_get_idx_for_instance(device);
if (idx < 0 || std::memcmp(uni_gp, &prev_uni_gps[idx], sizeof(uni_gamepad_t)) == 0)
{
return;
}
I2CDriver::PacketIn packet_in;
packet_in.index = static_cast<uint8_t>(idx);
switch (uni_gp->dpad)
{
case DPAD_UP:
packet_in.dpad = Gamepad::DPad::UP;
break;
case DPAD_DOWN:
packet_in.dpad = Gamepad::DPad::DOWN;
break;
case DPAD_LEFT:
packet_in.dpad = Gamepad::DPad::LEFT;
break;
case DPAD_RIGHT:
packet_in.dpad = Gamepad::DPad::RIGHT;
break;
case (DPAD_UP | DPAD_RIGHT):
packet_in.dpad = Gamepad::DPad::UP_RIGHT;
break;
case (DPAD_DOWN | DPAD_RIGHT):
packet_in.dpad = Gamepad::DPad::DOWN_RIGHT;
break;
case (DPAD_DOWN | DPAD_LEFT):
packet_in.dpad = Gamepad::DPad::DOWN_LEFT;
break;
case (DPAD_UP | DPAD_LEFT):
packet_in.dpad = Gamepad::DPad::UP_LEFT;
break;
default:
break;
}
if (uni_gp->buttons & BUTTON_A) packet_in.buttons |= Gamepad::Button::A;
if (uni_gp->buttons & BUTTON_B) packet_in.buttons |= Gamepad::Button::B;
if (uni_gp->buttons & BUTTON_X) packet_in.buttons |= Gamepad::Button::X;
if (uni_gp->buttons & BUTTON_Y) packet_in.buttons |= Gamepad::Button::Y;
if (uni_gp->buttons & BUTTON_SHOULDER_L) packet_in.buttons |= Gamepad::Button::LB;
if (uni_gp->buttons & BUTTON_SHOULDER_R) packet_in.buttons |= Gamepad::Button::RB;
if (uni_gp->buttons & BUTTON_THUMB_L) packet_in.buttons |= Gamepad::Button::L3;
if (uni_gp->buttons & BUTTON_THUMB_R) packet_in.buttons |= Gamepad::Button::R3;
if (uni_gp->misc_buttons & MISC_BUTTON_BACK) packet_in.buttons |= Gamepad::Button::BACK;
if (uni_gp->misc_buttons & MISC_BUTTON_START) packet_in.buttons |= Gamepad::Button::START;
if (uni_gp->misc_buttons & MISC_BUTTON_SYSTEM) packet_in.buttons |= Gamepad::Button::SYS;
if (uni_gp->misc_buttons & MISC_BUTTON_CAPTURE) packet_in.buttons |= Gamepad::Button::MISC;
packet_in.trigger_l = Scale::uint10_to_uint8(uni_gp->brake);
packet_in.trigger_r = Scale::uint10_to_uint8(uni_gp->throttle);
packet_in.joystick_lx = Scale::int10_to_int16(uni_gp->axis_x);
packet_in.joystick_ly = Scale::int10_to_int16(uni_gp->axis_y);
packet_in.joystick_rx = Scale::int10_to_int16(uni_gp->axis_rx);
packet_in.joystick_ry = Scale::int10_to_int16(uni_gp->axis_ry);
i2c_driver_.i2c_write_blocking_safe(I2CDriver::MULTI_SLAVE ? packet_in.index + 1 : 0x01, packet_in);
std::memcpy(&prev_uni_gps[idx], uni_gp, sizeof(uni_gamepad_t));
}
static const uni_property_t* get_property_cb(uni_property_idx_t idx)
{
return nullptr;
}
static void oob_event_cb(uni_platform_oob_event_t event, void* data)
{
return;
}
uni_platform* get_driver()
{
static uni_platform driver =
{
.name = "OGXMiniW",
.init = init,
.on_init_complete = init_complete_cb,
.on_device_discovered = device_discovered_cb,
.on_device_connected = device_connected_cb,
.on_device_disconnected = device_disconnected_cb,
.on_device_ready = device_ready_cb,
.on_controller_data = controller_data_cb,
.get_property = get_property_cb,
.on_oob_event = oob_event_cb,
};
return &driver;
}
void run_i2c_task(void* parameter)
{
i2c_driver_.initialize_i2c();
i2c_driver_.run_tasks();
}
//Public
bool any_connected()
{
for (auto& connected : devs_conn_)
{
if (connected.load())
{
return true;
}
}
return false;
}
bool connected(uint8_t index)
{
return devs_conn_[index].load();
}
void run_task()
{
board_api::init_pins();
xTaskCreatePinnedToCore(
run_i2c_task,
"i2c",
2048 * 2,
nullptr,
configMAX_PRIORITIES-8,
nullptr,
1 );
btstack_init();
uni_platform_set_custom(get_driver());
uni_init(0, nullptr);
btstack_timer_source_t led_timer;
led_timer.process = check_led_cb;
led_timer.context = nullptr;
btstack_run_loop_set_timer(&led_timer, LED_TIME_MS);
btstack_run_loop_add_timer(&led_timer);
btstack_run_loop_execute();
}
} // namespace BP32

View File

@@ -1,13 +0,0 @@
#ifndef _BLUEPAD32_DRIVER_H_
#define _BLUEPAD32_DRIVER_H_
#include <cstdint>
namespace BP32
{
void run_task();
bool any_connected();
bool connected(uint8_t index);
}
#endif // _BLUEPAD32_DRIVER_H_

View File

@@ -1,100 +0,0 @@
#ifndef GAMEPAD_H
#define GAMEPAD_H
#include <cstdint>
namespace Gamepad
{
namespace DPad
{
static constexpr uint8_t UP = 0x01;
static constexpr uint8_t DOWN = 0x02;
static constexpr uint8_t LEFT = 0x04;
static constexpr uint8_t RIGHT = 0x08;
static constexpr uint8_t UP_LEFT = UP | LEFT;
static constexpr uint8_t UP_RIGHT = UP | RIGHT;
static constexpr uint8_t DOWN_LEFT = DOWN | LEFT;
static constexpr uint8_t DOWN_RIGHT = DOWN | RIGHT;
static constexpr uint8_t NONE = 0x00;
}
namespace Button
{
static constexpr uint16_t A = 0x0001;
static constexpr uint16_t B = 0x0002;
static constexpr uint16_t X = 0x0004;
static constexpr uint16_t Y = 0x0008;
static constexpr uint16_t L3 = 0x0010;
static constexpr uint16_t R3 = 0x0020;
static constexpr uint16_t BACK = 0x0040;
static constexpr uint16_t START = 0x0080;
static constexpr uint16_t LB = 0x0100;
static constexpr uint16_t RB = 0x0200;
static constexpr uint16_t SYS = 0x0400;
static constexpr uint16_t MISC = 0x0800;
}
} // namespace Gamepad
namespace Scale
{
namespace INT_16
{
static constexpr int16_t MIN = INT16_MIN;
static constexpr int16_t MID = 0;
static constexpr int16_t MAX = INT16_MAX;
}
namespace UINT_16
{
static constexpr uint16_t MIN = 0;
static constexpr uint16_t MID = 0x8000;
static constexpr uint16_t MAX = 0xFFFF;
}
namespace UINT_8
{
static constexpr uint8_t MAX = 0xFF;
static constexpr uint8_t MID = 0x80;
static constexpr uint8_t MIN = 0x00;
}
namespace INT_10
{
static constexpr int32_t MIN = -512;
static constexpr int32_t MAX = 511;
}
namespace UINT_10
{
static constexpr int32_t MAX = 1023;
}
static inline int16_t int10_to_int16(int32_t value)
{
constexpr int32_t scale_factor = INT_16::MAX - INT_16::MIN;
constexpr int32_t range = INT_10::MAX - INT_10::MIN;
if (value >= INT_10::MAX)
{
return INT_16::MAX;
}
else if (value <= INT_10::MIN)
{
return INT_16::MIN;
}
int32_t scaled_value = (value - INT_10::MIN) * scale_factor;
return static_cast<int16_t>(scaled_value / range + INT_16::MIN);
}
static inline uint8_t uint10_to_uint8(int32_t value)
{
if (value > UINT_10::MAX)
{
value = UINT_10::MAX;
}
else if (value < 0)
{
value = 0;
}
return static_cast<uint8_t>(value >> 2);
}
} // namespace Scale
#endif // GAMEPAD_H

View File

@@ -1,76 +0,0 @@
#include <driver/gpio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "sdkconfig.h"
#include "board/board_api.h"
namespace board_api {
SemaphoreHandle_t leds_mutex_ = nullptr;
SemaphoreHandle_t reset_mutex_ = nullptr;
void init_pins()
{
if (leds_mutex_ == nullptr)
{
leds_mutex_ = xSemaphoreCreateMutex();
}
if (reset_mutex_ == nullptr)
{
reset_mutex_ = xSemaphoreCreateMutex();
}
if (xSemaphoreTake(leds_mutex_, portMAX_DELAY))
{
for (const auto& LED_PIN : LED_PINS)
{
gpio_reset_pin(LED_PIN);
gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
gpio_set_level(LED_PIN, 0);
}
xSemaphoreGive(leds_mutex_);
}
// if (xSemaphoreTake(reset_mutex_, portMAX_DELAY))
// {
// gpio_reset_pin(RESET_PIN);
// gpio_set_direction(RESET_PIN, GPIO_MODE_INPUT);
// gpio_set_level(RESET_PIN, 1);
// xSemaphoreGive(reset_mutex_);
// }
}
//Set LED by index
void set_led(uint8_t index, bool state)
{
if constexpr (NUM_LEDS < 1)
{
return;
}
if (index >= NUM_LEDS)
{
return;
}
if (xSemaphoreTake(leds_mutex_, portMAX_DELAY))
{
gpio_set_level(LED_PINS[index], state ? 1 : 0);
xSemaphoreGive(leds_mutex_);
}
}
//Set first LED
void set_led(bool state)
{
if constexpr (NUM_LEDS < 1)
{
return;
}
if (xSemaphoreTake(leds_mutex_, portMAX_DELAY))
{
gpio_set_level(LED_PINS[0], state ? 1 : 0);
xSemaphoreGive(leds_mutex_);
}
}
} // namespace board_api

View File

@@ -1,43 +0,0 @@
#ifndef _BOARD_API_H_
#define _BOARD_API_H_
#include <cstdint>
#include <driver/gpio.h>
#include "sdkconfig.h"
#define MAX_GPIO_NUM 40
namespace board_api
{
static constexpr gpio_num_t RESET_PIN = static_cast<gpio_num_t>(CONFIG_RESET_PIN);
static_assert(RESET_PIN < MAX_GPIO_NUM, "Invalid RESET_PIN");
static constexpr gpio_num_t LED_PINS[] =
{
#if defined(CONFIG_ENABLE_LED_1) && (CONFIG_LED_PIN_1 < MAX_GPIO_NUM) && (CONFIG_BLUEPAD32_MAX_DEVICES > 0)
static_cast<gpio_num_t>(CONFIG_LED_PIN_1),
#if defined(CONFIG_ENABLE_LED_2) && (CONFIG_LED_PIN_2 < MAX_GPIO_NUM) && (CONFIG_BLUEPAD32_MAX_DEVICES > 1)
static_cast<gpio_num_t>(CONFIG_LED_PIN_2),
#if defined(CONFIG_ENABLE_LED_3) && (CONFIG_LED_PIN_3 < MAX_GPIO_NUM) && (CONFIG_BLUEPAD32_MAX_DEVICES > 2)
static_cast<gpio_num_t>(CONFIG_LED_PIN_3),
#if defined(CONFIG_ENABLE_LED_4) && (CONFIG_LED_PIN_4 < MAX_GPIO_NUM) && (CONFIG_BLUEPAD32_MAX_DEVICES > 3)
static_cast<gpio_num_t>(CONFIG_LED_PIN_4),
#endif // CONFIG_ENABLE_LED_4
#endif // CONFIG_ENABLE_LED_3
#endif // CONFIG_ENABLE_LED_2
#endif // CONFIG_ENABLE_LED_1
};
static constexpr uint8_t NUM_LEDS = sizeof(LED_PINS) / sizeof(LED_PINS[0]);
void init_pins();
void set_led(uint8_t index, bool state);
void set_led(bool state);
}
#endif // _BOARD_API_H_

View File

@@ -1,15 +0,0 @@
idf_component_register(
SRCS
"main.c"
"c_wrapper.cpp"
"Board/board_api.cpp"
"Bluepad32/Bluepad32.cpp"
"I2CDriver/I2CDriver.cpp"
INCLUDE_DIRS
"."
REQUIRES
bluepad32
btstack
driver
nvs_flash
)

View File

@@ -1,44 +0,0 @@
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/timers.h>
#include <driver/gpio.h>
#include <esp_log.h>
#include "I2CDriver/I2CDriver.h"
#include "Bluepad32/Bluepad32.h"
I2CDriver::~I2CDriver()
{
i2c_driver_delete(I2C_NUM_0);
}
void I2CDriver::initialize_i2c()
{
i2c_config_t conf;
std::memset(&conf, 0, sizeof(i2c_config_t));
conf.mode = I2C_MODE_MASTER;
conf.sda_io_num = GPIO_NUM_21;
conf.scl_io_num = GPIO_NUM_22;
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
conf.master.clk_speed = 1000 * 1000;
i2c_param_config(I2C_NUM_0, &conf);
i2c_driver_install(I2C_NUM_0, conf.mode, 0, 0, 0);
}
void I2CDriver::run_tasks()
{
std::function<void()> task;
while (true)
{
while (task_queue_.pop(task))
{
task();
}
vTaskDelay(1);
}
}

View File

@@ -1,132 +0,0 @@
#ifndef _I2C_DRIVER_H_
#define _I2C_DRIVER_H_
#include <cstdint>
#include <cstring>
#include <functional>
#include <driver/i2c.h>
#include "sdkconfig.h"
#include "RingBuffer.h"
class I2CDriver
{
public:
static constexpr bool MULTI_SLAVE =
#if CONFIG_MULTI_SLAVE_MODE == 0
false;
#else
true;
#endif
enum class PacketID : uint8_t { UNKNOWN = 0, SET_PAD, GET_PAD };
#pragma pack(push, 1)
struct PacketIn
{
uint8_t packet_len;
uint8_t packet_id;
uint8_t index;
uint8_t dpad;
uint16_t buttons;
uint8_t trigger_l;
uint8_t trigger_r;
int16_t joystick_lx;
int16_t joystick_ly;
int16_t joystick_rx;
int16_t joystick_ry;
PacketIn()
{
std::memset(this, 0, sizeof(PacketIn));
packet_len = sizeof(PacketIn);
packet_id = static_cast<uint8_t>(PacketID::SET_PAD);
}
};
static_assert(sizeof(PacketIn) == 16, "PacketIn is misaligned");
struct PacketOut
{
uint8_t packet_len;
uint8_t packet_id;
uint8_t index;
uint8_t rumble_l;
uint8_t rumble_r;
uint8_t reserved[3];
PacketOut()
{
std::memset(this, 0, sizeof(PacketOut));
packet_len = sizeof(PacketOut);
packet_id = static_cast<uint8_t>(PacketID::GET_PAD);
}
};
static_assert(sizeof(PacketOut) == 8, "PacketOut is misaligned");
#pragma pack(pop)
I2CDriver() = default;
~I2CDriver();
void initialize_i2c();
//Does not return
void run_tasks();
inline void i2c_write_blocking_safe(uint8_t address, const PacketIn& packet_in)
{
task_queue_.push([this, address, packet_in]()
{
i2c_write_blocking(address, reinterpret_cast<const uint8_t*>(&packet_in), sizeof(PacketIn));
});
}
inline void i2c_read_blocking_safe(uint8_t address, std::function<void(const PacketOut&)> callback)
{
task_queue_.push([this, address, callback]()
{
PacketOut packet_out;
if (i2c_read_blocking(address, reinterpret_cast<uint8_t*>(&packet_out), sizeof(PacketOut)) == ESP_OK)
{
callback(packet_out);
}
});
}
private:
using TaskQueue = RingBuffer<std::function<void()>, 6>;
TaskQueue task_queue_;
inline esp_err_t i2c_write_blocking(uint8_t address, const uint8_t* buffer, size_t len)
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (address << 1) | I2C_MASTER_WRITE, true);
i2c_master_write(cmd, buffer, len, true);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, pdMS_TO_TICKS(2));
i2c_cmd_link_delete(cmd);
return ret;
}
inline esp_err_t i2c_read_blocking(uint8_t address, uint8_t* buffer, size_t len)
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (address << 1) | I2C_MASTER_READ, true);
if (len > 1)
{
i2c_master_read(cmd, buffer, len - 1, I2C_MASTER_ACK);
}
i2c_master_read_byte(cmd, buffer + len - 1, I2C_MASTER_NACK);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, pdMS_TO_TICKS(2));
i2c_cmd_link_delete(cmd);
return ret;
}
};
#endif // _I2C_DRIVER_H_

View File

@@ -1,50 +0,0 @@
menu "OGXMini Options"
config RESET_PIN
int "Set reset pin"
default 9
config MULTI_SLAVE_MODE
bool "Enable multiple slave devices"
default n
config ENABLE_LED_1
bool "Enable LED 1"
default y
config LED_PIN_1
int "Set LED 1 pin"
default 15
depends on ENABLE_LED_1
config ENABLE_LED_2
bool "Enable LED 2"
default n
depends on ENABLE_LED_1
config LED_PIN_2
int "Set LED 2 pin"
default 255
depends on ENABLE_LED_2
config ENABLE_LED_3
bool "Enable LED 3"
default n
depends on ENABLE_LED_2
config LED_PIN_3
int "Set LED 3 pin"
default 255
depends on ENABLE_LED_3
config ENABLE_LED_4
bool "Enable LED 4"
default n
depends on ENABLE_LED_3
config LED_PIN_4
int "Set LED 4 pin"
default 255
depends on ENABLE_LED_4
endmenu

View File

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

View File

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

View File

@@ -1,16 +0,0 @@
#ifndef _C_WRAPPER_H_
#define _C_WRAPPER_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
void cpp_main();
#ifdef __cplusplus
}
#endif
#endif // _C_WRAPPER_H_

View File

@@ -1,9 +0,0 @@
#include <stdlib.h>
#include <stdint.h>
#include "c_wrapper.h"
void app_main(void)
{
cpp_main();
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,42 +0,0 @@
#
# ESP32 options
#
CONFIG_COMPILER_OPTIMIZATION_PERF=y
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_ESP32_XTAL_FREQ_AUTO=y
CONFIG_XTAL_FREQ_AUTO=y
# Bluetooh related
CONFIG_BT_ENABLED=y
CONFIG_BT_CONTROLLER_ONLY=y
# Enable Dualmode (BLE and BR/EDR)
CONFIG_BTDM_CTRL_MODE_BTDM=y
#CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=y
# Should be, at least, one more than CONFIG_BLUEPAD32_MAX_DEVICES
# See: https://gitlab.com/ricardoquesada/bluepad32/-/issues/11
CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN=5
CONFIG_BTDM_CTRL_BLE_MAX_CONN=5
CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN=0
CONFIG_BTDM_CTRL_AUTO_LATENCY=y
CONFIG_BTDM_CTRL_MODEM_SLEEP=n
CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y
#
# FreeRTOS
#
# Enable FreeRTOS stats formatting functions, needed for 'tasks' console command
CONFIG_FREERTOS_USE_TRACE_FACILITY=y
CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y
#
# Bluepad32 options
#
CONFIG_BLUEPAD32_MAX_DEVICES=4
CONFIG_BLUEPAD32_PLATFORM_CUSTOM=y
#
# Add here other options
#

View File

@@ -1,20 +0,0 @@
{
"configurations": [
{
"name": "Pico",
"includePath": [
"${PICO_SDK_PATH}/**"
],
"forcedInclude": [
"${PICO_SDK_PATH}/src/common/pico_base/include/pico.h",
"${workspaceFolder}/build/generated/pico_base/pico/config_autogen.h"
],
"defines": [],
"compileCommands": "${workspaceFolder}/build/compile_commands.json",
"cStandard": "c17",
"cppStandard": "c++14",
"intelliSenseMode": "linux-gcc-arm"
}
],
"version": 4
}

View File

@@ -1,87 +0,0 @@
{
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
"cmake.buildEnvironment": {
"PICO_SDK_PATH": "C:/Programming/pico-sdk"
},
"cmake.environment": {
"PICO_SDK_PATH": "C:/Programming/pico-sdk"
},
"cmake.configureArgs": [
"-DOGXM_BOARD=W_ESP32",
"-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"
}
}

View File

@@ -1,323 +0,0 @@
cmake_minimum_required(VERSION 3.13)
set(FW_NAME "OGX-Mini")
set(FW_VERSION "v1.0.0a2")
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(SRC ${CMAKE_CURRENT_LIST_DIR}/src)
set(EXTERNAL_DIR ${CMAKE_CURRENT_LIST_DIR}/../external)
include(${EXTERNAL_DIR}/init_submodules.cmake)
include(${EXTERNAL_DIR}/patch_libs.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/cmake/get_pico_sdk.cmake)
init_git_submodules(${EXTERNAL_DIR})
apply_lib_patches(${EXTERNAL_DIR})
get_pico_sdk(${EXTERNAL_DIR})
set(PICO_PIO_USB_PATH ${EXTERNAL_DIR}/Pico-PIO-USB)
set(PICO_TINYUSB_PATH ${EXTERNAL_DIR}/tinyusb)
set(BLUEPAD32_ROOT ${EXTERNAL_DIR}/bluepad32)
set(BTSTACK_ROOT ${BLUEPAD32_ROOT}/external/btstack)
set(PICO_BTSTACK_PATH ${BTSTACK_ROOT})
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}/TaskQueue/TaskQueue.cpp
${SRC}/Board/board_api.cpp
${SRC}/UserSettings/UserSettings.cpp
${SRC}/UserSettings/UserProfile.cpp
${SRC}/USBDevice/tud_callbacks.cpp
${SRC}/USBDevice/DeviceManager.cpp
${SRC}/USBDevice/DeviceDriver/DeviceDriver.cpp
${SRC}/USBDevice/DeviceDriver/PSClassic/PSClassic.cpp
${SRC}/USBDevice/DeviceDriver/PS3/PS3.cpp
${SRC}/USBDevice/DeviceDriver/Switch/Switch.cpp
${SRC}/USBDevice/DeviceDriver/XInput/XInput.cpp
${SRC}/USBDevice/DeviceDriver/XboxOG/XboxOG_GP.cpp
${SRC}/USBDevice/DeviceDriver/XboxOG/XboxOG_SB.cpp
${SRC}/USBDevice/DeviceDriver/XboxOG/XboxOG_XR.cpp
${SRC}/USBDevice/DeviceDriver/DInput/DInput.cpp
${SRC}/USBDevice/DeviceDriver/WebApp/WebApp.cpp
${SRC}/USBDevice/DeviceDriver/XInput/tud_xinput/tud_xinput.cpp
${SRC}/USBDevice/DeviceDriver/XboxOG/tud_xid/tud_xid.cpp
)
set(LIBS_BOARD
# Base
pico_stdlib
pico_multicore
pico_rand
hardware_timer
hardware_clocks
hardware_flash
tinyusb_device
tinyusb_board
# UART
hardware_uart
hardware_irq
)
set(INC_DIRS_BOARD
)
# Config options
# Max gamepads
set(MAX_GAMEPADS 1 CACHE STRING "Set number of gamepads, 1 to 4")
if (MAX_GAMEPADS GREATER 4 OR MAX_GAMEPADS LESS 1)
message(FATAL_ERROR "MAX_GAMEPADS must be between 1 and 4")
endif()
add_definitions(-DMAX_GAMEPADS=${MAX_GAMEPADS})
# Board type
set(OGXM_BOARD "PI_PICO" CACHE STRING "Set board type, options can be found in src/board_config.h")
set(FLASH_SIZE_MB 2)
set(PICO_BOARD none)
if (OGXM_BOARD STREQUAL "PI_PICO")
set(EN_USB_HOST TRUE)
elseif (OGXM_BOARD STREQUAL "PI_PICO2")
set(EN_USB_HOST TRUE)
set(PICO_PLATFORM rp2350)
set(FLASH_SIZE_MB 4)
elseif(OGXM_BOARD STREQUAL "ADA_FEATHER")
set(EN_USB_HOST TRUE)
set(EN_RGB TRUE)
set(FLASH_SIZE_MB 8)
elseif(OGXM_BOARD STREQUAL "RP_ZERO")
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 "EXTERNAL_4CH")
set(EN_USB_HOST TRUE)
set(EN_4CH TRUE)
set(EN_RGB TRUE)
elseif(OGXM_BOARD STREQUAL "PI_PICOW")
set(EN_BLUETOOTH TRUE)
set(PICO_BOARD pico_w)
elseif(OGXM_BOARD STREQUAL "W_ESP32")
set(EN_ESP32 TRUE)
set(EN_UART_BRIDGE TRUE)
else()
message(FATAL_ERROR "Invalid OGXM_BOARD value. See options in src/board_config.h")
endif()
add_definitions(-DOGXM_BOARD=${OGXM_BOARD})
if(EN_USB_HOST)
message(STATUS "USB host enabled.")
add_compile_definitions(CONFIG_EN_USB_HOST=1)
list(APPEND SOURCES_BOARD
${SRC}/USBHost/tuh_callbacks.cpp
# HID
${SRC}/USBHost/HostDriver/DInput/DInput.cpp
${SRC}/USBHost/HostDriver/PSClassic/PSClassic.cpp
${SRC}/USBHost/HostDriver/SwitchWired/SwitchWired.cpp
${SRC}/USBHost/HostDriver/SwitchPro/SwitchPro.cpp
${SRC}/USBHost/HostDriver/PS5/PS5.cpp
${SRC}/USBHost/HostDriver/PS4/PS4.cpp
${SRC}/USBHost/HostDriver/PS3/PS3.cpp
${SRC}/USBHost/HostDriver/N64/N64.cpp
${SRC}/USBHost/HostDriver/HIDGeneric/HIDGeneric.cpp
${SRC}/USBHost/HIDParser/HIDJoystick.cpp
${SRC}/USBHost/HIDParser/HIDReportDescriptor.cpp
${SRC}/USBHost/HIDParser/HIDReportDescriptorElements.cpp
${SRC}/USBHost/HIDParser/HIDReportDescriptorUsages.cpp
${SRC}/USBHost/HIDParser/HIDUtils.cpp
# XInput
${SRC}/USBHost/HostDriver/XInput/XboxOG.cpp
${SRC}/USBHost/HostDriver/XInput/XboxOne.cpp
${SRC}/USBHost/HostDriver/XInput/Xbox360.cpp
${SRC}/USBHost/HostDriver/XInput/Xbox360W.cpp
${SRC}/USBHost/HostDriver/XInput/tuh_xinput/tuh_xinput.cpp
)
list(APPEND LIBS_BOARD
tinyusb_host
tinyusb_pico_pio_usb
)
endif()
if(EN_BLUETOOTH)
add_compile_definitions(CONFIG_EN_BLUETOOTH=1)
message(STATUS "Bluetooth enabled.")
list(APPEND SOURCES_BOARD
${SRC}/Bluepad32/Bluepad32.cpp
)
list(APPEND INC_DIRS_BOARD
${SRC}
${BTSTACK_ROOT}/3rd-party/bluedroid/encoder/include
${BTSTACK_ROOT}/3rd-party/bluedroid/decoder/include
)
list(APPEND LIBS_BOARD
pico_cyw43_arch_none
pico_btstack_classic
pico_btstack_cyw43
bluepad32
)
endif()
if(EN_RGB)
add_compile_definitions(CONFIG_EN_RGB=1)
message(STATUS "RGB enabled.")
list(APPEND SOURCES_BOARD
${SRC}/Board/Pico_WS2812/WS2812.cpp
)
list(APPEND LIBS_BOARD
hardware_pio
)
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 LIBS_BOARD
hardware_i2c
pico_i2c_slave
)
endif()
if(EN_ESP32)
add_compile_definitions(CONFIG_EN_ESP32=1)
message(STATUS "ESP32 enabled.")
list(APPEND SOURCES_BOARD
${SRC}/I2CDriver/ESP32/I2CDriver.cpp
)
list(APPEND LIBS_BOARD
hardware_i2c
pico_i2c_slave
)
endif()
if(EN_UART_BRIDGE)
add_compile_definitions(CONFIG_EN_UART_BRIDGE=1)
message(STATUS "UART bridge enabled.")
list(APPEND SOURCES_BOARD
${SRC}/USBDevice/DeviceDriver/UARTBridge/UARTBridge.cpp
${SRC}/USBDevice/DeviceDriver/UARTBridge/uart_bridge/uart_bridge.c
)
endif()
add_compile_definitions(PICO_FLASH_SIZE_BYTES=${FLASH_SIZE_MB}*1024*1024)
add_compile_definitions(FIRMWARE_VERSION="${FW_VERSION}")
# Check for DVD dongle firmware
if(EXISTS ${SRC}/USBDevice/DeviceDriver/XboxOG/tud_xid/tud_xid_xremote_rom.h)
message(STATUS "XRemote ROM available.")
add_definitions(-DXREMOTE_ROM_AVAILABLE)
endif()
if(NOT EN_BLUETOOTH)
add_compile_definitions(PICO_BOOT_STAGE2_CHOOSE_GENERIC_03H=1)
add_compile_definitions(PICO_XOSC_STARTUP_DELAY_MULTIPLIER=64)
endif()
include(${PICO_SDK_PATH}/pico_sdk_init.cmake)
message("PICO_SDK_VERSION_STRING: ${PICO_SDK_VERSION_STRING}")
if(PICO_SDK_VERSION_STRING VERSION_LESS "2.1.0")
message(FATAL_ERROR "Raspberry Pi Pico SDK version 2.1.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")
endif()
project(${FW_NAME} C CXX ASM)
pico_sdk_init()
add_executable(${FW_NAME} ${SOURCES_BOARD})
set(BUILD_STR "")
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(BUILD_STR "-Debug")
pico_enable_stdio_uart(${FW_NAME} 1)
target_compile_definitions(${FW_NAME} PRIVATE
PICO_DEFAULT_UART=1
PICO_DEFAULT_UART_TX_PIN=4
PICO_DEFAULT_UART_RX_PIN=5
)
add_compile_definitions(LOG=1)
add_compile_definitions(CFG_TUSB_DEBUG=1)
add_compile_definitions(OGXM_DEBUG=1)
target_compile_options(${FW_NAME} PRIVATE
-Wall # Enable most warnings
-Wextra # Enable extra warnings
-Wconversion # Warn on type conversion issues
-Wsign-conversion # Warn on sign conversion issues
-Wno-unused-parameter # Disable warnings for unused parameters
# -Werror # Treat warnings as errors
)
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
pico_enable_stdio_uart(${FW_NAME} 0)
add_compile_definitions(CFG_TUSB_DEBUG=0)
add_compile_options(
-O3 # Optimize for speed
-mcpu=cortex-m0plus # Target ARM Cortex-M0+
-mthumb # Use Thumb instruction set
-ffunction-sections # Place each function in its own section
-fdata-sections # Place each data item in its own section
-fomit-frame-pointer # Omit frame pointers
-finline-functions # Enable inlining
)
add_link_options(
-Wl,--gc-sections # Remove unused sections
-flto # Link-Time Optimization
)
endif()
pico_set_program_name(${FW_NAME} ${FW_NAME})
pico_set_program_version(${FW_NAME} ${FW_VERSION})
target_include_directories(${FW_NAME} PRIVATE ${SRC})
if(EN_RGB)
pico_generate_pio_header(${FW_NAME} ${SRC}/Board/Pico_WS2812/WS2812.pio)
endif()
include_directories(${INC_DIRS_BOARD})
if(EN_USB_HOST)
add_subdirectory(${PICO_PIO_USB_PATH} ${CMAKE_BINARY_DIR}/Pico-PIO-USB)
endif()
if(EN_BLUETOOTH)
add_subdirectory(${BLUEPAD32_ROOT}/src/components/bluepad32 libbluepad32)
endif()
target_link_libraries(${FW_NAME} PRIVATE ${LIBS_BOARD})
set(EXE_FILENAME "${FW_NAME}-${FW_VERSION}-${OGXM_BOARD}${BUILD_STR}")
set_target_properties(${FW_NAME} PROPERTIES OUTPUT_NAME ${EXE_FILENAME})
pico_add_extra_outputs(${FW_NAME})

View File

@@ -1,17 +0,0 @@
function(get_pico_sdk EXTERNAL_DIR)
if(NOT DEFINED ENV{PICO_SDK_PATH})
message("PICO_SDK_PATH not set, downloading Pico SDK...")
set(PICO_SDK_PATH ${EXTERNAL_DIR}/pico-sdk PARENT_SCOPE)
if(NOT EXISTS ${PICO_SDK_PATH})
execute_process(
COMMAND git clone --recursive https://github.com/raspberrypi/pico-sdk.git
WORKING_DIRECTORY ${EXTERNAL_DIR}
)
endif()
else()
message("Using PICO_SDK_PATH from environment: $ENV{PICO_SDK_PATH}")
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH} PARENT_SCOPE)
endif()
set(PICOTOOL_FETCH_FROM_GIT_PATH ${EXTERNAL_DIR}/picotool PARENT_SCOPE)
endfunction()

View File

@@ -1,323 +0,0 @@
#include <atomic>
#include <cstring>
#include <functional>
#include <pico/mutex.h>
#include <pico/cyw43_arch.h>
#include "btstack_run_loop.h"
#include "uni.h"
#include "sdkconfig.h"
#include "Bluepad32/Bluepad32.h"
#include "Board/board_api.h"
#ifndef CONFIG_BLUEPAD32_PLATFORM_CUSTOM
#error "Pico W must use BLUEPAD32_PLATFORM_CUSTOM"
#endif
static_assert((CONFIG_BLUEPAD32_MAX_DEVICES == MAX_GAMEPADS), "Mismatch between BP32 and Gamepad max devices");
namespace bluepad32 {
static constexpr uint32_t FEEDBACK_TIME_MS = 250;
static constexpr uint32_t LED_CHECK_TIME_MS = 500;
struct BTDevice
{
bool connected{false};
Gamepad* gamepad{nullptr};
};
BTDevice bt_devices_[MAX_GAMEPADS];
btstack_timer_source_t feedback_timer_;
btstack_timer_source_t led_timer_;
bool led_timer_set_{false};
bool feedback_timer_set_{false};
bool any_connected()
{
for (auto& device : bt_devices_)
{
if (device.connected)
{
return true;
}
}
return false;
}
//This solves a function pointer/crash issue with bluepad32
void set_rumble(uni_hid_device_t* bp_device, uint16_t length, uint8_t rumble_l, uint8_t rumble_r)
{
switch (bp_device->controller_type)
{
case CONTROLLER_TYPE_XBoxOneController:
uni_hid_parser_xboxone_play_dual_rumble(bp_device, 0, length + 10, rumble_l, rumble_r);
break;
case CONTROLLER_TYPE_AndroidController:
if (bp_device->vendor_id == UNI_HID_PARSER_STADIA_VID && bp_device->product_id == UNI_HID_PARSER_STADIA_PID)
{
uni_hid_parser_stadia_play_dual_rumble(bp_device, 0, length, rumble_l, rumble_r);
}
break;
case CONTROLLER_TYPE_PSMoveController:
uni_hid_parser_psmove_play_dual_rumble(bp_device, 0, length, rumble_l, rumble_r);
break;
case CONTROLLER_TYPE_PS3Controller:
uni_hid_parser_ds3_play_dual_rumble(bp_device, 0, length, rumble_l, rumble_r);
break;
case CONTROLLER_TYPE_PS4Controller:
uni_hid_parser_ds4_play_dual_rumble(bp_device, 0, length, rumble_l, rumble_r);
break;
case CONTROLLER_TYPE_PS5Controller:
uni_hid_parser_ds5_play_dual_rumble(bp_device, 0, length, rumble_l, rumble_r);
break;
case CONTROLLER_TYPE_WiiController:
uni_hid_parser_wii_play_dual_rumble(bp_device, 0, length, rumble_l, rumble_r);
break;
case CONTROLLER_TYPE_SwitchProController:
case CONTROLLER_TYPE_SwitchJoyConRight:
case CONTROLLER_TYPE_SwitchJoyConLeft:
uni_hid_parser_switch_play_dual_rumble(bp_device, 0, length, rumble_l, rumble_r);
break;
default:
break;
}
}
static void send_feedback_cb(btstack_timer_source *ts)
{
uni_hid_device_t* bp_device = nullptr;
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
{
if (!bt_devices_[i].connected ||
!(bp_device = uni_hid_device_get_instance_for_idx(i)))
{
continue;
}
Gamepad::PadOut gp_out = bt_devices_[i].gamepad->get_pad_out();
if (gp_out.rumble_l > 0 || gp_out.rumble_r > 0)
{
set_rumble(bp_device, static_cast<uint16_t>(FEEDBACK_TIME_MS), gp_out.rumble_l, gp_out.rumble_r);
}
}
btstack_run_loop_set_timer(ts, FEEDBACK_TIME_MS);
btstack_run_loop_add_timer(ts);
}
static void check_led_cb(btstack_timer_source *ts)
{
static bool led_state = false;
led_state = !led_state;
board_api::set_led(any_connected() ? true : led_state);
btstack_run_loop_set_timer(ts, LED_CHECK_TIME_MS);
btstack_run_loop_add_timer(ts);
}
//BT Driver
static void init(int argc, const char** arg_V)
{
if (!led_timer_set_)
{
led_timer_set_ = true;
led_timer_.process = check_led_cb;
led_timer_.context = nullptr;
btstack_run_loop_set_timer(&led_timer_, LED_CHECK_TIME_MS);
btstack_run_loop_add_timer(&led_timer_);
}
}
static void init_complete_cb(void)
{
uni_bt_enable_new_connections_unsafe(true);
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))
{
return UNI_ERROR_IGNORE_DEVICE;
}
return UNI_ERROR_SUCCESS;
}
static void device_connected_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)
{
return;
}
bt_devices_[idx].connected = false;
if (!led_timer_set_)
{
led_timer_set_ = true;
led_timer_.process = check_led_cb;
led_timer_.context = nullptr;
btstack_run_loop_set_timer(&led_timer_, LED_CHECK_TIME_MS);
btstack_run_loop_add_timer(&led_timer_);
}
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)
{
int idx = uni_hid_device_get_idx_for_instance(device);
if (idx >= MAX_GAMEPADS || idx < 0)
{
return UNI_ERROR_SUCCESS;
}
bt_devices_[idx].connected = true;
if (led_timer_set_)
{
led_timer_set_ = false;
btstack_run_loop_remove_timer(&led_timer_);
board_api::set_led(true);
}
if (!feedback_timer_set_)
{
feedback_timer_set_ = true;
feedback_timer_.process = send_feedback_cb;
feedback_timer_.context = nullptr;
btstack_run_loop_set_timer(&feedback_timer_, FEEDBACK_TIME_MS);
btstack_run_loop_add_timer(&feedback_timer_);
}
return UNI_ERROR_SUCCESS;
}
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 uni_gamepad_t prev_uni_gp[MAX_GAMEPADS] = {};
if (controller->klass != UNI_CONTROLLER_CLASS_GAMEPAD)
{
return;
}
uni_gamepad_t *uni_gp = &controller->gamepad;
int idx = uni_hid_device_get_idx_for_instance(device);
Gamepad* gamepad = bt_devices_[idx].gamepad;
Gamepad::PadIn gp_in;
switch (uni_gp->dpad)
{
case DPAD_UP:
gp_in.dpad = gamepad->MAP_DPAD_UP;
break;
case DPAD_DOWN:
gp_in.dpad = gamepad->MAP_DPAD_DOWN;
break;
case DPAD_LEFT:
gp_in.dpad = gamepad->MAP_DPAD_LEFT;
break;
case DPAD_RIGHT:
gp_in.dpad = gamepad->MAP_DPAD_RIGHT;
break;
case DPAD_UP | DPAD_RIGHT:
gp_in.dpad = gamepad->MAP_DPAD_UP_RIGHT;
break;
case DPAD_DOWN | DPAD_RIGHT:
gp_in.dpad = gamepad->MAP_DPAD_DOWN_RIGHT;
break;
case DPAD_DOWN | DPAD_LEFT:
gp_in.dpad = gamepad->MAP_DPAD_DOWN_LEFT;
break;
case DPAD_UP | DPAD_LEFT:
gp_in.dpad = gamepad->MAP_DPAD_UP_LEFT;
break;
default:
break;
}
if (uni_gp->buttons & BUTTON_A) gp_in.buttons |= gamepad->MAP_BUTTON_A;
if (uni_gp->buttons & BUTTON_B) gp_in.buttons |= gamepad->MAP_BUTTON_B;
if (uni_gp->buttons & BUTTON_X) gp_in.buttons |= gamepad->MAP_BUTTON_X;
if (uni_gp->buttons & BUTTON_Y) gp_in.buttons |= gamepad->MAP_BUTTON_Y;
if (uni_gp->buttons & BUTTON_SHOULDER_L) gp_in.buttons |= gamepad->MAP_BUTTON_LB;
if (uni_gp->buttons & BUTTON_SHOULDER_R) gp_in.buttons |= gamepad->MAP_BUTTON_RB;
if (uni_gp->buttons & BUTTON_THUMB_L) gp_in.buttons |= gamepad->MAP_BUTTON_L3;
if (uni_gp->buttons & BUTTON_THUMB_R) gp_in.buttons |= gamepad->MAP_BUTTON_R3;
if (uni_gp->misc_buttons & MISC_BUTTON_BACK) gp_in.buttons |= gamepad->MAP_BUTTON_BACK;
if (uni_gp->misc_buttons & MISC_BUTTON_START) gp_in.buttons |= gamepad->MAP_BUTTON_START;
if (uni_gp->misc_buttons & MISC_BUTTON_SYSTEM) gp_in.buttons |= gamepad->MAP_BUTTON_SYS;
gp_in.trigger_l = Scale::uint10_to_uint8(uni_gp->brake);
gp_in.trigger_r = Scale::uint10_to_uint8(uni_gp->throttle);
gp_in.joystick_lx = Scale::int10_to_int16(uni_gp->axis_x);
gp_in.joystick_ly = Scale::int10_to_int16(uni_gp->axis_y);
gp_in.joystick_rx = Scale::int10_to_int16(uni_gp->axis_rx);
gp_in.joystick_ry = Scale::int10_to_int16(uni_gp->axis_ry);
gamepad->set_pad_in(gp_in);
}
const uni_property_t* get_property_cb(uni_property_idx_t idx)
{
return nullptr;
}
uni_platform* get_driver()
{
static uni_platform driver =
{
.name = "OGXMiniW",
.init = init,
.on_init_complete = init_complete_cb,
.on_device_discovered = device_discovered_cb,
.on_device_connected = device_connected_cb,
.on_device_disconnected = device_disconnected_cb,
.on_device_ready = device_ready_cb,
.on_controller_data = controller_data_cb,
.get_property = get_property_cb,
.on_oob_event = oob_event_cb,
};
return &driver;
}
//Public API
void run_task(Gamepad (&gamepads)[MAX_GAMEPADS])
{
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
{
bt_devices_[i].gamepad = &gamepads[i];
}
uni_platform_set_custom(get_driver());
uni_init(0, nullptr);
btstack_run_loop_execute();
}
} // namespace bluepad32

View File

@@ -1,18 +0,0 @@
#ifndef _BLUEPAD_32_H_
#define _BLUEPAD_32_H_
#include <cstdint>
#include <array>
#include "Gamepad.h"
#include "board_config.h"
/* NOTE: Everything bluepad32/uni needs to be wrapped
and kept away from tinyusb due to naming conflicts */
namespace bluepad32
{
void run_task(Gamepad (&gamepads)[MAX_GAMEPADS]);
}
#endif // _BLUEPAD_32_H_

View File

@@ -1,114 +0,0 @@
/*
Copyright ForsakenNGS 2021
https://github.com/ForsakenNGS/Pico_WS2812
*/
#include "Board/Pico_WS2812/WS2812.hpp"
#include "WS2812.pio.h"
WS2812::WS2812(uint pin, uint length, PIO pio, uint sm) {
initialize(pin, length, pio, sm, NONE, GREEN, RED, BLUE);
}
WS2812::WS2812(uint pin, uint length, PIO pio, uint sm, DataFormat format) {
switch (format) {
case FORMAT_RGB:
initialize(pin, length, pio, sm, NONE, RED, GREEN, BLUE);
break;
case FORMAT_GRB:
initialize(pin, length, pio, sm, NONE, GREEN, RED, BLUE);
break;
case FORMAT_WRGB:
initialize(pin, length, pio, sm, WHITE, RED, GREEN, BLUE);
break;
}
}
WS2812::WS2812(uint pin, uint length, PIO pio, uint sm, DataByte b1, DataByte b2, DataByte b3) {
initialize(pin, length, pio, sm, b1, b1, b2, b3);
}
WS2812::WS2812(uint pin, uint length, PIO pio, uint sm, DataByte b1, DataByte b2, DataByte b3, DataByte b4) {
initialize(pin, length, pio, sm, b1, b2, b3, b4);
}
WS2812::~WS2812() {
}
void WS2812::initialize(uint pin, uint length, PIO pio, uint sm, DataByte b1, DataByte b2, DataByte b3, DataByte b4) {
this->pin = pin;
this->length = length;
this->pio = pio;
this->sm = sm;
this->data = new uint32_t[length];
this->bytes[0] = b1;
this->bytes[1] = b2;
this->bytes[2] = b3;
this->bytes[3] = b4;
uint offset = pio_add_program(pio, &ws2812_program);
uint bits = (b1 == NONE ? 24 : 32);
ws2812_program_init(pio, sm, offset, pin, 800000, bits);
}
uint32_t WS2812::convertData(uint32_t rgbw) {
uint32_t result = 0;
for (uint b = 0; b < 4; b++) {
switch (bytes[b]) {
case RED:
result |= (rgbw & 0xFF);
break;
case GREEN:
result |= (rgbw & 0xFF00) >> 8;
break;
case BLUE:
result |= (rgbw & 0xFF0000) >> 16;
break;
case WHITE:
result |= (rgbw & 0xFF000000) >> 24;
break;
}
result <<= 8;
}
return result;
}
void WS2812::setPixelColor(uint index, uint32_t color) {
if (index < length) {
data[index] = convertData(color);
}
}
void WS2812::setPixelColor(uint index, uint8_t red, uint8_t green, uint8_t blue) {
setPixelColor(index, RGB(red, green, blue));
}
void WS2812::setPixelColor(uint index, uint8_t red, uint8_t green, uint8_t blue, uint8_t white) {
setPixelColor(index, RGBW(red, green, blue, white));
}
void WS2812::fill(uint32_t color) {
fill(color, 0, length);
}
void WS2812::fill(uint32_t color, uint first) {
fill(color, first, length-first);
}
void WS2812::fill(uint32_t color, uint first, uint count) {
uint last = (first + count);
if (last > length) {
last = length;
}
color = convertData(color);
for (uint i = first; i < last; i++) {
data[i] = color;
}
}
void WS2812::show() {
for (uint i = 0; i < length; i++) {
pio_sm_put_blocking(pio, sm, data[i]);
}
}

View File

@@ -1,63 +0,0 @@
/*
Copyright ForsakenNGS 2021
https://github.com/ForsakenNGS/Pico_WS2812
*/
#ifndef WS2812_H
#define WS2812_H
#include <array>
#include <pico/types.h>
#include <hardware/pio.h>
class WS2812 {
public:
enum DataByte {
NONE=0,
RED=1,
GREEN=2,
BLUE=3,
WHITE=4
};
enum DataFormat {
FORMAT_RGB=0,
FORMAT_GRB=1,
FORMAT_WRGB=2
};
WS2812(uint pin, uint length, PIO pio, uint sm);
WS2812(uint pin, uint length, PIO pio, uint sm, DataFormat format);
WS2812(uint pin, uint length, PIO pio, uint sm, DataByte b1, DataByte b2, DataByte b3);
WS2812(uint pin, uint length, PIO pio, uint sm, DataByte b1, DataByte b2, DataByte b3, DataByte b4);
~WS2812();
static uint32_t RGB(uint8_t red, uint8_t green, uint8_t blue) {
return (uint32_t)(blue) << 16 | (uint32_t)(green) << 8 | (uint32_t)(red);
};
static uint32_t RGBW(uint8_t red, uint8_t green, uint8_t blue, uint8_t white) {
return (uint32_t)(white) << 24 | (uint32_t)(blue) << 16 | (uint32_t)(green) << 8 | (uint32_t)(red);
}
void setPixelColor(uint index, uint32_t color);
void setPixelColor(uint index, uint8_t red, uint8_t green, uint8_t blue);
void setPixelColor(uint index, uint8_t red, uint8_t green, uint8_t blue, uint8_t white);
void fill(uint32_t color);
void fill(uint32_t color, uint first);
void fill(uint32_t color, uint first, uint count);
void show();
private:
uint pin;
uint length;
PIO pio;
uint sm;
DataByte bytes[4];
uint32_t *data;
void initialize(uint pin, uint length, PIO pio, uint sm, DataByte b1, DataByte b2, DataByte b3, DataByte b4);
uint32_t convertData(uint32_t rgbw);
};
#endif

View File

@@ -1,44 +0,0 @@
.program ws2812
.side_set 1
.define public T1 2
.define public T2 5
.define public T3 3
.lang_opt python sideset_init = pico.PIO.OUT_HIGH
.lang_opt python out_init = pico.PIO.OUT_HIGH
.lang_opt python out_shiftdir = 1
.wrap_target
bitloop:
out x, 1 side 0 [T3 - 1]
jmp !x send_zero side 1 [T1 - 1]
send_one:
jmp bitloop side 1 [T2 - 1]
send_zero:
nop side 0 [T2 - 1]
.wrap
% c-sdk {
#include "hardware/clocks.h"
static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin, float freq, uint bits) {
pio_gpio_init(pio, pin);
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
pio_sm_config c = ws2812_program_get_default_config(offset);
sm_config_set_sideset_pins(&c, pin);
sm_config_set_out_shift(&c, false, true, bits);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
int cycles_per_bit = ws2812_T1 + ws2812_T2 + ws2812_T3;
float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit);
sm_config_set_clkdiv(&c, div);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
%}

View File

@@ -1,229 +0,0 @@
#include <pico/stdlib.h>
#include <pico/mutex.h>
#include <hardware/clocks.h>
#include <hardware/gpio.h>
#include <hardware/watchdog.h>
#include "Board/board_api.h"
#include "OGXMini/Debug.h"
#include "board_config.h"
#if defined(CONFIG_EN_BLUETOOTH)
#include <pico/cyw43_arch.h>
#endif // defined(CONFIG_EN_BLUETOOTH)
#if defined(CONFIG_EN_RGB)
#include "WS2812.pio.h"
#include "Board/Pico_WS2812/WS2812.hpp"
#endif // defined(CONFIG_EN_RGB)
namespace board_api {
bool inited_ = false;
mutex_t gpio_mutex_;
void init_vcc_en_pin_unsafe()
{
#if defined(VCC_EN_PIN)
gpio_init(VCC_EN_PIN);
gpio_set_dir(VCC_EN_PIN, GPIO_OUT);
gpio_put(VCC_EN_PIN, 1);
#endif
}
void init_rgb_unsafe()
{
#if defined(CONFIG_EN_RGB) && defined(RGB_PWR_PIN)
gpio_init(RGB_PWR_PIN);
gpio_set_dir(RGB_PWR_PIN, GPIO_OUT);
gpio_put(RGB_PWR_PIN, 1);
#endif // defined(CONFIG_EN_RGB) && defined(RGB_PWR_PIN)
}
void init_led_indicator_unsafe()
{
#if defined(LED_INDICATOR_PIN) && !defined(CONFIG_EN_BLUETOOTH)
gpio_init(LED_INDICATOR_PIN);
gpio_set_dir(LED_INDICATOR_PIN, GPIO_OUT);
gpio_put(LED_INDICATOR_PIN, 0);
#endif // defined(LED_INDICATOR_PIN)
}
void init_esp32_io_unsafe()
{
#if defined(CONFIG_EN_ESP32)
gpio_init(ESP_PROG_PIN);
gpio_set_dir(ESP_PROG_PIN, GPIO_OUT);
gpio_put(ESP_PROG_PIN, 1);
gpio_init(ESP_RST_PIN);
gpio_set_dir(ESP_RST_PIN, GPIO_OUT);
gpio_put(ESP_RST_PIN, 1);
#endif //defined(CONFIG_EN_ESP32)
}
void init_uart_bridge_io_unsafe()
{
#if defined(CONFIG_EN_UART_BRIDGE)
gpio_init(MODE_SEL_PIN);
gpio_set_dir(MODE_SEL_PIN, GPIO_IN);
gpio_pull_up(MODE_SEL_PIN);
#endif // defined(CONFIG_EN_UART_BRIDGE)
}
void init_uart_debug_unsafe()
{
#if defined(OGXM_DEBUG)
uart_init(DEBUG_UART_PORT, PICO_DEFAULT_UART_BAUD_RATE);
gpio_set_function(PICO_DEFAULT_UART_TX_PIN, GPIO_FUNC_UART);
gpio_set_function(PICO_DEFAULT_UART_RX_PIN, GPIO_FUNC_UART);
#endif // defined(OGXM_DEBUG)
}
void set_led(bool state)
{
mutex_enter_blocking(&gpio_mutex_);
if (!inited_)
{
mutex_exit(&gpio_mutex_);
return;
}
#if defined(CONFIG_EN_RGB)
static WS2812 ws2812 = WS2812(RGB_PXL_PIN, 1, pio1, 0, WS2812::FORMAT_GRB);
ws2812.setPixelColor(0, state ? WS2812::RGB(0x00, 0xFF, 0x00) : WS2812::RGB(0xFF, 0, 0));
ws2812.show();
#endif // defined(CONFIG_EN_RGB)
#if defined(CONFIG_EN_BLUETOOTH)
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, state ? 1 : 0);
#elif defined(LED_INDICATOR_PIN)
gpio_put(LED_INDICATOR_PIN, state ? 1 : 0);
#endif //defined(CONFIG_EN_RGB)
mutex_exit(&gpio_mutex_);
}
#if defined(CONFIG_EN_UART_BRIDGE)
bool uart_bridge_mode()
{
if (!inited_)
{
return false;
}
bool mode = false;
mutex_enter_blocking(&gpio_mutex_);
gpio_pull_up(MODE_SEL_PIN);
if (gpio_get(MODE_SEL_PIN) == 0)
{
mode = true;
}
mutex_exit(&gpio_mutex_);
return mode;
}
#endif // defined(CONFIG_EN_UART_BRIDGE)
#if defined(CONFIG_EN_ESP32)
void reset_esp32_unsafe()
{
gpio_put(ESP_RST_PIN, 0);
sleep_ms(500);
gpio_put(ESP_RST_PIN, 1);
sleep_ms(250);
}
void reset_esp32()
{
if (!inited_)
{
return;
}
mutex_enter_blocking(&gpio_mutex_);
reset_esp32_unsafe();
mutex_exit(&gpio_mutex_);
}
void enter_esp32_prog_mode()
{
if (!inited_)
{
return;
}
mutex_enter_blocking(&gpio_mutex_);
gpio_put(ESP_PROG_PIN, 1);
sleep_ms(250);
gpio_put(ESP_PROG_PIN, 0);
sleep_ms(250);
reset_esp32_unsafe();
gpio_put(ESP_PROG_PIN, 1);
mutex_exit(&gpio_mutex_);
}
#endif // defined(CONFIG_EN_ESP32)
void reboot()
{
#define AIRCR_REG (*((volatile uint32_t *)(0xE000ED0C)))
#define AIRCR_SYSRESETREQ (1 << 2)
#define AIRCR_VECTKEY (0x5FA << 16)
AIRCR_REG = AIRCR_VECTKEY | AIRCR_SYSRESETREQ;
while(1);
}
void init_board()
{
if (inited_)
{
return;
}
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_))
{
mutex_init(&gpio_mutex_);
}
mutex_enter_blocking(&gpio_mutex_);
init_uart_debug_unsafe();
init_vcc_en_pin_unsafe();
init_rgb_unsafe();
init_led_indicator_unsafe();
init_esp32_io_unsafe();
init_uart_bridge_io_unsafe();
inited_ = true;
mutex_exit(&gpio_mutex_);
#if (OGXM_BOARD != PI_PICOW) // cyw43_arch needs to be inited from core1 first
set_led(false);
#endif
OGXM_LOG("Board initialized\n");
}
} // namespace board_api

View File

@@ -1,18 +0,0 @@
#ifndef _OGXM_BOARD_API_H_
#define _OGXM_BOARD_API_H_
#include <cstdint>
#include <string>
namespace board_api
{
void init_board();
void set_led(bool state);
void reboot();
bool uart_bridge_mode();
void reset_esp32();
void enter_esp32_prog_mode();
}
#endif // _OGXM_BOARD_API_H_

View File

@@ -1,66 +0,0 @@
#ifndef _CDC_DEV_DESCRIPTORS_H_
#define _CDC_DEV_DESCRIPTORS_H_
#include <cstdint>
#include <cstring>
#include "tusb.h"
namespace CDCDesc
{
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
static const uint16_t VID = 0xCafe;
static const uint16_t PID = (0x4000 | _PID_MAP(CDC, 0));
static const uint16_t USB_VER = 0x0200;
const tusb_desc_device_t DESC_DEVICE =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = USB_VER,
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = VID,
.idProduct = PID,
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
enum Itf
{
CDC_0 = 0,
CDC_0_DATA,
ITF_TOTAL
};
static const int CONFIG_LEN = (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN);
static const uint8_t DESC_CONFIG[] =
{
TUD_CONFIG_DESCRIPTOR(1, Itf::ITF_TOTAL, 0, CONFIG_LEN, 0x00, 500),
TUD_CDC_DESCRIPTOR(Itf::CDC_0, 4, 0x80 | (Itf::CDC_0 + 1), 8, (Itf::CDC_0 + 2), 0x80 | (Itf::CDC_0 + 2), 64),
};
static const uint8_t STRING_DESC_LANGUAGE[] = { 0x09, 0x04 };
static const uint8_t STRING_MANUFACTURER[] = "Wired Opposite";
static const uint8_t STRING_PRODUCT[] = "OGX-Mini";
static const uint8_t STRING_INTERFACE[] = "OGX-Mini CDC";
static const uint8_t *DESC_STRING[] =
{
STRING_DESC_LANGUAGE,
STRING_MANUFACTURER,
STRING_PRODUCT,
nullptr, //Serial
STRING_INTERFACE
};
}; // namespace CDCDesc
#endif // _CDC_DEV_DESCRIPTORS_H_

View File

@@ -1,302 +0,0 @@
#ifndef _DINPUT_DESCRIPTORS_H_
#define _DINPUT_DESCRIPTORS_H_
#include <cstdint>
#include <cstring>
#include "tusb.h"
#include "board_config.h"
namespace DInput
{
static constexpr uint8_t DPAD_MASK = 0x0F;
static constexpr uint8_t AXIS_MIN = 0x00;
static constexpr uint8_t AXIS_MID = 0x80;
static constexpr uint8_t AXIS_MAX = 0xFF;
namespace Buttons0
{
static constexpr uint8_t SQUARE = 0x01;
static constexpr uint8_t CROSS = 0x02;
static constexpr uint8_t CIRCLE = 0x04;
static constexpr uint8_t TRIANGLE = 0x08;
static constexpr uint8_t L1 = 0x10;
static constexpr uint8_t R1 = 0x20;
static constexpr uint8_t L2 = 0x40;
static constexpr uint8_t R2 = 0x80;
};
namespace Buttons1
{
static constexpr uint8_t SELECT = 0x01;
static constexpr uint8_t START = 0x02;
static constexpr uint8_t L3 = 0x04;
static constexpr uint8_t R3 = 0x08;
static constexpr uint8_t PS = 0x10;
static constexpr uint8_t TP = 0x20;
};
namespace DPad
{
static constexpr uint8_t UP = 0x00;
static constexpr uint8_t UP_RIGHT = 0x01;
static constexpr uint8_t RIGHT = 0x02;
static constexpr uint8_t DOWN_RIGHT = 0x03;
static constexpr uint8_t DOWN = 0x04;
static constexpr uint8_t DOWN_LEFT = 0x05;
static constexpr uint8_t LEFT = 0x06;
static constexpr uint8_t UP_LEFT = 0x07;
static constexpr uint8_t CENTER = 0x08;
};
#pragma pack(push, 1)
struct InReport
{
uint8_t buttons[2];
uint8_t dpad;
uint8_t joystick_lx;
uint8_t joystick_ly;
uint8_t joystick_rx;
uint8_t joystick_ry;
uint8_t right_axis;
uint8_t left_axis;
uint8_t up_axis;
uint8_t down_axis;
uint8_t triangle_axis;
uint8_t circle_axis;
uint8_t cross_axis;
uint8_t square_axis;
uint8_t l1_axis;
uint8_t r1_axis;
uint8_t l2_axis;
uint8_t r2_axis;
InReport()
{
std::memset(this, 0, sizeof(InReport));
}
};
#pragma pack(pop)
static_assert(sizeof(InReport) == 19, "DInput::InReport is misaligned");
static const uint8_t STRING_DESC_LANGUAGE[] = { 0x09, 0x04 };
static const uint8_t STRING_MANUFACTURER[] = "SHANWAN";
static const uint8_t STRING_PRODUCT[] = "2In1 USB Joystick";
static const uint8_t STRING_VERSION[] = "1.0";
static const uint8_t *STRING_DESCRIPTORS[] __attribute__((unused)) =
{
STRING_DESC_LANGUAGE,
STRING_MANUFACTURER,
STRING_PRODUCT,
STRING_VERSION
};
static const uint8_t DEVICE_DESCRIPTORS[] =
{
0x12, // bLength
0x01, // bDescriptorType (Device)
0x10, 0x01, // bcdUSB 1.10
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 64
0x63, 0x25, // idVendor 0x2563
0x75, 0x05, // idProduct 0x0575
0x00, 0x02, // bcdDevice 4.00
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x00, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t REPORT_DESCRIPTORS[] =
{
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x05, // Usage (Game Pad)
0xA1, 0x01, // Collection (Application)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x35, 0x00, // Physical Minimum (0)
0x45, 0x01, // Physical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x0D, // Report Count (13)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x0D, // Usage Maximum (0x0D)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x03, // Report Count (3)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x25, 0x07, // Logical Maximum (7)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
0x09, 0x39, // Usage (Hat switch)
0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0x65, 0x00, // Unit (None)
0x95, 0x01, // Report Count (1)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x46, 0xFF, 0x00, // Physical Maximum (255)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x32, // Usage (Z)
0x09, 0x35, // Usage (Rz)
0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x09, 0x20, // Usage (0x20)
0x09, 0x21, // Usage (0x21)
0x09, 0x22, // Usage (0x22)
0x09, 0x23, // Usage (0x23)
0x09, 0x24, // Usage (0x24)
0x09, 0x25, // Usage (0x25)
0x09, 0x26, // Usage (0x26)
0x09, 0x27, // Usage (0x27)
0x09, 0x28, // Usage (0x28)
0x09, 0x29, // Usage (0x29)
0x09, 0x2A, // Usage (0x2A)
0x09, 0x2B, // Usage (0x2B)
0x95, 0x0C, // Report Count (12)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x0A, 0x21, 0x26, // Usage (0x2621)
0x95, 0x08, // Report Count (8)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x0A, 0x21, 0x26, // Usage (0x2621)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x26, 0xFF, 0x03, // Logical Maximum (1023)
0x46, 0xFF, 0x03, // Physical Maximum (1023)
0x09, 0x2C, // Usage (0x2C)
0x09, 0x2D, // Usage (0x2D)
0x09, 0x2E, // Usage (0x2E)
0x09, 0x2F, // Usage (0x2F)
0x75, 0x10, // Report Size (16)
0x95, 0x04, // Report Count (4)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
};
// uint8_t const CONFIGURATION_DESCRIPTORS[] =
// {
// 0x09, // bLength
// 0x02, // bDescriptorType (Configuration)
// 0x29, 0x00, // wTotalLength 41
// 0x01, // bNumInterfaces 1
// 0x01, // bConfigurationValue
// 0x00, // iConfiguration (String Index)
// 0x80, // bmAttributes
// 0xFA, // bMaxPower 500mA
// 0x09, // bLength
// 0x04, // bDescriptorType (Interface)
// 0x00, // bInterfaceNumber 0
// 0x00, // bAlternateSetting
// 0x02, // bNumEndpoints 2
// 0x03, // bInterfaceClass
// 0x00, // bInterfaceSubClass
// 0x00, // bInterfaceProtocol
// 0x00, // iInterface (String Index)
// 0x09, // bLength
// 0x21, // bDescriptorType (HID)
// 0x10, 0x01, // bcdHID 1.10
// 0x00, // bCountryCode
// 0x01, // bNumDescriptors
// 0x22, // bDescriptorType[0] (HID)
// 0x89, 0x00, // wDescriptorLength[0] 137
// 0x07, // bLength
// 0x05, // bDescriptorType (Endpoint)
// 0x02, // bEndpointAddress (OUT/H2D)
// 0x03, // bmAttributes (Interrupt)
// 0x20, 0x00, // wMaxPacketSize 32
// 0x0A, // bInterval 10 (unit depends on device speed)
// 0x07, // bLength
// 0x05, // bDescriptorType (Endpoint)
// 0x81, // bEndpointAddress (IN/D2H)
// 0x03, // bmAttributes (Interrupt)
// 0x20, 0x00, // wMaxPacketSize 32
// 0x0A, // bInterval 10 (unit depends on device speed)
// };
enum Itf
{
NUM_HID1 = 0,
#if MAX_GAMEPADS > 1
NUM_HID2,
#endif
#if MAX_GAMEPADS > 2
NUM_HID3,
#endif
#if MAX_GAMEPADS > 3
NUM_HID4,
#endif
NUM_TOTAL
};
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + (TUD_HID_DESC_LEN * MAX_GAMEPADS))
// #define EPNUM_HID1 0x81
// #define EPNUM_HID2 0x82
// #define EPNUM_HID3 0x83
// #define EPNUM_HID4 0x84
uint8_t const CONFIGURATION_DESCRIPTORS[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR( 1,
Itf::NUM_TOTAL,
0,
CONFIG_TOTAL_LEN,
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
500),
// Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
TUD_HID_DESCRIPTOR( Itf::NUM_HID1,
0,
HID_ITF_PROTOCOL_NONE,
sizeof(REPORT_DESCRIPTORS),
(0x80 | (Itf::NUM_HID1 + 1)),
CFG_TUD_HID_EP_BUFSIZE,
1),
#if MAX_GAMEPADS > 1
TUD_HID_DESCRIPTOR( Itf::NUM_HID2,
0,
HID_ITF_PROTOCOL_NONE,
sizeof(REPORT_DESCRIPTORS),
(0x80 | (Itf::NUM_HID2 + 1)),
CFG_TUD_HID_EP_BUFSIZE,
1),
#endif
#if MAX_GAMEPADS > 2
TUD_HID_DESCRIPTOR( Itf::NUM_HID3,
0,
HID_ITF_PROTOCOL_NONE,
sizeof(REPORT_DESCRIPTORS),
(0x80 | (Itf::NUM_HID3 + 1)),
CFG_TUD_HID_EP_BUFSIZE,
1),
#endif
#if MAX_GAMEPADS > 3
TUD_HID_DESCRIPTOR( Itf::NUM_HID4,
0,
HID_ITF_PROTOCOL_NONE,
sizeof(REPORT_DESCRIPTORS),
(0x80 | (Itf::NUM_HID4 + 1)),
CFG_TUD_HID_EP_BUFSIZE,
1)
#endif
};
}; // namespace DInput
#endif // _DINPUT_DESCRIPTORS_H_

View File

@@ -1,50 +0,0 @@
#ifndef _N64_DESCRIPTORS_H_
#define _N64_DESCRIPTORS_H_
#include <cstdint>
namespace N64
{
static constexpr uint16_t DPAD_MASK = 0x0F;
static constexpr uint8_t JOY_MIN = 0x00;
static constexpr uint8_t JOY_MID = 0x80;
static constexpr uint8_t JOY_MAX = 0xFF;
namespace Buttons
{
static constexpr uint16_t DPAD_UP = 0x00;
static constexpr uint16_t DPAD_UP_RIGHT = 0x01;
static constexpr uint16_t DPAD_RIGHT = 0x02;
static constexpr uint16_t DPAD_RIGHT_DOWN = 0x03;
static constexpr uint16_t DPAD_DOWN = 0x04;
static constexpr uint16_t DPAD_DOWN_LEFT = 0x05;
static constexpr uint16_t DPAD_LEFT = 0x06;
static constexpr uint16_t DPAD_LEFT_UP = 0x07;
static constexpr uint16_t DPAD_NONE = 0x08;
static constexpr uint16_t C_UP = (1 << 4);
static constexpr uint16_t C_RIGHT = (1 << 5);
static constexpr uint16_t C_DOWN = (1 << 6);
static constexpr uint16_t C_LEFT = (1 << 7);
static constexpr uint16_t L = (1 << 8);
static constexpr uint16_t R = (1 << 9);
static constexpr uint16_t A = (1 << 10);
static constexpr uint16_t Z = (1 << 11);
static constexpr uint16_t B = (1 << 12);
static constexpr uint16_t START = (1 << 13);
};
#pragma pack(push, 1)
struct InReport
{
uint8_t joystick_x;
uint8_t joystick_y;
uint8_t padding[3];
uint16_t buttons;
};
static_assert(sizeof(InReport) == 7, "N64 InReport size is not correct");
#pragma pack(pop)
}; // namespace N64
#endif // _N64_DESCRIPTORS_H_

View File

@@ -1,440 +0,0 @@
#ifndef _PS3_DESCRIPTORS_H_
#define _PS3_DESCRIPTORS_H_
#include <stdint.h>
#include <cstring>
#include <pico/rand.h>
#include "tusb.h"
namespace PS3
{
static constexpr uint8_t MAGIC_BYTES[8] = { 0x21, 0x26, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
static constexpr uint8_t JOYSTICK_MID = 0x7F;
static constexpr uint16_t SIXAXIS_MID = 0xFF01;
namespace ReportID
{
static constexpr uint8_t FEATURE_01 = 0x01;
static constexpr uint8_t FEATURE_EF = 0xEF;
static constexpr uint8_t GET_PAIRING_INFO = 0xF2;
static constexpr uint8_t FEATURE_F4 = 0xF4;
static constexpr uint8_t FEATURE_F5 = 0xF5;
static constexpr uint8_t FEATURE_F7 = 0xF7;
static constexpr uint8_t FEATURE_F8 = 0xF8;
};
namespace PlugState
{
static constexpr uint8_t PLUGGED = 0x02;
static constexpr uint8_t UNPLUGGED = 0x03;
};
namespace PowerState
{
static constexpr uint8_t CHARGING = 0xEE;
static constexpr uint8_t NOT_CHARGING = 0xF1;
static constexpr uint8_t SHUTDOWN = 0x01;
static constexpr uint8_t DISCHARGING = 0x02;
static constexpr uint8_t LOW = 0x03;
static constexpr uint8_t HIGH = 0x04;
static constexpr uint8_t FULL = 0x05;
};
namespace RumbleState
{
static constexpr uint8_t WIRED_RUMBLE = 0x10;
static constexpr uint8_t WIRED_NO_RUMBLE = 0x12;
static constexpr uint8_t WIRELESS_RUMBLE = 0x14;
static constexpr uint8_t WIRELESS_NO_RUMBLE = 0x16;
};
namespace Buttons0
{
static constexpr uint8_t SELECT = 0x01;
static constexpr uint8_t L3 = 0x02;
static constexpr uint8_t R3 = 0x04;
static constexpr uint8_t START = 0x08;
static constexpr uint8_t DPAD_UP = 0x10;
static constexpr uint8_t DPAD_RIGHT = 0x20;
static constexpr uint8_t DPAD_DOWN = 0x40;
static constexpr uint8_t DPAD_LEFT = 0x80;
};
namespace Buttons1
{
static constexpr uint8_t L2 = 0x01;
static constexpr uint8_t R2 = 0x02;
static constexpr uint8_t L1 = 0x04;
static constexpr uint8_t R1 = 0x08;
static constexpr uint8_t TRIANGLE = 0x10;
static constexpr uint8_t CIRCLE = 0x20;
static constexpr uint8_t CROSS = 0x40;
static constexpr uint8_t SQUARE = 0x80;
};
namespace Buttons2
{
static constexpr uint8_t PS = 0x01;
static constexpr uint8_t TP = 0x02;
};
const uint8_t DEFAULT_OUT_REPORT[] =
{
0x01, 0xff, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0x00, 0x00, 0x00, 0x00, 0x00
};
#pragma pack(push, 1)
struct InReport
{
uint8_t report_id;
uint8_t unk0;
uint8_t buttons[3];
uint8_t unk1;
uint8_t joystick_lx;
uint8_t joystick_ly;
uint8_t joystick_rx;
uint8_t joystick_ry;
uint8_t unk2[2];
uint8_t move_power_status;
uint8_t unk3;
uint8_t up_axis;
uint8_t right_axis;
uint8_t down_axis;
uint8_t left_axis;
uint8_t l2_axis;
uint8_t r2_axis;
uint8_t l1_axis;
uint8_t r1_axis;
uint8_t triangle_axis;
uint8_t circle_axis;
uint8_t cross_axis;
uint8_t square_axis;
uint8_t unk4[3];
uint8_t plugged;
uint8_t power_status;
uint8_t rumble_status;
uint8_t reserved5[9];
uint16_t acceler_x;
uint16_t acceler_y;
uint16_t acceler_z;
uint16_t gyro_z;
InReport()
{
std::memset(this, 0, sizeof(InReport));
report_id = 0x01;
joystick_lx = JOYSTICK_MID;
joystick_ly = JOYSTICK_MID;
joystick_rx = JOYSTICK_MID;
joystick_ry = JOYSTICK_MID;
plugged = PlugState::PLUGGED;
power_status = PowerState::FULL;
rumble_status = RumbleState::WIRED_RUMBLE;
acceler_x = acceler_y = acceler_z = gyro_z = SIXAXIS_MID;
}
};
static_assert(sizeof(InReport) == 49, "PS3::InReport size mismatch");
struct OutReport
{
//uint8_t report_id;
uint8_t reserved0;
struct Rumble
{
uint8_t right_duration; /* Right motor duration (0xff means forever) */
uint8_t right_motor_on; /* Right (small) motor on/off, only supports values of 0 or 1 (off/on) */
uint8_t left_duration; /* Left motor duration (0xff means forever) */
uint8_t left_motor_force; /* left (large) motor, supports force values from 0 to 255 */
} rumble;
uint8_t reserved1[4];
uint8_t leds_bitmap; /* bitmap of enabled LEDs: LED_1 = 0x02, LED_2 = 0x04, ... */
struct LEDs
{
uint8_t time_enabled; /* the total time the led is active (0xff means forever) */
uint8_t duty_length; /* how long a cycle is in deciseconds (0 means "really fast") */
uint8_t enabled;
uint8_t duty_off; /* % of duty_length the led is off (0xff means 100%) */
uint8_t duty_on; /* % of duty_length the led is on (0xff mean 100%) */
} leds[4]; /* LEDx at (4 - x) */
struct LEDs unused; /* LED5, not actually soldered */
uint8_t reserved2[13];
OutReport()
{
std::memset(this, 0, sizeof(OutReport));
std::memcpy(this, DEFAULT_OUT_REPORT, sizeof(DEFAULT_OUT_REPORT));
}
};
static_assert(sizeof(OutReport) == 48, "PS3::OutReport size mismatch");
static_assert(sizeof(OutReport) >= sizeof(DEFAULT_OUT_REPORT));
static constexpr uint8_t DEFAULT_BT_INFO_HEADER[] =
{
0xFF, 0xFF,
0x00, 0x20, 0x40, 0xCE, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
struct BTInfo
{
uint8_t reserved0[2];
uint8_t device_address[7]; // leading zero followed by address
uint8_t host_address[7]; // leading zero followed by address
uint8_t reserved1;
BTInfo()
{
std::memset(this, 0, sizeof(BTInfo));
std::memcpy(device_address, DEFAULT_BT_INFO_HEADER, sizeof(DEFAULT_BT_INFO_HEADER));
for (uint8_t addr = 0; addr < 3; addr++)
{
device_address[4 + addr] = static_cast<uint8_t>(get_rand_32() % 0xff);
}
for (uint8_t addr = 0; addr < 6; addr++)
{
host_address[1 + addr] = static_cast<uint8_t>(get_rand_32() % 0xff);
}
}
};
static_assert(sizeof(BTInfo) == 17, "PS3::BTInfo size mismatch");
static_assert(sizeof(BTInfo) >= sizeof(DEFAULT_BT_INFO_HEADER));
#pragma pack(pop)
static const uint8_t STRING_LANGUAGE[] = { 0x09, 0x04 };
static const uint8_t STRING_MANUFACTURER[] = "Sony";
static const uint8_t STRING_PRODUCT[] = "PLAYSTATION(R)3 Controller";
static const uint8_t STRING_VERSION[] = "1.0";
static const uint8_t *STRING_DESCRIPTORS[] __attribute__((unused)) =
{
STRING_LANGUAGE,
STRING_MANUFACTURER,
STRING_PRODUCT,
STRING_VERSION
};
static const uint8_t DEVICE_DESCRIPTORS[] =
{
0x12, // bLength
0x01, // bDescriptorType (Device)
0x00, 0x02, // bcdUSB 2.00
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 64
0x4C, 0x05, // idVendor 0x054C
0x68, 0x02, // idProduct 0x0268
0x00, 0x01, // bcdDevice 2.00
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x00, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t REPORT_DESCRIPTORS[] =
{
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x04, // Usage (Joystick)
0xA1, 0x01, // Collection (Physical)
0xA1, 0x02, // Collection (Application)
0x85, 0x01, // Report ID (1)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
// NOTE: reserved byte
0x75, 0x01, // Report Size (1)
0x95, 0x13, // Report Count (19)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x35, 0x00, // Physical Minimum (0)
0x45, 0x01, // Physical Maximum (1)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x13, // Usage Maximum (0x13)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x01, // Report Size (1)
0x95, 0x0D, // Report Count (13)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
// NOTE: 32 bit integer, where 0:18 are buttons and 19:31 are reserved
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Undefined)
0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4)
0x35, 0x00, // Physical Minimum (0)
0x46, 0xFF, 0x00, // Physical Maximum (255)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x32, // Usage (Z)
0x09, 0x35, // Usage (Rz)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
// NOTE: four joysticks
0xC0, // End Collection
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x75, 0x08, // Report Size (8)
0x95, 0x27, // Report Count (39)
0x09, 0x01, // Usage (Pointer)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x08, // Report Size (8)
0x95, 0x30, // Report Count (48)
0x09, 0x01, // Usage (Pointer)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x75, 0x08, // Report Size (8)
0x95, 0x30, // Report Count (48)
0x09, 0x01, // Usage (Pointer)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
0xA1, 0x02, // Collection (Application)
0x85, 0x02, // Report ID (2)
0x75, 0x08, // Report Size (8)
0x95, 0x30, // Report Count (48)
0x09, 0x01, // Usage (Pointer)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
0xA1, 0x02, // Collection (Application)
0x85, 0xEE, // Report ID (238)
0x75, 0x08, // Report Size (8)
0x95, 0x30, // Report Count (48)
0x09, 0x01, // Usage (Pointer)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
0xA1, 0x02, // Collection (Application)
0x85, 0xEF, // Report ID (239)
0x75, 0x08, // Report Size (8)
0x95, 0x30, // Report Count (48)
0x09, 0x01, // Usage (Pointer)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
0xC0, // End Collection
};
static const uint8_t CONFIGURATION_DESCRIPTORS[] =
{
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0x29, 0x00, // wTotalLength 41
0x01, // bNumInterfaces 1
0x01, // bConfigurationValue
0x00, // iConfiguration (String Index)
0x80, // bmAttributes
0xFA, // bMaxPower 500mA
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x00, // bInterfaceNumber 0
0x00, // bAlternateSetting
0x02, // bNumEndpoints 2
0x03, // bInterfaceClass
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x09, // bLength
0x21, // bDescriptorType (HID)
0x11, 0x01, // bcdHID 1.17
0x00, // bCountryCode
0x01, // bNumDescriptors
0x22, // bDescriptorType[0] (HID)
0x94, 0x00, // wDescriptorLength[0] 148
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x02, // bEndpointAddress (OUT/H2D)
0x03, // bmAttributes (Interrupt)
0x40, 0x00, // wMaxPacketSize 64
0x01, // bInterval 1 (unit depends on device speed)
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x81, // bEndpointAddress (IN/D2H)
0x03, // bmAttributes (Interrupt)
0x40, 0x00, // wMaxPacketSize 64
0x01, // bInterval 1 (unit depends on device speed)
};
static constexpr uint8_t OUTPUT_0x01[] =
{
0x01, 0x04, 0x00, 0x0b, 0x0c, 0x01, 0x02, 0x18,
0x18, 0x18, 0x18, 0x09, 0x0a, 0x10, 0x11, 0x12,
0x13, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02,
0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x04, 0x04,
0x04, 0x04, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02,
0x07, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// calibration data
static constexpr uint8_t OUTPUT_0xEF[] =
{
0xef, 0x04, 0x00, 0x0b, 0x03, 0x01, 0xa0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff,
0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
};
// unknown
static constexpr uint8_t OUTPUT_0xF5[] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // host address - must match 0xf2
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// unknown
static constexpr uint8_t OUTPUT_0xF7[] =
{
0x02, 0x01, 0xf8, 0x02, 0xe2, 0x01, 0x05, 0xff,
0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// unknown
static constexpr uint8_t OUTPUT_0xF8[] =
{
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
} // namespace PS3
#endif // _PS3_DESCRIPTORS_H_

View File

@@ -1,114 +0,0 @@
#ifndef _PS4_DESCRIPTORS_H_
#define _PS4_DESCRIPTORS_H_
#include <cstdint>
namespace PS4
{
static constexpr uint8_t DPAD_MASK = 0x0F;
static constexpr uint8_t COUNTER_MASK = 0xFC;
static constexpr uint8_t AXIS_MAX = 0xFF;
static constexpr uint8_t AXIS_MIN = 0x00;
static constexpr uint8_t JOYSTICK_MID = 0x80;
namespace Buttons0
{
static constexpr uint8_t DPAD_UP = 0x00;
static constexpr uint8_t DPAD_UP_RIGHT = 0x01;
static constexpr uint8_t DPAD_RIGHT = 0x02;
static constexpr uint8_t DPAD_RIGHT_DOWN = 0x03;
static constexpr uint8_t DPAD_DOWN = 0x04;
static constexpr uint8_t DPAD_DOWN_LEFT = 0x05;
static constexpr uint8_t DPAD_LEFT = 0x06;
static constexpr uint8_t DPAD_LEFT_UP = 0x07;
static constexpr uint8_t DPAD_CENTER = 0x08;
static constexpr uint8_t SQUARE = 0x10;
static constexpr uint8_t CROSS = 0x20;
static constexpr uint8_t CIRCLE = 0x40;
static constexpr uint8_t TRIANGLE = 0x80;
};
namespace Buttons1
{
static constexpr uint8_t L1 = 0x01;
static constexpr uint8_t R1 = 0x02;
static constexpr uint8_t L2 = 0x04;
static constexpr uint8_t R2 = 0x08;
static constexpr uint8_t SHARE = 0x10;
static constexpr uint8_t OPTIONS = 0x20;
static constexpr uint8_t L3 = 0x40;
static constexpr uint8_t R3 = 0x80;
};
namespace Buttons2
{
static constexpr uint8_t PS = 0x01;
static constexpr uint8_t TP = 0x02;
};
#pragma pack(push, 1)
struct InReport
{
uint8_t report_id;
uint8_t joystick_lx;
uint8_t joystick_ly;
uint8_t joystick_rx;
uint8_t joystick_ry;
uint8_t buttons[3];
uint8_t trigger_l;
uint8_t trigger_r;
};
static_assert(sizeof(InReport) == 10);
struct OutReport
{
uint8_t report_id;
uint8_t set_rumble : 1;
uint8_t set_led : 1;
uint8_t set_led_blink : 1;
uint8_t set_ext_write : 1;
uint8_t set_left_volume : 1;
uint8_t set_right_volume : 1;
uint8_t set_mic_volume : 1;
uint8_t set_speaker_volume : 1;
uint8_t set_flags2;
uint8_t reserved;
uint8_t motor_right;
uint8_t motor_left;
uint8_t lightbar_red;
uint8_t lightbar_green;
uint8_t lightbar_blue;
uint8_t lightbar_blink_on;
uint8_t lightbar_blink_off;
uint8_t ext_data[8];
uint8_t volume_left;
uint8_t volume_right;
uint8_t volume_mic;
uint8_t volume_speaker;
uint8_t other[9];
};
static_assert(sizeof(OutReport) == 32);
#pragma pack(pop)
static const uint8_t LED_COLORS[][3] =
{
{ 0x00, 0x00, 0x40 }, // Blue
{ 0x40, 0x00, 0x00 }, // Red
{ 0x00, 0x40, 0x00 }, // Green
{ 0x20, 0x00, 0x20 }, // Pink
};
}; // namespace PS4
#endif // _PS4_DESCRIPTORS_H_

View File

@@ -1,150 +0,0 @@
#ifndef _PS5_DESCRIPTORS_H_
#define _PS5_DESCRIPTORS_H_
#include <cstdint>
#include <cstring>
namespace PS5
{
static constexpr uint8_t DPAD_MASK = 0x0F;
static constexpr uint8_t JOYSTICK_MID = 0x80;
namespace OutReportID
{
static constexpr uint8_t CONTROL = 0x02;
static constexpr uint8_t RUMBLE = 0x05;
};
namespace Buttons0
{
static constexpr uint8_t DPAD_UP = 0x00;
static constexpr uint8_t DPAD_UP_RIGHT = 0x01;
static constexpr uint8_t DPAD_RIGHT = 0x02;
static constexpr uint8_t DPAD_RIGHT_DOWN = 0x03;
static constexpr uint8_t DPAD_DOWN = 0x04;
static constexpr uint8_t DPAD_DOWN_LEFT = 0x05;
static constexpr uint8_t DPAD_LEFT = 0x06;
static constexpr uint8_t DPAD_LEFT_UP = 0x07;
static constexpr uint8_t DPAD_CENTER = 0x08;
static constexpr uint8_t SQUARE = 0x10;
static constexpr uint8_t CROSS = 0x20;
static constexpr uint8_t CIRCLE = 0x40;
static constexpr uint8_t TRIANGLE = 0x80;
};
namespace Buttons1
{
static constexpr uint8_t L1 = 0x01;
static constexpr uint8_t R1 = 0x02;
static constexpr uint8_t L2 = 0x04;
static constexpr uint8_t R2 = 0x08;
static constexpr uint8_t SHARE = 0x10;
static constexpr uint8_t OPTIONS = 0x20;
static constexpr uint8_t L3 = 0x40;
static constexpr uint8_t R3 = 0x80;
};
namespace Buttons2
{
static constexpr uint8_t PS = 0x01;
static constexpr uint8_t TP = 0x02;
static constexpr uint8_t MUTE = 0x04;
};
#pragma pack(push, 1)
struct InReport
{
uint8_t report_id;
uint8_t joystick_lx;
uint8_t joystick_ly;
uint8_t joystick_rx;
uint8_t joystick_ry;
uint8_t trigger_l;
uint8_t trigger_r;
uint8_t seq_number;
uint8_t buttons[4];
// Motion sensors
uint16_t gyro[3]; // Gyroscope data for x, y, z axes
uint16_t accel[3]; // Accelerometer data for x, y, z axes
uint32_t sensor_timestamp; // Timestamp for sensor data
uint8_t reserved0;
struct Touchpad
{
uint32_t counter : 7; // Incremented every time a finger touches the touchpad
uint32_t touching : 1; // Indicates if a finger is currently touching the touchpad
uint32_t x : 12; // X coordinate of the touchpoint
uint32_t y : 12; // Y coordinate of the touchpoint
} points[2]; // Array of touchpoints (up to 2)
// uint32_t touchpad[2];
uint8_t reserved1[12];
uint8_t status; // ?
uint8_t reserved2[10];
InReport()
{
std::memset(this, 0, sizeof(InReport));
}
};
static_assert(sizeof(InReport) == 60, "PS5::InReport is not correct size");
struct OutReport
{
uint8_t report_id;
uint8_t control_flag[2];
/* For DualShock 4 compatibility mode. */
uint8_t motor_right;
uint8_t motor_left;
/* Audio controls */
uint8_t headphone_audio_volume; /* 0-0x7f */
uint8_t speaker_audio_volume; /* 0-255 */
uint8_t internal_microphone_volume; /* 0-0x40 */
uint8_t audio_flags;
uint8_t mute_button_led;
uint8_t power_save_control;
/* right trigger motor */
uint8_t right_trigger_motor_mode;
uint8_t right_trigger_param[10];
/* right trigger motor */
uint8_t left_trigger_motor_mode;
uint8_t left_trigger_param[10];
uint8_t reserved2[4];
uint8_t reduce_motor_power;
uint8_t audio_flags2; /* 3 first bits: speaker pre-gain */
/* LEDs and lightbar */
uint8_t led_control_flag;
uint8_t reserved3[2];
uint8_t pulse_option;
uint8_t led_brightness;
uint8_t player_number;
uint8_t lightbar_red;
uint8_t lightbar_green;
uint8_t lightbar_blue;
OutReport()
{
std::memset(this, 0, sizeof(OutReport));
}
};
static_assert(sizeof(OutReport) == 48);
#pragma pack(pop)
}; // namespace PS5
#endif // _PS5_DESCRIPTORS_H_

View File

@@ -1,150 +0,0 @@
#ifndef _PSCLASSIC_DESCRIPTORS_H_
#define _PSCLASSIC_DESCRIPTORS_H_
#include <stdint.h>
namespace PSClassic
{
static constexpr uint16_t DPAD_MASK = 0x3C00;
static constexpr uint16_t JOTSTICK_MID = 0x7f;
namespace Buttons
{
static constexpr uint16_t TRIANGLE = (1U << 0);
static constexpr uint16_t CIRCLE = (1U << 1);
static constexpr uint16_t CROSS = (1U << 2);
static constexpr uint16_t SQUARE = (1U << 3);
static constexpr uint16_t L2 = (1U << 4);
static constexpr uint16_t R2 = (1U << 5);
static constexpr uint16_t L1 = (1U << 6);
static constexpr uint16_t R1 = (1U << 7);
static constexpr uint16_t SELECT = (1U << 8);
static constexpr uint16_t START = (1U << 9);
static constexpr uint16_t UP_LEFT = 0x0000 & DPAD_MASK;
static constexpr uint16_t UP = 0x0400 & DPAD_MASK;
static constexpr uint16_t UP_RIGHT = 0x0800 & DPAD_MASK;
static constexpr uint16_t LEFT = 0x1000 & DPAD_MASK;
static constexpr uint16_t CENTER = 0x1400 & DPAD_MASK;
static constexpr uint16_t RIGHT = 0x1800 & DPAD_MASK;
static constexpr uint16_t DOWN_LEFT = 0x2000 & DPAD_MASK;
static constexpr uint16_t DOWN = 0x2400 & DPAD_MASK;
static constexpr uint16_t DOWN_RIGHT = 0x2800 & DPAD_MASK;
};
struct InReport
{
uint16_t buttons;
};
static const uint8_t STRING_LANGUAGE[] = { 0x09, 0x04 };
static const uint8_t STRING_MANUFACTURER[] = "Sony Interactive Entertainment";
static const uint8_t STRING_PRODUCT[] = "Controller";
static const uint8_t STRING_VERSION[] = { };
static const uint8_t *STRING_DESCRIPTORS[] __attribute__((unused)) =
{
STRING_LANGUAGE,
STRING_MANUFACTURER,
STRING_PRODUCT,
STRING_VERSION
};
static const uint8_t DEVICE_DESCRIPTORS[] =
{
0x12, // bLength
0x01, // bDescriptorType (Device)
0x00, 0x02, // bcdUSB 2.00
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 64
0x4C, 0x05, // idVendor 0x054C
0xDA, 0x0C, // idProduct 0x0CDA
0x00, 0x01, // bcdDevice 2.00
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x00, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t HID_DESCRIPTORS[] =
{
0x09, // bLength
0x21, // bDescriptorType (HID)
0x11, 0x01, // bcdHID 1.11
0x00, // bCountryCode
0x01, // bNumDescriptors
0x22, // bDescriptorType[0] (HID)
0x31, 0x00, // wDescriptorLength[0] 49
};
static const uint8_t CONFIGURATION_DESCRIPTORS[] =
{
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0x22, 0x00, // wTotalLength 34
0x01, // bNumInterfaces 1
0x01, // bConfigurationValue
0x00, // iConfiguration (String Index)
0xA0, // bmAttributes Remote Wakeup
0x32, // bMaxPower 100mA
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x00, // bInterfaceNumber 0
0x00, // bAlternateSetting
0x01, // bNumEndpoints 1
0x03, // bInterfaceClass
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x09, // bLength
0x21, // bDescriptorType (HID)
0x11, 0x01, // bcdHID 1.11
0x00, // bCountryCode
0x01, // bNumDescriptors
0x22, // bDescriptorType[0] (HID)
0x31, 0x00, // wDescriptorLength[0] 49
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x81, // bEndpointAddress (IN/D2H)
0x03, // bmAttributes (Interrupt)
0x40, 0x00, // wMaxPacketSize 64
0x0A, // bInterval 10 (unit depends on device speed)
};
static const uint8_t REPORT_DESCRIPTORS[] =
{
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x05, // Usage (Game Pad)
0xA1, 0x01, // Collection (Application)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x0A, // Report Count (10)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x0A, // Usage Maximum (0x0A)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x02, // Logical Maximum (2)
0x35, 0x00, // Physical Minimum (0)
0x45, 0x02, // Physical Maximum (2)
0x75, 0x02, // Report Size (2)
0x95, 0x02, // Report Count (2)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x01, // Report Size (1)
0x95, 0x02, // Report Count (2)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
};
}; // namespace PSClassic
#endif // _PSCLASSIC_DESCRIPTORS_H_

View File

@@ -1,270 +0,0 @@
#ifndef SWITCH_PRO_DESCRIPTORS_H_
#define SWITCH_PRO_DESCRIPTORS_H_
#include <stdint.h>
namespace SwitchPro
{
static constexpr uint8_t INFO_CONN_MASK = 0xAB;
static constexpr uint8_t INFO_BATTERY_MASK = 0x0F;
namespace CMD
{
static constexpr uint8_t HID = 0x80;
static constexpr uint8_t RUMBLE_ONLY = 0x10;
static constexpr uint8_t AND_RUMBLE = 0x01;
static constexpr uint8_t LED = 0x30;
static constexpr uint8_t LED_HOME = 0x38;
static constexpr uint8_t GYRO = 0x40;
static constexpr uint8_t MODE = 0x03;
static constexpr uint8_t FULL_REPORT_MODE = 0x30;
static constexpr uint8_t HANDSHAKE = 0x02;
static constexpr uint8_t DISABLE_TIMEOUT = 0x04;
}
namespace Buttons0
{
static constexpr uint8_t Y = 0x01;
static constexpr uint8_t X = 0x02;
static constexpr uint8_t B = 0x04;
static constexpr uint8_t A = 0x08;
static constexpr uint8_t R = 0x40;
static constexpr uint8_t ZR = 0x80;
};
namespace Buttons1
{
static constexpr uint8_t MINUS = 0x01;
static constexpr uint8_t PLUS = 0x02;
static constexpr uint8_t L3 = 0x04;
static constexpr uint8_t R3 = 0x08;
static constexpr uint8_t HOME = 0x10;
static constexpr uint8_t CAPTURE = 0x20;
};
namespace Buttons2
{
static constexpr uint8_t DPAD_DOWN = 0x01;
static constexpr uint8_t DPAD_UP = 0x02;
static constexpr uint8_t DPAD_RIGHT = 0x04;
static constexpr uint8_t DPAD_LEFT = 0x08;
static constexpr uint8_t L = 0x40;
static constexpr uint8_t ZL = 0x80;
};
#pragma pack(push, 1)
struct InReport
{
uint8_t report_id;
uint8_t timer;
// uint8_t connInfo : 4;
// uint8_t battery : 4;
uint8_t info;
uint8_t buttons[3];
// uint16_t leftX : 12;
// uint16_t leftY : 12;
// uint16_t rightX : 12;
// uint16_t rightY : 12;
uint8_t joysticks[6];
uint8_t vibrator;
uint16_t accelerX;
uint16_t accelerY;
uint16_t accelerZ;
uint16_t velocityX;
uint16_t velocityY;
uint16_t velocityZ;
};
static_assert(sizeof(InReport) == 25, "InReport size is not correct");
struct OutReport
{
uint8_t command;
uint8_t sequence_counter;
uint8_t rumble_l[4];
uint8_t rumble_r[4];
uint8_t sub_command;
uint8_t sub_command_args[3];
};
static_assert(sizeof(OutReport) == 14, "OutReport size is not correct");
#pragma pack(pop)
// static const uint8_t switch_pro_string_language[] = { 0x09, 0x04 };
// static const uint8_t switch_pro_string_manufacturer[] = "Nintnedo Co., Ltd.";
// static const uint8_t switch_pro_string_product[] = "Pro Controller";
// static const uint8_t switch_pro_string_version[] = "000000000001";
// static const uint8_t *switch_pro_string_descriptors[] __attribute__((unused)) =
// {
// switch_pro_string_language,
// switch_pro_string_product, // switch these?
// switch_pro_string_manufacturer, // ?
// switch_pro_string_version
// };
// static const uint8_t switch_pro_device_descriptor[] =
// {
// 0x12, // bLength
// 0x01, // bDescriptorType (Device)
// 0x00, 0x02, // bcdUSB 2.00
// 0x00, // bDeviceClass (Use class information in the Interface Descriptors)
// 0x00, // bDeviceSubClass
// 0x00, // bDeviceProtocol
// 0x40, // bMaxPacketSize0 64
// 0x7E, 0x05, // idVendor 0x057E
// 0x09, 0x20, // idProduct 0x2009
// 0x00, 0x02, // bcdDevice 4.00
// 0x01, // iManufacturer (String Index)
// 0x02, // iProduct (String Index)
// 0x03, // iSerialNumber (String Index)
// 0x01, // bNumConfigurations 1
// };
// static const uint8_t switch_pro_configuration_descriptor[] =
// {
// 0x09, // bLength
// 0x02, // bDescriptorType (Configuration)
// 0x29, 0x00, // wTotalLength 41
// 0x01, // bNumInterfaces 1
// 0x01, // bConfigurationValue
// 0x00, // iConfiguration (String Index)
// 0xA0, // bmAttributes Remote Wakeup
// 0xFA, // bMaxPower 500mA
// 0x09, // bLength
// 0x04, // bDescriptorType (Interface)
// 0x00, // bInterfaceNumber 0
// 0x00, // bAlternateSetting
// 0x02, // bNumEndpoints 2
// 0x03, // bInterfaceClass
// 0x00, // bInterfaceSubClass
// 0x00, // bInterfaceProtocol
// 0x00, // iInterface (String Index)
// 0x09, // bLength
// 0x21, // bDescriptorType (HID)
// 0x11, 0x01, // bcdHID 1.11
// 0x00, // bCountryCode
// 0x01, // bNumDescriptors
// 0x22, // bDescriptorType[0] (HID)
// 0xCB, 0x00, // wDescriptorLength[0] 203
// 0x07, // bLength
// 0x05, // bDescriptorType (Endpoint)
// 0x81, // bEndpointAddress (IN/D2H)
// 0x03, // bmAttributes (Interrupt)
// 0x40, 0x00, // wMaxPacketSize 64
// 0x08, // bInterval 8 (unit depends on device speed)
// 0x07, // bLength
// 0x05, // bDescriptorType (Endpoint)
// 0x01, // bEndpointAddress (OUT/H2D)
// 0x03, // bmAttributes (Interrupt)
// 0x40, 0x00, // wMaxPacketSize 64
// 0x08, // bInterval 8 (unit depends on device speed)
// };
// static const uint8_t switch_pro_report_descriptor[] =
// {
// 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
// 0x15, 0x00, // Logical Minimum (0)
// 0x09, 0x04, // Usage (Joystick)
// 0xA1, 0x01, // Collection (Application)
// 0x85, 0x30, // Report ID (48)
// 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
// 0x05, 0x09, // Usage Page (Button)
// 0x19, 0x01, // Usage Minimum (0x01)
// 0x29, 0x0A, // Usage Maximum (0x0A)
// 0x15, 0x00, // Logical Minimum (0)
// 0x25, 0x01, // Logical Maximum (1)
// 0x75, 0x01, // Report Size (1)
// 0x95, 0x0A, // Report Count (10)
// 0x55, 0x00, // Unit Exponent (0)
// 0x65, 0x00, // Unit (None)
// 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
// 0x05, 0x09, // Usage Page (Button)
// 0x19, 0x0B, // Usage Minimum (0x0B)
// 0x29, 0x0E, // Usage Maximum (0x0E)
// 0x15, 0x00, // Logical Minimum (0)
// 0x25, 0x01, // Logical Maximum (1)
// 0x75, 0x01, // Report Size (1)
// 0x95, 0x04, // Report Count (4)
// 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
// 0x75, 0x01, // Report Size (1)
// 0x95, 0x02, // Report Count (2)
// 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
// 0x0B, 0x01, 0x00, 0x01, 0x00, // Usage (0x010001)
// 0xA1, 0x00, // Collection (Physical)
// 0x0B, 0x30, 0x00, 0x01, 0x00, // Usage (0x010030)
// 0x0B, 0x31, 0x00, 0x01, 0x00, // Usage (0x010031)
// 0x0B, 0x32, 0x00, 0x01, 0x00, // Usage (0x010032)
// 0x0B, 0x35, 0x00, 0x01, 0x00, // Usage (0x010035)
// 0x15, 0x00, // Logical Minimum (0)
// 0x27, 0xFF, 0xFF, 0x00, 0x00, // Logical Maximum (65534)
// 0x75, 0x10, // Report Size (16)
// 0x95, 0x04, // Report Count (4)
// 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
// 0xC0, // End Collection
// 0x0B, 0x39, 0x00, 0x01, 0x00, // Usage (0x010039)
// 0x15, 0x00, // Logical Minimum (0)
// 0x25, 0x07, // Logical Maximum (7)
// 0x35, 0x00, // Physical Minimum (0)
// 0x46, 0x3B, 0x01, // Physical Maximum (315)
// 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
// 0x75, 0x04, // Report Size (4)
// 0x95, 0x01, // Report Count (1)
// 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
// 0x05, 0x09, // Usage Page (Button)
// 0x19, 0x0F, // Usage Minimum (0x0F)
// 0x29, 0x12, // Usage Maximum (0x12)
// 0x15, 0x00, // Logical Minimum (0)
// 0x25, 0x01, // Logical Maximum (1)
// 0x75, 0x01, // Report Size (1)
// 0x95, 0x04, // Report Count (4)
// 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
// 0x75, 0x08, // Report Size (8)
// 0x95, 0x34, // Report Count (52)
// 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
// 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
// 0x85, 0x21, // Report ID (33)
// 0x09, 0x01, // Usage (0x01)
// 0x75, 0x08, // Report Size (8)
// 0x95, 0x3F, // Report Count (63)
// 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
// 0x85, 0x81, // Report ID (-127)
// 0x09, 0x02, // Usage (0x02)
// 0x75, 0x08, // Report Size (8)
// 0x95, 0x3F, // Report Count (63)
// 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
// 0x85, 0x01, // Report ID (1)
// 0x09, 0x03, // Usage (0x03)
// 0x75, 0x08, // Report Size (8)
// 0x95, 0x3F, // Report Count (63)
// 0x91, 0x83, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
// 0x85, 0x10, // Report ID (16)
// 0x09, 0x04, // Usage (0x04)
// 0x75, 0x08, // Report Size (8)
// 0x95, 0x3F, // Report Count (63)
// 0x91, 0x83, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
// 0x85, 0x80, // Report ID (-128)
// 0x09, 0x05, // Usage (0x05)
// 0x75, 0x08, // Report Size (8)
// 0x95, 0x3F, // Report Count (63)
// 0x91, 0x83, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
// 0x85, 0x82, // Report ID (-126)
// 0x09, 0x06, // Usage (0x06)
// 0x75, 0x08, // Report Size (8)
// 0x95, 0x3F, // Report Count (63)
// 0x91, 0x83, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
// 0xC0, // End Collection
// };
}; // namespace SwitchPro
#endif // SWITCH_PRO_DESCRIPTORS_H_

View File

@@ -1,258 +0,0 @@
#ifndef _SWITCH_WIRED_DESCRIPTORS_H_
#define _SWITCH_WIRED_DESCRIPTORS_H_
#include <stdint.h>
#include "tusb.h"
namespace SwitchWired
{
static constexpr uint8_t JOYSTICK_MID = 0x80;
namespace DPad
{
static constexpr uint8_t UP = 0x00;
static constexpr uint8_t UP_RIGHT = 0x01;
static constexpr uint8_t RIGHT = 0x02;
static constexpr uint8_t DOWN_RIGHT = 0x03;
static constexpr uint8_t DOWN = 0x04;
static constexpr uint8_t DOWN_LEFT = 0x05;
static constexpr uint8_t LEFT = 0x06;
static constexpr uint8_t UP_LEFT = 0x07;
static constexpr uint8_t CENTER = 0x08;
};
namespace Buttons
{
static constexpr uint16_t Y = (1U << 0);
static constexpr uint16_t B = (1U << 1);
static constexpr uint16_t A = (1U << 2);
static constexpr uint16_t X = (1U << 3);
static constexpr uint16_t L = (1U << 4);
static constexpr uint16_t R = (1U << 5);
static constexpr uint16_t ZL = (1U << 6);
static constexpr uint16_t ZR = (1U << 7);
static constexpr uint16_t MINUS = (1U << 8);
static constexpr uint16_t PLUS = (1U << 9);
static constexpr uint16_t L3 = (1U << 10);
static constexpr uint16_t R3 = (1U << 11);
static constexpr uint16_t HOME = (1U << 12);
static constexpr uint16_t CAPTURE = (1U << 13);
};
#pragma pack(push, 1)
struct InReport
{
uint16_t buttons{0};
uint8_t dpad{DPad::CENTER};
uint8_t joystick_lx{JOYSTICK_MID};
uint8_t joystick_ly{JOYSTICK_MID};
uint8_t joystick_rx{JOYSTICK_MID};
uint8_t joystick_ry{JOYSTICK_MID};
uint8_t vendor{0};
};
static_assert(sizeof(InReport) == 8, "SwitchWired::InReport is not the correct size");
#pragma pack(pop)
static const uint8_t STRING_LANGUAGE[] = { 0x09, 0x04 };
static const uint8_t STRING_MANUFACTURER[] = "HORI CO.,LTD.";
static const uint8_t STRING_PRODUCT[] = "POKKEN CONTROLLER";
static const uint8_t STRING_VERSION[] = "1.0";
static const uint8_t *STRING_DESCRIPTORS[] __attribute__((unused)) =
{
STRING_LANGUAGE,
STRING_MANUFACTURER,
STRING_PRODUCT,
STRING_VERSION
};
static const uint8_t DEVICE_DESCRIPTORS[] =
{
0x12, // bLength
0x01, // bDescriptorType (Device)
0x00, 0x02, // bcdUSB 2.00
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 64
0x0D, 0x0F, // idVendor 0x0F0D
0x92, 0x00, // idProduct 0x92
0x00, 0x01, // bcdDevice 2.00
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x00, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t HID_DESCRIPTORS[] =
{
0x09, // bLength
0x21, // bDescriptorType (HID)
0x11, 0x01, // bcdHID 1.11
0x00, // bCountryCode
0x01, // bNumDescriptors
0x22, // bDescriptorType[0] (HID)
0x56, 0x00, // wDescriptorLength[0] 86
};
static const uint8_t REPORT_DESCRIPTORS[] =
{
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x05, // Usage (Game Pad)
0xA1, 0x01, // Collection (Application)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x35, 0x00, // Physical Minimum (0)
0x45, 0x01, // Physical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x10, // Report Count (16)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x10, // Usage Maximum (0x10)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x25, 0x07, // Logical Maximum (7)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
0x09, 0x39, // Usage (Hat switch)
0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0x65, 0x00, // Unit (None)
0x95, 0x01, // Report Count (1)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x46, 0xFF, 0x00, // Physical Maximum (255)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x32, // Usage (Z)
0x09, 0x35, // Usage (Rz)
0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x09, 0x20, // Usage (0x20)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x0A, 0x21, 0x26, // Usage (0x2621)
0x95, 0x08, // Report Count (8)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
};
// static const uint8_t CONFIGURATION_DESCRIPTORS[] =
// {
// 0x09, // bLength
// 0x02, // bDescriptorType (Configuration)
// 0x29, 0x00, // wTotalLength 41
// 0x01, // bNumInterfaces 1
// 0x01, // bConfigurationValue
// 0x00, // iConfiguration (String Index)
// 0x80, // bmAttributes
// 0xFA, // bMaxPower 500mA
// 0x09, // bLength
// 0x04, // bDescriptorType (Interface)
// 0x00, // bInterfaceNumber 0
// 0x00, // bAlternateSetting
// 0x02, // bNumEndpoints 2
// 0x03, // bInterfaceClass
// 0x00, // bInterfaceSubClass
// 0x00, // bInterfaceProtocol
// 0x00, // iInterface (String Index)
// 0x09, // bLength
// 0x21, // bDescriptorType (HID)
// 0x11, 0x01, // bcdHID 1.11
// 0x00, // bCountryCode
// 0x01, // bNumDescriptors
// 0x22, // bDescriptorType[0] (HID)
// 0x56, 0x00, // wDescriptorLength[0] 86
// 0x07, // bLength
// 0x05, // bDescriptorType (Endpoint)
// 0x02, // bEndpointAddress (OUT/H2D)
// 0x03, // bmAttributes (Interrupt)
// 0x40, 0x00, // wMaxPacketSize 64
// 0x01, // bInterval 1 (unit depends on device speed)
// 0x07, // bLength
// 0x05, // bDescriptorType (Endpoint)
// 0x81, // bEndpointAddress (IN/D2H)
// 0x03, // bmAttributes (Interrupt)
// 0x40, 0x00, // wMaxPacketSize 64
// 0x01, // bInterval 1 (unit depends on device speed)
// };
enum
{
ITF_NUM_HID1,
#if MAX_GAMEPADS > 1
ITF_NUM_HID2,
#endif
#if MAX_GAMEPADS > 2
ITF_NUM_HID3,
#endif
#if MAX_GAMEPADS > 3
ITF_NUM_HID4,
#endif
ITF_NUM_TOTAL
};
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + (TUD_HID_DESC_LEN * MAX_GAMEPADS))
#define EPNUM_HID1 0x81
#define EPNUM_HID2 0x82
#define EPNUM_HID3 0x83
#define EPNUM_HID4 0x84
uint8_t const CONFIGURATION_DESCRIPTORS[] = {
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR( 1,
ITF_NUM_TOTAL,
0,
CONFIG_TOTAL_LEN,
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
500),
// Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
TUD_HID_DESCRIPTOR( ITF_NUM_HID1,
0,
HID_ITF_PROTOCOL_NONE,
sizeof(REPORT_DESCRIPTORS),
EPNUM_HID1,
CFG_TUD_HID_EP_BUFSIZE,
1),
#if MAX_GAMEPADS > 1
TUD_HID_DESCRIPTOR( ITF_NUM_HID2,
0,
HID_ITF_PROTOCOL_NONE,
sizeof(REPORT_DESCRIPTORS),
EPNUM_HID2,
CFG_TUD_HID_EP_BUFSIZE,
1),
#endif
#if MAX_GAMEPADS > 2
TUD_HID_DESCRIPTOR( ITF_NUM_HID3,
0,
HID_ITF_PROTOCOL_NONE,
sizeof(REPORT_DESCRIPTORS),
EPNUM_HID3,
CFG_TUD_HID_EP_BUFSIZE,
1),
#endif
#if MAX_GAMEPADS > 3
TUD_HID_DESCRIPTOR( ITF_NUM_HID4,
0,
HID_ITF_PROTOCOL_NONE,
sizeof(REPORT_DESCRIPTORS),
EPNUM_HID4,
CFG_TUD_HID_EP_BUFSIZE,
1)
#endif
};
}; // namespace SwitchWired
#endif // _SWITCH_WIRED_DESCRIPTORS_H_

View File

@@ -1,255 +0,0 @@
#ifndef _XINPUT_DESCRIPTORS_H_
#define _XINPUT_DESCRIPTORS_H_
#include <cstdint>
#include <cstring>
namespace XInput
{
static constexpr size_t ENDPOINT_IN_SIZE = 20;
static constexpr size_t ENDPOINT_OUT_SIZE = 32;
namespace Chatpad
{
static constexpr uint8_t CODE_1 = 23 ;
static constexpr uint8_t CODE_2 = 22 ;
static constexpr uint8_t CODE_3 = 21 ;
static constexpr uint8_t CODE_4 = 20 ;
static constexpr uint8_t CODE_5 = 19 ;
static constexpr uint8_t CODE_6 = 18 ;
static constexpr uint8_t CODE_7 = 17 ;
static constexpr uint8_t CODE_8 = 103;
static constexpr uint8_t CODE_9 = 102;
static constexpr uint8_t CODE_0 = 101;
static constexpr uint8_t CODE_Q = 39 ;
static constexpr uint8_t CODE_W = 38 ;
static constexpr uint8_t CODE_E = 37 ;
static constexpr uint8_t CODE_R = 36 ;
static constexpr uint8_t CODE_T = 35 ;
static constexpr uint8_t CODE_Y = 34 ;
static constexpr uint8_t CODE_U = 33 ;
static constexpr uint8_t CODE_I = 118;
static constexpr uint8_t CODE_O = 117;
static constexpr uint8_t CODE_P = 100;
static constexpr uint8_t CODE_A = 55;
static constexpr uint8_t CODE_S = 54;
static constexpr uint8_t CODE_D = 53;
static constexpr uint8_t CODE_F = 52;
static constexpr uint8_t CODE_G = 51;
static constexpr uint8_t CODE_H = 50;
static constexpr uint8_t CODE_J = 49;
static constexpr uint8_t CODE_K = 119;
static constexpr uint8_t CODE_L = 114;
static constexpr uint8_t CODE_COMMA = 98;
static constexpr uint8_t CODE_Z = 70;
static constexpr uint8_t CODE_X = 69;
static constexpr uint8_t CODE_C = 68;
static constexpr uint8_t CODE_V = 67;
static constexpr uint8_t CODE_B = 66;
static constexpr uint8_t CODE_N = 65;
static constexpr uint8_t CODE_M = 82;
static constexpr uint8_t CODE_PERIOD = 83;
static constexpr uint8_t CODE_ENTER = 99;
static constexpr uint8_t CODE_LEFT = 85;
static constexpr uint8_t CODE_SPACE = 84;
static constexpr uint8_t CODE_RIGHT = 81;
static constexpr uint8_t CODE_BACK = 113;
//Offset byte 25
static constexpr uint8_t CODE_SHIFT = 1;
static constexpr uint8_t CODE_GREEN = 2;
static constexpr uint8_t CODE_ORANGE = 4;
static constexpr uint8_t CODE_MESSENGER = 8;
};
namespace OutReportID
{
static constexpr uint8_t RUMBLE = 0x00;
static constexpr uint8_t LED = 0x01;
};
namespace Buttons0
{
static constexpr uint8_t DPAD_UP = (1U << 0);
static constexpr uint8_t DPAD_DOWN = (1U << 1);
static constexpr uint8_t DPAD_LEFT = (1U << 2);
static constexpr uint8_t DPAD_RIGHT = (1U << 3);
static constexpr uint8_t START = (1U << 4);
static constexpr uint8_t BACK = (1U << 5);
static constexpr uint8_t L3 = (1U << 6);
static constexpr uint8_t R3 = (1U << 7);
};
namespace Buttons1
{
static constexpr uint8_t LB = (1U << 0);
static constexpr uint8_t RB = (1U << 1);
static constexpr uint8_t HOME = (1U << 2);
static constexpr uint8_t A = (1U << 4);
static constexpr uint8_t B = (1U << 5);
static constexpr uint8_t X = (1U << 6);
static constexpr uint8_t Y = (1U << 7);
};
#pragma pack(push, 1)
struct InReport
{
uint8_t report_id;
uint8_t report_size;
uint8_t buttons[2];
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 reserved[6];
InReport()
{
std::memset(this, 0, sizeof(InReport));
report_size = sizeof(InReport);
}
};
static_assert(sizeof(InReport) == 20, "XInput::InReport is misaligned");
struct WiredChatpadReport
{
uint8_t report_id;
uint8_t chatpad[3];
WiredChatpadReport()
{
std::memset(this, 0, sizeof(WiredChatpadReport));
}
};
static_assert(sizeof(WiredChatpadReport) == 4, "XInput::WiredChatpadReport is misaligned");
struct InReportWireless
{
uint8_t command[4];
uint8_t report_id;
uint8_t report_size;
uint8_t buttons[2];
uint8_t trigger_l;
uint8_t trigger_r;
int16_t joystick_lx;
int16_t joystick_ly;
int16_t joystick_rx;
int16_t joystick_ry; // 18
uint8_t reserved[6];
uint8_t chatpad_status;
uint8_t chatpad[3];
InReportWireless()
{
std::memset(this, 0, sizeof(InReportWireless));
report_size = sizeof(InReportWireless);
}
};
static_assert(sizeof(InReportWireless) == 28, "XInput::InReportWireless is misaligned");
struct OutReport
{
uint8_t report_id;
uint8_t report_size;
uint8_t led;
uint8_t rumble_l;
uint8_t rumble_r;
uint8_t reserved[3];
OutReport()
{
std::memset(this, 0, sizeof(OutReport));
}
};
static_assert(sizeof(OutReport) == 8, "XInput::OutReport is misaligned");
#pragma pack(pop)
static const uint8_t STRING_LANGUAGE[] = { 0x09, 0x04 };
static const uint8_t STRING_MANUFACTURER[] = "Microsoft";
static const uint8_t STRING_PRODUCT[] = "XInput STANDARD GAMEPAD";
static const uint8_t STRING_VERSION[] = "1.0";
static const uint8_t *DESC_STRING[] __attribute__((unused)) =
{
STRING_LANGUAGE,
STRING_MANUFACTURER,
STRING_PRODUCT,
STRING_VERSION
};
static const uint8_t DESC_DEVICE[] =
{
0x12, // bLength
0x01, // bDescriptorType (Device)
0x00, 0x02, // bcdUSB 2.00
0xFF, // bDeviceClass
0xFF, // bDeviceSubClass
0xFF, // bDeviceProtocol
0x40, // bMaxPacketSize0 64
0x5E, 0x04, // idVendor 0x045E
0x8E, 0x02, // idProduct 0x028E
0x14, 0x01, // bcdDevice 2.14
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x03, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t DESC_CONFIGURATION[] =
{
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0x30, 0x00, // wTotalLength 48
0x01, // bNumInterfaces 1
0x01, // bConfigurationValue
0x00, // iConfiguration (String Index)
0x80, // bmAttributes
0xFA, // bMaxPower 500mA
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x00, // bInterfaceNumber 0
0x00, // bAlternateSetting
0x02, // bNumEndpoints 2
0xFF, // bInterfaceClass
0x5D, // bInterfaceSubClass
0x01, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x10, // bLength
0x21, // bDescriptorType (HID)
// 0x10, 0x01, // bcdHID 1.10
0x00, 0x01, // bcdHID 1.00
0x01, // bCountryCode
0x24, // bNumDescriptors
0x81, // bDescriptorType[0] (Unknown 0x81)
0x14, 0x03, // wDescriptorLength[0] 788
0x00, // bDescriptorType[1] (Unknown 0x00)
0x03, 0x13, // wDescriptorLength[1] 4867
0x01, // bDescriptorType[2] (Unknown 0x02)
0x00, 0x03, // wDescriptorLength[2] 768
0x00, // bDescriptorType[3] (Unknown 0x00)
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x81, // bEndpointAddress (IN/D2H)
0x03, // bmAttributes (Interrupt)
0x20, 0x00, // wMaxPacketSize 32
0x01, // bInterval 1 (unit depends on device speed)
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x01, // bEndpointAddress (OUT/H2D)
0x03, // bmAttributes (Interrupt)
0x20, 0x00, // wMaxPacketSize 32
0x08, // bInterval 8 (unit depends on device speed)
};
};
#endif // _XINPUT_DESCRIPTORS_H_

View File

@@ -1,630 +0,0 @@
#ifndef _XBOX_OG_DESCRIPTORS_H_
#define _XBOX_OG_DESCRIPTORS_H_
#include <cstdint>
#include "tusb.h"
namespace XboxOG
{
//Control request constants
static constexpr uint8_t GET_DESC_REQ_TYPE = 0xC1;
static constexpr uint8_t GET_DESC_REQ = 0x06;
static constexpr uint16_t GET_DESC_VALUE = 0x4200;
static constexpr uint8_t GET_DESC_SUBTYPE_GP_DUKE = 0x01;
static constexpr uint8_t GET_DESC_SUBTYPE_GP_S = 0x02;
static constexpr uint8_t GET_DESC_SUBTYPE_WHEEL = 0x10;
static constexpr uint8_t GET_DESC_SUBTYPE_STICK = 0x20;
static constexpr uint8_t GET_DESC_SUBTYPE_LIGHTGUN = 0x50;
static constexpr uint8_t GET_CAP_REQ_TYPE = 0xC1;
static constexpr uint8_t GET_CAP_REQ = 0x01;
static constexpr uint16_t GET_CAP_VALUE_IN = 0x0100;
static constexpr uint16_t GET_CAP_VALUE_OUT = 0x0200;
static constexpr uint8_t SET_REPORT_REQ_TYPE = 0x21;
static constexpr uint8_t SET_REPORT_REQ = 0x09;
static constexpr uint16_t SET_REPORT_VALUE = 0x0200;
static constexpr uint8_t GET_REPORT_REQ_TYPE = 0xA1;
static constexpr uint8_t GET_REPORT_REQ = 1;
static constexpr uint16_t GET_REPORT_VALUE = 0x0100;
namespace GP //Duke/S
{
namespace Buttons
{
static constexpr uint8_t DPAD_UP = (1 << 0);
static constexpr uint8_t DPAD_DOWN = (1 << 1);
static constexpr uint8_t DPAD_LEFT = (1 << 2);
static constexpr uint8_t DPAD_RIGHT = (1 << 3);
static constexpr uint8_t START = (1 << 4);
static constexpr uint8_t BACK = (1 << 5);
static constexpr uint8_t L3 = (1 << 6);
static constexpr uint8_t R3 = (1 << 7);
};
#pragma pack(push, 1)
struct InReport
{
uint8_t reserved1;
uint8_t report_len;
uint8_t buttons;
uint8_t reserved2;
uint8_t a;
uint8_t b;
uint8_t x;
uint8_t y;
uint8_t black;
uint8_t white;
uint8_t trigger_l;
uint8_t trigger_r;
int16_t joystick_lx;
int16_t joystick_ly;
int16_t joystick_rx;
int16_t joystick_ry;
};
static_assert(sizeof(InReport) == 20, "XboxOG::InReport is not the correct size");
struct OutReport
{
uint8_t reserved;
uint8_t report_len;
uint16_t rumble_l;
uint16_t rumble_r;
};
static_assert(sizeof(OutReport) == 6, "XboxOG::OutReport is not the correct size");
#pragma pack(pop)
static const uint8_t STRING_LANGUAGE[] = { 0x09, 0x04 };
static const uint8_t STRING_MANUFACTURER[] = "";
static const uint8_t STRING_PRODUCT[] = "";
static const uint8_t STRING_VERSION[] = "1.0";
static const uint8_t *STRING_DESCRIPTORS[] __attribute__((unused)) =
{
STRING_LANGUAGE,
STRING_MANUFACTURER,
STRING_PRODUCT,
STRING_VERSION
};
static const tusb_desc_device_t DEVICE_DESCRIPTORS =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0110,
.bDeviceClass = 0x00,
.bDeviceSubClass = 0x00,
.bDeviceProtocol = 0x00,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = 0x045E,
.idProduct = 0x0289,
.bcdDevice = 0x0121,
.iManufacturer = 0x00,
.iProduct = 0x00,
.iSerialNumber = 0x00,
.bNumConfigurations = 0x01
};
static constexpr uint8_t INTERFACE_CLASS = 0x58;
static constexpr uint8_t INTERFACE_SUBCLASS = 0x42;
static constexpr uint16_t DRIVER_LEN = 9+7+7;
static constexpr uint16_t CONFIG_DESC_TOTAL_LEN = DRIVER_LEN + TUD_CONFIG_DESC_LEN;
enum Interface
{
NUM_DUKE = 0,
NUM_TOTAL
};
#define TUD_XID_DUKE_DESCRIPTOR(_itfnum, _epout, _epin) \
/* Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, INTERFACE_CLASS, INTERFACE_SUBCLASS, 0x00, 0x00,\
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(32), 4, \
/* Endpoint Out */\
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(32), 4
static const uint8_t CONFIGURATION_DESCRIPTORS[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR( 1,
Interface::NUM_TOTAL,
0,
CONFIG_DESC_TOTAL_LEN,
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
500),
TUD_XID_DUKE_DESCRIPTOR(Interface::NUM_DUKE,
Interface::NUM_DUKE + 1,
0x80 | (Interface::NUM_DUKE + 1)),
};
static const uint8_t XID_DEVICE_DESCRIPTORS[] =
{
0x10,
0x42,
0x00, 0x01,
0x01,
0x02,
0x14,
0x06,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
static const uint8_t XID_CAPABILITIES_IN[] =
{
0x00,
0x14,
0xFF,
0x00,
0xFF,
0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF
};
static const uint8_t XID_CAPABILITIES_OUT[] =
{
0x00,
0x06,
0xFF, 0xFF, 0xFF, 0xFF
};
}; // GP
namespace SB // Steel Battalion
{
static constexpr uint16_t AIMING_MID = 32768;
static constexpr uint16_t BUTTONS2_TOGGLE_MID = 0xFFFC;
namespace Buttons0
{
static constexpr uint16_t RIGHTJOYMAINWEAPON = 0x0001;
static constexpr uint16_t RIGHTJOYFIRE = 0x0002;
static constexpr uint16_t RIGHTJOYLOCKON = 0x0004;
static constexpr uint16_t EJECT = 0x0008;
static constexpr uint16_t COCKPITHATCH = 0x0010;
static constexpr uint16_t IGNITION = 0x0020;
static constexpr uint16_t START = 0x0040;
static constexpr uint16_t MULTIMONOPENCLOSE = 0x0080;
static constexpr uint16_t MULTIMONMAPZOOMINOUT = 0x0100;
static constexpr uint16_t MULTIMONMODESELECT = 0x0200;
static constexpr uint16_t MULTIMONSUBMONITOR = 0x0400;
static constexpr uint16_t MAINMONZOOMIN = 0x0800;
static constexpr uint16_t MAINMONZOOMOUT = 0x1000;
static constexpr uint16_t FUNCTIONFSS = 0x2000;
static constexpr uint16_t FUNCTIONMANIPULATOR = 0x4000;
static constexpr uint16_t FUNCTIONLINECOLORCHANGE = 0x8000;
};
namespace Buttons1
{
static constexpr uint16_t WASHING = 0x0001;
static constexpr uint16_t EXTINGUISHER = 0x0002;
static constexpr uint16_t CHAFF = 0x0004;
static constexpr uint16_t FUNCTIONTANKDETACH = 0x0008;
static constexpr uint16_t FUNCTIONOVERRIDE = 0x0010;
static constexpr uint16_t FUNCTIONNIGHTSCOPE = 0x0020;
static constexpr uint16_t FUNCTIONF1 = 0x0040;
static constexpr uint16_t FUNCTIONF2 = 0x0080;
static constexpr uint16_t FUNCTIONF3 = 0x0100;
static constexpr uint16_t WEAPONCONMAIN = 0x0200;
static constexpr uint16_t WEAPONCONSUB = 0x0400;
static constexpr uint16_t WEAPONCONMAGAZINE = 0x0800;
static constexpr uint16_t COMM1 = 0x1000;
static constexpr uint16_t COMM2 = 0x2000;
static constexpr uint16_t COMM3 = 0x4000;
static constexpr uint16_t COMM4 = 0x8000;
};
namespace Buttons2
{
static constexpr uint16_t COMM5 = 0x0001;
static constexpr uint16_t LEFTJOYSIGHTCHANGE = 0x0002;
static constexpr uint16_t TOGGLEFILTERCONTROL = 0x0004;
static constexpr uint16_t TOGGLEOXYGENSUPPLY = 0x0008;
static constexpr uint16_t TOGGLEFUELFLOWRATE = 0x0010;
static constexpr uint16_t TOGGLEBUFFREMATERIAL = 0x0020;
static constexpr uint16_t TOGGLEVTLOCATION = 0x0040;
};
namespace Axis
{
static constexpr uint16_t AIMINGX = 0x0001;
static constexpr uint16_t AIMINGY = 0x0002;
static constexpr uint16_t LEVER = 0x0004;
static constexpr uint16_t SIGHTX = 0x0008;
static constexpr uint16_t SIGHTY = 0x0010;
static constexpr uint16_t LPEDAL = 0x0020;
static constexpr uint16_t MPEDAL = 0x0040;
static constexpr uint16_t RPEDAL = 0x0080;
static constexpr uint16_t TUNER = 0x0100;
static constexpr uint16_t GEAR = 0x0200;
};
namespace Gear
{
static constexpr int8_t R = 7;
static constexpr int8_t N = 8;
static constexpr int8_t G1 = 9;
static constexpr int8_t G2 = 10;
static constexpr int8_t G3 = 11;
static constexpr int8_t G4 = 12;
static constexpr int8_t G5 = 13;
};
#pragma pack(push, 1)
struct InReport
{
uint8_t zero;
uint8_t bLength;
uint16_t dButtons[3];
uint16_t aimingX; //0 to 2^16 left to right
uint16_t aimingY; //0 to 2^16 top to bottom
int16_t rotationLever;
int16_t sightChangeX;
int16_t sightChangeY;
uint16_t leftPedal; //Sidestep, 0x0000 to 0xFF00
uint16_t middlePedal; //Brake, 0x0000 to 0xFF00
uint16_t rightPedal; //Acceleration, 0x0000 to oxFF00
int8_t tunerDial; //0-15 is from 9oclock, around clockwise
int8_t gearLever; //7-13 is gears R,1,2,3,4,5
};
static_assert(sizeof(InReport) == 26, "XboxOGSB::InReport is not the correct size");
struct OutReport
{
uint8_t zero;
uint8_t bLength;
uint8_t CockpitHatch_EmergencyEject;
uint8_t Start_Ignition;
uint8_t MapZoomInOut_OpenClose;
uint8_t SubMonitorModeSelect_ModeSelect;
uint8_t MainMonitorZoomOut_MainMonitorZoomIn;
uint8_t Manipulator_ForecastShootingSystem;
uint8_t Washing_LineColorChange;
uint8_t Chaff_Extinguisher;
uint8_t Override_TankDetach;
uint8_t F1_NightScope;
uint8_t F3_F2;
uint8_t SubWeaponControl_MainWeaponControl;
uint8_t Comm1_MagazineChange;
uint8_t Comm3_Comm2;
uint8_t Comm5_Comm4;
uint8_t GearR_;
uint8_t Gear1_GearN;
uint8_t Gear3_Gear2;
uint8_t Gear5_Gear4;
uint8_t dummy;
};
static_assert(sizeof(OutReport) == 22, "XboxOGSB::OutReport is not the correct size");
#pragma pack(pop)
static const uint8_t STRING_LANGUAGE[] = { 0x09, 0x04 };
static const uint8_t STRING_MANUFACTURER[] = "";
static const uint8_t STRING_PRODUCT[] = "";
static const uint8_t STRING_VERSION[] = "1.0";
static const uint8_t *STRING_DESCRIPTORS[] __attribute__((unused)) =
{
STRING_LANGUAGE,
STRING_MANUFACTURER,
STRING_PRODUCT,
STRING_VERSION
};
static constexpr uint8_t INTERFACE_CLASS = 0x58;
static constexpr uint8_t INTERFACE_SUBCLASS = 0x42;
static constexpr uint16_t DRIVER_LEN = 9+7+7;
static constexpr uint16_t CONFIG_DESC_TOTAL_LEN = DRIVER_LEN + TUD_CONFIG_DESC_LEN;
enum Interface
{
NUM_STEELBATTALION = 0,
NUM_TOTAL
};
#define TUD_XID_SB_DESCRIPTOR(_itfnum, _epout, _epin) \
/* Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, INTERFACE_CLASS, INTERFACE_SUBCLASS, 0x00, 0x00,\
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(32), 4, \
/* Endpoint Out */\
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(32), 4
static uint8_t const CONFIGURATION_DESCRIPTORS[] =
{
TUD_CONFIG_DESCRIPTOR( 1,
Interface::NUM_TOTAL,
0,
CONFIG_DESC_TOTAL_LEN,
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
500),
TUD_XID_SB_DESCRIPTOR( Interface::NUM_STEELBATTALION,
Interface::NUM_STEELBATTALION + 1,
0x80 | (Interface::NUM_STEELBATTALION + 1)),
};
static const uint8_t XID_DEVICE_DESCRIPTORS[] =
{
0x10,
0x42,
0x00, 0x01,
0x80,
0x01,
0x1A,
0x16,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
static const uint8_t XID_CAPABILITIES_IN[] =
{
0x00,
0x1A,
0xFF,
0xFF,
0xFF,
0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF
};
static const uint8_t XID_CAPABILITIES_OUT[] =
{
0x00,
0x16,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF
};
}; // SB
namespace XR //XRemote
{
#define XID_REMOTE_INTERFACE_CLASS 0x58
#define XID_REMOTE_INTERFACE_SUBCLASS 0x42
#define XID_XREMOTE_ROM_CLASS 0x59
namespace ButtonCode
{
static constexpr uint16_t SELECT = 0x0A0B;
static constexpr uint16_t UP = 0x0AA6;
static constexpr uint16_t DOWN = 0x0AA7;
static constexpr uint16_t RIGHT = 0x0AA8;
static constexpr uint16_t LEFT = 0x0AA9;
static constexpr uint16_t INFO = 0x0AC3;
static constexpr uint16_t NINE = 0x0AC6;
static constexpr uint16_t EIGHT = 0x0AC7;
static constexpr uint16_t SEVEN = 0x0AC8;
static constexpr uint16_t SIX = 0x0AC9;
static constexpr uint16_t FIVE = 0x0ACA;
static constexpr uint16_t FOUR = 0x0ACB;
static constexpr uint16_t THREE = 0x0ACC;
static constexpr uint16_t TWO = 0x0ACD;
static constexpr uint16_t ONE = 0x0ACE;
static constexpr uint16_t ZERO = 0x0ACF;
static constexpr uint16_t DISPLAY = 0x0AD5;
static constexpr uint16_t BACK = 0x0AD8;
static constexpr uint16_t SKIP_MINUS = 0x0ADD;
static constexpr uint16_t SKIP_PLUS = 0x0ADF;
static constexpr uint16_t STOP = 0x0AE0;
static constexpr uint16_t REVERSE = 0x0AE2;
static constexpr uint16_t FORWARD = 0x0AE3;
static constexpr uint16_t TITLE = 0x0AE5;
static constexpr uint16_t PAUSE = 0x0AE6;
static constexpr uint16_t PLAY = 0x0AEA;
static constexpr uint16_t MENU = 0x0AF7;
};
#pragma pack(push, 1)
struct InReport
{
uint8_t zero;
uint8_t bLength;
uint16_t buttonCode;
uint16_t timeElapsed; // ms since last button press
};
static_assert(sizeof(InReport) == 6, "XboxOGXRemote::InReport is not the correct size");
#pragma pack(pop)
static constexpr uint16_t DRIVER_LEN = 9+7+9;
// enum xboxog_xremote_xid_interface
// {
// ITF_NUM_XID_XREMOTE = 0,
// ITF_NUM_XID_XREMOTE_ROM,
// XID_REMOTE_ITF_NUM_TOTAL
// };
// #define TUD_XID_XREMOTE_DESC_LEN (9+7+9)
// #define TUD_XID_XREMOTE_DESCRIPTOR(_itfnum, _epin) \
// /* Interface 0 (HID DATA)*/\
// 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, XID_REMOTE_INTERFACE_CLASS, XID_REMOTE_INTERFACE_SUBCLASS, 0x00, 0x00,\
// /* Endpoint In */\
// 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(8), 16, \
// /* Interface 1 (ROM DATA)*/\
// 9, TUSB_DESC_INTERFACE, _itfnum + 1, 0, 0, XID_XREMOTE_ROM_CLASS, 0x00, 0x00, 0x00
// #define XID_REMOTE_CONFIG_TOTAL_LEN \
// (TUD_CONFIG_DESC_LEN) + \
// (TUD_XID_XREMOTE_DESC_LEN)
// static const uint8_t CONFIGURATION_DESCRIPTORS[] =
// {
// // Config number, interface count, string index, total length, attribute, power in mA
// TUD_CONFIG_DESCRIPTOR( 1,
// XID_REMOTE_ITF_NUM_TOTAL,
// 0,
// XID_REMOTE_CONFIG_TOTAL_LEN,
// TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
// 500),
// TUD_XID_XREMOTE_DESCRIPTOR( ITF_NUM_XID_XREMOTE,
// 0x80 | (ITF_NUM_XID_XREMOTE + 1)),
// };
static const uint8_t DEVICE_DESCRIPTORS[] =
{
0x12, // bLength
0x01, // bDescriptorType (Device)
0x10, 0x01, // bcdUSB 1.10
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 64
0x5E, 0x04, // idVendor 0x045E
0x84, 0x02, // idProduct 0x0284
0x30, 0x01, // bcdDevice 2.30
0x00, // iManufacturer (String Index)
0x00, // iProduct (String Index)
0x00, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t CONFIGURATION_DESCRIPTORS[] =
{
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0x22, 0x00, // wTotalLength 34
0x02, // bNumInterfaces 2
0x01, // bConfigurationValue
0x00, // iConfiguration (String Index)
0x80, // bmAttributes
0xFA, // bMaxPower 500mA
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x00, // bInterfaceNumber 0
0x00, // bAlternateSetting
0x01, // bNumEndpoints 1
0x58, // bInterfaceClass
0x42, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x81, // bEndpointAddress (IN/D2H)
0x03, // bmAttributes (Interrupt)
0x08, 0x00, // wMaxPacketSize 8
0x10, // bInterval 16 (unit depends on device speed)
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x01, // bInterfaceNumber 1
0x00, // bAlternateSetting
0x00, // bNumEndpoints 0
0x59, // bInterfaceClass
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
};
static const uint8_t XID_DEVICE_DESCRIPTORS[] =
{
0x08,
0x42,
0x00, 0x01,
0x03,
0x00,
0x06,
0x00
};
}; // XR
namespace COM
{
static constexpr uint8_t INTERFACE_CLASS = 0x78;
static constexpr uint8_t INTERFACE_SUBCLASS = 0x00;
static const uint8_t DEVICE_DESCRIPTORS[] =
{
0x12, // bLength
0x01, // bDescriptorType (Device)
0x10, 0x01, // bcdUSB 1.10
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x08, // bMaxPacketSize0 8
0x5E, 0x04, // idVendor 0x045E
0x83, 0x02, // idProduct 0x0283
0x58, 0x01, // bcdDevice 2.58
0x00, // iManufacturer (String Index)
0x00, // iProduct (String Index)
0x00, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t CONFIGURATION_DESCRIPTORS[]
{
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0x2D, 0x00, // wTotalLength 45
0x02, // bNumInterfaces 2
0x01, // bConfigurationValue
0x00, // iConfiguration (String Index)
0x80, // bmAttributes
0x32, // bMaxPower 100mA
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x00, // bInterfaceNumber 0
0x00, // bAlternateSetting
0x01, // bNumEndpoints 1
0x78, // bInterfaceClass
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x09, // bLength
0x05, // bDescriptorType (Endpoint)
0x04, // bEndpointAddress (OUT/H2D)
0x05, // bmAttributes (Isochronous, Async, Data EP)
0x30, 0x00, // wMaxPacketSize 48
0x01, // bInterval 1 (unit depends on device speed)
0x00, 0x00,
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x01, // bInterfaceNumber 1
0x00, // bAlternateSetting
0x01, // bNumEndpoints 1
0x78, // bInterfaceClass
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x09, // bLength
0x05, // bDescriptorType (Endpoint)
0x85, // bEndpointAddress (IN/D2H)
0x05, // bmAttributes (Isochronous, Async, Data EP)
0x30, 0x00, // wMaxPacketSize 48
0x01, // bInterval 1 (unit depends on device speed)
0x00, 0x00,
};
}; // COM
}; // namespace XboxOG
#endif // _XBOX_OG_DESCRIPTORS_H_

View File

@@ -1,63 +0,0 @@
#ifndef _XBOX_ONE_DESCRIPTORS_H_
#define _XBOX_ONE_DESCRIPTORS_H_
#include <cstdint>
namespace XboxOne
{
namespace Buttons0
{
static constexpr uint8_t SYNC = (1 << 0);
static constexpr uint8_t GUIDE = (1 << 1);
static constexpr uint8_t START = (1 << 2);
static constexpr uint8_t BACK = (1 << 3);
static constexpr uint8_t A = (1 << 4);
static constexpr uint8_t B = (1 << 5);
static constexpr uint8_t X = (1 << 6);
static constexpr uint8_t Y = (1 << 7);
};
namespace Buttons1
{
static constexpr uint8_t DPAD_UP = (1 << 0);
static constexpr uint8_t DPAD_DOWN = (1 << 1);
static constexpr uint8_t DPAD_LEFT = (1 << 2);
static constexpr uint8_t DPAD_RIGHT = (1 << 3);
static constexpr uint8_t LB = (1 << 4);
static constexpr uint8_t RB = (1 << 5);
static constexpr uint8_t L3 = (1 << 6);
static constexpr uint8_t R3 = (1 << 7);
};
#pragma pack(push, 1)
struct InReport
{
struct GipHeader
{
uint8_t command;
uint8_t client : 4;
uint8_t needsAck : 1;
uint8_t internal : 1;
uint8_t chunkStart : 1;
uint8_t chunked : 1;
uint8_t sequence;
uint8_t length;
} header;
uint8_t buttons[2];
uint16_t trigger_l;
uint16_t trigger_r;
int16_t joystick_lx;
int16_t joystick_ly;
int16_t joystick_rx;
int16_t joystick_ry;
uint8_t reserved[18]; // 18-byte padding at the end
};
static_assert(sizeof(InReport) == 36, "XboxOne::InReport is not the correct size");
#pragma pack(pop)
}; // namespace XboxOne
#endif // _XBOX_ONE_DESCRIPTORS_H_

View File

@@ -1,340 +0,0 @@
#ifndef _GAMEPAD_H_
#define _GAMEPAD_H_
#include <cstdint>
#include <atomic>
#include <limits>
#include <cstring>
#include <array>
#include <pico/mutex.h>
#include "Scale.h"
#include "UserSettings/UserProfile.h"
class Gamepad
{
public:
//Defaults used by device to get buttons
static constexpr uint8_t DPAD_UP = 0x01;
static constexpr uint8_t DPAD_DOWN = 0x02;
static constexpr uint8_t DPAD_LEFT = 0x04;
static constexpr uint8_t DPAD_RIGHT = 0x08;
static constexpr uint8_t DPAD_UP_LEFT = DPAD_UP | DPAD_LEFT;
static constexpr uint8_t DPAD_UP_RIGHT = DPAD_UP | DPAD_RIGHT;
static constexpr uint8_t DPAD_DOWN_LEFT = DPAD_DOWN | DPAD_LEFT;
static constexpr uint8_t DPAD_DOWN_RIGHT = DPAD_DOWN | DPAD_RIGHT;
static constexpr uint8_t DPAD_NONE = 0x00;
static constexpr uint16_t BUTTON_A = 0x0001;
static constexpr uint16_t BUTTON_B = 0x0002;
static constexpr uint16_t BUTTON_X = 0x0004;
static constexpr uint16_t BUTTON_Y = 0x0008;
static constexpr uint16_t BUTTON_L3 = 0x0010;
static constexpr uint16_t BUTTON_R3 = 0x0020;
static constexpr uint16_t BUTTON_BACK = 0x0040;
static constexpr uint16_t BUTTON_START = 0x0080;
static constexpr uint16_t BUTTON_LB = 0x0100;
static constexpr uint16_t BUTTON_RB = 0x0200;
static constexpr uint16_t BUTTON_SYS = 0x0400;
static constexpr uint16_t BUTTON_MISC = 0x0800;
static constexpr uint8_t ANALOG_OFF_UP = 0;
static constexpr uint8_t ANALOG_OFF_DOWN = 1;
static constexpr uint8_t ANALOG_OFF_LEFT = 2;
static constexpr uint8_t ANALOG_OFF_RIGHT = 3;
static constexpr uint8_t ANALOG_OFF_A = 4;
static constexpr uint8_t ANALOG_OFF_B = 5;
static constexpr uint8_t ANALOG_OFF_X = 6;
static constexpr uint8_t ANALOG_OFF_Y = 7;
static constexpr uint8_t ANALOG_OFF_LB = 8;
static constexpr uint8_t ANALOG_OFF_RB = 9;
//Mappings used by host to set buttons
uint8_t MAP_DPAD_UP = DPAD_UP ;
uint8_t MAP_DPAD_DOWN = DPAD_DOWN ;
uint8_t MAP_DPAD_LEFT = DPAD_LEFT ;
uint8_t MAP_DPAD_RIGHT = DPAD_RIGHT ;
uint8_t MAP_DPAD_UP_LEFT = DPAD_UP_LEFT ;
uint8_t MAP_DPAD_UP_RIGHT = DPAD_UP_RIGHT ;
uint8_t MAP_DPAD_DOWN_LEFT = DPAD_DOWN_LEFT ;
uint8_t MAP_DPAD_DOWN_RIGHT = DPAD_DOWN_RIGHT;
uint8_t MAP_DPAD_NONE = DPAD_NONE ;
uint16_t MAP_BUTTON_A = BUTTON_A ;
uint16_t MAP_BUTTON_B = BUTTON_B ;
uint16_t MAP_BUTTON_X = BUTTON_X ;
uint16_t MAP_BUTTON_Y = BUTTON_Y ;
uint16_t MAP_BUTTON_L3 = BUTTON_L3 ;
uint16_t MAP_BUTTON_R3 = BUTTON_R3 ;
uint16_t MAP_BUTTON_BACK = BUTTON_BACK ;
uint16_t MAP_BUTTON_START = BUTTON_START;
uint16_t MAP_BUTTON_LB = BUTTON_LB ;
uint16_t MAP_BUTTON_RB = BUTTON_RB ;
uint16_t MAP_BUTTON_SYS = BUTTON_SYS ;
uint16_t MAP_BUTTON_MISC = BUTTON_MISC ;
uint8_t MAP_ANALOG_OFF_UP = ANALOG_OFF_UP ;
uint8_t MAP_ANALOG_OFF_DOWN = ANALOG_OFF_DOWN ;
uint8_t MAP_ANALOG_OFF_LEFT = ANALOG_OFF_LEFT ;
uint8_t MAP_ANALOG_OFF_RIGHT = ANALOG_OFF_RIGHT;
uint8_t MAP_ANALOG_OFF_A = ANALOG_OFF_A ;
uint8_t MAP_ANALOG_OFF_B = ANALOG_OFF_B ;
uint8_t MAP_ANALOG_OFF_X = ANALOG_OFF_X ;
uint8_t MAP_ANALOG_OFF_Y = ANALOG_OFF_Y ;
uint8_t MAP_ANALOG_OFF_LB = ANALOG_OFF_LB ;
uint8_t MAP_ANALOG_OFF_RB = ANALOG_OFF_RB ;
#pragma pack(push, 1)
struct PadIn
{
uint8_t dpad;
uint16_t buttons;
uint8_t trigger_l;
uint8_t trigger_r;
int16_t joystick_lx;
int16_t joystick_ly;
int16_t joystick_rx;
int16_t joystick_ry;
// uint8_t chatpad[3];
uint8_t analog[10];
PadIn()
{
std::memset(this, 0, sizeof(PadIn));
}
};
struct PadOut
{
uint8_t rumble_l;
uint8_t rumble_r;
PadOut()
{
std::memset(this, 0, sizeof(PadOut));
}
};
using ChatpadIn = std::array<uint8_t, 3>;
#pragma pack(pop)
Gamepad()
{
mutex_init(&pad_in_mutex_);
mutex_init(&pad_out_mutex_);
mutex_init(&chatpad_in_mutex_);
reset_pad_in();
reset_pad_out();
reset_chatpad_in();
};
~Gamepad() = default;
//Get
inline bool new_pad_in() const { return new_pad_in_.load(); }
inline bool new_pad_out() const { return new_pad_out_.load(); }
//True if both host and device have enabled analog
inline bool analog_enabled() const { return analog_enabled_.load(std::memory_order_relaxed); }
inline PadIn get_pad_in()
{
mutex_enter_blocking(&pad_in_mutex_);
PadIn pad_in = pad_in_;
new_pad_in_.store(false);
mutex_exit(&pad_in_mutex_);
return pad_in;
}
inline PadOut get_pad_out()
{
mutex_enter_blocking(&pad_out_mutex_);
PadOut pad_out = pad_out_;
new_pad_out_.store(false);
mutex_exit(&pad_out_mutex_);
return pad_out;
}
inline ChatpadIn get_chatpad_in()
{
mutex_enter_blocking(&chatpad_in_mutex_);
ChatpadIn chatpad_in = chatpad_in_;
mutex_exit(&chatpad_in_mutex_);
return chatpad_in;
}
//Set
void set_analog_device(bool value)
{
analog_device_.store(value);
if (analog_host_.load() && analog_device_.load() && profile_analog_enabled_)
{
analog_enabled_.store(true);
}
}
void set_analog_host(bool value)
{
analog_host_.store(value);
if (analog_host_.load() && analog_device_.load() && profile_analog_enabled_)
{
analog_enabled_.store(true);
}
}
void set_profile(const UserProfile& user_profile)
{
set_profile_options(user_profile);
set_profile_mappings(user_profile);
set_profile_deadzones(user_profile);
}
inline void set_pad_in(PadIn pad_in)
{
pad_in.trigger_l = (pad_in.trigger_l > dz_.trigger_l) ? pad_in.trigger_l : UINT_8::MIN;
pad_in.trigger_r = (pad_in.trigger_r > dz_.trigger_r) ? pad_in.trigger_r : UINT_8::MIN;
pad_in.joystick_lx = (pad_in.joystick_lx < dz_.joystick_l_neg || pad_in.joystick_lx > dz_.joystick_l_pos) ? pad_in.joystick_lx : INT_16::MID;
pad_in.joystick_ly = (pad_in.joystick_ly < dz_.joystick_l_neg || pad_in.joystick_ly > dz_.joystick_l_pos) ? pad_in.joystick_ly : INT_16::MID;
pad_in.joystick_rx = (pad_in.joystick_rx < dz_.joystick_r_neg || pad_in.joystick_rx > dz_.joystick_r_pos) ? pad_in.joystick_rx : INT_16::MID;
pad_in.joystick_ry = (pad_in.joystick_ry < dz_.joystick_r_neg || pad_in.joystick_ry > dz_.joystick_r_pos) ? pad_in.joystick_ry : INT_16::MID;
pad_in.joystick_ly = profile_invert_ly_ ? Scale::invert_joy(pad_in.joystick_ly) : pad_in.joystick_ly;
pad_in.joystick_ry = profile_invert_ry_ ? Scale::invert_joy(pad_in.joystick_ry) : pad_in.joystick_ry;
mutex_enter_blocking(&pad_in_mutex_);
pad_in_ = pad_in;
new_pad_in_.store(true);
mutex_exit(&pad_in_mutex_);
}
inline void set_pad_out(const PadOut& pad_out)
{
mutex_enter_blocking(&pad_out_mutex_);
pad_out_ = pad_out;
new_pad_out_.store(true);
mutex_exit(&pad_out_mutex_);
}
inline void set_chatpad_in(const ChatpadIn& chatpad_in)
{
mutex_enter_blocking(&chatpad_in_mutex_);
chatpad_in_ = chatpad_in;
mutex_exit(&chatpad_in_mutex_);
}
inline void reset_pad_in()
{
mutex_enter_blocking(&pad_in_mutex_);
pad_in_ = PadIn();
mutex_exit(&pad_in_mutex_);
new_pad_in_.store(true);
}
inline void reset_pad_out()
{
mutex_enter_blocking(&pad_out_mutex_);
pad_out_ = PadOut();
new_pad_out_.store(true);
mutex_exit(&pad_out_mutex_);
}
inline void reset_chatpad_in()
{
mutex_enter_blocking(&chatpad_in_mutex_);
chatpad_in_.fill(0);
mutex_exit(&chatpad_in_mutex_);
}
private:
mutex_t pad_in_mutex_;
mutex_t pad_out_mutex_;
mutex_t chatpad_in_mutex_;
PadOut pad_out_;
PadIn pad_in_;
ChatpadIn chatpad_in_;
std::atomic<bool> new_pad_in_{false};
std::atomic<bool> new_pad_out_{false};
std::atomic<bool> analog_enabled_{false};
std::atomic<bool> analog_host_{false};
std::atomic<bool> analog_device_{false};
bool profile_invert_ly_{false};
bool profile_invert_ry_{false};
bool profile_analog_enabled_{false};
struct Deadzones
{
uint8_t trigger_l{0};
uint8_t trigger_r{0};
int16_t joystick_l_neg{0};
int16_t joystick_l_pos{0};
int16_t joystick_r_neg{0};
int16_t joystick_r_pos{0};
} dz_;
void set_profile_options(const UserProfile& profile)
{
profile_invert_ly_ = profile.invert_ly ? true : false;
profile_invert_ry_ = profile.invert_ry ? true : false;
profile_analog_enabled_ = profile.analog_enabled ? true : false;
}
void set_profile_mappings(const UserProfile& profile)
{
MAP_DPAD_UP = profile.dpad_up;
MAP_DPAD_DOWN = profile.dpad_down;
MAP_DPAD_LEFT = profile.dpad_left;
MAP_DPAD_RIGHT = profile.dpad_right;
MAP_DPAD_UP_LEFT = profile.dpad_up | profile.dpad_left;
MAP_DPAD_UP_RIGHT = profile.dpad_up | profile.dpad_right;
MAP_DPAD_DOWN_LEFT = profile.dpad_down | profile.dpad_left;
MAP_DPAD_DOWN_RIGHT = profile.dpad_down | profile.dpad_right;
MAP_DPAD_NONE = 0;
MAP_BUTTON_A = profile.button_a;
MAP_BUTTON_B = profile.button_b;
MAP_BUTTON_X = profile.button_x;
MAP_BUTTON_Y = profile.button_y;
MAP_BUTTON_L3 = profile.button_l3;
MAP_BUTTON_R3 = profile.button_r3;
MAP_BUTTON_BACK = profile.button_back;
MAP_BUTTON_START = profile.button_start;
MAP_BUTTON_LB = profile.button_lb;
MAP_BUTTON_RB = profile.button_rb;
MAP_BUTTON_SYS = profile.button_sys;
MAP_BUTTON_MISC = profile.button_misc;
MAP_ANALOG_OFF_UP = profile.analog_off_up;
MAP_ANALOG_OFF_DOWN = profile.analog_off_down;
MAP_ANALOG_OFF_LEFT = profile.analog_off_left;
MAP_ANALOG_OFF_RIGHT = profile.analog_off_right;
MAP_ANALOG_OFF_A = profile.analog_off_a;
MAP_ANALOG_OFF_B = profile.analog_off_b;
MAP_ANALOG_OFF_X = profile.analog_off_x;
MAP_ANALOG_OFF_Y = profile.analog_off_y;
MAP_ANALOG_OFF_LB = profile.analog_off_lb;
MAP_ANALOG_OFF_RB = profile.analog_off_rb;
}
void set_profile_deadzones(const UserProfile& profile) //Deadzones in the profile are 0-255 (0-100%)
{
dz_.trigger_l = profile.dz_trigger_l;
dz_.trigger_r = profile.dz_trigger_r;
dz_.joystick_l_pos = Scale::uint8_to_int16(profile.dz_joystick_l / 2);
dz_.joystick_l_neg = Scale::invert_joy(dz_.joystick_l_pos);
dz_.joystick_r_pos = Scale::uint8_to_int16(profile.dz_joystick_r / 2);
dz_.joystick_r_neg = Scale::invert_joy(dz_.joystick_r_pos);
}
};
#endif // _GAMEPAD_H_

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,13 +0,0 @@
#ifndef _I2CDRIVER_ESP_H_
#define _I2CDRIVER_ESP_H_
#include <cstdint>
#include "Gamepad.h"
namespace I2CDriver
{
void initialize(Gamepad (&gamepads)[MAX_GAMEPADS]);
}
#endif // _I2CDRIVER_ESP_H_

View File

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

View File

@@ -1,18 +0,0 @@
#ifndef _OGX_MINI_H_
#define _OGX_MINI_H_
#include <cstdint>
#include "UserSettings/UserSettings.h"
namespace OGXMini
{
static constexpr int32_t FEEDBACK_DELAY_MS = 150;
static constexpr int32_t TUD_CHECK_DELAY_MS = 500;
void run_program();
void update_tud_status(bool host_mounted);
} // namespace OGXMini
#endif // _OGX_MINI_H_

View File

@@ -1,131 +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 "OGXMini/OGXMini.h"
#include "I2CDriver/4Channel/I2CManager.h"
#include "Gamepad.h"
#include "TaskQueue/TaskQueue.h"
namespace OGXMini {
Gamepad gamepads_[MAX_GAMEPADS];
std::atomic<bool> tud_inited_{false};
void core1_task()
{
HostManager& host_manager = HostManager::get_instance();
host_manager.initialize(gamepads_);
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();
}
}
//Called by tusb host or i2c driver so we know to connect or disconnect usb
void update_tud_status(bool host_mounted)
{
board_api::set_led(host_mounted);
if (!host_mounted && tud_inited_.load())
{
TaskQueue::Core0::queue_task([]()
{
tud_disconnect();
sleep_ms(300);
multicore_reset_core1();
sleep_ms(300);
board_api::reboot();
});
}
else if (!tud_inited_.load())
{
TaskQueue::Core0::queue_task([]()
{
tud_init(BOARD_TUD_RHPORT);
});
}
}
void set_gp_check_timer(uint32_t task_id, UserSettings& user_settings)
{
TaskQueue::Core0::queue_delayed_task(task_id, UserSettings::GP_CHECK_DELAY_MS, true, [&user_settings]
{
//Check gamepad inputs for button combo to change usb device driver
if (user_settings.check_for_driver_change(gamepads_[0]))
{
//This will store the new mode and reboot the pico
user_settings.store_driver_type_safe(user_settings.get_current_driver());
}
});
}
void run_program()
{
UserSettings user_settings;
user_settings.initialize_flash();
board_api::init_board();
for (uint8_t i = 0; i < MAX_GAMEPADS; ++i)
{
gamepads_[i].set_profile(user_settings.get_profile_by_index(i));
}
DeviceManager::get_instance().initialize_driver(user_settings.get_current_driver(), gamepads_);
I2CManager::get_instance().initialize_driver();
multicore_reset_core1();
multicore_launch_core1(core1_task);
uint32_t tid_gp_check = TaskQueue::Core0::get_new_task_id();
set_gp_check_timer(tid_gp_check, user_settings);
DeviceDriver* device_driver = DeviceManager::get_instance().get_driver();
I2CDriver* i2c_driver = I2CManager::get_instance().get_driver();
//Wait for something to call tud_init
while (!tud_inited())
{
TaskQueue::Core0::process_tasks();
sleep_ms(10);
}
tud_inited_.store(true);
while (true)
{
TaskQueue::Core0::process_tasks();
i2c_driver->process(gamepads_);
device_driver->process(0, gamepads_[0]);
tud_task();
sleep_us(100);
}
}
} // namespace OGXMini
#endif // OGXM_BOARD == INTERNAL_4CH || OGXM_BOARD == EXTERNAL_4CH

View File

@@ -1,104 +0,0 @@
#include "board_config.h"
#if OGXM_BOARD == W_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.h"
#include "TaskQueue/TaskQueue.h"
namespace OGXMini {
static Gamepad gamepads_[MAX_GAMEPADS];
//Not using this for ESP32 currently
void update_tud_status(bool host_mounted) { }
void core1_task()
{
I2CDriver::initialize(gamepads_);
while (true)
{
tight_loop_contents();
}
}
void run_esp32_uart_bridge()
{
DeviceManager& device_manager = DeviceManager::get_instance();
device_manager.initialize_driver(DeviceDriver::Type::UART_BRIDGE, gamepads_);
board_api::enter_esp32_prog_mode();
device_manager.get_driver()->process(0, gamepads_[0]); //Runs UART Bridge task, doesn't return
}
void set_gp_check_timer(uint32_t task_id, UserSettings& user_settings)
{
TaskQueue::Core0::queue_delayed_task(task_id, UserSettings::GP_CHECK_DELAY_MS, true, [&user_settings]
{
//Check gamepad inputs for button combo to change usb device driver
if (user_settings.check_for_driver_change(gamepads_[0]))
{
//This will store the new mode and reboot the pico
user_settings.store_driver_type_safe(user_settings.get_current_driver());
}
});
}
void run_program()
{
UserSettings user_settings;
user_settings.initialize_flash();
board_api::init_board();
if (board_api::uart_bridge_mode())
{
run_esp32_uart_bridge();
return;
}
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_);
multicore_reset_core1();
multicore_launch_core1(core1_task);
board_api::reset_esp32();
uint32_t tid_gp_check = TaskQueue::Core0::get_new_task_id();
set_gp_check_timer(tid_gp_check, user_settings);
DeviceDriver* device_driver = DeviceManager::get_instance().get_driver();
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

View File

@@ -1,88 +0,0 @@
#include "board_config.h"
#if (OGXM_BOARD == PI_PICOW)
#include <pico/multicore.h>
#include <pico/cyw43_arch.h>
#include "tusb.h"
#include "bsp/board_api.h"
#include "USBDevice/DeviceManager.h"
#include "Board/board_api.h"
#include "Bluepad32/Bluepad32.h"
#include "OGXMini/OGXMini.h"
#include "Gamepad.h"
#include "TaskQueue/TaskQueue.h"
namespace OGXMini {
Gamepad gamepads_[MAX_GAMEPADS];
//Not using this for Pico W currently
void update_tud_status(bool host_mounted) { }
void core1_task()
{
if (cyw43_arch_init() != 0)
{
panic("CYW43 init failed");
}
//Doesn't return, don't do anything with core1 unless it's executing within the BTStack loop
bluepad32::run_task(gamepads_);
}
void set_gp_check_timer(uint32_t task_id, UserSettings& user_settings)
{
TaskQueue::Core0::queue_delayed_task(task_id, UserSettings::GP_CHECK_DELAY_MS, true, [&user_settings]
{
//Check gamepad inputs for button combo to change usb device driver
if (user_settings.check_for_driver_change(gamepads_[0]))
{
//This will store the new mode and reboot the pico
user_settings.store_driver_type_safe(user_settings.get_current_driver());
}
});
}
void run_program()
{
UserSettings user_settings;
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_);
multicore_reset_core1();
multicore_launch_core1(core1_task);
uint32_t tid_gp_check = TaskQueue::Core0::get_new_task_id();
set_gp_check_timer(tid_gp_check, user_settings);
DeviceDriver* device_driver = DeviceManager::get_instance().get_driver();
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 == PI_PICOW)

View File

@@ -1,130 +0,0 @@
#include "board_config.h"
#if (OGXM_BOARD == ADA_FEATHER) || (OGXM_BOARD == RP_ZERO) || (OGXM_BOARD == PI_PICO) || (OGXM_BOARD == PI_PICO2)
#include <pico/multicore.h>
#include "tusb.h"
#include "bsp/board_api.h"
#include "pio_usb.h"
#include "USBHost/HostManager.h"
#include "USBDevice/DeviceManager.h"
#include "OGXMini/OGXMini.h"
#include "TaskQueue/TaskQueue.h"
#include "Gamepad.h"
#include "Board/board_api.h"
namespace OGXMini {
Gamepad gamepads_[MAX_GAMEPADS];
void core1_task()
{
HostManager& host_manager = HostManager::get_instance();
host_manager.initialize(gamepads_);
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();
}
}
//Called by tusb host or i2c driver so we know to connect or disconnect usb
void update_tud_status(bool host_mounted)
{
static bool tud_is_inited = false;
board_api::set_led(host_mounted);
if (!host_mounted && tud_is_inited)
{
TaskQueue::Core0::queue_task([]()
{
tud_disconnect();
sleep_ms(300);
multicore_reset_core1();
sleep_ms(300);
board_api::reboot();
});
}
else if (!tud_is_inited)
{
if (TaskQueue::Core0::queue_task([]() { tud_init(BOARD_TUD_RHPORT); }))
{
tud_is_inited = true;
}
}
}
void set_gp_check_timer(uint32_t task_id, UserSettings& user_settings)
{
TaskQueue::Core0::queue_delayed_task(task_id, UserSettings::GP_CHECK_DELAY_MS, true, [&user_settings]
{
//Check gamepad inputs for button combo to change usb device driver
if (user_settings.check_for_driver_change(gamepads_[0]))
{
//This will store the new mode and reboot the pico
user_settings.store_driver_type_safe(user_settings.get_current_driver());
}
});
}
void run_program()
{
UserSettings user_settings;
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_);
multicore_reset_core1();
multicore_launch_core1(core1_task);
uint32_t tid_gp_check = TaskQueue::Core0::get_new_task_id();
set_gp_check_timer(tid_gp_check, user_settings);
DeviceDriver* device_driver = device_manager.get_driver();
// Wait for something to call update_tud_status()
while (!tud_inited())
{
TaskQueue::Core0::process_tasks();
sleep_ms(100);
}
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 == ADA_FEATHER) || (OGXM_BOARD == RP_ZERO) || (OGXM_BOARD == PI_PICO) || (OGXM_BOARD == PI_PICO2)

View File

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

View File

@@ -1,351 +0,0 @@
#include <array>
#include <algorithm>
#include <atomic>
#include <pico/stdlib.h>
#include <hardware/timer.h>
#include <hardware/irq.h>
#include <hardware/sync.h>
#include "Board/board_api.h"
#include "board_config.h"
#include "TaskQueue/TaskQueue.h"
namespace TaskQueue {
class CoreQueue
{
public:
enum class CoreNum : uint8_t
{
Core0 = 0,
Core1,
};
CoreQueue(CoreNum core_num)
: core_num_(core_num)
{
uint32_t idx = (core_num_ == CoreNum::Core0) ? 0 : 1;
#if (OGXM_BOARD != PI_PICOW)
alarm_num_ = idx;
#else
alarm_num_ = idx + 1; //BTStack uses alarm 0
#endif
instances_[idx] = this;
hw_set_bits(&timer_hw->inte, 1u << alarm_num_);
irq_set_exclusive_handler(
TIMER_IRQ(alarm_num_),
(core_num_ == CoreNum::Core0) ? timer_irq_wrapper_c0 : timer_irq_wrapper_c1);
irq_set_enabled(TIMER_IRQ(alarm_num_), true);
}
~CoreQueue() = default;
uint32_t get_new_task_id()
{
return new_task_id_++;
}
bool queue_delayed_task(uint32_t task_id, uint32_t delay_ms, bool repeating, const std::function<void()>& function)
{
uint32_t irq_state = spin_lock_blocking(spinlock_delayed_);
for (const auto& task : task_queue_delayed_)
{
if (task.task_id == task_id)
{
spin_unlock(spinlock_delayed_, irq_state);
return false;
}
}
hw_set_bits(&timer_hw->inte, 1u << alarm_num_);
//Might come back to this, there is overflow potential
uint64_t target_time = timer_hw->timerawl + static_cast<uint64_t>(delay_ms) * 1000;
for (auto& task : task_queue_delayed_)
{
if (!task.function)
{
task.target_time = target_time;
task.interval_ms = repeating ? delay_ms : 0;
task.function = function;
task.task_id = task_id;
auto it = std::min_element(task_queue_delayed_.begin(), task_queue_delayed_.end(), [](const DelayedTask& a, const DelayedTask& b)
{
return a.function && (!b.function || a.target_time < b.target_time);
});
if (it != task_queue_delayed_.end() && it->function)
{
timer_hw->alarm[alarm_num_] = static_cast<uint32_t>(it->target_time);
}
spin_unlock(spinlock_delayed_, irq_state);
return true;
}
}
spin_unlock(spinlock_delayed_, irq_state);
return false;
}
void cancel_delayed_task(uint32_t task_id)
{
uint32_t irq_state = spin_lock_blocking(spinlock_delayed_);
bool found = false;
for (auto& task : task_queue_delayed_)
{
if (task.task_id == task_id)
{
task.function = nullptr;
task.task_id = 0;
task.interval_ms = 0;
found = true;
}
}
if (!found)
{
spin_unlock(spinlock_delayed_, irq_state);
return;
}
hw_set_bits(&timer_hw->inte, 1u << alarm_num_);
int64_t next_target_time = get_next_target_time_unsafe(task_queue_delayed_);
if (next_target_time >= 0)
{
timer_hw->alarm[alarm_num_] = static_cast<uint32_t>(next_target_time);
}
spin_unlock(spinlock_delayed_, irq_state);
}
bool queue_task(const std::function<void()>& function)
{
uint32_t irq_state = spin_lock_blocking(spinlock_queue_);
for (auto& task : task_queue_)
{
if (!task.function)
{
task.function = function;
spin_unlock(spinlock_queue_, irq_state);
return true;
}
}
spin_unlock(spinlock_queue_, irq_state);
return false;
}
void process_tasks()
{
uint32_t irq_state = spin_lock_blocking(spinlock_queue_);
for (auto& task : task_queue_)
{
if (task.function)
{
auto function = task.function;
task.function = nullptr;
spin_unlock(spinlock_queue_, irq_state);
function();
irq_state = spin_lock_blocking(spinlock_queue_);
}
else
{
break; //No more tasks
}
}
spin_unlock(spinlock_queue_, irq_state);
}
private:
CoreQueue& operator=(const CoreQueue&) = delete;
CoreQueue(CoreQueue&&) = delete;
CoreQueue& operator=(CoreQueue&&) = delete;
static CoreQueue* instances_[static_cast<uint8_t>(CoreNum::Core1) + 1];
struct Task
{
// uint32_t task_id = 0;
std::function<void()> function = nullptr;
};
struct DelayedTask
{
uint32_t task_id = 0;
uint32_t interval_ms = 0;
uint64_t target_time = 0;
std::function<void()> function = nullptr;
};
static constexpr uint8_t MAX_TASKS = 8;
static constexpr uint8_t MAX_DELAYED_TASKS = MAX_TASKS * 2;
CoreNum core_num_;
uint32_t alarm_num_;
uint32_t new_task_id_ = 1;
int spinlock_queue_num_ = spin_lock_claim_unused(true);
int spinlock_delayed_num_ = spin_lock_claim_unused(true);
spin_lock_t* spinlock_queue_ = spin_lock_instance(static_cast<uint>(spinlock_queue_num_));
spin_lock_t* spinlock_delayed_ = spin_lock_instance(static_cast<uint>(spinlock_delayed_num_));
std::array<Task, MAX_TASKS> task_queue_;
std::array<DelayedTask, MAX_DELAYED_TASKS> task_queue_delayed_;
static void timer_irq_wrapper_c0()
{
instances_[static_cast<uint8_t>(CoreNum::Core0)]->timer_irq_handler();
}
static void timer_irq_wrapper_c1()
{
instances_[static_cast<uint8_t>(CoreNum::Core1)]->timer_irq_handler();
}
static inline uint32_t TIMER_IRQ(uint32_t alarm_num)
{
return timer_hardware_alarm_get_irq_num(timer_hw, alarm_num);
}
static inline uint64_t get_time_64_us()
{
static spin_lock_t* spinlock_time_ = nullptr;
if (!spinlock_time_)
{
int spinlock_time_num = spin_lock_claim_unused(true);
spinlock_time_ = spin_lock_instance(static_cast<uint>(spinlock_time_num));
}
uint32_t irq_state = spin_lock_blocking(spinlock_time_);
uint32_t lo = timer_hw->timelr;
uint32_t hi = timer_hw->timehr;
spin_unlock(spinlock_time_, irq_state);
return ((uint64_t) hi << 32u) | lo;;
}
void timer_irq_handler()
{
hw_clear_bits(&timer_hw->intr, 1u << alarm_num_);
uint64_t now = get_time_64_us();
uint32_t irq_state = spin_lock_blocking(spinlock_delayed_);
for (auto& task : task_queue_delayed_)
{
if (task.function && task.target_time <= now)
{
auto function = task.function;
if (task.interval_ms)
{
task.target_time += (task.interval_ms * 1000);
}
else
{
task.function = nullptr;
task.task_id = 0;
}
spin_unlock(spinlock_delayed_, irq_state);
queue_task(function);
irq_state = spin_lock_blocking(spinlock_delayed_);
}
}
int64_t next_target_time = get_next_target_time_unsafe(task_queue_delayed_);
if (next_target_time >= 0)
{
timer_hw->alarm[alarm_num_] = static_cast<uint32_t>(next_target_time);
}
spin_unlock(spinlock_delayed_, irq_state);
}
static inline int64_t get_next_target_time_unsafe(std::array<DelayedTask, MAX_DELAYED_TASKS>& task_queue_delayed)
{
auto it = std::min_element(task_queue_delayed.begin(), task_queue_delayed.end(), [](const DelayedTask& a, const DelayedTask& b)
{
//Get task with the earliest target time
return a.function && (!b.function || a.target_time < b.target_time);
});
if (it != task_queue_delayed.end() && it->function)
{
return static_cast<int64_t>(it->target_time);
}
return -1;
}
}; // class CoreQueue
CoreQueue* CoreQueue::instances_[static_cast<uint8_t>(CoreQueue::CoreNum::Core1) + 1]{nullptr};
namespace Core0
{
static inline CoreQueue& get_core_0()
{
static CoreQueue core(CoreQueue::CoreNum::Core0);
return core;
}
uint32_t get_new_task_id()
{
return get_core_0().get_new_task_id();
}
void cancel_delayed_task(uint32_t task_id)
{
get_core_0().cancel_delayed_task(task_id);
}
bool queue_delayed_task(uint32_t task_id, uint32_t delay_ms, bool repeating, const std::function<void()>& function)
{
return get_core_0().queue_delayed_task(task_id, delay_ms, repeating, function);
}
bool queue_task(const std::function<void()>& function)
{
return get_core_0().queue_task(function);
}
void process_tasks()
{
get_core_0().process_tasks();
}
}
#if OGXM_BOARD != PI_PICOW
namespace Core1
{
static inline CoreQueue& get_core_1()
{
static CoreQueue core(CoreQueue::CoreNum::Core1);
return core;
}
uint32_t get_new_task_id()
{
return get_core_1().get_new_task_id();
}
void cancel_delayed_task(uint32_t task_id)
{
get_core_1().cancel_delayed_task(task_id);
}
bool queue_delayed_task(uint32_t task_id, uint32_t delay_ms, bool repeating, const std::function<void()>& function)
{
return get_core_1().queue_delayed_task(task_id, delay_ms, repeating, function);
}
bool queue_task(const std::function<void()>& function)
{
return get_core_1().queue_task(function);
}
void process_tasks()
{
get_core_1().process_tasks();
}
}
#endif // OGXM_BOARD != PI_PICOW
} // namespace TaskQueue

View File

@@ -1,35 +0,0 @@
#ifndef TASK_QUEUE_H
#define TASK_QUEUE_H
#include <cstdint>
#include <functional>
#include "board_config.h"
/* Queue tasks to be executed with process_tasks() in the main loop on either core.
Don't use this on the core running BTStack, that is not safe. */
namespace TaskQueue
{
namespace Core0
{
uint32_t get_new_task_id();
void cancel_delayed_task(uint32_t task_id);
bool queue_delayed_task(uint32_t task_id, uint32_t delay_ms, bool repeating, const std::function<void()>& function);
bool queue_task(const std::function<void()>& function);
void process_tasks();
}
#if OGXM_BOARD != PI_PICOW
namespace Core1
{
uint32_t get_new_task_id();
void cancel_delayed_task(uint32_t task_id);
bool queue_delayed_task(uint32_t task_id, uint32_t delay_ms, bool repeating, const std::function<void()>& function);
bool queue_task(const std::function<void()>& function);
void process_tasks();
}
#endif // OGXM_BOARD != PI_PICOW
} // namespace TaskQueue
#endif // TASK_QUEUE_H

View File

@@ -1,175 +0,0 @@
#include <cstring>
#include "class/hid/hid_device.h"
#include "Descriptors/PS3.h"
#include "USBDevice/DeviceDriver/DInput/DInput.h"
bool DInputDevice::control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
{
if (request->bmRequestType == 0xA1 &&
request->bRequest == HID_REQ_CONTROL_GET_REPORT &&
request->wValue == 0x0300 )
{
return tud_control_xfer(rhport, request, const_cast<void*>(static_cast<const void*>(PS3::MAGIC_BYTES)), sizeof(PS3::MAGIC_BYTES));
}
return hidd_control_xfer_cb(rhport, stage, request);
}
void DInputDevice::initialize()
{
for (auto& in_report : in_reports_)
{
std::memset(reinterpret_cast<void*>(&in_report), 0, sizeof(DInput::InReport));
in_report.dpad = DInput::DPad::CENTER;
in_report.joystick_lx = DInput::AXIS_MID;
in_report.joystick_ly = DInput::AXIS_MID;
in_report.joystick_rx = DInput::AXIS_MID;
in_report.joystick_ry = DInput::AXIS_MID;
}
class_driver_ = {
.name = TUD_DRV_NAME("HID"),
.init = hidd_init,
.deinit = hidd_deinit,
.reset = hidd_reset,
.open = hidd_open,
.control_xfer_cb = DInputDevice::control_xfer_cb,
.xfer_cb = hidd_xfer_cb,
.sof = NULL
};
}
void DInputDevice::process(const uint8_t idx, Gamepad& gamepad)
{
DInput::InReport& in_report = in_reports_[idx];
if (gamepad.new_pad_in())
{
Gamepad::PadIn gp_in = gamepad.get_pad_in();
switch (gp_in.dpad)
{
case Gamepad::DPAD_UP:
in_report.dpad = DInput::DPad::UP;
break;
case Gamepad::DPAD_DOWN:
in_report.dpad = DInput::DPad::DOWN;
break;
case Gamepad::DPAD_LEFT:
in_report.dpad = DInput::DPad::LEFT;
break;
case Gamepad::DPAD_RIGHT:
in_report.dpad = DInput::DPad::RIGHT;
break;
case Gamepad::DPAD_UP_LEFT:
in_report.dpad = DInput::DPad::UP_LEFT;
break;
case Gamepad::DPAD_UP_RIGHT:
in_report.dpad = DInput::DPad::UP_RIGHT;
break;
case Gamepad::DPAD_DOWN_LEFT:
in_report.dpad = DInput::DPad::DOWN_LEFT;
break;
case Gamepad::DPAD_DOWN_RIGHT:
in_report.dpad = DInput::DPad::DOWN_RIGHT;
break;
default:
in_report.dpad = DInput::DPad::CENTER;
break;
}
std::memset(in_report.buttons, 0, sizeof(in_report.buttons));
if (gp_in.buttons & Gamepad::BUTTON_A) in_report.buttons[0] |= DInput::Buttons0::CROSS;
if (gp_in.buttons & Gamepad::BUTTON_B) in_report.buttons[0] |= DInput::Buttons0::CIRCLE;
if (gp_in.buttons & Gamepad::BUTTON_X) in_report.buttons[0] |= DInput::Buttons0::SQUARE;
if (gp_in.buttons & Gamepad::BUTTON_Y) in_report.buttons[0] |= DInput::Buttons0::TRIANGLE;
if (gp_in.buttons & Gamepad::BUTTON_LB) in_report.buttons[0] |= DInput::Buttons0::L1;
if (gp_in.buttons & Gamepad::BUTTON_RB) in_report.buttons[0] |= DInput::Buttons0::R1;
if (gp_in.buttons & Gamepad::BUTTON_L3) in_report.buttons[1] |= DInput::Buttons1::L3;
if (gp_in.buttons & Gamepad::BUTTON_R3) in_report.buttons[1] |= DInput::Buttons1::R3;
if (gp_in.buttons & Gamepad::BUTTON_BACK) in_report.buttons[1] |= DInput::Buttons1::SELECT;
if (gp_in.buttons & Gamepad::BUTTON_START) in_report.buttons[1] |= DInput::Buttons1::START;
if (gp_in.buttons & Gamepad::BUTTON_SYS) in_report.buttons[1] |= DInput::Buttons1::PS;
if (gp_in.buttons & Gamepad::BUTTON_MISC) in_report.buttons[1] |= DInput::Buttons1::TP;
if (gamepad.analog_enabled())
{
in_report.up_axis = gp_in.analog[Gamepad::ANALOG_OFF_UP];
in_report.down_axis = gp_in.analog[Gamepad::ANALOG_OFF_DOWN];
in_report.right_axis = gp_in.analog[Gamepad::ANALOG_OFF_RIGHT];
in_report.left_axis = gp_in.analog[Gamepad::ANALOG_OFF_LEFT];
in_report.triangle_axis = gp_in.analog[Gamepad::ANALOG_OFF_Y];
in_report.circle_axis = gp_in.analog[Gamepad::ANALOG_OFF_X];
in_report.cross_axis = gp_in.analog[Gamepad::ANALOG_OFF_B];
in_report.square_axis = gp_in.analog[Gamepad::ANALOG_OFF_A];
in_report.r1_axis = gp_in.analog[Gamepad::ANALOG_OFF_RB];
in_report.l1_axis = gp_in.analog[Gamepad::ANALOG_OFF_LB];
}
in_report.joystick_lx = Scale::int16_to_uint8(gp_in.joystick_lx);
in_report.joystick_ly = Scale::int16_to_uint8(gp_in.joystick_ly);
in_report.joystick_rx = Scale::int16_to_uint8(gp_in.joystick_rx);
in_report.joystick_ry = Scale::int16_to_uint8(gp_in.joystick_ry);
in_report.l2_axis = gp_in.trigger_l;
in_report.r2_axis = gp_in.trigger_r;
}
if (tud_suspended())
{
tud_remote_wakeup();
}
if (tud_hid_n_ready(idx))
{
tud_hid_n_report(idx, 0, reinterpret_cast<void*>(&in_report), sizeof(DInput::InReport));
}
}
uint16_t DInputDevice::get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
{
if (report_type != HID_REPORT_TYPE_INPUT || itf >= MAX_GAMEPADS)
{
return 0;
}
std::memcpy(buffer, &in_reports_[itf], sizeof(DInput::InReport));
return sizeof(DInput::InReport);
}
void DInputDevice::set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {}
bool DInputDevice::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
{
return false;
}
const uint16_t* DInputDevice::get_descriptor_string_cb(uint8_t index, uint16_t langid)
{
const char* value = reinterpret_cast<const char*>(DInput::STRING_DESCRIPTORS[index]);
return get_string_descriptor(value, index);
}
const uint8_t* DInputDevice::get_descriptor_device_cb()
{
return DInput::DEVICE_DESCRIPTORS;
}
const uint8_t* DInputDevice::get_hid_descriptor_report_cb(uint8_t itf)
{
return DInput::REPORT_DESCRIPTORS;
}
const uint8_t* DInputDevice::get_descriptor_configuration_cb(uint8_t index)
{
return DInput::CONFIGURATION_DESCRIPTORS;
}
const uint8_t* DInputDevice::get_descriptor_device_qualifier_cb()
{
return nullptr;
}

View File

@@ -1,31 +0,0 @@
#ifndef _DINPUT_DEVICE_H_
#define _DINPUT_DEVICE_H_
#include <cstdint>
#include <array>
#include "board_config.h"
#include "USBDevice/DeviceDriver/DeviceDriver.h"
#include "Descriptors/DInput.h"
class DInputDevice : public DeviceDriver
{
public:
void initialize() override;
void process(const uint8_t idx, Gamepad& gamepad) override;
uint16_t get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) override;
void set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) override;
bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) override;
const uint16_t* get_descriptor_string_cb(uint8_t index, uint16_t langid) override;
const uint8_t* get_descriptor_device_cb() override;
const uint8_t* get_hid_descriptor_report_cb(uint8_t itf) override;
const uint8_t* get_descriptor_configuration_cb(uint8_t index) override;
const uint8_t* get_descriptor_device_qualifier_cb() override;
private:
std::array<DInput::InReport, MAX_GAMEPADS> in_reports_;
static bool control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
};
#endif // _DINPUT_DEVICE_H_

View File

@@ -1,29 +0,0 @@
#include "class/cdc/cdc_device.h"
#include "bsp/board_api.h"
#include "USBDevice/DeviceDriver/DeviceDriver.h"
uint16_t* DeviceDriver::get_string_descriptor(const char* value, uint8_t index)
{
static uint16_t string_desc_buffer[32];
size_t char_count;
if ( index == 0 )
{
char_count = 1;
}
else
{
char_count = strlen(value);
if (char_count > 31)
{
char_count = 31;
}
}
for (uint8_t i = 0; i < char_count; i++)
{
string_desc_buffer[i + 1] = value[i];
}
string_desc_buffer[0] = static_cast<uint16_t>((0x03 << 8) | (2 * static_cast<uint8_t>(char_count) + 2));
return string_desc_buffer;
}

View File

@@ -1,55 +0,0 @@
#ifndef _DEVICE_DRIVER_H_
#define _DEVICE_DRIVER_H_
#include <cstdint>
#include "tusb.h"
#include "class/hid/hid.h"
#include "device/usbd_pvt.h"
#include "Gamepad.h"
#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
#define TUD_DRV_NAME(name) name
#else
#define TUD_DRV_NAME(name) NULL
#endif
class DeviceDriver
{
public:
enum class Type : uint8_t
{
NONE = 0,
PS3 = 1,
DINPUT = 2,
SWITCH = 4,
PSCLASSIC = 5,
XINPUT = 6,
XBOXOG = 7,
XBOXOG_SB = 8,
XBOXOG_XR = 9,
WEBAPP = 100,
UART_BRIDGE = 101
};
virtual void initialize() = 0;
virtual void process(const uint8_t idx, Gamepad& gamepad) = 0;
virtual uint16_t get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t req_len) = 0;
virtual void set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t buffer_size) = 0;
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) = 0;
virtual const uint16_t* get_descriptor_string_cb(uint8_t index, uint16_t langid) = 0;
virtual const uint8_t* get_descriptor_device_cb() = 0;
virtual const uint8_t* get_hid_descriptor_report_cb(uint8_t itf) = 0;
virtual const uint8_t* get_descriptor_configuration_cb(uint8_t index) = 0;
virtual const uint8_t* get_descriptor_device_qualifier_cb() = 0;
const usbd_class_driver_t* get_class_driver() { return &class_driver_; };
protected:
usbd_class_driver_t class_driver_;
uint16_t* get_string_descriptor(const char* value, uint8_t index);
};
#endif // _DEVICE_DRIVER_H_

View File

@@ -1,241 +0,0 @@
#include <cstring>
#include <algorithm>
#include "USBDevice/DeviceDriver/PS3/PS3.h"
void PS3Device::initialize()
{
class_driver_ =
{
.name = TUD_DRV_NAME("PS3"),
.init = hidd_init,
.deinit = hidd_deinit,
.reset = hidd_reset,
.open = hidd_open,
.control_xfer_cb = hidd_control_xfer_cb,
.xfer_cb = hidd_xfer_cb,
.sof = NULL
};
}
void PS3Device::process(const uint8_t idx, Gamepad& gamepad)
{
if (gamepad.new_pad_in())
{
Gamepad::PadIn gp_in = gamepad.get_pad_in();
report_in_ = PS3::InReport();
switch (gp_in.dpad)
{
case Gamepad::DPAD_UP:
report_in_.buttons[0] = PS3::Buttons0::DPAD_UP;
break;
case Gamepad::DPAD_DOWN:
report_in_.buttons[0] = PS3::Buttons0::DPAD_DOWN;
break;
case Gamepad::DPAD_LEFT:
report_in_.buttons[0] = PS3::Buttons0::DPAD_LEFT;
break;
case Gamepad::DPAD_RIGHT:
report_in_.buttons[0] = PS3::Buttons0::DPAD_RIGHT;
break;
case Gamepad::DPAD_UP_LEFT:
report_in_.buttons[0] = PS3::Buttons0::DPAD_UP | PS3::Buttons0::DPAD_LEFT;
break;
case Gamepad::DPAD_UP_RIGHT:
report_in_.buttons[0] = PS3::Buttons0::DPAD_UP | PS3::Buttons0::DPAD_RIGHT;
break;
case Gamepad::DPAD_DOWN_LEFT:
report_in_.buttons[0] = PS3::Buttons0::DPAD_DOWN | PS3::Buttons0::DPAD_LEFT;
break;
case Gamepad::DPAD_DOWN_RIGHT:
report_in_.buttons[0] = PS3::Buttons0::DPAD_DOWN | PS3::Buttons0::DPAD_RIGHT;
break;
default:
break;
}
if (gp_in.buttons & Gamepad::BUTTON_X) report_in_.buttons[1] |= PS3::Buttons1::SQUARE;
if (gp_in.buttons & Gamepad::BUTTON_A) report_in_.buttons[1] |= PS3::Buttons1::CROSS;
if (gp_in.buttons & Gamepad::BUTTON_Y) report_in_.buttons[1] |= PS3::Buttons1::TRIANGLE;
if (gp_in.buttons & Gamepad::BUTTON_B) report_in_.buttons[1] |= PS3::Buttons1::CIRCLE;
if (gp_in.buttons & Gamepad::BUTTON_LB) report_in_.buttons[1] |= PS3::Buttons1::L1;
if (gp_in.buttons & Gamepad::BUTTON_RB) report_in_.buttons[1] |= PS3::Buttons1::R1;
if (gp_in.buttons & Gamepad::BUTTON_BACK) report_in_.buttons[0] |= PS3::Buttons0::SELECT;
if (gp_in.buttons & Gamepad::BUTTON_START) report_in_.buttons[0] |= PS3::Buttons0::START;
if (gp_in.buttons & Gamepad::BUTTON_L3) report_in_.buttons[0] |= PS3::Buttons0::L3;
if (gp_in.buttons & Gamepad::BUTTON_R3) report_in_.buttons[0] |= PS3::Buttons0::R3;
if (gp_in.buttons & Gamepad::BUTTON_SYS) report_in_.buttons[2] |= PS3::Buttons2::PS;
if (gp_in.buttons & Gamepad::BUTTON_MISC) report_in_.buttons[2] |= PS3::Buttons2::TP;
if (gp_in.trigger_l) report_in_.buttons[1] |= PS3::Buttons1::L2;
if (gp_in.trigger_r) report_in_.buttons[1] |= PS3::Buttons1::R2;
report_in_.joystick_lx = Scale::int16_to_uint8(gp_in.joystick_lx);
report_in_.joystick_ly = Scale::int16_to_uint8(gp_in.joystick_ly);
report_in_.joystick_rx = Scale::int16_to_uint8(gp_in.joystick_rx);
report_in_.joystick_ry = Scale::int16_to_uint8(gp_in.joystick_ry);
if (gamepad.analog_enabled())
{
report_in_.up_axis = gp_in.analog[Gamepad::ANALOG_OFF_UP];
report_in_.down_axis = gp_in.analog[Gamepad::ANALOG_OFF_DOWN];
report_in_.right_axis = gp_in.analog[Gamepad::ANALOG_OFF_RIGHT];
report_in_.left_axis = gp_in.analog[Gamepad::ANALOG_OFF_LEFT];
report_in_.triangle_axis = gp_in.analog[Gamepad::ANALOG_OFF_Y];
report_in_.circle_axis = gp_in.analog[Gamepad::ANALOG_OFF_B];
report_in_.cross_axis = gp_in.analog[Gamepad::ANALOG_OFF_A];
report_in_.square_axis = gp_in.analog[Gamepad::ANALOG_OFF_X];
report_in_.r1_axis = gp_in.analog[Gamepad::ANALOG_OFF_RB];
report_in_.l1_axis = gp_in.analog[Gamepad::ANALOG_OFF_LB];
}
else
{
report_in_.up_axis = (gp_in.dpad & Gamepad::DPAD_UP) ? 0xFF : 0;
report_in_.down_axis = (gp_in.dpad & Gamepad::DPAD_DOWN) ? 0xFF : 0;
report_in_.right_axis = (gp_in.dpad & Gamepad::DPAD_RIGHT) ? 0xFF : 0;
report_in_.left_axis = (gp_in.dpad & Gamepad::DPAD_LEFT) ? 0xFF : 0;
report_in_.triangle_axis = (gp_in.buttons & Gamepad::BUTTON_Y) ? 0xFF : 0;
report_in_.circle_axis = (gp_in.buttons & Gamepad::BUTTON_X) ? 0xFF : 0;
report_in_.cross_axis = (gp_in.buttons & Gamepad::BUTTON_B) ? 0xFF : 0;
report_in_.square_axis = (gp_in.buttons & Gamepad::BUTTON_A) ? 0xFF : 0;
report_in_.r1_axis = (gp_in.buttons & Gamepad::BUTTON_RB) ? 0xFF : 0;
report_in_.l1_axis = (gp_in.buttons & Gamepad::BUTTON_LB) ? 0xFF : 0;
}
}
if (tud_suspended())
{
tud_remote_wakeup();
}
if (tud_hid_ready())
{
//PS3 seems to start using stale data if a report isn't sent every frame
tud_hid_report(0, reinterpret_cast<uint8_t*>(&report_in_), sizeof(PS3::InReport));
}
if (new_report_out_)
{
Gamepad::PadOut gp_out;
gp_out.rumble_l = report_out_.rumble.left_motor_force;
gp_out.rumble_r = report_out_.rumble.right_motor_on ? UINT_8::MAX : 0;
gamepad.set_pad_out(gp_out);
new_report_out_ = false;
}
}
uint16_t PS3Device::get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
{
if (report_type == HID_REPORT_TYPE_INPUT)
{
std::memcpy(buffer, &report_in_, sizeof(PS3::InReport));
return sizeof(PS3::InReport);
}
else if (report_type == HID_REPORT_TYPE_FEATURE)
{
uint16_t resp_len = 0;
uint8_t ctr = 0;
switch(report_id)
{
case PS3::ReportID::FEATURE_01:
resp_len = reqlen;
std::memcpy(buffer, PS3::OUTPUT_0x01, resp_len);
return resp_len;
case PS3::ReportID::FEATURE_EF:
resp_len = reqlen;
std::memcpy(buffer, PS3::OUTPUT_0xEF, resp_len);
buffer[6] = ef_byte_;
return resp_len;
case PS3::ReportID::GET_PAIRING_INFO:
resp_len = reqlen;
std::memcpy(buffer, &bt_info_, resp_len);
return resp_len;
case PS3::ReportID::FEATURE_F5:
resp_len = reqlen;
std::memcpy(buffer, PS3::OUTPUT_0xF5, resp_len);
for (ctr = 0; ctr < 6; ctr++)
{
buffer[1+ctr] = bt_info_.host_address[ctr];
}
return resp_len;
case PS3::ReportID::FEATURE_F7:
resp_len = reqlen;
std::memcpy(buffer, PS3::OUTPUT_0xF7, resp_len);
return resp_len;
case PS3::ReportID::FEATURE_F8:
resp_len = reqlen;
std::memcpy(buffer, PS3::OUTPUT_0xF8, resp_len);
buffer[6] = ef_byte_;
return resp_len;
}
}
return 0;
}
void PS3Device::set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize)
{
if (report_type == HID_REPORT_TYPE_FEATURE)
{
switch(report_id)
{
case PS3::ReportID::FEATURE_EF:
ef_byte_ = buffer[6];
break;
}
}
else if (report_type == HID_REPORT_TYPE_OUTPUT)
{
// DS3 command
uint8_t const *buf = buffer;
if (report_id == 0 && bufsize > 0)
{
report_id = buffer[0];
bufsize = bufsize - 1;
buf = &buffer[1];
}
switch(report_id)
{
case PS3::ReportID::FEATURE_01:
new_report_out_ = true;
std::memcpy(&report_out_, buf, std::min(bufsize, static_cast<uint16_t>(sizeof(PS3::OutReport))));
break;
}
}
}
bool PS3Device::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
{
return false;
}
const uint16_t* PS3Device::get_descriptor_string_cb(uint8_t index, uint16_t langid)
{
const char *value = reinterpret_cast<const char*>(PS3::STRING_DESCRIPTORS[index]);
return get_string_descriptor(value, index);
}
const uint8_t* PS3Device::get_descriptor_device_cb()
{
return PS3::DEVICE_DESCRIPTORS;
}
const uint8_t* PS3Device::get_hid_descriptor_report_cb(uint8_t itf)
{
return PS3::REPORT_DESCRIPTORS;
}
const uint8_t* PS3Device::get_descriptor_configuration_cb(uint8_t index)
{
return PS3::CONFIGURATION_DESCRIPTORS;
}
const uint8_t* PS3Device::get_descriptor_device_qualifier_cb()
{
return nullptr;
}

View File

@@ -1,32 +0,0 @@
#ifndef _PS3_DEVICE_H_
#define _PS3_DEVICE_H_
#include <cstdint>
#include <array>
#include "USBDevice/DeviceDriver/DeviceDriver.h"
#include "Descriptors/PS3.h"
class PS3Device : public DeviceDriver
{
public:
void initialize() override;
void process(const uint8_t idx, Gamepad& gamepad) override;
uint16_t get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) override;
void set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) override;
bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) override;
const uint16_t* get_descriptor_string_cb(uint8_t index, uint16_t langid) override;
const uint8_t* get_descriptor_device_cb() override;
const uint8_t* get_hid_descriptor_report_cb(uint8_t itf) override;
const uint8_t* get_descriptor_configuration_cb(uint8_t index) override;
const uint8_t* get_descriptor_device_qualifier_cb() override;
private:
PS3::InReport report_in_;
PS3::OutReport report_out_;
PS3::BTInfo bt_info_;
uint8_t ef_byte_;
bool new_report_out_{false};
};
#endif // _PS3_DEVICE_H_

View File

@@ -1,160 +0,0 @@
#include <cstring>
#include "USBDevice/DeviceDriver/PSClassic/PSClassic.h"
void PSClassicDevice::initialize()
{
class_driver_ =
{
.name = TUD_DRV_NAME("PSClassic"),
.init = hidd_init,
.deinit = hidd_deinit,
.reset = hidd_reset,
.open = hidd_open,
.control_xfer_cb = hidd_control_xfer_cb,
.xfer_cb = hidd_xfer_cb,
.sof = NULL
};
}
void PSClassicDevice::process(const uint8_t idx, Gamepad& gamepad)
{
if (gamepad.new_pad_in())
{
Gamepad::PadIn gp_in = gamepad.get_pad_in();
switch (gp_in.dpad)
{
case Gamepad::DPAD_UP:
in_report_.buttons = PSClassic::Buttons::UP;
break;
case Gamepad::DPAD_DOWN:
in_report_.buttons = PSClassic::Buttons::DOWN;
break;
case Gamepad::DPAD_LEFT:
in_report_.buttons = PSClassic::Buttons::LEFT;
break;
case Gamepad::DPAD_RIGHT:
in_report_.buttons = PSClassic::Buttons::RIGHT;
break;
case Gamepad::DPAD_UP_LEFT:
in_report_.buttons = PSClassic::Buttons::UP_LEFT;
break;
case Gamepad::DPAD_UP_RIGHT:
in_report_.buttons = PSClassic::Buttons::UP_RIGHT;
break;
case Gamepad::DPAD_DOWN_LEFT:
in_report_.buttons = PSClassic::Buttons::DOWN_LEFT;
break;
case Gamepad::DPAD_DOWN_RIGHT:
in_report_.buttons = PSClassic::Buttons::DOWN_RIGHT;
break;
default:
in_report_.buttons = PSClassic::Buttons::CENTER;
break;
}
int16_t joy_lx = gp_in.joystick_lx;
int16_t joy_ly = Scale::invert_joy(gp_in.joystick_ly);
int16_t joy_rx = gp_in.joystick_rx;
int16_t joy_ry = Scale::invert_joy(gp_in.joystick_ry);
if (meets_pos_threshold(joy_lx, joy_rx))
{
if (meets_neg_45_threshold(joy_ly, joy_ry))
{
in_report_.buttons = PSClassic::Buttons::DOWN_RIGHT;
}
else if (meets_pos_45_threshold(joy_ly, joy_ry))
{
in_report_.buttons = PSClassic::Buttons::UP_RIGHT;
}
else
{
in_report_.buttons = PSClassic::Buttons::RIGHT;
}
}
else if (meets_neg_threshold(joy_lx, joy_rx))
{
if (meets_neg_45_threshold(joy_ly, joy_ry))
{
in_report_.buttons = PSClassic::Buttons::DOWN_LEFT;
}
else if (meets_pos_45_threshold(joy_ly, joy_ry))
{
in_report_.buttons = PSClassic::Buttons::UP_LEFT;
}
else
{
in_report_.buttons = PSClassic::Buttons::LEFT;
}
}
else if (meets_neg_threshold(joy_ly, joy_ry))
{
in_report_.buttons = PSClassic::Buttons::DOWN;
}
else if (meets_pos_threshold(joy_ly, joy_ry))
{
in_report_.buttons = PSClassic::Buttons::UP;
}
if (gp_in.buttons & Gamepad::BUTTON_A) in_report_.buttons |= PSClassic::Buttons::CROSS;
if (gp_in.buttons & Gamepad::BUTTON_B) in_report_.buttons |= PSClassic::Buttons::CIRCLE;
if (gp_in.buttons & Gamepad::BUTTON_X) in_report_.buttons |= PSClassic::Buttons::SQUARE;
if (gp_in.buttons & Gamepad::BUTTON_Y) in_report_.buttons |= PSClassic::Buttons::TRIANGLE;
if (gp_in.buttons & Gamepad::BUTTON_LB) in_report_.buttons |= PSClassic::Buttons::L1;
if (gp_in.buttons & Gamepad::BUTTON_RB) in_report_.buttons |= PSClassic::Buttons::R1;
if (gp_in.buttons & Gamepad::BUTTON_BACK) in_report_.buttons |= PSClassic::Buttons::SELECT;
if (gp_in.buttons & Gamepad::BUTTON_START) in_report_.buttons |= PSClassic::Buttons::START;
if (gp_in.trigger_l) in_report_.buttons |= PSClassic::Buttons::L2;
if (gp_in.trigger_r) in_report_.buttons |= PSClassic::Buttons::R2;
}
if (tud_suspended())
{
tud_remote_wakeup();
}
if (tud_hid_n_ready(idx))
{
tud_hid_n_report(idx, 0, reinterpret_cast<uint8_t*>(&in_report_), sizeof(PSClassic::InReport));
}
}
uint16_t PSClassicDevice::get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
{
std::memcpy(buffer, &in_report_, sizeof(PSClassic::InReport));
return sizeof(PSClassic::InReport);
}
void PSClassicDevice::set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {}
bool PSClassicDevice::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
{
return false;
}
const uint16_t* PSClassicDevice::get_descriptor_string_cb(uint8_t index, uint16_t langid)
{
const char* value = reinterpret_cast<const char*>(PSClassic::STRING_DESCRIPTORS[index]);
return get_string_descriptor(value, index);
}
const uint8_t* PSClassicDevice::get_descriptor_device_cb()
{
return PSClassic::DEVICE_DESCRIPTORS;
}
const uint8_t* PSClassicDevice::get_hid_descriptor_report_cb(uint8_t itf)
{
return PSClassic::REPORT_DESCRIPTORS;
}
const uint8_t* PSClassicDevice::get_descriptor_configuration_cb(uint8_t index)
{
return PSClassic::CONFIGURATION_DESCRIPTORS;
}
const uint8_t* PSClassicDevice::get_descriptor_device_qualifier_cb()
{
return nullptr;
}

View File

@@ -1,40 +0,0 @@
#ifndef _D_PSCLASSIC_DRIVER_H_
#define _D_PSCLASSIC_DRIVER_H_
#include <cstdint>
#include "tusb.h"
#include "Gamepad.h"
#include "Descriptors/PSClassic.h"
#include "USBDevice/DeviceDriver/DeviceDriver.h"
class PSClassicDevice : public DeviceDriver
{
public:
void initialize() override;
void process(const uint8_t idx, Gamepad& gamepad) override;
uint16_t get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) override;
void set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) override;
bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) override;
const uint16_t* get_descriptor_string_cb(uint8_t index, uint16_t langid) override;
const uint8_t* get_descriptor_device_cb() override;
const uint8_t* get_hid_descriptor_report_cb(uint8_t itf) ;
const uint8_t* get_descriptor_configuration_cb(uint8_t index) override;
const uint8_t* get_descriptor_device_qualifier_cb() override;
private:
static constexpr int16_t JOY_POS_THRESHOLD = 10000;
static constexpr int16_t JOY_NEG_THRESHOLD = -10000;
static constexpr int16_t JOY_POS_45_THRESHOLD = JOY_POS_THRESHOLD * 2;
static constexpr int16_t JOY_NEG_45_THRESHOLD = JOY_NEG_THRESHOLD * 2;
PSClassic::InReport in_report_{0};
inline bool meets_pos_threshold(int16_t joy_l, int16_t joy_r) { return (joy_l >= JOY_POS_THRESHOLD) || (joy_r >= JOY_POS_THRESHOLD); }
inline bool meets_neg_threshold(int16_t joy_l, int16_t joy_r) { return (joy_l <= JOY_NEG_THRESHOLD) || (joy_r <= JOY_NEG_THRESHOLD); }
inline bool meets_pos_45_threshold(int16_t joy_l, int16_t joy_r) { return (joy_l >= JOY_POS_45_THRESHOLD) || (joy_r >= JOY_POS_45_THRESHOLD); }
inline bool meets_neg_45_threshold(int16_t joy_l, int16_t joy_r) { return (joy_l <= JOY_NEG_45_THRESHOLD) || (joy_r <= JOY_NEG_45_THRESHOLD); }
};
#endif // _D_PSCLASSIC_DRIVER_H_

View File

@@ -1,136 +0,0 @@
#include <cstring>
#include "USBDevice/DeviceDriver/Switch/Switch.h"
void SwitchDevice::initialize()
{
class_driver_ =
{
.name = TUD_DRV_NAME("SWITCH"),
.init = hidd_init,
.deinit = hidd_deinit,
.reset = hidd_reset,
.open = hidd_open,
.control_xfer_cb = hidd_control_xfer_cb,
.xfer_cb = hidd_xfer_cb,
.sof = NULL
};
in_report_.fill(SwitchWired::InReport());
}
void SwitchDevice::process(const uint8_t idx, Gamepad& gamepad)
{
SwitchWired::InReport& in_report = in_report_[idx];
if (gamepad.new_pad_in())
{
Gamepad::PadIn gp_in = gamepad.get_pad_in();
switch (gp_in.dpad)
{
case Gamepad::DPAD_UP:
in_report.dpad = SwitchWired::DPad::UP;
break;
case Gamepad::DPAD_DOWN:
in_report.dpad = SwitchWired::DPad::DOWN;
break;
case Gamepad::DPAD_LEFT:
in_report.dpad = SwitchWired::DPad::LEFT;
break;
case Gamepad::DPAD_RIGHT:
in_report.dpad = SwitchWired::DPad::RIGHT;
break;
case Gamepad::DPAD_UP_LEFT:
in_report.dpad = SwitchWired::DPad::UP_LEFT;
break;
case Gamepad::DPAD_UP_RIGHT:
in_report.dpad = SwitchWired::DPad::UP_RIGHT;
break;
case Gamepad::DPAD_DOWN_LEFT:
in_report.dpad = SwitchWired::DPad::DOWN_LEFT;
break;
case Gamepad::DPAD_DOWN_RIGHT:
in_report.dpad = SwitchWired::DPad::DOWN_RIGHT;
break;
default:
in_report.dpad = SwitchWired::DPad::CENTER;
break;
}
in_report.buttons = 0;
if (gp_in.buttons & Gamepad::BUTTON_X) in_report.buttons |= SwitchWired::Buttons::Y;
if (gp_in.buttons & Gamepad::BUTTON_A) in_report.buttons |= SwitchWired::Buttons::B;
if (gp_in.buttons & Gamepad::BUTTON_Y) in_report.buttons |= SwitchWired::Buttons::X;
if (gp_in.buttons & Gamepad::BUTTON_B) in_report.buttons |= SwitchWired::Buttons::A;
if (gp_in.buttons & Gamepad::BUTTON_LB) in_report.buttons |= SwitchWired::Buttons::L;
if (gp_in.buttons & Gamepad::BUTTON_RB) in_report.buttons |= SwitchWired::Buttons::R;
if (gp_in.buttons & Gamepad::BUTTON_BACK) in_report.buttons |= SwitchWired::Buttons::MINUS;
if (gp_in.buttons & Gamepad::BUTTON_START) in_report.buttons |= SwitchWired::Buttons::PLUS;
if (gp_in.buttons & Gamepad::BUTTON_L3) in_report.buttons |= SwitchWired::Buttons::L3;
if (gp_in.buttons & Gamepad::BUTTON_R3) in_report.buttons |= SwitchWired::Buttons::R3;
if (gp_in.buttons & Gamepad::BUTTON_SYS) in_report.buttons |= SwitchWired::Buttons::HOME;
if (gp_in.buttons & Gamepad::BUTTON_MISC) in_report.buttons |= SwitchWired::Buttons::CAPTURE;
if (gp_in.trigger_l) in_report.buttons |= SwitchWired::Buttons::ZL;
if (gp_in.trigger_r) in_report.buttons |= SwitchWired::Buttons::ZR;
in_report.joystick_lx = Scale::int16_to_uint8(gp_in.joystick_lx);
in_report.joystick_ly = Scale::int16_to_uint8(gp_in.joystick_ly);
in_report.joystick_rx = Scale::int16_to_uint8(gp_in.joystick_rx);
in_report.joystick_ry = Scale::int16_to_uint8(gp_in.joystick_ry);
}
if (tud_suspended())
{
tud_remote_wakeup();
}
if (tud_hid_n_ready(idx))
{
tud_hid_n_report(idx, 0, reinterpret_cast<uint8_t*>(&in_report), sizeof(SwitchWired::InReport));
}
}
uint16_t SwitchDevice::get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
{
if (report_type != HID_REPORT_TYPE_INPUT || itf >= MAX_GAMEPADS)
{
return 0;
}
std::memcpy(buffer, &in_report_[itf], sizeof(SwitchWired::InReport));
return sizeof(SwitchWired::InReport);
}
void SwitchDevice::set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {}
bool SwitchDevice::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
{
return false;
}
const uint16_t* SwitchDevice::get_descriptor_string_cb(uint8_t index, uint16_t langid)
{
const char *value = reinterpret_cast<const char*>(SwitchWired::STRING_DESCRIPTORS[index]);
return get_string_descriptor(value, index);
}
const uint8_t* SwitchDevice::get_descriptor_device_cb()
{
return SwitchWired::DEVICE_DESCRIPTORS;
}
const uint8_t* SwitchDevice::get_hid_descriptor_report_cb(uint8_t itf)
{
return SwitchWired::REPORT_DESCRIPTORS;
}
const uint8_t* SwitchDevice::get_descriptor_configuration_cb(uint8_t index)
{
return SwitchWired::CONFIGURATION_DESCRIPTORS;
}
const uint8_t* SwitchDevice::get_descriptor_device_qualifier_cb()
{
return nullptr;
}

View File

@@ -1,28 +0,0 @@
#ifndef _SWITCH_DEVICE_H_
#define _SWITCH_DEVICE_H_
#include <cstdint>
#include <array>
#include "USBDevice/DeviceDriver/DeviceDriver.h"
#include "Descriptors/SwitchWired.h"
class SwitchDevice : public DeviceDriver
{
public:
void initialize() override;
void process(const uint8_t idx, Gamepad& gamepad) override;
uint16_t get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) override;
void set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) override;
bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) override;
const uint16_t* get_descriptor_string_cb(uint8_t index, uint16_t langid) override;
const uint8_t* get_descriptor_device_cb() override;
const uint8_t* get_hid_descriptor_report_cb(uint8_t itf) override;
const uint8_t* get_descriptor_configuration_cb(uint8_t index) override;
const uint8_t* get_descriptor_device_qualifier_cb() override;
private:
std::array<SwitchWired::InReport, MAX_GAMEPADS> in_report_;
};
#endif // _SWITCH_DEVICE_H_

View File

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

View File

@@ -1,26 +0,0 @@
#ifndef _UART_BRIDGE_DEVICE_H_
#define _UART_BRIDGE_DEVICE_H_
#include "USBDevice/DeviceDriver/DeviceDriver.h"
#include "UserSettings/UserProfile.h"
//process() only needs to be called once to start the UART bridge
class UARTBridgeDevice : public DeviceDriver
{
public:
void initialize() override;
void process(const uint8_t idx, Gamepad& gamepad) override;
uint16_t get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) override;
void set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) override;
bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) override;
const uint16_t* get_descriptor_string_cb(uint8_t index, uint16_t langid) override;
const uint8_t* get_descriptor_device_cb() override;
const uint8_t* get_hid_descriptor_report_cb(uint8_t itf) override;
const uint8_t* get_descriptor_configuration_cb(uint8_t index) override;
const uint8_t* get_descriptor_device_qualifier_cb() override;
private:
bool task_running_ = false;
};
#endif // _UART_BRIDGE_DEVICE_H_

View File

@@ -1,329 +0,0 @@
// SPDX-License-Identifier: MIT
/*
* Copyright (c) 2021 Álvaro Fernández Rojas <noltari@gmail.com>
*
* This file is based on a file originally part of the
* MicroPython project, http://micropython.org/
*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
* Copyright (c) 2019 Damien P. George
*/
#include <hardware/irq.h>
#include <hardware/structs/sio.h>
#include <hardware/uart.h>
#include <hardware/flash.h>
#include <hardware/clocks.h>
#include <pico/multicore.h>
#include <pico/stdlib.h>
#include <string.h>
#include "tusb.h"
#if !defined(MIN)
#define MIN(a, b) ((a > b) ? b : a)
#endif /* MIN */
#define BUFFER_SIZE 2560
#define DEF_BIT_RATE 115200
#define DEF_STOP_BITS 1
#define DEF_PARITY 0
#define DEF_DATA_BITS 8
typedef struct {
uart_inst_t *const inst;
uint irq;
void *irq_fn;
uint8_t tx_pin;
uint8_t rx_pin;
} uart_id_t;
typedef struct {
cdc_line_coding_t usb_lc;
cdc_line_coding_t uart_lc;
mutex_t lc_mtx;
uint8_t uart_buffer[BUFFER_SIZE];
uint32_t uart_pos;
mutex_t uart_mtx;
uint8_t usb_buffer[BUFFER_SIZE];
uint32_t usb_pos;
mutex_t usb_mtx;
} uart_data_t;
void uart0_irq_fn(void);
void uart1_irq_fn(void);
const uart_id_t UART_ID[CFG_TUD_CDC] = {
{
.inst = uart0,
.irq = UART0_IRQ,
.irq_fn = &uart0_irq_fn,
.tx_pin = UART0_TX_PIN,
.rx_pin = UART0_RX_PIN,
},
#if CFG_TUD_CDC > 1
{
.inst = uart1,
.irq = UART1_IRQ,
.irq_fn = &uart1_irq_fn,
.tx_pin = 4,
.rx_pin = 5,
}
#endif
};
uart_data_t UART_DATA[CFG_TUD_CDC];
static inline uint databits_usb2uart(uint8_t data_bits)
{
switch (data_bits) {
case 5:
return 5;
case 6:
return 6;
case 7:
return 7;
default:
return 8;
}
}
static inline uart_parity_t parity_usb2uart(uint8_t usb_parity)
{
switch (usb_parity) {
case 1:
return UART_PARITY_ODD;
case 2:
return UART_PARITY_EVEN;
default:
return UART_PARITY_NONE;
}
}
static inline uint stopbits_usb2uart(uint8_t stop_bits)
{
switch (stop_bits) {
case 2:
return 2;
default:
return 1;
}
}
void update_uart_cfg(uint8_t itf)
{
const uart_id_t *ui = &UART_ID[itf];
uart_data_t *ud = &UART_DATA[itf];
mutex_enter_blocking(&ud->lc_mtx);
if (ud->usb_lc.bit_rate != ud->uart_lc.bit_rate) {
uart_set_baudrate(ui->inst, ud->usb_lc.bit_rate);
ud->uart_lc.bit_rate = ud->usb_lc.bit_rate;
}
if ((ud->usb_lc.stop_bits != ud->uart_lc.stop_bits) ||
(ud->usb_lc.parity != ud->uart_lc.parity) ||
(ud->usb_lc.data_bits != ud->uart_lc.data_bits)) {
uart_set_format(ui->inst,
databits_usb2uart(ud->usb_lc.data_bits),
stopbits_usb2uart(ud->usb_lc.stop_bits),
parity_usb2uart(ud->usb_lc.parity));
ud->uart_lc.data_bits = ud->usb_lc.data_bits;
ud->uart_lc.parity = ud->usb_lc.parity;
ud->uart_lc.stop_bits = ud->usb_lc.stop_bits;
}
mutex_exit(&ud->lc_mtx);
}
void usb_read_bytes(uint8_t itf)
{
uart_data_t *ud = &UART_DATA[itf];
uint32_t len = tud_cdc_n_available(itf);
if (len &&
mutex_try_enter(&ud->usb_mtx, NULL)) {
len = MIN(len, BUFFER_SIZE - ud->usb_pos);
if (len) {
uint32_t count;
count = tud_cdc_n_read(itf, &ud->usb_buffer[ud->usb_pos], len);
ud->usb_pos += count;
}
mutex_exit(&ud->usb_mtx);
}
}
void usb_write_bytes(uint8_t itf)
{
uart_data_t *ud = &UART_DATA[itf];
if (ud->uart_pos &&
mutex_try_enter(&ud->uart_mtx, NULL)) {
uint32_t count;
count = tud_cdc_n_write(itf, ud->uart_buffer, ud->uart_pos);
if (count < ud->uart_pos)
memmove(ud->uart_buffer, &ud->uart_buffer[count],
ud->uart_pos - count);
ud->uart_pos -= count;
mutex_exit(&ud->uart_mtx);
if (count)
tud_cdc_n_write_flush(itf);
}
}
void usb_cdc_process(uint8_t itf)
{
uart_data_t *ud = &UART_DATA[itf];
mutex_enter_blocking(&ud->lc_mtx);
tud_cdc_n_get_line_coding(itf, &ud->usb_lc);
mutex_exit(&ud->lc_mtx);
usb_read_bytes(itf);
usb_write_bytes(itf);
}
static inline void uart_read_bytes(uint8_t itf)
{
uart_data_t *ud = &UART_DATA[itf];
const uart_id_t *ui = &UART_ID[itf];
if (uart_is_readable(ui->inst)) {
mutex_enter_blocking(&ud->uart_mtx);
while (uart_is_readable(ui->inst) &&
(ud->uart_pos < BUFFER_SIZE)) {
ud->uart_buffer[ud->uart_pos] = uart_getc(ui->inst);
ud->uart_pos++;
}
mutex_exit(&ud->uart_mtx);
}
}
void uart0_irq_fn(void)
{
uart_read_bytes(0);
}
void uart1_irq_fn(void)
{
uart_read_bytes(1);
}
void uart_write_bytes(uint8_t itf)
{
uart_data_t *ud = &UART_DATA[itf];
if (ud->usb_pos &&
mutex_try_enter(&ud->usb_mtx, NULL)) {
const uart_id_t *ui = &UART_ID[itf];
uint32_t count = 0;
while (uart_is_writable(ui->inst) &&
count < ud->usb_pos) {
uart_putc_raw(ui->inst, ud->usb_buffer[count]);
count++;
}
if (count < ud->usb_pos)
memmove(ud->usb_buffer, &ud->usb_buffer[count],
ud->usb_pos - count);
ud->usb_pos -= count;
mutex_exit(&ud->usb_mtx);
}
}
void init_uart_data(uint8_t itf)
{
const uart_id_t *ui = &UART_ID[itf];
uart_data_t *ud = &UART_DATA[itf];
/* Pinmux */
gpio_set_function(ui->tx_pin, GPIO_FUNC_UART);
gpio_set_function(ui->rx_pin, GPIO_FUNC_UART);
/* USB CDC LC */
ud->usb_lc.bit_rate = DEF_BIT_RATE;
ud->usb_lc.data_bits = DEF_DATA_BITS;
ud->usb_lc.parity = DEF_PARITY;
ud->usb_lc.stop_bits = DEF_STOP_BITS;
/* UART LC */
ud->uart_lc.bit_rate = DEF_BIT_RATE;
ud->uart_lc.data_bits = DEF_DATA_BITS;
ud->uart_lc.parity = DEF_PARITY;
ud->uart_lc.stop_bits = DEF_STOP_BITS;
/* Buffer */
ud->uart_pos = 0;
ud->usb_pos = 0;
/* Mutex */
mutex_init(&ud->lc_mtx);
mutex_init(&ud->uart_mtx);
mutex_init(&ud->usb_mtx);
/* UART start */
uart_init(ui->inst, ud->usb_lc.bit_rate);
uart_set_hw_flow(ui->inst, false, false);
uart_set_format(ui->inst, databits_usb2uart(ud->usb_lc.data_bits),
stopbits_usb2uart(ud->usb_lc.stop_bits),
parity_usb2uart(ud->usb_lc.parity));
uart_set_fifo_enabled(ui->inst, false);
/* UART RX Interrupt */
irq_set_exclusive_handler(ui->irq, ui->irq_fn);
irq_set_enabled(ui->irq, true);
uart_set_irq_enables(ui->inst, true, false);
}
void core1_entry(void)
{
for (int itf = 0; itf < CFG_TUD_CDC; itf++)
{
init_uart_data(0);
}
while (1)
{
for (int itf = 0; itf < CFG_TUD_CDC; itf++)
{
update_uart_cfg(itf);
uart_write_bytes(itf);
}
}
}
int uart_bridge_run(void)
{
set_sys_clock_khz(125000, false);
tud_init(BOARD_TUD_RHPORT);
multicore_reset_core1();
multicore_launch_core1(core1_entry);
while (1)
{
tud_task();
for (int itf = 0; itf < CFG_TUD_CDC; itf++)
{
if (tud_cdc_n_connected(itf))
{
usb_cdc_process(itf);
}
}
}
return 0;
}

View File

@@ -1,17 +0,0 @@
#ifndef _UART_BRIDGE_H_
#define _UART_BRIDGE_H_
#ifdef __cplusplus
extern "C" {
#endif
int uart_bridge_run(void);
// const uint8_t *uart_bridge_descriptor_device_cb(void);
// const uint8_t *uart_bridge_descriptor_configuration_cb(uint8_t index);
// const uint16_t *uart_bridge_descriptor_string_cb(uint8_t index, uint16_t langid);
#ifdef __cplusplus
}
#endif
#endif // _UART_BRIDGE_H_

View File

@@ -1,151 +0,0 @@
#include "class/cdc/cdc_device.h"
#include "bsp/board_api.h"
#include "Descriptors/CDCDev.h"
#include "USBDevice/DeviceDriver/WebApp/WebApp.h"
void WebAppDevice::initialize()
{
class_driver_ =
{
.name = TUD_DRV_NAME("WEBAPP"),
.init = cdcd_init,
.deinit = cdcd_deinit,
.reset = cdcd_reset,
.open = cdcd_open,
.control_xfer_cb = cdcd_control_xfer_cb,
.xfer_cb = cdcd_xfer_cb,
.sof = NULL
};
}
void WebAppDevice::process(const uint8_t idx, Gamepad& gamepad)
{
if (!tud_cdc_available() || !tud_cdc_connected())
{
return;
}
tud_cdc_write_flush();
tud_cdc_read(reinterpret_cast<void*>(&in_report_), sizeof(Report));
tud_cdc_read_flush();
bool success = false;
switch (in_report_.report_id)
{
case ReportID::INIT_READ:
in_report_.input_mode = static_cast<uint8_t>(user_settings_.get_current_driver());
in_report_.player_idx = 0;
in_report_.report_id = ReportID::RESP_OK;
in_report_.max_gamepads = MAX_GAMEPADS;
in_report_.profile.id = user_settings_.get_active_profile_id(in_report_.player_idx);
in_report_.profile = user_settings_.get_profile_by_id(in_report_.profile.id);
tud_cdc_write(reinterpret_cast<const void*>(&in_report_), sizeof(Report));
tud_cdc_write_flush();
break;
case ReportID::READ_PROFILE:
in_report_.input_mode = static_cast<uint8_t>(user_settings_.get_current_driver());
in_report_.profile = user_settings_.get_profile_by_id(in_report_.profile.id);
in_report_.report_id = ReportID::RESP_OK;
tud_cdc_write(reinterpret_cast<const void*>(&in_report_), sizeof(Report));
tud_cdc_write_flush();
break;
case ReportID::WRITE_PROFILE:
if (user_settings_.valid_mode(static_cast<DeviceDriver::Type>(in_report_.input_mode)))
{
success = user_settings_.store_profile_and_driver_type_safe(static_cast<DeviceDriver::Type>(in_report_.input_mode), in_report_.player_idx, in_report_.profile);
}
else
{
success = user_settings_.store_profile_safe(in_report_.player_idx, in_report_.profile);
}
if (!success)
{
in_report_.report_id = ReportID::RESP_ERROR;
tud_cdc_write(reinterpret_cast<const void*>(&in_report_), sizeof(Report));
tud_cdc_write_flush();
}
break;
default:
return;
}
}
uint16_t WebAppDevice::get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
{
return reqlen;
}
void WebAppDevice::set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {}
bool WebAppDevice::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
{
return false;
}
const uint16_t * WebAppDevice::get_descriptor_string_cb(uint8_t index, uint16_t langid)
{
static uint16_t desc_str[32 + 1];
size_t char_count = 0;
switch(index)
{
case 0:
std::memcpy(&desc_str[1], CDCDesc::DESC_STRING[0], 2);
char_count = 1;
break;
case 3:
char_count = board_usb_get_serial(&desc_str[1], 32);
break;
default:
if (index >= sizeof(CDCDesc::DESC_STRING) / sizeof(CDCDesc::DESC_STRING[0]))
{
return nullptr;
}
const char *str = reinterpret_cast<const char *>(CDCDesc::DESC_STRING[index]);
char_count = std::strlen(str);
const size_t max_count = sizeof(desc_str) / sizeof(desc_str[0]) - 1;
if (char_count > max_count)
{
char_count = max_count;
}
for (size_t i = 0; i < char_count; i++)
{
desc_str[1 + i] = str[i];
}
break;
}
desc_str[0] = static_cast<uint16_t>((TUSB_DESC_STRING << 8) | (2 * char_count + 2));
return desc_str;
}
const uint8_t * WebAppDevice::get_descriptor_device_cb()
{
return reinterpret_cast<const uint8_t*>(&CDCDesc::DESC_DEVICE);
}
const uint8_t * WebAppDevice::get_hid_descriptor_report_cb(uint8_t itf)
{
return nullptr;
}
const uint8_t * WebAppDevice::get_descriptor_configuration_cb(uint8_t index)
{
return CDCDesc::DESC_CONFIG;
}
const uint8_t * WebAppDevice::get_descriptor_device_qualifier_cb()
{
return nullptr;
}

View File

@@ -1,49 +0,0 @@
#ifndef _WEBAAPP_DEVICE_H_
#define _WEBAAPP_DEVICE_H_
#include "USBDevice/DeviceDriver/DeviceDriver.h"
#include "UserSettings/UserSettings.h"
#include "UserSettings/UserProfile.h"
class WebAppDevice : public DeviceDriver
{
public:
void initialize() override;
void process(const uint8_t idx, Gamepad& gamepad) override;
uint16_t get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) override;
void set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) override;
bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) override;
const uint16_t* get_descriptor_string_cb(uint8_t index, uint16_t langid) override;
const uint8_t* get_descriptor_device_cb() override;
const uint8_t* get_hid_descriptor_report_cb(uint8_t itf) override;
const uint8_t* get_descriptor_configuration_cb(uint8_t index) override;
const uint8_t* get_descriptor_device_qualifier_cb() override;
private:
struct ReportID
{
static constexpr uint8_t INIT_READ = 0x88;
static constexpr uint8_t READ_PROFILE = 0x01;
static constexpr uint8_t WRITE_PROFILE = 0x02;
static constexpr uint8_t RESP_OK = 0x10;
static constexpr uint8_t RESP_ERROR = 0x11;
};
#pragma pack(push, 1)
struct Report
{
uint8_t report_id{0};
uint8_t input_mode{0};
uint8_t max_gamepads{MAX_GAMEPADS};
uint8_t player_idx{0};
UserProfile profile{UserProfile()};
};
static_assert(sizeof(Report) == 50, "WebApp report size mismatch");
#pragma pack(pop)
UserSettings user_settings_{UserSettings()};
Report in_report_{Report()};
DeviceDriver::Type driver_type_{DeviceDriver::Type::WEBAPP};
};
#endif // _WEBAAPP_DEVICE_H_

View File

@@ -1,126 +0,0 @@
#include <cstring>
#include "USBDevice/DeviceDriver/XInput/tud_xinput/tud_xinput.h"
#include "USBDevice/DeviceDriver/XInput/XInput.h"
void XInputDevice::initialize()
{
class_driver_ = *tud_xinput::class_driver();
}
void XInputDevice::process(const uint8_t idx, Gamepad& gamepad)
{
if (gamepad.new_pad_in())
{
in_report_.buttons[0] = 0;
in_report_.buttons[1] = 0;
Gamepad::PadIn gp_in = gamepad.get_pad_in();
switch (gp_in.dpad)
{
case Gamepad::DPAD_UP:
in_report_.buttons[0] = XInput::Buttons0::DPAD_UP;
break;
case Gamepad::DPAD_DOWN:
in_report_.buttons[0] = XInput::Buttons0::DPAD_DOWN;
break;
case Gamepad::DPAD_LEFT:
in_report_.buttons[0] = XInput::Buttons0::DPAD_LEFT;
break;
case Gamepad::DPAD_RIGHT:
in_report_.buttons[0] = XInput::Buttons0::DPAD_RIGHT;
break;
case Gamepad::DPAD_UP_LEFT:
in_report_.buttons[0] = XInput::Buttons0::DPAD_UP | XInput::Buttons0::DPAD_LEFT;
break;
case Gamepad::DPAD_UP_RIGHT:
in_report_.buttons[0] = XInput::Buttons0::DPAD_UP | XInput::Buttons0::DPAD_RIGHT;
break;
case Gamepad::DPAD_DOWN_LEFT:
in_report_.buttons[0] = XInput::Buttons0::DPAD_DOWN | XInput::Buttons0::DPAD_LEFT;
break;
case Gamepad::DPAD_DOWN_RIGHT:
in_report_.buttons[0] = XInput::Buttons0::DPAD_DOWN | XInput::Buttons0::DPAD_RIGHT;
break;
default:
break;
}
if (gp_in.buttons & Gamepad::BUTTON_BACK) in_report_.buttons[0] |= XInput::Buttons0::BACK;
if (gp_in.buttons & Gamepad::BUTTON_START) in_report_.buttons[0] |= XInput::Buttons0::START;
if (gp_in.buttons & Gamepad::BUTTON_L3) in_report_.buttons[0] |= XInput::Buttons0::L3;
if (gp_in.buttons & Gamepad::BUTTON_R3) in_report_.buttons[0] |= XInput::Buttons0::R3;
if (gp_in.buttons & Gamepad::BUTTON_X) in_report_.buttons[1] |= XInput::Buttons1::X;
if (gp_in.buttons & Gamepad::BUTTON_A) in_report_.buttons[1] |= XInput::Buttons1::A;
if (gp_in.buttons & Gamepad::BUTTON_Y) in_report_.buttons[1] |= XInput::Buttons1::Y;
if (gp_in.buttons & Gamepad::BUTTON_B) in_report_.buttons[1] |= XInput::Buttons1::B;
if (gp_in.buttons & Gamepad::BUTTON_LB) in_report_.buttons[1] |= XInput::Buttons1::LB;
if (gp_in.buttons & Gamepad::BUTTON_RB) in_report_.buttons[1] |= XInput::Buttons1::RB;
if (gp_in.buttons & Gamepad::BUTTON_SYS) in_report_.buttons[1] |= XInput::Buttons1::HOME;
in_report_.trigger_l = gp_in.trigger_l;
in_report_.trigger_r = gp_in.trigger_r;
in_report_.joystick_lx = gp_in.joystick_lx;
in_report_.joystick_ly = Scale::invert_joy(gp_in.joystick_ly);
in_report_.joystick_rx = gp_in.joystick_rx;
in_report_.joystick_ry = Scale::invert_joy(gp_in.joystick_ry);
if (tud_suspended())
{
tud_remote_wakeup();
}
tud_xinput::send_report((uint8_t*)&in_report_, sizeof(XInput::InReport));
}
if (tud_xinput::receive_report(reinterpret_cast<uint8_t*>(&out_report_), sizeof(XInput::OutReport)) &&
out_report_.report_id == XInput::OutReportID::RUMBLE)
{
Gamepad::PadOut gp_out;
gp_out.rumble_l = out_report_.rumble_l;
gp_out.rumble_r = out_report_.rumble_r;
gamepad.set_pad_out(gp_out);
}
}
uint16_t XInputDevice::get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
{
std::memcpy(buffer, &in_report_, sizeof(XInput::InReport));
return sizeof(XInput::InReport);
}
void XInputDevice::set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {}
bool XInputDevice::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
{
return false;
}
const uint16_t * XInputDevice::get_descriptor_string_cb(uint8_t index, uint16_t langid)
{
const char *value = reinterpret_cast<const char*>(XInput::DESC_STRING[index]);
return get_string_descriptor(value, index);
}
const uint8_t * XInputDevice::get_descriptor_device_cb()
{
return XInput::DESC_DEVICE;
}
const uint8_t * XInputDevice::get_hid_descriptor_report_cb(uint8_t itf)
{
return nullptr;
}
const uint8_t * XInputDevice::get_descriptor_configuration_cb(uint8_t index)
{
return XInput::DESC_CONFIGURATION;
}
const uint8_t * XInputDevice::get_descriptor_device_qualifier_cb()
{
return nullptr;
}

View File

@@ -1,26 +0,0 @@
#ifndef _XINPUT_DEVICE_H_
#define _XINPUT_DEVICE_H_
#include "USBDevice/DeviceDriver/DeviceDriver.h"
#include "Descriptors/XInput.h"
class XInputDevice : public DeviceDriver
{
public:
void initialize() override;
void process(const uint8_t idx, Gamepad& gamepad) override;
uint16_t get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) override;
void set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) override;
bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) override;
const uint16_t* get_descriptor_string_cb(uint8_t index, uint16_t langid) override;
const uint8_t* get_descriptor_device_cb() override;
const uint8_t* get_hid_descriptor_report_cb(uint8_t itf) override;
const uint8_t* get_descriptor_configuration_cb(uint8_t index) override;
const uint8_t* get_descriptor_device_qualifier_cb() override;
private:
XInput::InReport in_report_;
XInput::OutReport out_report_;
};
#endif // _XINPUT_DEVICE_H_

View File

@@ -1,161 +0,0 @@
#include "tusb_option.h"
#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_XINPUT)
#include <cstring>
#include <algorithm>
#include "tusb.h"
#include "device/usbd_pvt.h"
#include "Descriptors/XInput.h"
#include "USBDevice/DeviceDriver/XInput/tud_xinput/tud_xinput.h"
namespace tud_xinput {
static constexpr uint16_t ENDPOINT_SIZE = 32;
uint8_t endpoint_in_ = 0xFF;
uint8_t endpoint_out_ = 0xFF;
uint8_t ep_in_buffer_[ENDPOINT_SIZE];
uint8_t ep_out_buffer_[ENDPOINT_SIZE];
//Class Driver
static void init(void)
{
endpoint_in_ = 0xFF;
endpoint_out_ = 0xFF;
std::memset(ep_out_buffer_, 0, ENDPOINT_SIZE);
std::memset(ep_in_buffer_, 0, ENDPOINT_SIZE);
}
static bool deinit(void)
{
init();
return true;
}
static void reset(uint8_t rhport)
{
init();
}
static uint16_t open(uint8_t rhport, tusb_desc_interface_t const *itf_descriptor, uint16_t max_length)
{
uint16_t driver_length = sizeof(tusb_desc_interface_t) + (itf_descriptor->bNumEndpoints * sizeof(tusb_desc_endpoint_t)) + 16;
TU_VERIFY(max_length >= driver_length, 0);
uint8_t const *current_descriptor = tu_desc_next(itf_descriptor);
uint8_t found_endpoints = 0;
while ((found_endpoints < itf_descriptor->bNumEndpoints) && (driver_length <= max_length))
{
tusb_desc_endpoint_t const *endpoint_descriptor = (tusb_desc_endpoint_t const *)current_descriptor;
if (TUSB_DESC_ENDPOINT == tu_desc_type(endpoint_descriptor))
{
TU_ASSERT(usbd_edpt_open(rhport, endpoint_descriptor));
if (tu_edpt_dir(endpoint_descriptor->bEndpointAddress) == TUSB_DIR_IN)
{
endpoint_in_ = endpoint_descriptor->bEndpointAddress;
}
else
{
endpoint_out_ = endpoint_descriptor->bEndpointAddress;
}
++found_endpoints;
}
current_descriptor = tu_desc_next(current_descriptor);
}
return driver_length;
}
static bool control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
{
return true;
}
static bool xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
{
if (ep_addr == endpoint_out_)
{
usbd_edpt_xfer(BOARD_TUD_RHPORT, endpoint_out_, ep_out_buffer_, ENDPOINT_SIZE);
}
return true;
}
// Public API
const usbd_class_driver_t* class_driver()
{
static const usbd_class_driver_t tud_class_driver_ =
{
#if CFG_TUSB_DEBUG >= 2
.name = "XINPUT",
#else
.name = NULL,
#endif
.init = init,
.deinit = deinit,
.reset = reset,
.open = open,
.control_xfer_cb = control_xfer_cb,
.xfer_cb = xfer_cb,
.sof = NULL
};
return &tud_class_driver_;
}
bool send_report_ready()
{
if (tud_ready() &&
(endpoint_in_ != 0xFF) &&
(!usbd_edpt_busy(BOARD_TUD_RHPORT, endpoint_in_)))
{
return true;
}
return false;
}
bool receive_report_ready()
{
if (tud_ready() &&
(endpoint_out_ != 0xFF) &&
(!usbd_edpt_busy(BOARD_TUD_RHPORT, endpoint_out_)))
{
return true;
}
return false;
}
bool send_report(const uint8_t *report, uint16_t len)
{
if (send_report_ready())
{
std::memcpy(ep_in_buffer_, report, std::min(len, ENDPOINT_SIZE));
usbd_edpt_claim(BOARD_TUD_RHPORT, endpoint_in_);
usbd_edpt_xfer(BOARD_TUD_RHPORT, endpoint_in_, ep_in_buffer_, sizeof(XInput::InReport));
usbd_edpt_release(BOARD_TUD_RHPORT, endpoint_in_);
return true;
}
return false;
}
bool receive_report(uint8_t *report, uint16_t len)
{
if (receive_report_ready())
{
usbd_edpt_claim(BOARD_TUD_RHPORT, endpoint_out_);
usbd_edpt_xfer(BOARD_TUD_RHPORT, endpoint_out_, ep_out_buffer_, ENDPOINT_SIZE);
usbd_edpt_release(BOARD_TUD_RHPORT, endpoint_out_);
}
std::memcpy(report, ep_out_buffer_, std::min(len, ENDPOINT_SIZE));
return true;
}
} // namespace tud_xinput
#endif // (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_XINPUT)

View File

@@ -1,18 +0,0 @@
#ifndef _TUD_XINPUT_H_
#define _TUD_XINPUT_H_
#include <cstdint>
#include "tusb.h"
#include "device/usbd_pvt.h"
namespace tud_xinput
{
bool send_report_ready();
bool send_report(const uint8_t *report, uint16_t len);
bool receive_report(uint8_t *report, uint16_t len);
const usbd_class_driver_t* class_driver();
} // namespace tud_xinput
#endif // _TUD_XINPUT_H_

View File

@@ -1,141 +0,0 @@
#include <cstring>
#include <vector>
#include "USBDevice/DeviceDriver/XboxOG/tud_xid/tud_xid.h"
#include "USBDevice/DeviceDriver/XboxOG/XboxOG_GP.h"
void XboxOGDevice::initialize()
{
tud_xid::initialize(tud_xid::Type::GAMEPAD);
class_driver_ = *tud_xid::class_driver();
std::memset(&in_report_, 0, sizeof(XboxOG::GP::InReport));
in_report_.report_len = sizeof(XboxOG::GP::InReport);
}
void XboxOGDevice::process(const uint8_t idx, Gamepad& gamepad)
{
if (gamepad.new_pad_in())
{
std::memset(&in_report_.buttons, 0, 8);
Gamepad::PadIn gp_in = gamepad.get_pad_in();
switch (gp_in.dpad)
{
case Gamepad::DPAD_UP:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_UP;
break;
case Gamepad::DPAD_DOWN:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_DOWN;
break;
case Gamepad::DPAD_LEFT:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_LEFT;
break;
case Gamepad::DPAD_RIGHT:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_RIGHT;
break;
case Gamepad::DPAD_UP_LEFT:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_UP | XboxOG::GP::Buttons::DPAD_LEFT;
break;
case Gamepad::DPAD_UP_RIGHT:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_UP | XboxOG::GP::Buttons::DPAD_RIGHT;
break;
case Gamepad::DPAD_DOWN_LEFT:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_DOWN | XboxOG::GP::Buttons::DPAD_LEFT;
break;
case Gamepad::DPAD_DOWN_RIGHT:
in_report_.buttons = XboxOG::GP::Buttons::DPAD_DOWN | XboxOG::GP::Buttons::DPAD_RIGHT;
break;
default:
break;
}
if (gp_in.buttons & Gamepad::BUTTON_BACK) in_report_.buttons |= XboxOG::GP::Buttons::BACK;
if (gp_in.buttons & Gamepad::BUTTON_START) in_report_.buttons |= XboxOG::GP::Buttons::START;
if (gp_in.buttons & Gamepad::BUTTON_L3) in_report_.buttons |= XboxOG::GP::Buttons::L3;
if (gp_in.buttons & Gamepad::BUTTON_R3) in_report_.buttons |= XboxOG::GP::Buttons::R3;
if (gamepad.analog_enabled())
{
in_report_.a = gp_in.analog[Gamepad::ANALOG_OFF_A];
in_report_.b = gp_in.analog[Gamepad::ANALOG_OFF_B];
in_report_.x = gp_in.analog[Gamepad::ANALOG_OFF_X];
in_report_.y = gp_in.analog[Gamepad::ANALOG_OFF_Y];
in_report_.white = gp_in.analog[Gamepad::ANALOG_OFF_LB];
in_report_.black = gp_in.analog[Gamepad::ANALOG_OFF_RB];
}
else
{
if (gp_in.buttons & Gamepad::BUTTON_X) in_report_.x = 0xFF;
if (gp_in.buttons & Gamepad::BUTTON_A) in_report_.a = 0xFF;
if (gp_in.buttons & Gamepad::BUTTON_Y) in_report_.y = 0xFF;
if (gp_in.buttons & Gamepad::BUTTON_B) in_report_.b = 0xFF;
if (gp_in.buttons & Gamepad::BUTTON_LB) in_report_.white = 0xFF;
if (gp_in.buttons & Gamepad::BUTTON_RB) in_report_.black = 0xFF;
}
in_report_.trigger_l = gp_in.trigger_l;
in_report_.trigger_r = gp_in.trigger_r;
in_report_.joystick_lx = gp_in.joystick_lx;
in_report_.joystick_ly = Scale::invert_joy(gp_in.joystick_ly);
in_report_.joystick_rx = gp_in.joystick_rx;
in_report_.joystick_ry = Scale::invert_joy(gp_in.joystick_ry);
if (tud_suspended())
{
tud_remote_wakeup();
}
if (tud_xid::send_report_ready(0))
{
tud_xid::send_report(0, reinterpret_cast<uint8_t*>(&in_report_), sizeof(XboxOG::GP::InReport));
}
}
if (tud_xid::receive_report(0, reinterpret_cast<uint8_t*>(&out_report_), sizeof(XboxOG::GP::OutReport)))
{
Gamepad::PadOut gp_out;
gp_out.rumble_l = Scale::uint16_to_uint8(out_report_.rumble_l);
gp_out.rumble_r = Scale::uint16_to_uint8(out_report_.rumble_r);
gamepad.set_pad_out(gp_out);
}
}
uint16_t XboxOGDevice::get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
{
std::memcpy(buffer, &in_report_, sizeof(in_report_));
return sizeof(XboxOG::GP::InReport);
}
void XboxOGDevice::set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {}
bool XboxOGDevice::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
{
return tud_xid::class_driver()->control_xfer_cb(rhport, stage, request);
}
const uint16_t* XboxOGDevice::get_descriptor_string_cb(uint8_t index, uint16_t langid)
{
const char *value = reinterpret_cast<const char*>(XboxOG::GP::STRING_DESCRIPTORS[index]);
return get_string_descriptor(value, index);
}
const uint8_t* XboxOGDevice::get_descriptor_device_cb()
{
return reinterpret_cast<const uint8_t*>(&XboxOG::GP::DEVICE_DESCRIPTORS);
}
const uint8_t* XboxOGDevice::get_hid_descriptor_report_cb(uint8_t itf)
{
return nullptr;
}
const uint8_t* XboxOGDevice::get_descriptor_configuration_cb(uint8_t index)
{
return XboxOG::GP::CONFIGURATION_DESCRIPTORS;
}
const uint8_t* XboxOGDevice::get_descriptor_device_qualifier_cb()
{
return nullptr;
}

View File

@@ -1,28 +0,0 @@
#ifndef _XBOXGOG_DEVICE_H_
#define _XBOXGOG_DEVICE_H_
#include <cstdint>
#include "USBDevice/DeviceDriver/DeviceDriver.h"
#include "Descriptors/XboxOG.h"
class XboxOGDevice : public DeviceDriver
{
public:
void initialize() override;
void process(uint8_t idx, Gamepad& gamepad) override;
uint16_t get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) override;
void set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) override;
bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) override;
const uint16_t* get_descriptor_string_cb(uint8_t index, uint16_t langid) override;
const uint8_t* get_descriptor_device_cb() override;
const uint8_t* get_hid_descriptor_report_cb(uint8_t itf) override;
const uint8_t* get_descriptor_configuration_cb(uint8_t index) override;
const uint8_t* get_descriptor_device_qualifier_cb() override;
private:
XboxOG::GP::InReport in_report_;
XboxOG::GP::OutReport out_report_;
};
#endif // _XBOXGOG_DEVICE_H_

View File

@@ -1,385 +0,0 @@
#include <cstring>
#include <cstdlib>
#include <pico/time.h>
#include "Descriptors/XInput.h"
#include "USBDevice/DeviceDriver/XboxOG/tud_xid/tud_xid.h"
#include "USBDevice/DeviceDriver/XboxOG/XboxOG_SB.h"
#include "OGXMini/Debug.h"
static constexpr std::array<XboxOGSBDevice::ButtonMap, 9> GP_MAP =
{{
{Gamepad::BUTTON_START, XboxOG::SB::Buttons0::START, 0},
{Gamepad::BUTTON_LB, XboxOG::SB::Buttons0::RIGHTJOYFIRE, 0},
{Gamepad::BUTTON_R3, XboxOG::SB::Buttons0::RIGHTJOYLOCKON, 0},
{Gamepad::BUTTON_B, XboxOG::SB::Buttons0::RIGHTJOYLOCKON, 0},
{Gamepad::BUTTON_RB, XboxOG::SB::Buttons0::RIGHTJOYMAINWEAPON, 0},
{Gamepad::BUTTON_A, XboxOG::SB::Buttons0::RIGHTJOYMAINWEAPON, 0},
{Gamepad::BUTTON_SYS, XboxOG::SB::Buttons0::EJECT, 0},
{Gamepad::BUTTON_L3, XboxOG::SB::Buttons2::LEFTJOYSIGHTCHANGE, 2},
{Gamepad::BUTTON_Y, XboxOG::SB::Buttons1::CHAFF, 1}
}};
static constexpr std::array<XboxOGSBDevice::ButtonMap, 19> CHATPAD_MAP =
{{
{XInput::Chatpad::CODE_0, XboxOG::SB::Buttons0::EJECT, 0},
{XInput::Chatpad::CODE_D, XboxOG::SB::Buttons1::WASHING, 1},
{XInput::Chatpad::CODE_F, XboxOG::SB::Buttons1::EXTINGUISHER, 1},
{XInput::Chatpad::CODE_G, XboxOG::SB::Buttons1::CHAFF, 1},
{XInput::Chatpad::CODE_X, XboxOG::SB::Buttons1::WEAPONCONMAIN, 1},
{XInput::Chatpad::CODE_RIGHT, XboxOG::SB::Buttons1::WEAPONCONMAIN, 1},
{XInput::Chatpad::CODE_C, XboxOG::SB::Buttons1::WEAPONCONSUB, 1},
{XInput::Chatpad::CODE_LEFT, XboxOG::SB::Buttons1::WEAPONCONSUB, 1},
{XInput::Chatpad::CODE_V, XboxOG::SB::Buttons1::WEAPONCONMAGAZINE, 1},
{XInput::Chatpad::CODE_SPACE, XboxOG::SB::Buttons1::WEAPONCONMAGAZINE, 1},
{XInput::Chatpad::CODE_U, XboxOG::SB::Buttons0::MULTIMONOPENCLOSE, 0},
{XInput::Chatpad::CODE_J, XboxOG::SB::Buttons0::MULTIMONMODESELECT, 0},
{XInput::Chatpad::CODE_N, XboxOG::SB::Buttons0::MAINMONZOOMIN, 0},
{XInput::Chatpad::CODE_I, XboxOG::SB::Buttons0::MULTIMONMAPZOOMINOUT, 0},
{XInput::Chatpad::CODE_K, XboxOG::SB::Buttons0::MULTIMONSUBMONITOR, 0},
{XInput::Chatpad::CODE_M, XboxOG::SB::Buttons0::MAINMONZOOMOUT, 0},
{XInput::Chatpad::CODE_ENTER, XboxOG::SB::Buttons0::START, 0},
{XInput::Chatpad::CODE_P, XboxOG::SB::Buttons0::COCKPITHATCH, 0},
{XInput::Chatpad::CODE_COMMA, XboxOG::SB::Buttons0::IGNITION, 0}
}};
static constexpr std::array<XboxOGSBDevice::ButtonMap, 5> CHATPAD_MAP_ALT1 =
{{
{XInput::Chatpad::CODE_1, XboxOG::SB::Buttons1::COMM1, 1},
{XInput::Chatpad::CODE_2, XboxOG::SB::Buttons1::COMM2, 1},
{XInput::Chatpad::CODE_3, XboxOG::SB::Buttons1::COMM3, 1},
{XInput::Chatpad::CODE_4, XboxOG::SB::Buttons1::COMM4, 1},
{XInput::Chatpad::CODE_5, XboxOG::SB::Buttons2::COMM5, 2}
}};
static constexpr std::array<XboxOGSBDevice::ButtonMap, 9> CHATPAD_MAP_ALT2=
{{
{XInput::Chatpad::CODE_1, XboxOG::SB::Buttons1::FUNCTIONF1, 1},
{XInput::Chatpad::CODE_2, XboxOG::SB::Buttons1::FUNCTIONTANKDETACH, 1},
{XInput::Chatpad::CODE_3, XboxOG::SB::Buttons0::FUNCTIONFSS, 0},
{XInput::Chatpad::CODE_4, XboxOG::SB::Buttons1::FUNCTIONF2, 1},
{XInput::Chatpad::CODE_5, XboxOG::SB::Buttons1::FUNCTIONOVERRIDE, 1},
{XInput::Chatpad::CODE_6, XboxOG::SB::Buttons0::FUNCTIONMANIPULATOR, 0},
{XInput::Chatpad::CODE_7, XboxOG::SB::Buttons1::FUNCTIONF3, 1},
{XInput::Chatpad::CODE_8, XboxOG::SB::Buttons1::FUNCTIONNIGHTSCOPE, 1},
{XInput::Chatpad::CODE_9, XboxOG::SB::Buttons0::FUNCTIONLINECOLORCHANGE, 0}
}};
static constexpr std::array<XboxOGSBDevice::ButtonMap, 5> CHATPAD_TOGGLE_MAP =
{{
{XInput::Chatpad::CODE_Q, XboxOG::SB::Buttons2::TOGGLEOXYGENSUPPLY, 2},
{XInput::Chatpad::CODE_A, XboxOG::SB::Buttons2::TOGGLEFILTERCONTROL, 2},
{XInput::Chatpad::CODE_W, XboxOG::SB::Buttons2::TOGGLEVTLOCATION, 2},
{XInput::Chatpad::CODE_S, XboxOG::SB::Buttons2::TOGGLEBUFFREMATERIAL, 2},
{XInput::Chatpad::CODE_Z, XboxOG::SB::Buttons2::TOGGLEFUELFLOWRATE, 2}
}};
void XboxOGSBDevice::initialize()
{
tud_xid::initialize(tud_xid::Type::STEELBATTALION);
class_driver_ = *tud_xid::class_driver();
std::memset(&in_report_, 0, sizeof(XboxOG::SB::InReport));
in_report_.bLength = sizeof(XboxOG::SB::InReport);
in_report_.gearLever = XboxOG::SB::Gear::N;
prev_in_report_ = in_report_;
}
void XboxOGSBDevice::process(const uint8_t idx, Gamepad& gamepad)
{
Gamepad::PadIn gp_in = gamepad.get_pad_in();
Gamepad::ChatpadIn gp_in_chatpad = gamepad.get_chatpad_in();
in_report_.dButtons[0] = 0;
in_report_.dButtons[1] = 0;
in_report_.dButtons[2] &= XboxOG::SB::BUTTONS2_TOGGLE_MID;
for (const auto& map : GP_MAP)
{
if (gp_in.buttons & map.gp_mask)
{
in_report_.dButtons[map.button_offset] |= map.sb_mask;
}
}
for (const auto& map : CHATPAD_MAP)
{
if (chatpad_pressed(gp_in_chatpad, map.gp_mask))
{
in_report_.dButtons[map.button_offset] |= map.sb_mask;
}
}
static std::array<bool, CHATPAD_TOGGLE_MAP.size() + 1> toggle_pressed{false};
for (uint8_t i = 0; i < CHATPAD_TOGGLE_MAP.size(); i++)
{
if (chatpad_pressed(gp_in_chatpad, CHATPAD_TOGGLE_MAP[i].gp_mask))
{
if (!toggle_pressed[i])
{
in_report_.dButtons[CHATPAD_TOGGLE_MAP[i].button_offset] ^= CHATPAD_TOGGLE_MAP[i].sb_mask;
toggle_pressed[i] = true;
}
}
else
{
toggle_pressed[i] = false;
}
}
if (chatpad_pressed(gp_in_chatpad, XInput::Chatpad::CODE_SHIFT))
{
if (!toggle_pressed.back())
{
if (in_report_.dButtons[2] & XboxOG::SB::BUTTONS2_TOGGLE_MID)
{
in_report_.dButtons[2] &= ~XboxOG::SB::BUTTONS2_TOGGLE_MID;
}
else
{
in_report_.dButtons[2] |= XboxOG::SB::BUTTONS2_TOGGLE_MID;
}
toggle_pressed.back() = true;
}
}
else
{
toggle_pressed.back() = false;
}
if (gp_in.buttons & Gamepad::BUTTON_X)
{
if (out_report_.Chaff_Extinguisher & 0x0F)
{
in_report_.dButtons[1] |= XboxOG::SB::Buttons1::EXTINGUISHER;
}
if (out_report_.Comm1_MagazineChange & 0x0F)
{
in_report_.dButtons[1] |= XboxOG::SB::Buttons1::WEAPONCONMAGAZINE;
}
if (out_report_.Washing_LineColorChange & 0xF0)
{
in_report_.dButtons[1] |= XboxOG::SB::Buttons1::WASHING;
}
}
if (chatpad_pressed(gp_in_chatpad, XInput::Chatpad::CODE_MESSENGER) || gp_in.buttons & Gamepad::BUTTON_BACK)
{
for (const auto& map : CHATPAD_MAP_ALT1)
{
if (chatpad_pressed(gp_in_chatpad, map.gp_mask))
{
in_report_.dButtons[map.button_offset] |= map.sb_mask;
}
}
if (gp_in.dpad & Gamepad::DPAD_UP && dpad_reset_)
{
in_report_.tunerDial = (in_report_.tunerDial + 1) % 16;
dpad_reset_ = false;
}
else if (gp_in.dpad & Gamepad::DPAD_DOWN && dpad_reset_)
{
in_report_.tunerDial = (in_report_.tunerDial + 15) % 16;
dpad_reset_ = false;
}
else if (!(gp_in.dpad & Gamepad::DPAD_DOWN) && !(gp_in.dpad & Gamepad::DPAD_UP))
{
dpad_reset_ = true;
}
}
else if (chatpad_pressed(gp_in_chatpad, XInput::Chatpad::CODE_ORANGE))
{
for (const auto& map : CHATPAD_MAP_ALT2)
{
if (chatpad_pressed(gp_in_chatpad, map.gp_mask))
{
in_report_.dButtons[map.button_offset] |= map.sb_mask;
}
}
// if (!(gp_in.dpad & Gamepad::DPAD_LEFT) && !(gp_in.dpad & Gamepad::DPAD_RIGHT))
// {
if (gp_in.dpad & Gamepad::DPAD_UP && dpad_reset_)
{
if (in_report_.gearLever < XboxOG::SB::Gear::G5)
{
in_report_.gearLever++;
}
dpad_reset_ = false;
}
else if (gp_in.dpad & Gamepad::DPAD_DOWN && dpad_reset_)
{
if (in_report_.gearLever > XboxOG::SB::Gear::R)
{
in_report_.gearLever--;
}
dpad_reset_ = false;
}
else if (!(gp_in.dpad & Gamepad::DPAD_DOWN) && !(gp_in.dpad & Gamepad::DPAD_UP))
{
dpad_reset_ = true;
}
// }
}
else
{
dpad_reset_ = true;
}
in_report_.leftPedal = Scale::uint8_to_uint16(gp_in.trigger_l);
in_report_.rightPedal = Scale::uint8_to_uint16(gp_in.trigger_r);
in_report_.middlePedal = chatpad_pressed( gp_in_chatpad, XInput::Chatpad::CODE_BACK) ? 0xFF00 : 0x0000;
in_report_.rotationLever= chatpad_pressed( gp_in_chatpad, XInput::Chatpad::CODE_MESSENGER) ? 0 :
(gp_in.buttons & Gamepad::BUTTON_BACK) ? 0 :
(gp_in.dpad & Gamepad::DPAD_LEFT) ? INT_16::MIN :
(gp_in.dpad & Gamepad::DPAD_RIGHT) ? INT_16::MAX : 0;
in_report_.sightChangeX = gp_in.joystick_lx;
in_report_.sightChangeY = gp_in.joystick_ly;
int32_t axis_value_x = static_cast<int32_t>(gp_in.joystick_rx);
if (std::abs(axis_value_x) > DEFAULT_DEADZONE)
{
vmouse_x_ += axis_value_x / sensitivity_;
}
int32_t axis_value_y = static_cast<int32_t>(Scale::invert_joy(gp_in.joystick_ry));
if (std::abs(axis_value_y) > DEFAULT_DEADZONE)
{
vmouse_y_ -= axis_value_y / sensitivity_;
}
if (vmouse_x_ < 0) vmouse_x_ = 0;
if (vmouse_x_ > UINT_16::MAX) vmouse_x_ = UINT_16::MAX;
if (vmouse_y_ > UINT_16::MAX) vmouse_y_ = UINT_16::MAX;
if (vmouse_y_ < 0) vmouse_y_ = 0;
if (gp_in.buttons & Gamepad::BUTTON_L3)
{
if ((time_us_32() / 1000) - aim_reset_timer_ > 500)
{
vmouse_x_ = XboxOG::SB::AIMING_MID;
vmouse_y_ = XboxOG::SB::AIMING_MID;
}
}
else
{
aim_reset_timer_ = time_us_32() / 1000;
}
in_report_.aimingX = static_cast<uint16_t>(vmouse_x_);
in_report_.aimingY = static_cast<uint16_t>(vmouse_y_);
if (tud_suspended())
{
tud_remote_wakeup();
}
if (tud_xid::send_report_ready(0) &&
std::memcmp(&prev_in_report_, &in_report_, sizeof(XboxOG::SB::InReport)) &&
tud_xid::send_report(0, reinterpret_cast<uint8_t*>(&in_report_), sizeof(XboxOG::SB::InReport)))
{
std::memcpy(&prev_in_report_, &in_report_, sizeof(XboxOG::SB::InReport));
}
if (chatpad_pressed(gp_in_chatpad, XInput::Chatpad::CODE_ORANGE))
{
uint16_t new_sense = 0;
if (chatpad_pressed(gp_in_chatpad, XInput::Chatpad::CODE_9))
{
new_sense = 200;
}
else if (chatpad_pressed(gp_in_chatpad, XInput::Chatpad::CODE_8))
{
new_sense = 250;
}
else if (chatpad_pressed(gp_in_chatpad, XInput::Chatpad::CODE_7))
{
new_sense = 300;
}
else if (chatpad_pressed(gp_in_chatpad, XInput::Chatpad::CODE_6))
{
new_sense = 350;
}
else if (chatpad_pressed(gp_in_chatpad, XInput::Chatpad::CODE_5))
{
new_sense = 400;
}
else if (chatpad_pressed(gp_in_chatpad, XInput::Chatpad::CODE_4))
{
new_sense = 650;
}
else if (chatpad_pressed(gp_in_chatpad, XInput::Chatpad::CODE_3))
{
new_sense = 800;
}
else if (chatpad_pressed(gp_in_chatpad, XInput::Chatpad::CODE_2))
{
new_sense = 1000;
}
else if (chatpad_pressed(gp_in_chatpad, XInput::Chatpad::CODE_1))
{
new_sense = 1200;
}
if (new_sense != 0)
{
sensitivity_ = new_sense;
}
}
if (tud_xid::receive_report(0, reinterpret_cast<uint8_t*>(&out_report_), sizeof(XboxOG::SB::OutReport)) &&
out_report_.bLength == sizeof(XboxOG::SB::OutReport))
{
Gamepad::PadOut gp_out;
gp_out.rumble_l = out_report_.Chaff_Extinguisher;
gp_out.rumble_l |= out_report_.Chaff_Extinguisher << 4;
gp_out.rumble_l |= out_report_.Comm1_MagazineChange << 4;
gp_out.rumble_l |= out_report_.CockpitHatch_EmergencyEject << 4;
gp_out.rumble_r = gp_out.rumble_l;
gamepad.set_pad_out(gp_out);
}
}
uint16_t XboxOGSBDevice::get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
{
std::memcpy(buffer, &in_report_, sizeof(in_report_));
return sizeof(XboxOG::SB::InReport);
}
void XboxOGSBDevice::set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {}
bool XboxOGSBDevice::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
{
return tud_xid::class_driver()->control_xfer_cb(rhport, stage, request);
}
const uint16_t* XboxOGSBDevice::get_descriptor_string_cb(uint8_t index, uint16_t langid)
{
const char *value = reinterpret_cast<const char*>(XboxOG::SB::STRING_DESCRIPTORS[index]);
return get_string_descriptor(value, index);
}
const uint8_t* XboxOGSBDevice::get_descriptor_device_cb()
{
return reinterpret_cast<const uint8_t*>(&XboxOG::GP::DEVICE_DESCRIPTORS);
}
const uint8_t* XboxOGSBDevice::get_hid_descriptor_report_cb(uint8_t itf)
{
return nullptr;
}
const uint8_t* XboxOGSBDevice::get_descriptor_configuration_cb(uint8_t index)
{
return XboxOG::SB::CONFIGURATION_DESCRIPTORS;
}
const uint8_t* XboxOGSBDevice::get_descriptor_device_qualifier_cb()
{
return nullptr;
}

View File

@@ -1,73 +0,0 @@
#ifndef _XBOXGOG_SB_DEVICE_H_
#define _XBOXGOG_SB_DEVICE_H_
#include <cstdint>
#include <numeric>
#include "Gamepad.h"
#include "USBDevice/DeviceDriver/DeviceDriver.h"
#include "Descriptors/XboxOG.h"
class XboxOGSBDevice : public DeviceDriver
{
public:
struct ButtonMap
{
uint16_t gp_mask;
uint16_t sb_mask;
uint8_t button_offset;
};
void initialize() override;
void process(const uint8_t idx, Gamepad& gamepad) override;
uint16_t get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) override;
void set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) override;
bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) override;
const uint16_t* get_descriptor_string_cb(uint8_t index, uint16_t langid) override;
const uint8_t* get_descriptor_device_cb() override;
const uint8_t* get_hid_descriptor_report_cb(uint8_t itf) override;
const uint8_t* get_descriptor_configuration_cb(uint8_t index) override;
const uint8_t* get_descriptor_device_qualifier_cb() override;
private:
static constexpr int16_t DEFAULT_DEADZONE = 7500;
static constexpr uint16_t DEFAULT_SENSE = 400;
int32_t vmouse_x_ = XboxOG::SB::AIMING_MID;
int32_t vmouse_y_ = XboxOG::SB::AIMING_MID;
uint16_t sensitivity_ = DEFAULT_SENSE;
uint32_t aim_reset_timer_ = 0;
bool dpad_reset_ = true;
XboxOG::SB::InReport in_report_;
XboxOG::SB::InReport prev_in_report_;
XboxOG::SB::OutReport out_report_;
static inline bool chatpad_pressed(const Gamepad::ChatpadIn& chatpad, const uint16_t keycode)
{
if (std::accumulate(std::begin(chatpad), std::end(chatpad), 0) == 0)
{
return false;
}
else if (keycode < 17 && (chatpad[0] & keycode))
{
return true;
}
else if (keycode < 17)
{
return false;
}
else if (chatpad[1] == keycode)
{
return true;
}
else if (chatpad[2] == keycode)
{
return true;
}
return false;
}
};
#endif // _XBOXGOG_SB_DEVICE_H_

View File

@@ -1,116 +0,0 @@
#include <cstring>
#include <vector>
#include "pico/stdlib.h"
#include "USBDevice/DeviceDriver/XboxOG/tud_xid/tud_xid.h"
#include "USBDevice/DeviceDriver/XboxOG/XboxOG_XR.h"
void XboxOGXRDevice::initialize()
{
tud_xid::initialize(tud_xid::Type::XREMOTE);
class_driver_ = *tud_xid::class_driver();
std::memset(&in_report_, 0, sizeof(XboxOG::XR::InReport));
in_report_.bLength = sizeof(XboxOG::XR::InReport);
}
void XboxOGXRDevice::process(const uint8_t idx, Gamepad& gamepad)
{
if (!tud_xid::xremote_rom_available())
{
return;
}
uint32_t time_elapsed = to_ms_since_boot(get_absolute_time()) - ms_timer_;
uint8_t index = tud_xid::get_index_by_type(0, tud_xid::Type::XREMOTE);
if (index == 0xFF || !gamepad.new_pad_in() || time_elapsed < 64)
{
return;
}
Gamepad::PadIn gp_in = gamepad.get_pad_in();
in_report_.buttonCode = 0;
if (gp_in.dpad & Gamepad::DPAD_UP) in_report_.buttonCode |= XboxOG::XR::ButtonCode::UP ;
if (gp_in.dpad & Gamepad::DPAD_DOWN) in_report_.buttonCode |= XboxOG::XR::ButtonCode::DOWN ;
if (gp_in.dpad & Gamepad::DPAD_LEFT) in_report_.buttonCode |= XboxOG::XR::ButtonCode::LEFT ;
if (gp_in.dpad & Gamepad::DPAD_RIGHT) in_report_.buttonCode |= XboxOG::XR::ButtonCode::RIGHT;
if (gp_in.buttons & Gamepad::BUTTON_SYS) in_report_.buttonCode |= XboxOG::XR::ButtonCode::DISPLAY;
if (gp_in.buttons & Gamepad::BUTTON_START) in_report_.buttonCode |= XboxOG::XR::ButtonCode::PLAY ;
if (gp_in.buttons & Gamepad::BUTTON_BACK) in_report_.buttonCode |= XboxOG::XR::ButtonCode::STOP ;
if (gp_in.buttons & Gamepad::BUTTON_L3 && !(gp_in.buttons & Gamepad::BUTTON_R3)) in_report_.buttonCode |= XboxOG::XR::ButtonCode::TITLE;
if (gp_in.buttons & Gamepad::BUTTON_R3 && !(gp_in.buttons & Gamepad::BUTTON_L3)) in_report_.buttonCode |= XboxOG::XR::ButtonCode::MENU;
if (gp_in.buttons & (Gamepad::BUTTON_L3 | Gamepad::BUTTON_R3)) in_report_.buttonCode |= XboxOG::XR::ButtonCode::INFO;
if (gp_in.buttons & Gamepad::BUTTON_A) in_report_.buttonCode |= XboxOG::XR::ButtonCode::SELECT ;
if (gp_in.buttons & Gamepad::BUTTON_Y) in_report_.buttonCode |= XboxOG::XR::ButtonCode::PAUSE ;
if (gp_in.buttons & Gamepad::BUTTON_X) in_report_.buttonCode |= XboxOG::XR::ButtonCode::DISPLAY;
if (gp_in.buttons & Gamepad::BUTTON_B) in_report_.buttonCode |= XboxOG::XR::ButtonCode::BACK ;
if (gp_in.buttons & Gamepad::BUTTON_LB && !(gp_in.buttons & Gamepad::BUTTON_RB)) in_report_.buttonCode |= XboxOG::XR::ButtonCode::SKIP_MINUS;
if (gp_in.buttons & Gamepad::BUTTON_RB && !(gp_in.buttons & Gamepad::BUTTON_LB)) in_report_.buttonCode |= XboxOG::XR::ButtonCode::SKIP_PLUS ;
if (gp_in.buttons & (Gamepad::BUTTON_LB | Gamepad::BUTTON_RB)) in_report_.buttonCode |= XboxOG::XR::ButtonCode::DISPLAY;
if (gp_in.trigger_l >= 100) in_report_.buttonCode |= XboxOG::XR::ButtonCode::REVERSE;
if (gp_in.trigger_r >= 100) in_report_.buttonCode |= XboxOG::XR::ButtonCode::FORWARD;
if (in_report_.buttonCode == 0x0000)
{
return;
}
in_report_.timeElapsed = static_cast<uint16_t>(time_elapsed);
if (tud_suspended())
{
tud_remote_wakeup();
}
if (tud_xid::send_report_ready(index) &&
tud_xid::send_report(index, reinterpret_cast<uint8_t*>(&in_report_), sizeof(XboxOG::XR::InReport)))
{
ms_timer_ = to_ms_since_boot(get_absolute_time());
}
}
uint16_t XboxOGXRDevice::get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
{
std::memcpy(buffer, &in_report_, sizeof(in_report_));
return sizeof(XboxOG::XR::InReport);
}
void XboxOGXRDevice::set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {}
bool XboxOGXRDevice::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
{
return tud_xid::class_driver()->control_xfer_cb(rhport, stage, request);
}
const uint16_t* XboxOGXRDevice::get_descriptor_string_cb(uint8_t index, uint16_t langid)
{
const char *value = reinterpret_cast<const char*>(XboxOG::GP::STRING_DESCRIPTORS[index]);
return get_string_descriptor(value, index);
}
const uint8_t* XboxOGXRDevice::get_descriptor_device_cb()
{
return reinterpret_cast<const uint8_t*>(&XboxOG::XR::DEVICE_DESCRIPTORS);
}
const uint8_t* XboxOGXRDevice::get_hid_descriptor_report_cb(uint8_t itf)
{
return nullptr;
}
const uint8_t* XboxOGXRDevice::get_descriptor_configuration_cb(uint8_t index)
{
return XboxOG::XR::CONFIGURATION_DESCRIPTORS;
}
const uint8_t* XboxOGXRDevice::get_descriptor_device_qualifier_cb()
{
return nullptr;
}

View File

@@ -1,28 +0,0 @@
#ifndef _XBOXGOG_XREMOTE_DEVICE_H_
#define _XBOXGOG_XREMOTE_DEVICE_H_
#include <cstdint>
#include "USBDevice/DeviceDriver/DeviceDriver.h"
#include "Descriptors/XboxOG.h"
class XboxOGXRDevice : public DeviceDriver
{
public:
void initialize() override;
void process(const uint8_t idx, Gamepad& gamepad) override;
uint16_t get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) override;
void set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) override;
bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) override;
const uint16_t* get_descriptor_string_cb(uint8_t index, uint16_t langid) override;
const uint8_t* get_descriptor_device_cb() override;
const uint8_t* get_hid_descriptor_report_cb(uint8_t itf) override;
const uint8_t* get_descriptor_configuration_cb(uint8_t index) override;
const uint8_t* get_descriptor_device_qualifier_cb() override;
private:
XboxOG::XR::InReport in_report_;
uint32_t ms_timer_;
};
#endif // _XBOXGOG_XREMOTE_DEVICE_H_

View File

@@ -1,486 +0,0 @@
#include "tusb_option.h"
#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_XID)
#include <cstring>
#include "USBDevice/DeviceDriver/XboxOG/tud_xid/tud_xid.h"
#include "Descriptors/XboxOG.h"
#if defined(XREMOTE_ROM_AVAILABLE)
#define XREMOTE_ENABLED 1
#include "USBDevice/DeviceDriver/XboxOG/tud_xid/tud_xid_xremote_rom.h"
#else
#define XREMOTE_ENABLED 0
#endif
namespace tud_xid {
static constexpr uint16_t ENDPOINT_SIZE = 32;
static constexpr uint8_t INTERFACE_MULT = XREMOTE_ENABLED + 1;
static constexpr uint8_t INTERFACE_CLASS = 0x58;
static constexpr uint8_t INTERFACE_SUBCLASS = 0x42;
enum class RequestType { SET_REPORT, GET_REPORT, GET_DESC, GET_CAPABILITIES_IN, GET_CAPABILITIES_OUT, UNKNOWN };
struct Interface
{
Type type{Type::GAMEPAD};
uint8_t itf_num{0xFF};
uint8_t ep_in{0xFF};
uint8_t ep_out{0xFF};
uint16_t ep_in_size{ENDPOINT_SIZE};
uint16_t ep_out_size{ENDPOINT_SIZE};
std::array<uint8_t, ENDPOINT_SIZE> ep_in_buffer;
std::array<uint8_t, ENDPOINT_SIZE> ep_out_buffer;
Interface()
{
ep_out_buffer.fill(0);
ep_in_buffer.fill(0);
}
};
static std::array<Interface, CFG_TUD_XID * INTERFACE_MULT> interfaces_;
static Type xid_type_{Type::GAMEPAD};
static inline RequestType get_request_type(const tusb_control_request_t *request)
{
if (request->bmRequestType == XboxOG::GET_REPORT_REQ_TYPE && request->bRequest == XboxOG::GET_REPORT_REQ && request->wValue == XboxOG::GET_REPORT_VALUE)
{
return RequestType::GET_REPORT;
}
if (request->bmRequestType == XboxOG::SET_REPORT_REQ_TYPE && request->bRequest == XboxOG::SET_REPORT_REQ && request->wValue == XboxOG::SET_REPORT_VALUE && request->wLength == static_cast<uint16_t>(0x06))
{
return RequestType::SET_REPORT;
}
if (request->bmRequestType == XboxOG::GET_DESC_REQ_TYPE && request->bRequest == XboxOG::GET_DESC_REQ && request->wValue == XboxOG::GET_DESC_VALUE)
{
return RequestType::GET_DESC;
}
if (request->bmRequestType == XboxOG::GET_CAP_REQ_TYPE && request->bRequest == XboxOG::GET_CAP_REQ)
{
if (request->wValue == XboxOG::GET_CAP_VALUE_IN)
{
return RequestType::GET_CAPABILITIES_IN;
}
else if (request->wValue == XboxOG::GET_CAP_VALUE_OUT)
{
return RequestType::GET_CAPABILITIES_OUT;
}
}
return RequestType::UNKNOWN;
}
static inline uint8_t get_idx_by_itf(uint8_t itf)
{
for (uint8_t i = 0; i < interfaces_.size(); i++)
{
if (interfaces_[i].itf_num == itf)
{
return i;
}
if (interfaces_[i].type == Type::XREMOTE)
{
if (itf == interfaces_[i].itf_num + 1)
{
return i;
}
}
}
return 0xFF;
}
static inline uint8_t get_idx_by_edpt(uint8_t edpt)
{
for (uint8_t i = 0; i < interfaces_.size(); i++)
{
if (interfaces_[i].ep_in == edpt || interfaces_[i].ep_out == edpt)
{
return i;
}
}
return 0xFF;
}
uint8_t get_index_by_type(uint8_t type_idx, Type type)
{
uint8_t type_idx_ = 0;
for (uint8_t i = 0; i < interfaces_.size(); i++)
{
if (interfaces_[i].type == type)
{
if (type_idx_ == type_idx)
{
return i;
}
type_idx_++;
}
}
return 0xFF;
}
static inline Interface* find_available_interface()
{
for (Interface &itf : interfaces_)
{
if (itf.itf_num == 0xFF)
{
return &itf;
}
}
return nullptr;
}
const uint8_t *xremote_get_rom()
{
#if XREMOTE_ENABLED
return XRemote::ROM;
#else
return nullptr;
#endif
}
//Class driver
static void xid_init()
{
for (Interface &itf : interfaces_)
{
itf = Interface();
itf.type = xid_type_;
}
}
static bool xid_deinit()
{
xid_init();
return true;
}
static void xid_reset(uint8_t rhport)
{
xid_init();
}
static uint16_t xid_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
{
TU_VERIFY(itf_desc->bInterfaceClass == INTERFACE_CLASS, 0);
TU_VERIFY(itf_desc->bInterfaceSubClass == INTERFACE_SUBCLASS, 0);
Interface *interface = find_available_interface();
TU_ASSERT(interface != nullptr, 0);
uint16_t driver_len = 0;
switch (interface->type)
{
case Type::GAMEPAD:
driver_len = XboxOG::GP::DRIVER_LEN;
break;
case Type::STEELBATTALION:
driver_len = XboxOG::SB::DRIVER_LEN;
break;
case Type::XREMOTE:
driver_len = XboxOG::XR::DRIVER_LEN;
break;
}
TU_ASSERT(max_len >= driver_len, 0);
const uint8_t *desc_ep = reinterpret_cast<const uint8_t*>(itf_desc);
int endpoint = 0;
int pos = 0;
while (endpoint < itf_desc->bNumEndpoints && pos < max_len)
{
if (tu_desc_type(desc_ep) != TUSB_DESC_ENDPOINT)
{
pos += tu_desc_len(desc_ep);
desc_ep = tu_desc_next(desc_ep);
continue;
}
const tusb_desc_endpoint_t *ep_desc = reinterpret_cast<const tusb_desc_endpoint_t*>(desc_ep);
TU_VERIFY(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType, 0);
TU_VERIFY(usbd_edpt_open(rhport, ep_desc), 0);
if (tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN)
{
interface->ep_in = ep_desc->bEndpointAddress;
interface->ep_in_size = ep_desc->wMaxPacketSize;
}
else
{
interface->ep_out = ep_desc->bEndpointAddress;
interface->ep_out_size = ep_desc->wMaxPacketSize;
}
interface->itf_num = itf_desc->bInterfaceNumber;
pos += tu_desc_len(desc_ep);
desc_ep = tu_desc_next(desc_ep);
endpoint++;
}
return driver_len;
}
static bool xid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
{
// uint8_t index = get_idx_by_edpt(ep_addr);
// TU_VERIFY(result == XFER_RESULT_SUCCESS, true);
// TU_VERIFY(index != 0xFF, true);
// TU_VERIFY(xferred_bytes < ENDPOINT_SIZE, true);
return true;
}
bool xremote_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, Interface *interface)
{
if (request->bmRequestType == 0xC1 && request->bRequest == 0x01 && request->wIndex == 1 && request->wValue == 0x0000)
{
if (stage == CONTROL_STAGE_SETUP)
{
TU_LOG1("Sending XREMOTE INFO\r\n");
const uint8_t *rom = xremote_get_rom();
if (rom == nullptr)
{
return false; //STALL
}
tud_control_xfer(rhport, request, const_cast<uint8_t*>(&rom[0]), request->wLength);
}
return true;
}
//ROM DATA (Interface 1)
else if (request->bmRequestType == 0xC1 && request->bRequest == 0x02 && request->wIndex == 1)
{
if (stage == CONTROL_STAGE_SETUP)
{
const uint8_t *rom = xremote_get_rom();
if (rom == nullptr)
{
return false; //STALL
}
tud_control_xfer(rhport, request, const_cast<uint8_t*>(&rom[request->wValue * 1024]), request->wLength);
}
return true;
}
return false;
}
bool steelbattalion_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, Interface *p_xid);
bool duke_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, Interface *p_xid);
bool xid_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
{
TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE);
uint8_t index = get_idx_by_itf(static_cast<uint8_t>(request->wIndex));
TU_VERIFY(index != 0xFF, false);
Interface& interface = interfaces_[index];
bool ret = false;
//Get HID Report
if (request->bmRequestType == 0xA1 && request->bRequest == 0x01 && request->wValue == 0x0100)
{
if (stage == CONTROL_STAGE_SETUP)
{
TU_LOG1("Sending HID report on control pipe for index %02x\n", request->wIndex);
tud_control_xfer(rhport, request, interface.ep_in_buffer.data(), std::min(request->wLength, interface.ep_in_size));
}
return true;
}
//Set HID Report
if (request->bmRequestType == 0x21 && request->bRequest == 0x09 && request->wValue == 0x0200 && request->wLength == 0x06)
{
if (stage == CONTROL_STAGE_SETUP)
{
//Host is sending a rumble command to control pipe. Queue receipt.
tud_control_xfer(rhport, request, interface.ep_out_buffer.data(), std::min(request->wLength, interface.ep_out_size));
}
else if (stage == CONTROL_STAGE_ACK)
{
//Receipt complete. Copy data to rumble struct
TU_LOG1("Got HID report from control pipe for index %02x\n", request->wIndex);
// memcpy(interface.out, interface.ep_out_buff, min(request->wLength, sizeof(interface.out)));
}
return true;
}
switch (interface.type)
{
case Type::GAMEPAD:
ret = duke_control_xfer(rhport, stage, request, &interface);
break;
case Type::STEELBATTALION:
ret = steelbattalion_control_xfer(rhport, stage, request, &interface);
break;
case Type::XREMOTE:
ret = xremote_control_xfer(rhport, stage, request, &interface);
break;
default:
break;
}
if (ret == false)
{
TU_LOG1("STALL: wIndex: %02x bmRequestType: %02x, bRequest: %02x, wValue: %04x\n",
request->wIndex,
request->bmRequestType,
request->bRequest,
request->wValue);
return false;
}
return true;
}
//Public API
//Call first before device stack is initialized with tud_init(), will default to Duke/Gamepad otherwise
void initialize(Type xid_type)
{
xid_type_ = xid_type;
}
const usbd_class_driver_t* class_driver()
{
static const usbd_class_driver_t tud_xid_class_driver =
{
#if CFG_TUSB_DEBUG >= 2
.name = "XID",
#else
.name = nullptr,
#endif
.init = xid_init,
.deinit = xid_deinit,
.reset = xid_reset,
.open = xid_open,
.control_xfer_cb = xid_control_xfer_cb,
.xfer_cb = xid_xfer_cb,
.sof = NULL
};
return &tud_xid_class_driver;
}
bool send_report_ready(uint8_t index)
{
TU_VERIFY(index < interfaces_.size(), false);
TU_VERIFY(interfaces_[index].ep_in != 0xFF, false);
return (tud_ready() && !usbd_edpt_busy(BOARD_TUD_RHPORT, interfaces_[index].ep_in));
}
bool send_report(uint8_t index, const uint8_t* report, uint16_t len)
{
TU_VERIFY(len < ENDPOINT_SIZE, false);
TU_VERIFY(send_report_ready(index), false);
if (tud_suspended())
{
tud_remote_wakeup();
}
uint16_t size = std::min(len, interfaces_[index].ep_in_size);
std::memcpy(interfaces_[index].ep_in_buffer.data(), report, size);
return usbd_edpt_xfer(BOARD_TUD_RHPORT, interfaces_[index].ep_in, interfaces_[index].ep_in_buffer.data(), size);
}
bool receive_report(uint8_t index, uint8_t *report, uint16_t len)
{
TU_VERIFY(index < interfaces_.size());
TU_VERIFY(interfaces_[index].ep_out != 0xFF);
TU_VERIFY(len < ENDPOINT_SIZE);
uint16_t size = std::min(len, interfaces_[index].ep_out_size);
if (tud_ready() && !usbd_edpt_busy(BOARD_TUD_RHPORT, interfaces_[index].ep_out))
{
usbd_edpt_xfer(BOARD_TUD_RHPORT, interfaces_[index].ep_out, interfaces_[index].ep_out_buffer.data(), size);
}
std::memcpy(report, interfaces_[index].ep_out_buffer.data(), size);
return true;
}
bool xremote_rom_available()
{
return (xremote_get_rom() != nullptr);
}
bool steelbattalion_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, Interface *p_xid)
{
if (request->bmRequestType == 0xC1 && request->bRequest == 0x06 && request->wValue == 0x4200)
{
if (stage == CONTROL_STAGE_SETUP)
{
TU_LOG1("Sending STEELBATTALION_DESC_XID\n");
tud_control_xfer(rhport, request, (void *)XboxOG::SB::XID_DEVICE_DESCRIPTORS, sizeof(XboxOG::SB::XID_DEVICE_DESCRIPTORS));
}
return true;
}
else if (request->bmRequestType == 0xC1 && request->bRequest == 0x01 && request->wValue == 0x0100)
{
if (stage == CONTROL_STAGE_SETUP)
{
TU_LOG1("Sending STEELBATTALION_CAPABILITIES_IN\n");
tud_control_xfer(rhport, request, (void *)XboxOG::SB::XID_CAPABILITIES_IN, sizeof(XboxOG::SB::XID_CAPABILITIES_IN));
}
return true;
}
else if (request->bmRequestType == 0xC1 && request->bRequest == 0x01 && request->wValue == 0x0200)
{
if (stage == CONTROL_STAGE_SETUP)
{
TU_LOG1("Sending STEELBATTALION_CAPABILITIES_OUT\n");
tud_control_xfer(rhport, request, (void *)XboxOG::SB::XID_CAPABILITIES_OUT, sizeof(XboxOG::SB::XID_CAPABILITIES_OUT));
}
return true;
}
return false;
}
bool duke_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, Interface *p_xid)
{
if (request->bmRequestType == 0xC1 && request->bRequest == 0x06 && request->wValue == 0x4200)
{
if (stage == CONTROL_STAGE_SETUP)
{
TU_LOG1("Sending DUKE_DESC_XID\n");
tud_control_xfer(rhport, request, (void *)XboxOG::GP::XID_DEVICE_DESCRIPTORS, sizeof(XboxOG::GP::XID_DEVICE_DESCRIPTORS));
}
return true;
}
else if (request->bmRequestType == 0xC1 && request->bRequest == 0x01 && request->wValue == 0x0100)
{
if (stage == CONTROL_STAGE_SETUP)
{
TU_LOG1("Sending DUKE_CAPABILITIES_IN\n");
tud_control_xfer(rhport, request, (void *)XboxOG::GP::XID_CAPABILITIES_IN, sizeof(XboxOG::GP::XID_CAPABILITIES_IN));
}
return true;
}
else if (request->bmRequestType == 0xC1 && request->bRequest == 0x01 && request->wValue == 0x0200)
{
if (stage == CONTROL_STAGE_SETUP)
{
TU_LOG1("Sending DUKE_CAPABILITIES_OUT\n");
tud_control_xfer(rhport, request, (void *)XboxOG::SB::XID_CAPABILITIES_OUT, sizeof(XboxOG::SB::XID_CAPABILITIES_OUT));
}
return true;
}
return false;
}
} // namespace TUDXID
#endif // TUSB_OPT_DEVICE_ENABLED && CFG_TUD_XID

View File

@@ -1,55 +0,0 @@
/*
TinyUSB XID Device driver based on https://github.com/Ryzee119/ogx360_t4
MIT License
Copyright (c) 2020 Ryan Wendland
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef _TUD_XID_H_
#define _TUD_XID_H_
#include <cstdint>
#include <array>
#include "tusb.h"
#include "device/usbd.h"
#include "device/usbd_pvt.h"
namespace tud_xid
{
enum class Type { GAMEPAD, STEELBATTALION, XREMOTE };
void initialize(tud_xid::Type xid_type);
const usbd_class_driver_t* class_driver();
uint8_t get_index_by_type(uint8_t type_index, tud_xid::Type xid_type);
bool receive_report(uint8_t idx, uint8_t* buffer, uint16_t len);
bool send_report(uint8_t idx, const uint8_t* buffer, uint16_t len);
bool send_report_ready(uint8_t idx);
bool xremote_rom_available();
} // namespace TUDXID
#endif // _TUD_XID_H_

View File

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

View File

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

View File

@@ -1,54 +0,0 @@
#include <cstdint>
#include "tusb.h"
#include "class/hid/hid_device.h"
#include "device/usbd_pvt.h"
#include "USBDevice/DeviceManager.h"
const usbd_class_driver_t *usbd_app_driver_get_cb(uint8_t *driver_count)
{
*driver_count = 1;
return DeviceManager::get_instance().get_driver()->get_class_driver();
}
uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
{
return DeviceManager::get_instance().get_driver()->get_report_cb(itf, report_id, report_type, buffer, reqlen);
}
void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize)
{
DeviceManager::get_instance().get_driver()->set_report_cb(itf, report_id, report_type, buffer, bufsize);
tud_hid_report(report_id, buffer, bufsize);
}
bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
{
return DeviceManager::get_instance().get_driver()->vendor_control_xfer_cb(rhport, stage, request);
}
uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{
return DeviceManager::get_instance().get_driver()->get_descriptor_string_cb(index, langid);
}
uint8_t const *tud_descriptor_device_cb()
{
return DeviceManager::get_instance().get_driver()->get_descriptor_device_cb();
}
uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf)
{
return DeviceManager::get_instance().get_driver()->get_hid_descriptor_report_cb(itf);
}
uint8_t const *tud_descriptor_configuration_cb(uint8_t index)
{
return DeviceManager::get_instance().get_driver()->get_descriptor_configuration_cb(index);
}
uint8_t const* tud_descriptor_device_qualifier_cb()
{
return DeviceManager::get_instance().get_driver()->get_descriptor_device_qualifier_cb();
}

View File

@@ -1,194 +0,0 @@
/*
MIT License
Copyright (c) 2024 o0zz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "USBHost/HIDParser/HIDJoystick.h"
#include "USBHost/HIDParser/HIDUtils.h"
#include <cstring>
/* ----------------------------------------------- */
static int32_t mapValue(int32_t value, int32_t in_min, int32_t in_max, int32_t out_min, int32_t out_max)
{
return (value - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
/* ----------------------------------------------- */
HIDJoystickData::HIDJoystickData() : index(0xFF),
support(0),
X(0),
Y(0),
Z(0),
Rx(0),
Ry(0),
Rz(0),
Slider(0),
Dial(0),
hat_switch(HIDJoystickHatSwitch::NEUTRAL),
button_count(0)
{
memset(buttons, 0, sizeof(buttons));
}
/* ----------------------------------------------- */
HIDJoystickData::~HIDJoystickData()
{
}
/* ----------------------------------------------- */
HIDJoystick::HIDJoystick(const std::shared_ptr<HIDReportDescriptor> &descriptor)
{
this->m_reports = descriptor->GetReports();
}
/* ----------------------------------------------- */
HIDJoystick::~HIDJoystick()
{
}
/* ----------------------------------------------- */
bool HIDJoystick::isValid()
{
return getCount() > 0;
}
/* ----------------------------------------------- */
uint8_t HIDJoystick::getCount()
{
uint8_t count = 0;
for (auto report : this->m_reports)
{
if (report.report_type == HIDIOReportType::Joystick || report.report_type == HIDIOReportType::GamePad)
count++;
}
return count;
}
/* ----------------------------------------------- */
bool HIDJoystick::parseData(uint8_t *data, uint16_t datalen, HIDJoystickData *joystick_data)
{
bool found = false;
uint8_t joystick_count = 0;
for (uint32_t i = 0; i < this->m_reports.size(); i++)
{
auto report = this->m_reports[i];
if (report.report_type != HIDIOReportType::Joystick && report.report_type != HIDIOReportType::GamePad)
continue;
joystick_count += 1;
for (auto ioblock : report.inputs)
{
uint32_t bitOffset = 0;
for (auto input : ioblock.data)
{
uint32_t value = HIDUtils::readBitsLE(data, bitOffset, input.size);
bitOffset += input.size;
if (bitOffset > (datalen * (uint32_t)8))
return false; // Out of range
if (input.type == HIDIOType::ReportId)
{
if (value != input.id)
break; // Not the correct report id
}
found = true;
joystick_data->index = joystick_count - 1;
if (input.type == HIDIOType::Button)
{
if (input.id >= MAX_BUTTONS)
return false;
joystick_data->buttons[input.id] = value;
if (joystick_data->button_count < input.id)
joystick_data->button_count = input.id;
}
else if (input.type == HIDIOType::X)
{
joystick_data->support |= JOYSTICK_SUPPORT_X;
joystick_data->X = mapValue(value, input.logical_min, input.logical_max, -32768, 32767);
}
else if (input.type == HIDIOType::Y)
{
joystick_data->support |= JOYSTICK_SUPPORT_Y;
joystick_data->Y = mapValue(value, input.logical_min, input.logical_max, -32768, 32767);
}
else if (input.type == HIDIOType::Z)
{
joystick_data->support |= JOYSTICK_SUPPORT_Z;
joystick_data->Z = mapValue(value, input.logical_min, input.logical_max, -32768, 32767);
}
else if (input.type == HIDIOType::Rx)
{
joystick_data->support |= JOYSTICK_SUPPORT_Rx;
joystick_data->Rx = mapValue(value, input.logical_min, input.logical_max, -32768, 32767);
}
else if (input.type == HIDIOType::Ry)
{
joystick_data->support |= JOYSTICK_SUPPORT_Ry;
joystick_data->Ry = mapValue(value, input.logical_min, input.logical_max, -32768, 32767);
}
else if (input.type == HIDIOType::Rz)
{
joystick_data->support |= JOYSTICK_SUPPORT_Rz;
joystick_data->Rz = mapValue(value, input.logical_min, input.logical_max, -32768, 32767);
}
else if (input.type == HIDIOType::Slider)
{
joystick_data->support |= JOYSTICK_SUPPORT_Slider;
joystick_data->Slider = mapValue(value, input.logical_min, input.logical_max, -32768, 32767);
}
else if (input.type == HIDIOType::Dial)
{
joystick_data->support |= JOYSTICK_SUPPORT_Dial;
joystick_data->Dial = mapValue(value, input.logical_min, input.logical_max, -32768, 32767);
}
else if (input.type == HIDIOType::HatSwitch)
{
joystick_data->support |= JOYSTICK_SUPPORT_HatSwitch;
joystick_data->hat_switch = (HIDJoystickHatSwitch)value;
}
}
if (found)
return true;
}
}
return false;
}

View File

@@ -1,92 +0,0 @@
/*
MIT License
Copyright (c) 2024 o0zz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "USBHost/HIDParser/HIDReportDescriptor.h"
#include <memory>
#include <vector>
#define MAX_BUTTONS 32
enum class HIDJoystickHatSwitch
{
UP = 0,
UP_RIGHT = 1,
RIGHT = 2,
DOWN_RIGHT = 3,
DOWN = 4,
DOWN_LEFT = 5,
LEFT = 6,
UP_LEFT = 7,
NEUTRAL = 8
};
#define JOYSTICK_SUPPORT_X 0x0001
#define JOYSTICK_SUPPORT_Y 0x0002
#define JOYSTICK_SUPPORT_Z 0x0004
#define JOYSTICK_SUPPORT_Rx 0x0008
#define JOYSTICK_SUPPORT_Ry 0x0010
#define JOYSTICK_SUPPORT_Rz 0x0020
#define JOYSTICK_SUPPORT_Slider 0x0040
#define JOYSTICK_SUPPORT_Dial 0x0080
#define JOYSTICK_SUPPORT_HatSwitch 0x0100
class HIDJoystickData
{
public:
HIDJoystickData();
~HIDJoystickData();
uint8_t index;
uint16_t support;
int16_t X; //-32768 to 32767
int16_t Y; //-32768 to 32767
int16_t Z; //-32768 to 32767
int16_t Rx; //-32768 to 32767
int16_t Ry; //-32768 to 32767
int16_t Rz; //-32768 to 32767
int16_t Slider; //-32768 to 32767
int16_t Dial; //-32768 to 32767
HIDJoystickHatSwitch hat_switch;
uint8_t button_count;
uint8_t buttons[MAX_BUTTONS];
};
class HIDJoystick
{
public:
HIDJoystick(const std::shared_ptr<HIDReportDescriptor> &descriptor);
~HIDJoystick();
bool isValid();
uint8_t getCount();
bool parseData(uint8_t *data, uint16_t datalen, HIDJoystickData *joystick_data);
private:
std::vector<HIDIOReport> m_reports;
};

View File

@@ -1,165 +0,0 @@
/*
MIT License
Copyright (c) 2024 o0zz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "USBHost/HIDParser/HIDReportDescriptor.h"
#include "USBHost/HIDParser/HIDReportDescriptorElements.h"
#include "USBHost/HIDParser/HIDReportDescriptorUsages.h"
#include <iostream>
#include <vector>
#include <memory>
#include <stack>
#include <cassert>
#include <algorithm>
// https://github.com/pasztorpisti/hid-report-parser/blob/master/src/hid_report_parser.cpp
// https://docs.kernel.org/hid/hidintro.html
HIDInputOutput::HIDInputOutput(HIDIOType type, uint32_t size, uint32_t id) : type(type),
sub_type(0),
size(size),
id(id),
logical_min(0),
logical_max(0),
physical_min(0),
physical_max(0),
unit(0),
unit_exponent(0)
{
}
HIDInputOutput::~HIDInputOutput()
{
}
HIDInputOutput::HIDInputOutput(const HIDUsage &usage, uint32_t idx) : type(HIDIOType::Unknown),
sub_type(0),
size(usage.property.size),
id(0),
logical_min(usage.property.logical_min),
logical_max(usage.property.logical_max),
physical_min(usage.property.physical_min),
physical_max(usage.property.physical_max),
unit(usage.property.unit),
unit_exponent(usage.property.unit_exponent)
{
if (usage.type == HIDUsageType::GenericDesktop)
{
if (usage.sub_type == (uint32_t)HIDUsageGenericDesktopSubType::X)
this->type = HIDIOType::X;
else if (usage.sub_type == (uint32_t)HIDUsageGenericDesktopSubType::Y)
this->type = HIDIOType::Y;
else if (usage.sub_type == (uint32_t)HIDUsageGenericDesktopSubType::Z)
this->type = HIDIOType::Z;
else if (usage.sub_type == (uint32_t)HIDUsageGenericDesktopSubType::Rx)
this->type = HIDIOType::Rx;
else if (usage.sub_type == (uint32_t)HIDUsageGenericDesktopSubType::Ry)
this->type = HIDIOType::Ry;
else if (usage.sub_type == (uint32_t)HIDUsageGenericDesktopSubType::Rz)
this->type = HIDIOType::Rz;
else if (usage.sub_type == (uint32_t)HIDUsageGenericDesktopSubType::Slider)
this->type = HIDIOType::Slider;
else if (usage.sub_type == (uint32_t)HIDUsageGenericDesktopSubType::Dial)
this->type = HIDIOType::Dial;
else if (usage.sub_type == (uint32_t)HIDUsageGenericDesktopSubType::HatSwitch)
this->type = HIDIOType::HatSwitch;
else if (usage.sub_type == (uint32_t)HIDUsageGenericDesktopSubType::Wheel)
this->type = HIDIOType::Wheel;
}
else if (usage.type == HIDUsageType::Button)
this->type = HIDIOType::Button;
else if (usage.type == HIDUsageType::ReportId)
this->type = HIDIOType::ReportId;
else if (usage.type == HIDUsageType::Padding)
this->type = HIDIOType::Padding;
else if (usage.type == HIDUsageType::VendorDefined)
{
this->type = HIDIOType::VendorDefined;
this->sub_type = usage.sub_type;
}
else
{
this->type = HIDIOType::Unknown;
this->sub_type = usage.sub_type;
}
this->id = usage.usage_min + idx;
}
/* -------------------------------------------------------------------- */
HIDReportDescriptor::HIDReportDescriptor()
{
}
/* -------------------------------------------------------------------- */
HIDReportDescriptor::HIDReportDescriptor(const uint8_t *hid_report_data, uint16_t hid_report_data_len)
{
parse(hid_report_data, hid_report_data_len);
}
/* -------------------------------------------------------------------- */
HIDReportDescriptor::~HIDReportDescriptor()
{
}
/* -------------------------------------------------------------------- */
void HIDReportDescriptor::parse(const uint8_t *hid_report_data, uint16_t hid_report_data_len)
{
HIDReportDescriptorElements hid_report_elements = HIDReportDescriptorElements(hid_report_data, hid_report_data_len);
std::vector<HIDReport> hid_report_usage = HIDReportDescriptorUsages::parse(hid_report_elements);
for (auto report : hid_report_usage)
{
m_reports.push_back(HIDIOReport((HIDIOReportType)report.usages[0].sub_type));
for (size_t k = 1; k < report.usages.size(); k++)
{
std::vector<HIDIOBlock> *ioblocks = NULL;
HIDUsage &usage = report.usages[k];
if (usage.io_type == HIDUsageIOType::Input)
ioblocks = &m_reports.back().inputs;
else if (usage.io_type == HIDUsageIOType::Output)
ioblocks = &m_reports.back().outputs;
else if (usage.io_type == HIDUsageIOType::Feature)
ioblocks = &m_reports.back().features;
else
continue;
for (uint32_t i = 0; i < usage.property.count; i++)
{
HIDInputOutput io(usage, i);
//We need to create a new block everytime we meet a ReportId and if there is no block
if (io.type == HIDIOType::ReportId || ioblocks->size() == 0)
ioblocks->push_back(HIDIOBlock());
ioblocks->back().data.push_back(io);
}
}
}
assert(m_reports.size() > 0);
}

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