Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b9038483ce | ||
|
|
e57de52cc4 | ||
|
|
ee05f9516a | ||
|
|
a87ed08a63 | ||
|
|
e3acca6d5c | ||
|
|
2c601723f1 | ||
|
|
d6dcbc52a7 | ||
|
|
e210b50c1a | ||
|
|
ae59b5e0c9 | ||
|
|
9ebbbc3735 | ||
|
|
f3ddd49252 | ||
|
|
f7da9a07d0 | ||
|
|
e2ececd2e0 | ||
|
|
3604c8e112 | ||
|
|
86c60d76a4 | ||
|
|
2613221d44 | ||
|
|
1f27c3d4b5 | ||
|
|
da72c91c04 | ||
|
|
933206398a | ||
|
|
0a053f8f3d | ||
|
|
b1535c9c75 | ||
|
|
383274c83b | ||
|
|
54bbdf0a41 | ||
|
|
b0fd734194 | ||
|
|
49fff842f2 |
28
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
28
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**What type of controller do you have the issue with?**
|
||||||
|
Please include the model, even better to include the PID/VID.
|
||||||
|
You can get the PID and VID like this:
|
||||||
|
- plug the controller into your computer
|
||||||
|
- open Device Manager
|
||||||
|
- right click the controller (probably listed under Human Interface Devices)
|
||||||
|
- select Properties
|
||||||
|
- go to the Details tab
|
||||||
|
- select Hardware IDs from the dropdown menu
|
||||||
|
It will look like this: HID\VID_046D&PID_C05A
|
||||||
|
|
||||||
|
**What platform are you using the OGX-Mini on?**
|
||||||
|
OG Xbox, PS3, Switch, etc.
|
||||||
|
|
||||||
|
**What board are you using?**
|
||||||
|
Pi Pico, Adafruit Feather, RP2040-Zero...
|
||||||
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context or screenshots about the feature request here.
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,5 +3,4 @@ build
|
|||||||
release
|
release
|
||||||
generated
|
generated
|
||||||
tools
|
tools
|
||||||
.ignore
|
.ignore
|
||||||
src/usbh/tusb_hid/experiment
|
|
||||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -4,3 +4,9 @@
|
|||||||
[submodule "lib/tinyusb"]
|
[submodule "lib/tinyusb"]
|
||||||
path = lib/tinyusb
|
path = lib/tinyusb
|
||||||
url = https://github.com/hathach/tinyusb.git
|
url = https://github.com/hathach/tinyusb.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
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
cmake_minimum_required(VERSION 3.12)
|
cmake_minimum_required(VERSION 3.12)
|
||||||
|
|
||||||
|
set(CMAKE_BUILD_TYPE Release)
|
||||||
message("Build type: \"${CMAKE_BUILD_TYPE}\"")
|
message("Build type: \"${CMAKE_BUILD_TYPE}\"")
|
||||||
|
|
||||||
# Project name
|
|
||||||
set(NAME OGX-Mini)
|
set(NAME OGX-Mini)
|
||||||
|
|
||||||
# Board type
|
|
||||||
set(PICO_BOARD none)
|
set(PICO_BOARD none)
|
||||||
|
|
||||||
# Fixes that allow some MCH2022 badges with a slowly starting oscillator to boot properly
|
# 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_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)
|
||||||
|
|
||||||
# SDK
|
|
||||||
include($ENV{PICO_SDK_PATH}/pico_sdk_init.cmake)
|
include($ENV{PICO_SDK_PATH}/pico_sdk_init.cmake)
|
||||||
|
|
||||||
project(${NAME} C CXX ASM)
|
project(${NAME} C CXX ASM)
|
||||||
@@ -22,45 +23,48 @@ 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}")
|
message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.3.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(PICO_PIO_USB_PATH "${CMAKE_CURRENT_LIST_DIR}/lib/Pico-PIO-USB")
|
set(ROOT ${CMAKE_CURRENT_LIST_DIR})
|
||||||
set(PICO_TINYUSB_PATH "${CMAKE_CURRENT_LIST_DIR}/lib/tinyusb")
|
|
||||||
|
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()
|
pico_sdk_init()
|
||||||
|
|
||||||
add_subdirectory(lib/Pico-PIO-USB)
|
# add_subdirectory(${ROOT}/lib)
|
||||||
add_subdirectory(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
|
file(GLOB_RECURSE SOURCES
|
||||||
"src/usbh/*"
|
${SRC_DIR}/main.cpp
|
||||||
"src/usbh/tusb_xinput/*"
|
${SRC_DIR}/input_mode.cpp
|
||||||
"src/usbh/tusb_hid/*"
|
|
||||||
"src/*"
|
${SRC_DIR}/usbh/tusb_host_manager.cpp
|
||||||
"src/utilities/*"
|
${SRC_DIR}/usbh/tusb_host.cpp
|
||||||
"src/usbd/*"
|
${SRC_DIR}/usbh/n64usb/N64USB.cpp
|
||||||
"src/usbd/shared/*"
|
${SRC_DIR}/usbh/ps3/Dualshock3.cpp
|
||||||
"src/usbd/switch/*"
|
${SRC_DIR}/usbh/ps3/DInput.cpp
|
||||||
"src/usbd/xboxog/*"
|
${SRC_DIR}/usbh/ps4/Dualshock4.cpp
|
||||||
"src/usbd/xinput/*")
|
${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
|
# Firmware
|
||||||
add_executable(${NAME}
|
add_executable(${NAME} ${SOURCES})
|
||||||
${SOURCES}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_include_directories(${NAME} PUBLIC
|
target_include_directories(${NAME} PUBLIC
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src ${CMAKE_CURRENT_LIST_DIR}/lib)
|
${ROOT}/src
|
||||||
|
${ROOT}/lib)
|
||||||
include_directories(
|
|
||||||
lib/)
|
|
||||||
|
|
||||||
#------- Comment out the following line if compiling for the normal Pi Pico -------#
|
|
||||||
|
|
||||||
add_compile_definitions(FEATHER_RP2040)
|
|
||||||
|
|
||||||
#------- USB host data +/- will be GPIO 0/1 ---------------------------------------#
|
|
||||||
|
|
||||||
# add_compile_definitions(HOST_DEBUG) # CDC device, include utilities/log.h and use log() as you would printf()
|
|
||||||
|
|
||||||
|
|
||||||
target_link_libraries(${NAME}
|
target_link_libraries(${NAME}
|
||||||
pico_stdlib
|
pico_stdlib
|
||||||
@@ -80,6 +84,8 @@ target_link_libraries(${NAME}
|
|||||||
tinyusb_pico_pio_usb
|
tinyusb_pico_pio_usb
|
||||||
CRC32
|
CRC32
|
||||||
cmsis_core
|
cmsis_core
|
||||||
|
xinput_host
|
||||||
|
tusb_gamepad
|
||||||
)
|
)
|
||||||
|
|
||||||
pico_add_extra_outputs(${NAME})
|
pico_add_extra_outputs(${NAME})
|
||||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2024 wiredopposite
|
Copyright (c) 2024 wiredOpposite (wiredopposite.com)
|
||||||
Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info)
|
Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info)
|
||||||
Copyright (c) 2021 Jason Skuby (mytechtoybox.com)
|
Copyright (c) 2021 Jason Skuby (mytechtoybox.com)
|
||||||
Copyright (c) 2020 Ryan Wendland
|
Copyright (c) 2020 Ryan Wendland
|
||||||
|
|||||||
40
Makefile
40
Makefile
@@ -1,40 +0,0 @@
|
|||||||
# Copyright (c) 2022 Nicolai Electronics
|
|
||||||
# SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
INSTALL_PREFIX := $PWD
|
|
||||||
BUILD_DIR := build
|
|
||||||
GENERATED_DIR := generated
|
|
||||||
|
|
||||||
.PHONY: all firmware flash clean install_rules $(BUILD_DIR) format
|
|
||||||
|
|
||||||
all: build flash
|
|
||||||
@echo "All tasks completed"
|
|
||||||
|
|
||||||
build:
|
|
||||||
mkdir -p $(BUILD_DIR)
|
|
||||||
mkdir -p $(GENERATED_DIR)
|
|
||||||
cd $(BUILD_DIR); cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX -DCMAKE_BUILD_TYPE=Release ..
|
|
||||||
$(MAKE) -C $(BUILD_DIR) --no-print-directory all
|
|
||||||
|
|
||||||
debug:
|
|
||||||
mkdir -p $(BUILD_DIR)
|
|
||||||
mkdir -p $(GENERATED_DIR)
|
|
||||||
cd $(BUILD_DIR); cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX -DCMAKE_BUILD_TYPE=Debug ..
|
|
||||||
$(MAKE) -C $(BUILD_DIR) --no-print-directory all
|
|
||||||
|
|
||||||
flash:
|
|
||||||
picotool load $(BUILD_DIR)/i2c_adapter.bin
|
|
||||||
picotool reboot
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf $(BUILD_DIR)
|
|
||||||
rm -rf $(GENERATED_DIR)
|
|
||||||
|
|
||||||
install_rules:
|
|
||||||
cp tools/99-pico.rules /etc/udev/rules.d/
|
|
||||||
@echo "reload rules with:"
|
|
||||||
@echo "\tudevadm control --reload-rules"
|
|
||||||
@echo "\tudevadm trigger"
|
|
||||||
|
|
||||||
format:
|
|
||||||
find . -iname '*.h' -o -iname '*.c' -o -iname '*.cpp' | grep -v '$(BUILD_DIR)' | xargs clang-format -i
|
|
||||||
30
README.md
30
README.md
@@ -1,7 +1,9 @@
|
|||||||
# OGX-Mini
|
# OGX-Mini
|
||||||

|

|
||||||
|
|
||||||
Firmware for the RP2040, setup for the [Adafruit Feather USB Host board](https://www.adafruit.com/product/5723) (can be used with the Pi Pico as well), capable of emulating gamepads for
|
Firmware for the RP2040, capable of emulating gamepads for several consoles. The firmware now comes in 3 flavors, for the [Adafruit Feather USB Host board](https://www.adafruit.com/product/5723), the Pi Pico, and the Waveshare RP2040-Zero.
|
||||||
|
|
||||||
|
## Supported platforms
|
||||||
- Original Xbox
|
- Original Xbox
|
||||||
- Playstation 3
|
- Playstation 3
|
||||||
- Nintendo Switch (docked)
|
- Nintendo Switch (docked)
|
||||||
@@ -12,12 +14,14 @@ Firmware for the RP2040, setup for the [Adafruit Feather USB Host board](https:/
|
|||||||
### Wired controllers
|
### Wired controllers
|
||||||
- Original Xbox Duke and S
|
- Original Xbox Duke and S
|
||||||
- Xbox 360, One, Series, and Elite
|
- Xbox 360, One, Series, and Elite
|
||||||
|
- Dualshock 3 (PS3)
|
||||||
- Dualshock 4 (PS4)
|
- Dualshock 4 (PS4)
|
||||||
- Dualsense (PS5, Dualsense Edge should work but it's untested)
|
- Dualsense (PS5, Dualsense Edge should work but it's untested)
|
||||||
- Nintendo Switch Pro
|
- Nintendo Switch Pro
|
||||||
- Nintendo Switch wired (tested with PowerA brand)
|
- Nintendo Switch wired (tested with PowerA brand)
|
||||||
- Nintendo 64 USB (experimental, tested with RetroLink brand)
|
- Nintendo 64 USB (experimental, tested with RetroLink brand)
|
||||||
- Playstation Classic
|
- Playstation Classic
|
||||||
|
- Generic DInput
|
||||||
|
|
||||||
### Wireless adapters
|
### Wireless adapters
|
||||||
- Xbox 360 PC adapter (Microsoft or clones, syncs 1 controller)
|
- Xbox 360 PC adapter (Microsoft or clones, syncs 1 controller)
|
||||||
@@ -44,16 +48,28 @@ Start + A (Cross for PlayStation and B for Switch gamepads)
|
|||||||
|
|
||||||
After a new mode is stored, the RP2040 will reset itself so you don't need to unplug it.
|
After a new mode is stored, the RP2040 will reset itself so you don't need to unplug it.
|
||||||
|
|
||||||
|
## Hardware
|
||||||
|
I've designed a PCB for the RP2040-Zero so you can make a small form-factor adapter yourself. The gerber files, schematic, and BOM are in Hardware folder.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
If you would like a prebuilt unit, you can purchase one, with cable and Xbox adapter included, from my website [wiredopposite.com](https://wiredopposite.com/product/ogx-mini-controller-adapter-for-original-xbox-playstation-3-and-switch-ogx360/) or my [Etsy store](https://www.etsy.com/listing/1426992904/ogx-mini-controller-adapter-for-original).
|
||||||
|
|
||||||
|
For the Pi Pico, this is a diagram of how you'd connect the extra USB port:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
For the [Adafruit Feather USB Host board](https://www.adafruit.com/product/5723), no extra work is needed.
|
||||||
|
|
||||||
## Adding supported controllers
|
## Adding supported controllers
|
||||||
If your third party controller isn't working, but the original version is listed above, send me the device's VID and PID and I'll add it so it's recognized properly.
|
If your third party controller isn't working, but the original version is listed above, send me the device's VID and PID and I'll add it so it's recognized properly.
|
||||||
|
|
||||||
## Compiling
|
## Compiling
|
||||||
You can compile this for the Pi Pico by commenting out this line in CMakeLists.txt
|
You can compile this for different boards by changing USBD_BOARD in the usbd_config.h file, you can also adjust USBD_MAX_GAMEPADS to enable more controllers on PlayStation 3 (this is experimental).
|
||||||
`add_compile_definitions(FEATHER_RP2040)`
|
|
||||||
That will set the D+ and D- host pins to GPIO 0 and 1.
|
|
||||||
|
|
||||||
Here's a diagram of how you'd use the Pico:
|
Choosing OGXM_PI_PICO will set the D+ and D- host pins to GPIO 0 and 1.
|
||||||

|
|
||||||
|
You can also choose OGXM_RPZERO_INTERPOSER for the RP2040-Zero and that will set D+ and D- to GPIO 10 and 11, so connecting a USB port is easier. You can still use the Pi Pico firmware on the RP2040-Zero (the other way around has not been tested though).
|
||||||
|
|
||||||
## Special thanks
|
## Special thanks
|
||||||
Thank you to Ryzee119 and the OpenStickCommunity, without their work this project would not exist.
|
Thank you to Ryzee119 and the OpenStickCommunity, without their work this project would not exist.
|
||||||
6
hardware/BOM_OGX-Mini_RP2040-Zero_Interposer.csv
Normal file
6
hardware/BOM_OGX-Mini_RP2040-Zero_Interposer.csv
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
References,Qty,Description,Manufacturer,MPN,Digikey,Mouser,RS,Newark,Farnell,LCSC,JLC Assembly
|
||||||
|
USB1,1,USB TYPE-A SINGLE PORT RIGHT ANG,,CU01SAH0S00,2987-CU01SAH0S00-ND,,,,,,
|
||||||
|
"R1,R2",2,RES 27 OHM 5% 1/8W 0805,,RC0805JR-0727RL,311-27ARCT-ND,,,,,,
|
||||||
|
R3,1,RES 470 OHM 1% 1/8W 0805 (Optional),,RC0805FR-07470RL,311-470CRCT-ND,,,,,,
|
||||||
|
LED1,1,LED GREEN CLEAR 0805 SMD (Optional),,150080GS75000,732-4983-1-ND,,,,,,
|
||||||
|
U1,1,Waveshare RP2040-Zero,,Waveshare RP2040-Zero,,,,,,,
|
||||||
|
BIN
hardware/Gerber_OGX-Mini_RP2040-Zero_Interposer.zip
Normal file
BIN
hardware/Gerber_OGX-Mini_RP2040-Zero_Interposer.zip
Normal file
Binary file not shown.
5
hardware/README.md
Normal file
5
hardware/README.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Gerber, BOM, and schematic for an RP2040-Zero interposer board you can make yourself. LED1 and R3 are both optional.
|
||||||
|
|
||||||
|
The RP2040-Zero board can be found on Amazon and AliExpress.
|
||||||
|
|
||||||
|

|
||||||
1951
hardware/Schematic_OGX-Mini_RP2040-Zero_Interposer.pdf
Normal file
1951
hardware/Schematic_OGX-Mini_RP2040-Zero_Interposer.pdf
Normal file
File diff suppressed because it is too large
Load Diff
BIN
images/OGX-Mini-github.jpg
Normal file
BIN
images/OGX-Mini-github.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 507 KiB |
BIN
images/OGX-Mini-rpzero-int.jpg
Normal file
BIN
images/OGX-Mini-rpzero-int.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 594 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 110 KiB |
Submodule lib/tinyusb updated: 938cae818f...290f4bea91
1
lib/tusb_gamepad
Submodule
1
lib/tusb_gamepad
Submodule
Submodule lib/tusb_gamepad added at 5e5ee00ee8
1
lib/tusb_xinput
Submodule
1
lib/tusb_xinput
Submodule
Submodule lib/tusb_xinput added at b34398847a
@@ -1,62 +0,0 @@
|
|||||||
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
|
|
||||||
|
|
||||||
# This can be dropped into an external project to help locate this SDK
|
|
||||||
# It should be include()ed prior to project()
|
|
||||||
|
|
||||||
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
|
|
||||||
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
|
|
||||||
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
|
|
||||||
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
|
|
||||||
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
|
|
||||||
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
|
|
||||||
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
|
|
||||||
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
|
|
||||||
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
|
|
||||||
|
|
||||||
if (NOT PICO_SDK_PATH)
|
|
||||||
if (PICO_SDK_FETCH_FROM_GIT)
|
|
||||||
include(FetchContent)
|
|
||||||
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
|
|
||||||
if (PICO_SDK_FETCH_FROM_GIT_PATH)
|
|
||||||
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
|
|
||||||
endif ()
|
|
||||||
FetchContent_Declare(
|
|
||||||
pico_sdk
|
|
||||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
|
||||||
GIT_TAG master
|
|
||||||
)
|
|
||||||
if (NOT pico_sdk)
|
|
||||||
message("Downloading Raspberry Pi Pico SDK")
|
|
||||||
FetchContent_Populate(pico_sdk)
|
|
||||||
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
|
|
||||||
endif ()
|
|
||||||
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
|
|
||||||
else ()
|
|
||||||
message(FATAL_ERROR
|
|
||||||
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
|
|
||||||
)
|
|
||||||
endif ()
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
|
|
||||||
if (NOT EXISTS ${PICO_SDK_PATH})
|
|
||||||
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
|
|
||||||
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
|
|
||||||
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
|
|
||||||
|
|
||||||
include(${PICO_SDK_INIT_CMAKE_FILE})
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
#include <cstdint>
|
|
||||||
|
|
||||||
#include "Gamepad.h"
|
|
||||||
#include "usbh/tusb_hid/shared.h"
|
|
||||||
|
|
||||||
void Gamepad::reset_state()
|
|
||||||
{
|
|
||||||
state.up = state.down = state.left = state.right = false;
|
|
||||||
state.a = state.b = state.x = state.y = false;
|
|
||||||
state.l3 = state.r3 = state.back = state.start = false;
|
|
||||||
state.rb = state.lb = state.sys = state.misc = false;
|
|
||||||
state.lt = state.rt = 0;
|
|
||||||
state.lx = state.ly = state.rx = state.ry = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GamepadOut::update_gamepad_rumble(uint8_t left_rumble, uint8_t right_rumble)
|
|
||||||
{
|
|
||||||
out_state.lrumble = left_rumble;
|
|
||||||
out_state.rrumble = right_rumble;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GamepadOut::rumble_hid_reset()
|
|
||||||
{
|
|
||||||
if (out_state.lrumble != UINT8_MAX)
|
|
||||||
{
|
|
||||||
out_state.lrumble = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_state.rrumble != UINT8_MAX)
|
|
||||||
{
|
|
||||||
gamepadOut.out_state.rrumble = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#ifndef _GAMEPAD_H_
|
|
||||||
#define _GAMEPAD_H_
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
#include "usbh/tusb_hid/ps3.h"
|
|
||||||
#include "usbh/tusb_hid/ps4.h"
|
|
||||||
#include "usbh/tusb_hid/ps5.h"
|
|
||||||
#include "usbh/tusb_xinput/xinput_host.h"
|
|
||||||
|
|
||||||
struct GamepadState{
|
|
||||||
bool up {false};
|
|
||||||
bool down {false};
|
|
||||||
bool left {false};
|
|
||||||
bool right {false};
|
|
||||||
bool a {false};
|
|
||||||
bool b {false};
|
|
||||||
bool x {false};
|
|
||||||
bool y {false};
|
|
||||||
bool l3 {false};
|
|
||||||
bool r3 {false};
|
|
||||||
bool back {false};
|
|
||||||
bool start {false};
|
|
||||||
bool rb {false};
|
|
||||||
bool lb {false};
|
|
||||||
bool sys {false};
|
|
||||||
bool misc {false};
|
|
||||||
uint8_t lt {0};
|
|
||||||
uint8_t rt {0};
|
|
||||||
int16_t lx {0};
|
|
||||||
int16_t ly {0};
|
|
||||||
int16_t rx {0};
|
|
||||||
int16_t ry {0};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GamepadOutState{
|
|
||||||
uint8_t lrumble {0};
|
|
||||||
uint8_t rrumble {0};
|
|
||||||
};
|
|
||||||
|
|
||||||
class Gamepad {
|
|
||||||
public:
|
|
||||||
GamepadState state;
|
|
||||||
|
|
||||||
void update_gamepad_state_from_xinput(const xinput_gamepad_t* xinput_data);
|
|
||||||
void reset_state();
|
|
||||||
};
|
|
||||||
|
|
||||||
class GamepadOut {
|
|
||||||
public:
|
|
||||||
GamepadOutState out_state;
|
|
||||||
|
|
||||||
void update_gamepad_rumble(uint8_t left_rumble, uint8_t right_rumble);
|
|
||||||
void rumble_hid_reset();
|
|
||||||
};
|
|
||||||
|
|
||||||
extern Gamepad gamepad;
|
|
||||||
extern GamepadOut gamepadOut;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // _GAMEPAD_H_
|
|
||||||
@@ -1,276 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define HID_ENDPOINT_SIZE 64
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
*
|
|
||||||
* Endpoint Buffer Configuration
|
|
||||||
*
|
|
||||||
**************************************************************************/
|
|
||||||
|
|
||||||
#define ENDPOINT0_SIZE 64
|
|
||||||
|
|
||||||
#define GAMEPAD_INTERFACE 0
|
|
||||||
#define GAMEPAD_ENDPOINT 1
|
|
||||||
#define GAMEPAD_SIZE 64
|
|
||||||
|
|
||||||
#define LSB(n) (n & 255)
|
|
||||||
#define MSB(n) ((n >> 8) & 255)
|
|
||||||
|
|
||||||
#define DINPUT_HAT_UP 0x00
|
|
||||||
#define DINPUT_HAT_UPRIGHT 0x01
|
|
||||||
#define DINPUT_HAT_RIGHT 0x02
|
|
||||||
#define DINPUT_HAT_DOWNRIGHT 0x03
|
|
||||||
#define DINPUT_HAT_DOWN 0x04
|
|
||||||
#define DINPUT_HAT_DOWNLEFT 0x05
|
|
||||||
#define DINPUT_HAT_LEFT 0x06
|
|
||||||
#define DINPUT_HAT_UPLEFT 0x07
|
|
||||||
#define DINPUT_HAT_NOTHING 0x08
|
|
||||||
|
|
||||||
#define DINPUT_JOYSTICK_MIN 0x00
|
|
||||||
#define DINPUT_JOYSTICK_MID 0x80
|
|
||||||
#define DINPUT_JOYSTICK_MAX 0xFF
|
|
||||||
|
|
||||||
typedef struct __attribute((packed, aligned(1)))
|
|
||||||
{
|
|
||||||
// digital buttons, 0 = off, 1 = on
|
|
||||||
// uint8_t report_id;
|
|
||||||
// uint8_t padding;
|
|
||||||
|
|
||||||
uint8_t square_btn : 1;
|
|
||||||
uint8_t cross_btn : 1;
|
|
||||||
uint8_t circle_btn : 1;
|
|
||||||
uint8_t triangle_btn : 1;
|
|
||||||
|
|
||||||
uint8_t l1_btn : 1;
|
|
||||||
uint8_t r1_btn : 1;
|
|
||||||
uint8_t l2_btn : 1;
|
|
||||||
uint8_t r2_btn : 1;
|
|
||||||
|
|
||||||
uint8_t select_btn : 1;
|
|
||||||
uint8_t start_btn : 1;
|
|
||||||
uint8_t l3_btn : 1;
|
|
||||||
uint8_t r3_btn : 1;
|
|
||||||
|
|
||||||
uint8_t ps_btn : 1;
|
|
||||||
uint8_t tp_btn : 1;
|
|
||||||
// uint8_t l2_btn_alt : 1;
|
|
||||||
|
|
||||||
// uint8_t r2_btn_alt : 1;
|
|
||||||
uint8_t : 2;
|
|
||||||
|
|
||||||
// digital direction, use the dir_* constants(enum)
|
|
||||||
// 8 = center, 0 = up, 1 = up/right, 2 = right, 3 = right/down
|
|
||||||
// 4 = down, 5 = down/left, 6 = left, 7 = left/up
|
|
||||||
|
|
||||||
// uint8_t direction;
|
|
||||||
uint8_t direction : 4;
|
|
||||||
uint8_t : 4;
|
|
||||||
|
|
||||||
// left and right analog sticks, 0x00 left/up, 0x80 middle, 0xff right/down
|
|
||||||
|
|
||||||
uint8_t l_x_axis;
|
|
||||||
uint8_t l_y_axis;
|
|
||||||
uint8_t r_x_axis;
|
|
||||||
uint8_t r_y_axis;
|
|
||||||
|
|
||||||
// Gonna assume these are button analog values for the d-pad.
|
|
||||||
// NOTE: NOT EVEN SURE THIS IS RIGHT, OR IN THE CORRECT ORDER
|
|
||||||
uint8_t right_axis;
|
|
||||||
uint8_t left_axis;
|
|
||||||
uint8_t up_axis;
|
|
||||||
uint8_t down_axis;
|
|
||||||
|
|
||||||
// button axis, 0x00 = unpressed, 0xff = fully pressed
|
|
||||||
|
|
||||||
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;
|
|
||||||
} DInputReport;
|
|
||||||
|
|
||||||
// struct DInputLed {
|
|
||||||
// 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%) */
|
|
||||||
// } __attribute__((packed));
|
|
||||||
|
|
||||||
// struct DInputRumble {
|
|
||||||
// uint8_t padding;
|
|
||||||
// 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 */
|
|
||||||
// } __attribute__((packed));
|
|
||||||
|
|
||||||
// struct DInputOutReport {
|
|
||||||
// struct DInputRumble rumble;
|
|
||||||
// uint8_t padding[4];
|
|
||||||
// uint8_t leds_bitmap; /* bitmap of enabled LEDs: LED_1 = 0x02, LED_2 = 0x04, ... */
|
|
||||||
// struct DInputLed led[4]; /* LEDx at (4 - x) */
|
|
||||||
// struct DInputLed _reserved; /* LED5, not actually soldered */
|
|
||||||
// } __attribute__((packed));
|
|
||||||
|
|
||||||
static const uint8_t dinput_string_language[] = { 0x09, 0x04 };
|
|
||||||
static const uint8_t dinput_string_manufacturer[] = "SHANWAN";
|
|
||||||
static const uint8_t dinput_string_product[] = "2In1 USB Joystick";
|
|
||||||
static const uint8_t dinput_string_version[] = "1.0";
|
|
||||||
|
|
||||||
static const uint8_t *dinput_string_descriptors[] __attribute__((unused)) =
|
|
||||||
{
|
|
||||||
dinput_string_language,
|
|
||||||
dinput_string_manufacturer,
|
|
||||||
dinput_string_product,
|
|
||||||
dinput_string_version
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t dinput_device_descriptor[] =
|
|
||||||
{
|
|
||||||
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 dinput_report_descriptor[] =
|
|
||||||
{
|
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t dinput_hid_descriptor[] =
|
|
||||||
{
|
|
||||||
0x09, // bLength
|
|
||||||
0x21, // bDescriptorType (HID)
|
|
||||||
0x10, 0x01, // bcdHID 1.10
|
|
||||||
0x00, // bCountryCode
|
|
||||||
0x01, // bNumDescriptors
|
|
||||||
0x22, // bDescriptorType[0] (HID)
|
|
||||||
0x89, 0x00, // wDescriptorLength[0] 137
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t dinput_configuration_descriptor[] =
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
};
|
|
||||||
@@ -1,264 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define HID_ENDPOINT_SIZE 64
|
|
||||||
|
|
||||||
// Mac OS-X and Linux automatically load the correct drivers. On
|
|
||||||
// Windows, even though the driver is supplied by Microsoft, an
|
|
||||||
// INF file is needed to load the driver. These numbers need to
|
|
||||||
// match the INF file.
|
|
||||||
#define VENDOR_ID 0x10C4
|
|
||||||
#define PRODUCT_ID 0x82C0
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
*
|
|
||||||
* Endpoint Buffer Configuration
|
|
||||||
*
|
|
||||||
**************************************************************************/
|
|
||||||
|
|
||||||
#define ENDPOINT0_SIZE 64
|
|
||||||
|
|
||||||
#define GAMEPAD_INTERFACE 0
|
|
||||||
#define GAMEPAD_ENDPOINT 1
|
|
||||||
#define GAMEPAD_SIZE 64
|
|
||||||
|
|
||||||
#define LSB(n) (n & 255)
|
|
||||||
#define MSB(n) ((n >> 8) & 255)
|
|
||||||
|
|
||||||
// HAT report (4 bits)
|
|
||||||
#define HID_HAT_UP 0x00
|
|
||||||
#define HID_HAT_UPRIGHT 0x01
|
|
||||||
#define HID_HAT_RIGHT 0x02
|
|
||||||
#define HID_HAT_DOWNRIGHT 0x03
|
|
||||||
#define HID_HAT_DOWN 0x04
|
|
||||||
#define HID_HAT_DOWNLEFT 0x05
|
|
||||||
#define HID_HAT_LEFT 0x06
|
|
||||||
#define HID_HAT_UPLEFT 0x07
|
|
||||||
#define HID_HAT_NOTHING 0x08
|
|
||||||
|
|
||||||
// Button report (16 bits)
|
|
||||||
#define HID_MASK_SQUARE (1U << 0)
|
|
||||||
#define HID_MASK_CROSS (1U << 1)
|
|
||||||
#define HID_MASK_CIRCLE (1U << 2)
|
|
||||||
#define HID_MASK_TRIANGLE (1U << 3)
|
|
||||||
#define HID_MASK_L1 (1U << 4)
|
|
||||||
#define HID_MASK_R1 (1U << 5)
|
|
||||||
#define HID_MASK_L2 (1U << 6)
|
|
||||||
#define HID_MASK_R2 (1U << 7)
|
|
||||||
#define HID_MASK_SELECT (1U << 8)
|
|
||||||
#define HID_MASK_START (1U << 9)
|
|
||||||
#define HID_MASK_L3 (1U << 10)
|
|
||||||
#define HID_MASK_R3 (1U << 11)
|
|
||||||
#define HID_MASK_PS (1U << 12)
|
|
||||||
#define HID_MASK_TP (1U << 13)
|
|
||||||
|
|
||||||
// HID analog sticks only report 8 bits
|
|
||||||
#define HID_JOYSTICK_MIN 0x00
|
|
||||||
#define HID_JOYSTICK_MID 0x80
|
|
||||||
#define HID_JOYSTICK_MAX 0xFF
|
|
||||||
|
|
||||||
typedef struct __attribute((packed, aligned(1)))
|
|
||||||
{
|
|
||||||
// digital buttons, 0 = off, 1 = on
|
|
||||||
|
|
||||||
uint8_t square_btn : 1;
|
|
||||||
uint8_t cross_btn : 1;
|
|
||||||
uint8_t circle_btn : 1;
|
|
||||||
uint8_t triangle_btn : 1;
|
|
||||||
|
|
||||||
uint8_t l1_btn : 1;
|
|
||||||
uint8_t r1_btn : 1;
|
|
||||||
uint8_t l2_btn : 1;
|
|
||||||
uint8_t r2_btn : 1;
|
|
||||||
|
|
||||||
uint8_t select_btn : 1;
|
|
||||||
uint8_t start_btn : 1;
|
|
||||||
uint8_t l3_btn : 1;
|
|
||||||
uint8_t r3_btn : 1;
|
|
||||||
|
|
||||||
uint8_t ps_btn : 1;
|
|
||||||
uint8_t tp_btn : 1;
|
|
||||||
// uint8_t l2_btn_alt : 1;
|
|
||||||
|
|
||||||
// uint8_t r2_btn_alt : 1;
|
|
||||||
uint8_t : 2;
|
|
||||||
|
|
||||||
// digital direction, use the dir_* constants(enum)
|
|
||||||
// 8 = center, 0 = up, 1 = up/right, 2 = right, 3 = right/down
|
|
||||||
// 4 = down, 5 = down/left, 6 = left, 7 = left/up
|
|
||||||
|
|
||||||
uint8_t direction;
|
|
||||||
|
|
||||||
// left and right analog sticks, 0x00 left/up, 0x80 middle, 0xff right/down
|
|
||||||
|
|
||||||
uint8_t l_x_axis;
|
|
||||||
uint8_t l_y_axis;
|
|
||||||
uint8_t r_x_axis;
|
|
||||||
uint8_t r_y_axis;
|
|
||||||
|
|
||||||
// Gonna assume these are button analog values for the d-pad.
|
|
||||||
// NOTE: NOT EVEN SURE THIS IS RIGHT, OR IN THE CORRECT ORDER
|
|
||||||
uint8_t right_axis;
|
|
||||||
uint8_t left_axis;
|
|
||||||
uint8_t up_axis;
|
|
||||||
uint8_t down_axis;
|
|
||||||
|
|
||||||
// button axis, 0x00 = unpressed, 0xff = fully pressed
|
|
||||||
|
|
||||||
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;
|
|
||||||
} HIDReport;
|
|
||||||
|
|
||||||
static const uint8_t hid_string_language[] = { 0x09, 0x04 };
|
|
||||||
static const uint8_t hid_string_manufacturer[] = "Raspberry Pi";
|
|
||||||
static const uint8_t hid_string_product[] = "OGX-Mini";
|
|
||||||
static const uint8_t hid_string_version[] = "1.0";
|
|
||||||
|
|
||||||
static const uint8_t *hid_string_descriptors[] __attribute__((unused)) =
|
|
||||||
{
|
|
||||||
hid_string_language,
|
|
||||||
hid_string_manufacturer,
|
|
||||||
hid_string_product,
|
|
||||||
hid_string_version
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t hid_device_descriptor[] =
|
|
||||||
{
|
|
||||||
18, // bLength
|
|
||||||
1, // bDescriptorType
|
|
||||||
0x00, 0x02, // bcdUSB
|
|
||||||
0, // bDeviceClass
|
|
||||||
0, // bDeviceSubClass
|
|
||||||
0, // bDeviceProtocol
|
|
||||||
ENDPOINT0_SIZE, // bMaxPacketSize0
|
|
||||||
LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor
|
|
||||||
LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct
|
|
||||||
0x00, 0x01, // bcdDevice
|
|
||||||
1, // iManufacturer
|
|
||||||
2, // iProduct
|
|
||||||
0, // iSerialNumber
|
|
||||||
1 // bNumConfigurations
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t hid_report_descriptor[] =
|
|
||||||
{
|
|
||||||
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
|
|
||||||
0x09, 0x05, // USAGE (Gamepad)
|
|
||||||
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, 0x0e, // REPORT_COUNT (13)
|
|
||||||
0x05, 0x09, // USAGE_PAGE (Button)
|
|
||||||
0x19, 0x01, // USAGE_MINIMUM (Button 1)
|
|
||||||
0x29, 0x0e, // USAGE_MAXIMUM (Button 13)
|
|
||||||
0x81, 0x02, // INPUT (Data,Var,Abs)
|
|
||||||
0x95, 0x02, // REPORT_COUNT (3)
|
|
||||||
0x81, 0x01, // INPUT (Cnst,Ary,Abs)
|
|
||||||
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
|
|
||||||
0x25, 0x07, // LOGICAL_MAXIMUM (7)
|
|
||||||
0x46, 0x3b, 0x01, // PHYSICAL_MAXIMUM (315)
|
|
||||||
0x75, 0x04, // REPORT_SIZE (4)
|
|
||||||
0x95, 0x01, // REPORT_COUNT (1)
|
|
||||||
0x65, 0x14, // UNIT (Eng Rot:Angular Pos)
|
|
||||||
0x09, 0x39, // USAGE (Hat switch)
|
|
||||||
0x81, 0x42, // INPUT (Data,Var,Abs,Null)
|
|
||||||
0x65, 0x00, // UNIT (None)
|
|
||||||
0x95, 0x01, // REPORT_COUNT (1)
|
|
||||||
0x81, 0x01, // INPUT (Cnst,Ary,Abs)
|
|
||||||
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 (6)
|
|
||||||
0x81, 0x02, // INPUT (Data,Var,Abs)
|
|
||||||
0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Specific)
|
|
||||||
0x09, 0x20, // Unknown
|
|
||||||
0x09, 0x21, // Unknown
|
|
||||||
0x09, 0x22, // Unknown
|
|
||||||
0x09, 0x23, // Unknown
|
|
||||||
0x09, 0x24, // Unknown
|
|
||||||
0x09, 0x25, // Unknown
|
|
||||||
0x09, 0x26, // Unknown
|
|
||||||
0x09, 0x27, // Unknown
|
|
||||||
0x09, 0x28, // Unknown
|
|
||||||
0x09, 0x29, // Unknown
|
|
||||||
0x09, 0x2a, // Unknown
|
|
||||||
0x09, 0x2b, // Unknown
|
|
||||||
0x95, 0x0c, // REPORT_COUNT (12)
|
|
||||||
0x81, 0x02, // INPUT (Data,Var,Abs)
|
|
||||||
0x0a, 0x21, 0x26, // Unknown
|
|
||||||
0x95, 0x08, // REPORT_COUNT (8)
|
|
||||||
0xb1, 0x02, // FEATURE (Data,Var,Abs)
|
|
||||||
0xc0 // END_COLLECTION
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t hid_hid_descriptor[] =
|
|
||||||
{
|
|
||||||
0x09, // bLength
|
|
||||||
0x21, // bDescriptorType (HID)
|
|
||||||
0x11, 0x01, // bcdHID 1.11
|
|
||||||
0x00, // bCountryCode
|
|
||||||
0x01, // bNumDescriptors
|
|
||||||
0x22, // bDescriptorType[0] (HID)
|
|
||||||
sizeof(hid_report_descriptor), 0x00, // wDescriptorLength[0] 90
|
|
||||||
};
|
|
||||||
|
|
||||||
#define CONFIG1_DESC_SIZE (9+9+9+7)
|
|
||||||
static const uint8_t hid_configuration_descriptor[] =
|
|
||||||
{
|
|
||||||
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
|
|
||||||
9, // bLength;
|
|
||||||
2, // bDescriptorType;
|
|
||||||
LSB(CONFIG1_DESC_SIZE), // wTotalLength
|
|
||||||
MSB(CONFIG1_DESC_SIZE),
|
|
||||||
1, // bNumInterfaces
|
|
||||||
1, // bConfigurationValue
|
|
||||||
0, // iConfiguration
|
|
||||||
0x80, // bmAttributes
|
|
||||||
50, // bMaxPower
|
|
||||||
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
|
|
||||||
9, // bLength
|
|
||||||
4, // bDescriptorType
|
|
||||||
GAMEPAD_INTERFACE, // bInterfaceNumber
|
|
||||||
0, // bAlternateSetting
|
|
||||||
1, // bNumEndpoints
|
|
||||||
0x03, // bInterfaceClass (0x03 = HID)
|
|
||||||
0x00, // bInterfaceSubClass (0x00 = No Boot)
|
|
||||||
0x00, // bInterfaceProtocol (0x00 = No Protocol)
|
|
||||||
0, // iInterface
|
|
||||||
// HID interface descriptor, HID 1.11 spec, section 6.2.1
|
|
||||||
9, // bLength
|
|
||||||
0x21, // bDescriptorType
|
|
||||||
0x11, 0x01, // bcdHID
|
|
||||||
0, // bCountryCode
|
|
||||||
1, // bNumDescriptors
|
|
||||||
0x22, // bDescriptorType
|
|
||||||
sizeof(hid_report_descriptor), // wDescriptorLength
|
|
||||||
0,
|
|
||||||
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
|
|
||||||
7, // bLength
|
|
||||||
5, // bDescriptorType
|
|
||||||
GAMEPAD_ENDPOINT | 0x80, // bEndpointAddress
|
|
||||||
0x03, // bmAttributes (0x03=intr)
|
|
||||||
GAMEPAD_SIZE, 0, // wMaxPacketSize
|
|
||||||
1 // bInterval (1 ms)
|
|
||||||
};
|
|
||||||
@@ -1,298 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define HID_ENDPOINT_SIZE 64
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
*
|
|
||||||
* Endpoint Buffer Configuration
|
|
||||||
*
|
|
||||||
**************************************************************************/
|
|
||||||
|
|
||||||
#define ENDPOINT0_SIZE 64
|
|
||||||
|
|
||||||
#define GAMEPAD_INTERFACE 0
|
|
||||||
#define GAMEPAD_ENDPOINT 1
|
|
||||||
#define GAMEPAD_SIZE 64
|
|
||||||
|
|
||||||
#define LSB(n) (n & 255)
|
|
||||||
#define MSB(n) ((n >> 8) & 255)
|
|
||||||
|
|
||||||
#define PS3_HAT_UP 0x00
|
|
||||||
#define PS3_HAT_UPRIGHT 0x01
|
|
||||||
#define PS3_HAT_RIGHT 0x02
|
|
||||||
#define PS3_HAT_DOWNRIGHT 0x03
|
|
||||||
#define PS3_HAT_DOWN 0x04
|
|
||||||
#define PS3_HAT_DOWNLEFT 0x05
|
|
||||||
#define PS3_HAT_LEFT 0x06
|
|
||||||
#define PS3_HAT_UPLEFT 0x07
|
|
||||||
#define PS3_HAT_NOTHING 0x08
|
|
||||||
|
|
||||||
#define PS3_MASK_SQUARE (1U << 0)
|
|
||||||
#define PS3_MASK_CROSS (1U << 1)
|
|
||||||
#define PS3_MASK_CIRCLE (1U << 2)
|
|
||||||
#define PS3_MASK_TRIANGLE (1U << 3)
|
|
||||||
#define PS3_MASK_L1 (1U << 4)
|
|
||||||
#define PS3_MASK_R1 (1U << 5)
|
|
||||||
#define PS3_MASK_L2 (1U << 6)
|
|
||||||
#define PS3_MASK_R2 (1U << 7)
|
|
||||||
#define PS3_MASK_SELECT (1U << 8)
|
|
||||||
#define PS3_MASK_START (1U << 9)
|
|
||||||
#define PS3_MASK_L3 (1U << 10)
|
|
||||||
#define PS3_MASK_R3 (1U << 11)
|
|
||||||
#define PS3_MASK_PS (1U << 12)
|
|
||||||
#define PS3_MASK_TP (1U << 13)
|
|
||||||
|
|
||||||
#define PS3_JOYSTICK_MIN 0x00
|
|
||||||
#define PS3_JOYSTICK_MID 0x80
|
|
||||||
#define PS3_JOYSTICK_MAX 0xFF
|
|
||||||
|
|
||||||
typedef struct __attribute((packed, aligned(1)))
|
|
||||||
{
|
|
||||||
uint8_t report_id;
|
|
||||||
uint8_t unk0;
|
|
||||||
|
|
||||||
uint8_t select : 1;
|
|
||||||
uint8_t l3 : 1;
|
|
||||||
uint8_t r3 : 1;
|
|
||||||
uint8_t start : 1;
|
|
||||||
uint8_t up : 1;
|
|
||||||
uint8_t right : 1;
|
|
||||||
uint8_t down : 1;
|
|
||||||
uint8_t left : 1;
|
|
||||||
|
|
||||||
uint8_t l2 : 1;
|
|
||||||
uint8_t r2 : 1;
|
|
||||||
uint8_t l1 : 1;
|
|
||||||
uint8_t r1 : 1;
|
|
||||||
uint8_t triangle : 1;
|
|
||||||
uint8_t circle : 1;
|
|
||||||
uint8_t cross : 1;
|
|
||||||
uint8_t square : 1;
|
|
||||||
|
|
||||||
uint8_t ps : 1;
|
|
||||||
uint8_t : 0;
|
|
||||||
|
|
||||||
uint8_t unknown1;
|
|
||||||
|
|
||||||
uint8_t left_x;
|
|
||||||
uint8_t left_y;
|
|
||||||
uint8_t right_x;
|
|
||||||
uint8_t right_y;
|
|
||||||
|
|
||||||
uint8_t unknown2[4];
|
|
||||||
|
|
||||||
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 unknown3[15];
|
|
||||||
|
|
||||||
int16_t acceler_x;
|
|
||||||
int16_t acceler_y;
|
|
||||||
int16_t acceler_z;
|
|
||||||
|
|
||||||
int16_t velocity_z;
|
|
||||||
} Dualshock3Report;
|
|
||||||
|
|
||||||
struct sixaxis_led {
|
|
||||||
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%) */
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct sixaxis_rumble {
|
|
||||||
uint8_t padding;
|
|
||||||
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 */
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct sixaxis_output_report {
|
|
||||||
struct sixaxis_rumble rumble;
|
|
||||||
uint8_t padding[4];
|
|
||||||
uint8_t leds_bitmap; /* bitmap of enabled LEDs: LED_1 = 0x02, LED_2 = 0x04, ... */
|
|
||||||
struct sixaxis_led led[4]; /* LEDx at (4 - x) */
|
|
||||||
struct sixaxis_led _reserved; /* LED5, not actually soldered */
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
static const uint8_t ps3_string_language[] = { 0x09, 0x04 };
|
|
||||||
static const uint8_t ps3_string_manufacturer[] = "Sony";
|
|
||||||
static const uint8_t ps3_string_product[] = "PLAYSTATION(R)3 Controller";
|
|
||||||
static const uint8_t ps3_string_version[] = "1.0";
|
|
||||||
|
|
||||||
static const uint8_t *ps3_string_descriptors[] __attribute__((unused)) =
|
|
||||||
{
|
|
||||||
ps3_string_language,
|
|
||||||
ps3_string_manufacturer,
|
|
||||||
ps3_string_product,
|
|
||||||
ps3_string_version
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t ps3_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
|
|
||||||
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 ps3_report_descriptor[] =
|
|
||||||
{
|
|
||||||
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
|
||||||
0x09, 0x04, // Usage (Joystick)
|
|
||||||
0xA1, 0x01, // Collection (Application)
|
|
||||||
0xA1, 0x02, // Collection (Logical)
|
|
||||||
0x85, 0x01, // Report ID (1)
|
|
||||||
0x75, 0x08, // Report Size (8)
|
|
||||||
0x95, 0x01, // Report Count (1)
|
|
||||||
0x15, 0x00, // Logical Minimum (0)
|
|
||||||
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
|
||||||
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
|
||||||
0x75, 0x01, // Report Size (1)
|
|
||||||
0x95, 0x13, // Report Count (19)
|
|
||||||
0x15, 0x00, // Logical Minimum (0)
|
|
||||||
0x25, 0x01, // Logical Maximum (1)
|
|
||||||
0x35, 0x00, // Physical Minimum (0)
|
|
||||||
0x45, 0x01, // Physical Maximum (1)
|
|
||||||
0x05, 0x09, // Usage Page (Button)
|
|
||||||
0x19, 0x01, // Usage Minimum (0x01)
|
|
||||||
0x29, 0x13, // Usage Maximum (0x13)
|
|
||||||
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
|
||||||
0x75, 0x01, // Report Size (1)
|
|
||||||
0x95, 0x0D, // Report Count (13)
|
|
||||||
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
|
|
||||||
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
|
||||||
0x15, 0x00, // Logical Minimum (0)
|
|
||||||
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
|
||||||
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
|
||||||
0x09, 0x01, // Usage (Pointer)
|
|
||||||
0xA1, 0x00, // Collection (Physical)
|
|
||||||
0x75, 0x08, // Report Size (8)
|
|
||||||
0x95, 0x04, // Report Count (4)
|
|
||||||
0x35, 0x00, // Physical Minimum (0)
|
|
||||||
0x46, 0xFF, 0x00, // Physical Maximum (255)
|
|
||||||
0x09, 0x30, // Usage (X)
|
|
||||||
0x09, 0x31, // Usage (Y)
|
|
||||||
0x09, 0x32, // Usage (Z)
|
|
||||||
0x09, 0x35, // Usage (Rz)
|
|
||||||
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
|
||||||
0xC0, // End Collection
|
|
||||||
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
|
||||||
0x75, 0x08, // Report Size (8)
|
|
||||||
0x95, 0x27, // Report Count (39)
|
|
||||||
0x09, 0x01, // Usage (Pointer)
|
|
||||||
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
|
||||||
0x75, 0x08, // Report Size (8)
|
|
||||||
0x95, 0x30, // Report Count (48)
|
|
||||||
0x09, 0x01, // Usage (Pointer)
|
|
||||||
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
|
||||||
0x75, 0x08, // Report Size (8)
|
|
||||||
0x95, 0x30, // Report Count (48)
|
|
||||||
0x09, 0x01, // Usage (Pointer)
|
|
||||||
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
|
||||||
0xC0, // End Collection
|
|
||||||
0xA1, 0x02, // Collection (Logical)
|
|
||||||
0x85, 0x02, // Report ID (2)
|
|
||||||
0x75, 0x08, // Report Size (8)
|
|
||||||
0x95, 0x30, // Report Count (48)
|
|
||||||
0x09, 0x01, // Usage (Pointer)
|
|
||||||
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
|
||||||
0xC0, // End Collection
|
|
||||||
0xA1, 0x02, // Collection (Logical)
|
|
||||||
0x85, 0xEE, // Report ID (-18)
|
|
||||||
0x75, 0x08, // Report Size (8)
|
|
||||||
0x95, 0x30, // Report Count (48)
|
|
||||||
0x09, 0x01, // Usage (Pointer)
|
|
||||||
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
|
||||||
0xC0, // End Collection
|
|
||||||
0xA1, 0x02, // Collection (Logical)
|
|
||||||
0x85, 0xEF, // Report ID (-17)
|
|
||||||
0x75, 0x08, // Report Size (8)
|
|
||||||
0x95, 0x30, // Report Count (48)
|
|
||||||
0x09, 0x01, // Usage (Pointer)
|
|
||||||
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
|
||||||
0xC0, // End Collection
|
|
||||||
0xC0, // End Collection
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t ps3_hid_descriptor[] =
|
|
||||||
{
|
|
||||||
0x09, // bLength
|
|
||||||
0x21, // bDescriptorType (HID)
|
|
||||||
0x11, 0x01, // bcdHID 1.11
|
|
||||||
0x00, // bCountryCode
|
|
||||||
0x01, // bNumDescriptors
|
|
||||||
0x22, // bDescriptorType[0] (HID)
|
|
||||||
0x94, 0x00, // wDescriptorLength[0] 148
|
|
||||||
};
|
|
||||||
|
|
||||||
// #define CONFIG1_DESC_SIZE (9+9+9+7)
|
|
||||||
static const uint8_t ps3_configuration_descriptor[] =
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
0x94, 0x00, // wDescriptorLength[0] 148
|
|
||||||
|
|
||||||
0x07, // bLength
|
|
||||||
0x05, // bDescriptorType (Endpoint)
|
|
||||||
0x81, // bEndpointAddress (IN/D2H)
|
|
||||||
0x03, // bmAttributes (Interrupt)
|
|
||||||
0x40, 0x00, // wMaxPacketSize 64
|
|
||||||
0x0A, // bInterval 10 (unit depends on device speed)
|
|
||||||
|
|
||||||
0x07, // bLength
|
|
||||||
0x05, // bDescriptorType (Endpoint)
|
|
||||||
0x02, // bEndpointAddress (OUT/H2D)
|
|
||||||
0x03, // bmAttributes (Interrupt)
|
|
||||||
0x40, 0x00, // wMaxPacketSize 64
|
|
||||||
0x0A, // bInterval 10 (unit depends on device speed)
|
|
||||||
};
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define PSCLASSIC_ENDPOINT_SIZE 64
|
|
||||||
|
|
||||||
// Button report (16 bits)
|
|
||||||
#define PSCLASSIC_MASK_TRIANGLE (1U << 0)
|
|
||||||
#define PSCLASSIC_MASK_CIRCLE (1U << 1)
|
|
||||||
#define PSCLASSIC_MASK_CROSS (1U << 2)
|
|
||||||
#define PSCLASSIC_MASK_SQUARE (1U << 3)
|
|
||||||
#define PSCLASSIC_MASK_L2 (1U << 4)
|
|
||||||
#define PSCLASSIC_MASK_R2 (1U << 5)
|
|
||||||
#define PSCLASSIC_MASK_L1 (1U << 6)
|
|
||||||
#define PSCLASSIC_MASK_R1 (1U << 7)
|
|
||||||
#define PSCLASSIC_MASK_SELECT (1U << 8)
|
|
||||||
#define PSCLASSIC_MASK_START (1U << 9)
|
|
||||||
|
|
||||||
#define PSCLASSIC_MASK_UP_LEFT 0x0000
|
|
||||||
#define PSCLASSIC_MASK_UP 0x0400
|
|
||||||
#define PSCLASSIC_MASK_UP_RIGHT 0x0800
|
|
||||||
#define PSCLASSIC_MASK_LEFT 0x1000
|
|
||||||
#define PSCLASSIC_MASK_CENTER 0x1400
|
|
||||||
#define PSCLASSIC_MASK_RIGHT 0x1800
|
|
||||||
#define PSCLASSIC_MASK_DOWN_LEFT 0x2000
|
|
||||||
#define PSCLASSIC_MASK_DOWN 0x2400
|
|
||||||
#define PSCLASSIC_MASK_DOWN_RIGHT 0x2800
|
|
||||||
|
|
||||||
#define PSCLASSIC_JOYSTICK_MID 0x7f
|
|
||||||
|
|
||||||
typedef struct __attribute((packed, aligned(1)))
|
|
||||||
{
|
|
||||||
uint16_t buttons; // 10 buttons (1 bit each)
|
|
||||||
} PSClassicReport;
|
|
||||||
|
|
||||||
static const uint8_t psclassic_string_language[] = { 0x09, 0x04 };
|
|
||||||
static const uint8_t psclassic_string_manufacturer[] = "Sony Interactive Entertainment";
|
|
||||||
static const uint8_t psclassic_string_product[] = "Controller";
|
|
||||||
static const uint8_t psclassic_string_version[] = { };
|
|
||||||
|
|
||||||
static const uint8_t *psclassic_string_descriptors[] __attribute__((unused)) =
|
|
||||||
{
|
|
||||||
psclassic_string_language,
|
|
||||||
psclassic_string_manufacturer,
|
|
||||||
psclassic_string_product,
|
|
||||||
psclassic_string_version
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t psclassic_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
|
|
||||||
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 psclassic_hid_descriptor[] =
|
|
||||||
{
|
|
||||||
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 psclassic_configuration_descriptor[] =
|
|
||||||
{
|
|
||||||
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 psclassic_report_descriptor[] =
|
|
||||||
{
|
|
||||||
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
|
|
||||||
};
|
|
||||||
@@ -1,244 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define SWITCH_ENDPOINT_SIZE 64
|
|
||||||
|
|
||||||
// HAT report (4 bits)
|
|
||||||
#define SWITCH_HAT_UP 0x00
|
|
||||||
#define SWITCH_HAT_UPRIGHT 0x01
|
|
||||||
#define SWITCH_HAT_RIGHT 0x02
|
|
||||||
#define SWITCH_HAT_DOWNRIGHT 0x03
|
|
||||||
#define SWITCH_HAT_DOWN 0x04
|
|
||||||
#define SWITCH_HAT_DOWNLEFT 0x05
|
|
||||||
#define SWITCH_HAT_LEFT 0x06
|
|
||||||
#define SWITCH_HAT_UPLEFT 0x07
|
|
||||||
#define SWITCH_HAT_NOTHING 0x08
|
|
||||||
|
|
||||||
// Button report (16 bits)
|
|
||||||
#define SWITCH_MASK_Y (1U << 0)
|
|
||||||
#define SWITCH_MASK_B (1U << 1)
|
|
||||||
#define SWITCH_MASK_A (1U << 2)
|
|
||||||
#define SWITCH_MASK_X (1U << 3)
|
|
||||||
#define SWITCH_MASK_L (1U << 4)
|
|
||||||
#define SWITCH_MASK_R (1U << 5)
|
|
||||||
#define SWITCH_MASK_ZL (1U << 6)
|
|
||||||
#define SWITCH_MASK_ZR (1U << 7)
|
|
||||||
#define SWITCH_MASK_MINUS (1U << 8)
|
|
||||||
#define SWITCH_MASK_PLUS (1U << 9)
|
|
||||||
#define SWITCH_MASK_L3 (1U << 10)
|
|
||||||
#define SWITCH_MASK_R3 (1U << 11)
|
|
||||||
#define SWITCH_MASK_HOME (1U << 12)
|
|
||||||
#define SWITCH_MASK_CAPTURE (1U << 13)
|
|
||||||
|
|
||||||
// Switch analog sticks only report 8 bits
|
|
||||||
#define SWITCH_JOYSTICK_MIN 0x00
|
|
||||||
#define SWITCH_JOYSTICK_MID 0x80
|
|
||||||
#define SWITCH_JOYSTICK_MAX 0xFF
|
|
||||||
|
|
||||||
struct SwitchProReport
|
|
||||||
{
|
|
||||||
uint8_t reportId;
|
|
||||||
uint8_t timer;
|
|
||||||
|
|
||||||
uint8_t connInfo : 4;
|
|
||||||
uint8_t battery : 4;
|
|
||||||
|
|
||||||
uint8_t y : 1;
|
|
||||||
uint8_t x : 1;
|
|
||||||
uint8_t b : 1;
|
|
||||||
uint8_t a : 1;
|
|
||||||
uint8_t : 2;
|
|
||||||
uint8_t r : 1;
|
|
||||||
uint8_t zr : 1;
|
|
||||||
|
|
||||||
uint8_t minus : 1;
|
|
||||||
uint8_t plus : 1;
|
|
||||||
uint8_t stickR : 1;
|
|
||||||
uint8_t stickL : 1;
|
|
||||||
uint8_t home : 1;
|
|
||||||
uint8_t capture : 1;
|
|
||||||
uint8_t : 0;
|
|
||||||
|
|
||||||
uint8_t down : 1;
|
|
||||||
uint8_t up : 1;
|
|
||||||
uint8_t right : 1;
|
|
||||||
uint8_t left : 1;
|
|
||||||
uint8_t : 2;
|
|
||||||
uint8_t l : 1;
|
|
||||||
uint8_t zl : 1;
|
|
||||||
|
|
||||||
uint16_t leftX : 12;
|
|
||||||
uint16_t leftY : 12;
|
|
||||||
uint16_t rightX : 12;
|
|
||||||
uint16_t rightY : 12;
|
|
||||||
|
|
||||||
uint8_t vibrator;
|
|
||||||
|
|
||||||
uint16_t accelerX;
|
|
||||||
uint16_t accelerY;
|
|
||||||
uint16_t accelerZ;
|
|
||||||
|
|
||||||
uint16_t velocityX;
|
|
||||||
uint16_t velocityY;
|
|
||||||
uint16_t velocityZ;
|
|
||||||
}
|
|
||||||
__attribute__((packed));
|
|
||||||
|
|
||||||
typedef struct __attribute((packed, aligned(1)))
|
|
||||||
{
|
|
||||||
uint16_t buttons;
|
|
||||||
uint8_t hat;
|
|
||||||
uint8_t lx;
|
|
||||||
uint8_t ly;
|
|
||||||
uint8_t rx;
|
|
||||||
uint8_t ry;
|
|
||||||
uint8_t vendor;
|
|
||||||
} SwitchReport;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint16_t buttons;
|
|
||||||
uint8_t hat;
|
|
||||||
uint8_t lx;
|
|
||||||
uint8_t ly;
|
|
||||||
uint8_t rx;
|
|
||||||
uint8_t ry;
|
|
||||||
} SwitchOutReport;
|
|
||||||
|
|
||||||
|
|
||||||
static const uint8_t switch_string_language[] = { 0x09, 0x04 };
|
|
||||||
static const uint8_t switch_string_manufacturer[] = "HORI CO.,LTD.";
|
|
||||||
static const uint8_t switch_string_product[] = "POKKEN CONTROLLER";
|
|
||||||
static const uint8_t switch_string_version[] = "1.0";
|
|
||||||
|
|
||||||
static const uint8_t *switch_string_descriptors[] __attribute__((unused)) =
|
|
||||||
{
|
|
||||||
switch_string_language,
|
|
||||||
switch_string_manufacturer,
|
|
||||||
switch_string_product,
|
|
||||||
switch_string_version
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t switch_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
|
|
||||||
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 switch_hid_descriptor[] =
|
|
||||||
{
|
|
||||||
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 switch_configuration_descriptor[] =
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t switch_report_descriptor[] =
|
|
||||||
{
|
|
||||||
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
|
|
||||||
};
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "tusb.h"
|
|
||||||
#include "bsp/board_api.h"
|
|
||||||
|
|
||||||
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
|
|
||||||
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
|
|
||||||
*
|
|
||||||
* Auto ProductID layout's Bitmap:
|
|
||||||
* [MSB] HID | MSC | CDC [LSB]
|
|
||||||
*/
|
|
||||||
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
|
|
||||||
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
|
|
||||||
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
|
|
||||||
|
|
||||||
#define USB_VID 0xCafe
|
|
||||||
#define USB_BCD 0x0200
|
|
||||||
|
|
||||||
tusb_desc_device_t const usbserial_device_descriptor =
|
|
||||||
{
|
|
||||||
.bLength = sizeof(tusb_desc_device_t),
|
|
||||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
|
||||||
.bcdUSB = USB_BCD,
|
|
||||||
|
|
||||||
// Use Interface Association Descriptor (IAD) for CDC
|
|
||||||
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
|
|
||||||
.bDeviceClass = TUSB_CLASS_MISC,
|
|
||||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
|
||||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
|
||||||
|
|
||||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
|
||||||
|
|
||||||
.idVendor = USB_VID,
|
|
||||||
.idProduct = USB_PID,
|
|
||||||
.bcdDevice = 0x0100,
|
|
||||||
|
|
||||||
.iManufacturer = 0x01,
|
|
||||||
.iProduct = 0x02,
|
|
||||||
.iSerialNumber = 0x03,
|
|
||||||
|
|
||||||
.bNumConfigurations = 0x01
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
ITF_NUM_CDC = 0,
|
|
||||||
ITF_NUM_CDC_DATA,
|
|
||||||
ITF_NUM_TOTAL
|
|
||||||
};
|
|
||||||
|
|
||||||
#define EPNUM_CDC_NOTIF 0x81
|
|
||||||
#define EPNUM_CDC_OUT 0x02
|
|
||||||
#define EPNUM_CDC_IN 0x82
|
|
||||||
|
|
||||||
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
|
|
||||||
|
|
||||||
uint8_t const usbserial_configuration_descriptor[] =
|
|
||||||
{
|
|
||||||
// Config number, interface count, string index, total length, attribute, power in mA
|
|
||||||
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
|
|
||||||
|
|
||||||
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
|
|
||||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
STRID_LANGID = 0,
|
|
||||||
STRID_MANUFACTURER,
|
|
||||||
STRID_PRODUCT,
|
|
||||||
STRID_SERIAL,
|
|
||||||
};
|
|
||||||
|
|
||||||
// array of pointer to string descriptors
|
|
||||||
char const *string_desc_arr[] =
|
|
||||||
{
|
|
||||||
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
|
|
||||||
"TinyUSB", // 1: Manufacturer
|
|
||||||
"TinyUSB Device", // 2: Product
|
|
||||||
NULL, // 3: Serials will use unique ID if possible
|
|
||||||
"TinyUSB CDC", // 4: CDC Interface
|
|
||||||
};
|
|
||||||
|
|
||||||
static uint16_t _desc_str[32 + 1];
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2021 Jason Skuby (mytechtoybox.com)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define XINPUT_ENDPOINT_SIZE 20
|
|
||||||
|
|
||||||
// Buttons 1 (8 bits)
|
|
||||||
// TODO: Consider using an enum class here.
|
|
||||||
#define XBOX_MASK_UP (1U << 0)
|
|
||||||
#define XBOX_MASK_DOWN (1U << 1)
|
|
||||||
#define XBOX_MASK_LEFT (1U << 2)
|
|
||||||
#define XBOX_MASK_RIGHT (1U << 3)
|
|
||||||
#define XBOX_MASK_START (1U << 4)
|
|
||||||
#define XBOX_MASK_BACK (1U << 5)
|
|
||||||
#define XBOX_MASK_LS (1U << 6)
|
|
||||||
#define XBOX_MASK_RS (1U << 7)
|
|
||||||
|
|
||||||
// Buttons 2 (8 bits)
|
|
||||||
// TODO: Consider using an enum class here.
|
|
||||||
#define XBOX_MASK_LB (1U << 0)
|
|
||||||
#define XBOX_MASK_RB (1U << 1)
|
|
||||||
#define XBOX_MASK_HOME (1U << 2)
|
|
||||||
//#define UNUSED (1U << 3)
|
|
||||||
#define XBOX_MASK_A (1U << 4)
|
|
||||||
#define XBOX_MASK_B (1U << 5)
|
|
||||||
#define XBOX_MASK_X (1U << 6)
|
|
||||||
#define XBOX_MASK_Y (1U << 7)
|
|
||||||
|
|
||||||
#define XBOX_REPORT_TYPE_RUMBLE 0x00
|
|
||||||
#define XBOX_REPORT_TYPE_LED 0x01
|
|
||||||
|
|
||||||
typedef struct __attribute((packed, aligned(1)))
|
|
||||||
{
|
|
||||||
uint8_t report_id;
|
|
||||||
uint8_t report_size;
|
|
||||||
uint8_t buttons1;
|
|
||||||
uint8_t buttons2;
|
|
||||||
uint8_t lt;
|
|
||||||
uint8_t rt;
|
|
||||||
int16_t lx;
|
|
||||||
int16_t ly;
|
|
||||||
int16_t rx;
|
|
||||||
int16_t ry;
|
|
||||||
uint8_t _reserved[6];
|
|
||||||
} XInputReport;
|
|
||||||
|
|
||||||
typedef struct __attribute((packed, aligned(1)))
|
|
||||||
{
|
|
||||||
uint8_t report_type;
|
|
||||||
uint8_t report_size;
|
|
||||||
uint8_t led;
|
|
||||||
uint8_t lrumble;
|
|
||||||
uint8_t rrumble;
|
|
||||||
uint8_t reserved[3];
|
|
||||||
} XInputOutReport;
|
|
||||||
|
|
||||||
static const uint8_t xinput_string_language[] = { 0x09, 0x04 };
|
|
||||||
static const uint8_t xinput_string_manfacturer[] = "Microsoft";
|
|
||||||
static const uint8_t xinput_string_product[] = "XInput STANDARD GAMEPAD";
|
|
||||||
static const uint8_t xinput_string_version[] = "1.0";
|
|
||||||
|
|
||||||
static const uint8_t *xinput_string_descriptors[] __attribute__((unused)) =
|
|
||||||
{
|
|
||||||
xinput_string_language,
|
|
||||||
xinput_string_manfacturer,
|
|
||||||
xinput_string_product,
|
|
||||||
xinput_string_version
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t xinput_device_descriptor[] =
|
|
||||||
{
|
|
||||||
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 xinput_configuration_descriptor[] =
|
|
||||||
{
|
|
||||||
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
|
|
||||||
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)
|
|
||||||
};
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "usbd/xboxog/xid/xid_driver.h"
|
|
||||||
|
|
||||||
#define XboxOriginalReport USB_XboxGamepad_InReport_t
|
|
||||||
|
|
||||||
static const uint8_t xboxoriginal_string_language[] = { 0x09, 0x04 };
|
|
||||||
static const uint8_t xboxoriginal_string_manufacturer[] = "";
|
|
||||||
static const uint8_t xboxoriginal_string_product[] = "";
|
|
||||||
static const uint8_t xboxoriginal_string_version[] = "1.0";
|
|
||||||
|
|
||||||
static const uint8_t *xboxoriginal_string_descriptors[] __attribute__((unused)) =
|
|
||||||
{
|
|
||||||
xboxoriginal_string_language,
|
|
||||||
xboxoriginal_string_manufacturer,
|
|
||||||
xboxoriginal_string_product,
|
|
||||||
xboxoriginal_string_version
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t *xboxoriginal_device_descriptor = (const uint8_t*)&XID_DESC_DEVICE;
|
|
||||||
|
|
||||||
static const uint8_t *xboxoriginal_configuration_descriptor = (const uint8_t*)&XID_DESC_CONFIGURATION;
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "pico/stdlib.h"
|
#include "pico/stdlib.h"
|
||||||
#include "pico/multicore.h"
|
#include "pico/multicore.h"
|
||||||
#include "hardware/flash.h"
|
#include "hardware/flash.h"
|
||||||
@@ -16,7 +15,10 @@
|
|||||||
#define FLASH_TARGET_OFFSET (256 * 1024)
|
#define FLASH_TARGET_OFFSET (256 * 1024)
|
||||||
#define FLASH_SIZE_BYTES (2 * 1024 * 1024)
|
#define FLASH_SIZE_BYTES (2 * 1024 * 1024)
|
||||||
|
|
||||||
void system_reset() {
|
InputMode current_input_mode;
|
||||||
|
|
||||||
|
void system_reset()
|
||||||
|
{
|
||||||
AIRCR_REG = AIRCR_VECTKEY | AIRCR_SYSRESETREQ;
|
AIRCR_REG = AIRCR_VECTKEY | AIRCR_SYSRESETREQ;
|
||||||
while(1);
|
while(1);
|
||||||
}
|
}
|
||||||
@@ -36,44 +38,42 @@ bool store_input_mode(enum InputMode new_mode)
|
|||||||
|
|
||||||
restore_interrupts(saved_interrupts);
|
restore_interrupts(saved_interrupts);
|
||||||
|
|
||||||
return true;
|
const uint8_t *flash_target_contents = (const uint8_t *)(XIP_BASE + FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE);
|
||||||
|
|
||||||
// const uint8_t *flash_target_contents = (const uint8_t *)(XIP_BASE + FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE);
|
if ((uint8_t)saved_mode != *flash_target_contents)
|
||||||
|
|
||||||
// if ((uint8_t)saved_mode != *flash_target_contents)
|
|
||||||
// {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool change_input_mode(Gamepad previous_gamepad)
|
|
||||||
{
|
|
||||||
if (!previous_gamepad.state.start)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
InputMode new_mode;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (previous_gamepad.state.up)
|
bool change_input_mode(GamepadButtons buttons)
|
||||||
|
{
|
||||||
|
if (!buttons.start)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputMode new_mode = current_input_mode;
|
||||||
|
|
||||||
|
if (buttons.up)
|
||||||
{
|
{
|
||||||
new_mode = INPUT_MODE_XINPUT;
|
new_mode = INPUT_MODE_XINPUT;
|
||||||
}
|
}
|
||||||
else if (previous_gamepad.state.left)
|
else if (buttons.left)
|
||||||
{
|
{
|
||||||
new_mode = INPUT_MODE_HID;
|
new_mode = INPUT_MODE_DINPUT;
|
||||||
}
|
}
|
||||||
else if (previous_gamepad.state.right)
|
else if (buttons.right)
|
||||||
{
|
{
|
||||||
new_mode = INPUT_MODE_XBOXORIGINAL;
|
new_mode = INPUT_MODE_XBOXORIGINAL;
|
||||||
}
|
}
|
||||||
else if (previous_gamepad.state.down)
|
else if (buttons.down)
|
||||||
{
|
{
|
||||||
new_mode = INPUT_MODE_SWITCH;
|
new_mode = INPUT_MODE_SWITCH;
|
||||||
}
|
}
|
||||||
else if (previous_gamepad.state.a)
|
else if (buttons.a)
|
||||||
{
|
{
|
||||||
new_mode = INPUT_MODE_PSCLASSIC;
|
new_mode = INPUT_MODE_PSCLASSIC;
|
||||||
}
|
}
|
||||||
@@ -82,9 +82,6 @@ bool change_input_mode(Gamepad previous_gamepad)
|
|||||||
|
|
||||||
if (new_mode)
|
if (new_mode)
|
||||||
{
|
{
|
||||||
// tinyusb needs to be kaput in order to write to the flash
|
|
||||||
// just hangs otherwise
|
|
||||||
|
|
||||||
tud_disconnect();
|
tud_disconnect();
|
||||||
sleep_ms(300);
|
sleep_ms(300);
|
||||||
multicore_reset_core1(); // stop tusb host
|
multicore_reset_core1(); // stop tusb host
|
||||||
@@ -101,18 +98,31 @@ bool change_input_mode(Gamepad previous_gamepad)
|
|||||||
|
|
||||||
enum InputMode get_input_mode()
|
enum InputMode get_input_mode()
|
||||||
{
|
{
|
||||||
#ifdef HOST_DEBUG
|
#if (CDC_DEBUG > 0)
|
||||||
return INPUT_MODE_USBSERIAL;
|
return INPUT_MODE_USBSERIAL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const uint8_t *stored_value = (const uint8_t *)(XIP_BASE + FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE);
|
const uint8_t *stored_value = (const uint8_t *)(XIP_BASE + FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE);
|
||||||
|
|
||||||
|
#if (MAX_GAMEPADS < 1)
|
||||||
|
if ((*stored_value == INPUT_MODE_DINPUT) || (*stored_value == INPUT_MODE_SWITCH))
|
||||||
|
{
|
||||||
|
current_input_mode = (enum InputMode)*stored_value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
current_input_mode = INPUT_MODE_DINPUT;
|
||||||
|
}
|
||||||
|
#else
|
||||||
if (*stored_value >= INPUT_MODE_XINPUT && *stored_value <= INPUT_MODE_XBOXORIGINAL)
|
if (*stored_value >= INPUT_MODE_XINPUT && *stored_value <= INPUT_MODE_XBOXORIGINAL)
|
||||||
{
|
{
|
||||||
return(enum InputMode)*stored_value;
|
current_input_mode = (enum InputMode)*stored_value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return INPUT_MODE_XBOXORIGINAL;
|
current_input_mode = INPUT_MODE_XBOXORIGINAL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return current_input_mode;
|
||||||
}
|
}
|
||||||
@@ -5,21 +5,10 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Gamepad.h"
|
#include "tusb_gamepad.h"
|
||||||
|
|
||||||
enum InputMode
|
|
||||||
{
|
|
||||||
INPUT_MODE_XINPUT = 0x01,
|
|
||||||
INPUT_MODE_SWITCH = 0x02,
|
|
||||||
INPUT_MODE_HID = 0x03,
|
|
||||||
INPUT_MODE_PSCLASSIC = 0x04,
|
|
||||||
INPUT_MODE_XBOXORIGINAL = 0x05,
|
|
||||||
INPUT_MODE_USBSERIAL = 0x06,
|
|
||||||
// INPUT_MODE_CONFIG,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum InputMode get_input_mode();
|
enum InputMode get_input_mode();
|
||||||
bool change_input_mode(Gamepad previous_gamepad_state);
|
bool change_input_mode(GamepadButtons buttons);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
32
src/main.cpp
32
src/main.cpp
@@ -1,24 +1,18 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "pico/stdlib.h"
|
#include "pico/stdlib.h"
|
||||||
#include "pico/multicore.h"
|
#include "pico/multicore.h"
|
||||||
|
|
||||||
#include "tusb.h"
|
#include "tusb.h"
|
||||||
#include "bsp/board_api.h"
|
#include "bsp/board_api.h"
|
||||||
|
#include "tusb_gamepad.h"
|
||||||
|
#include "drivermanager.h"
|
||||||
|
#include "drivers/gpdriver.h"
|
||||||
|
|
||||||
#include "usbh/tusb_host.h"
|
#include "usbh/tusb_host.h"
|
||||||
|
|
||||||
#include "usbd/drivermanager.h"
|
|
||||||
#include "usbd/gpdriver.h"
|
|
||||||
|
|
||||||
#include "Gamepad.h"
|
|
||||||
#include "input_mode.h"
|
#include "input_mode.h"
|
||||||
|
|
||||||
Gamepad gamepad;
|
|
||||||
GamepadOut gamepadOut;
|
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
set_sys_clock_khz(120000, true);
|
set_sys_clock_khz(120000, true);
|
||||||
@@ -34,28 +28,32 @@ int main(void)
|
|||||||
multicore_reset_core1();
|
multicore_reset_core1();
|
||||||
multicore_launch_core1(usbh_main);
|
multicore_launch_core1(usbh_main);
|
||||||
|
|
||||||
Gamepad previous_gamepad = gamepad;
|
GamepadButtons prev_gamepad_buttons = gamepad(0)->buttons;
|
||||||
absolute_time_t last_time_gamepad_changed = get_absolute_time();
|
absolute_time_t last_time_gamepad_changed = get_absolute_time();
|
||||||
absolute_time_t last_time_gamepad_checked = get_absolute_time();
|
absolute_time_t last_time_gamepad_checked = get_absolute_time();
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
uint8_t outBuffer[64];
|
for (int i = 0; i < MAX_GAMEPADS; i++)
|
||||||
GPDriver* driver = driverManager.getDriver();
|
{
|
||||||
driver->process(&gamepad, outBuffer);
|
uint8_t outBuffer[64];
|
||||||
|
GPDriver* driver = driverManager.getDriver();
|
||||||
|
driver->process(i, gamepad(i), outBuffer);
|
||||||
|
driver->update_rumble(i, gamepad(i));
|
||||||
|
}
|
||||||
|
|
||||||
if (absolute_time_diff_us(last_time_gamepad_checked, get_absolute_time()) >= 500000)
|
if (absolute_time_diff_us(last_time_gamepad_checked, get_absolute_time()) >= 500000)
|
||||||
{
|
{
|
||||||
// check if digital buttons have changed (first 16 bytes of gamepad.state)
|
// check if digital buttons have changed
|
||||||
if (memcmp(&gamepad.state, &previous_gamepad.state, 16) != 0)
|
if (memcmp(&gamepad(0)->buttons, &prev_gamepad_buttons, sizeof(GamepadButtons)) != 0)
|
||||||
{
|
{
|
||||||
memcpy(&previous_gamepad.state, &gamepad.state, sizeof(gamepad.state));
|
memcpy(&prev_gamepad_buttons, &gamepad(0)->buttons, sizeof(GamepadButtons));
|
||||||
last_time_gamepad_changed = get_absolute_time();
|
last_time_gamepad_changed = get_absolute_time();
|
||||||
}
|
}
|
||||||
// haven't changed for 3 seconds
|
// haven't changed for 3 seconds
|
||||||
else if (absolute_time_diff_us(last_time_gamepad_changed, get_absolute_time()) >= 3000000)
|
else if (absolute_time_diff_us(last_time_gamepad_changed, get_absolute_time()) >= 3000000)
|
||||||
{
|
{
|
||||||
if (!change_input_mode(previous_gamepad))
|
if (!change_input_mode(prev_gamepad_buttons))
|
||||||
{
|
{
|
||||||
last_time_gamepad_changed = get_absolute_time();
|
last_time_gamepad_changed = get_absolute_time();
|
||||||
}
|
}
|
||||||
|
|||||||
39
src/ogxm_config.h
Normal file
39
src/ogxm_config.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef _OGXM_CONFIG_H_
|
||||||
|
#define _OGXM_CONFIG_H_
|
||||||
|
|
||||||
|
#define ADAFRUIT_FEATHER_USBH 1
|
||||||
|
#define PI_PICO 2
|
||||||
|
#define RP2040_ZERO_INTERPOSER 3
|
||||||
|
|
||||||
|
// Options //
|
||||||
|
#define OGXM_BOARD ADAFRUIT_FEATHER_USBH
|
||||||
|
#define CDC_DEBUG 0
|
||||||
|
// ------- //
|
||||||
|
|
||||||
|
#if OGXM_BOARD == ADAFRUIT_FEATHER_USBH
|
||||||
|
#define PIO_USB_DP_PIN 16 // DM = 17
|
||||||
|
#define LED_INDICATOR_PIN 13
|
||||||
|
#define VCC_EN_PIN 18
|
||||||
|
// #define NEOPIXEL_PWR_PIN 20
|
||||||
|
// #define NEOPIXEL_CTRL_PIN 21
|
||||||
|
|
||||||
|
#elif OGXM_BOARD == PI_PICO
|
||||||
|
#define PIO_USB_DP_PIN 0 // DM = 1
|
||||||
|
#define LED_INDICATOR_PIN 25
|
||||||
|
|
||||||
|
#elif OGXM_BOARD == RP2040_ZERO_INTERPOSER
|
||||||
|
#define PIO_USB_DP_PIN 10 // DM = 11
|
||||||
|
#define LED_INDICATOR_PIN 13
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef OGXM_BOARD
|
||||||
|
#error OGXM_BOARD must be defined in ogxm_config.h
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CDC_DEBUG
|
||||||
|
#define CDC_DEBUG 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _OGXM_CONFIG_H_
|
||||||
@@ -26,6 +26,10 @@
|
|||||||
#ifndef _TUSB_CONFIG_H_
|
#ifndef _TUSB_CONFIG_H_
|
||||||
#define _TUSB_CONFIG_H_
|
#define _TUSB_CONFIG_H_
|
||||||
|
|
||||||
|
#include "board_config.h"
|
||||||
|
|
||||||
|
#define MAX_GAMEPADS 1
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@@ -87,7 +91,7 @@
|
|||||||
#define CFG_TUD_ENABLED 1
|
#define CFG_TUD_ENABLED 1
|
||||||
|
|
||||||
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
|
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
|
||||||
// #define CFG_TUSB_DEBUG 1
|
#define CFG_TUSB_DEBUG 0
|
||||||
|
|
||||||
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
||||||
* Tinyusb use follows macros to declare transferring memory so that they can be put
|
* Tinyusb use follows macros to declare transferring memory so that they can be put
|
||||||
@@ -126,7 +130,7 @@
|
|||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||||
#define CFG_TUD_ENDPOINT0_SIZE 64
|
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CFG_TUD_CDC_RX_BUFSIZE 256
|
#define CFG_TUD_CDC_RX_BUFSIZE 256
|
||||||
@@ -135,7 +139,7 @@
|
|||||||
//------------- CLASS -------------//
|
//------------- CLASS -------------//
|
||||||
#define CFG_TUD_CDC 1
|
#define CFG_TUD_CDC 1
|
||||||
#define CFG_TUD_ECM_RNDIS 0
|
#define CFG_TUD_ECM_RNDIS 0
|
||||||
#define CFG_TUD_HID 2
|
#define CFG_TUD_HID (MAX_GAMEPADS + 1)
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
// HOST CONFIGURATION
|
// HOST CONFIGURATION
|
||||||
@@ -150,12 +154,12 @@
|
|||||||
// Size of buffer to hold descriptors and other data used for enumeration
|
// Size of buffer to hold descriptors and other data used for enumeration
|
||||||
#define CFG_TUH_ENUMERATION_BUFSIZE 512
|
#define CFG_TUH_ENUMERATION_BUFSIZE 512
|
||||||
|
|
||||||
#define CFG_TUH_HUB 1
|
#define CFG_TUH_HUB MAX_GAMEPADS
|
||||||
#define CFG_TUH_CDC 0
|
#define CFG_TUH_CDC 0
|
||||||
#define CFG_TUH_HID 1 // typical keyboard + mouse device can have 3-4 HID interfaces
|
#define CFG_TUH_HID MAX_GAMEPADS // typical keyboard + mouse device can have 3-4 HID interfaces
|
||||||
#define CFG_TUH_MSC 0
|
#define CFG_TUH_MSC 0
|
||||||
#define CFG_TUH_VENDOR 0
|
#define CFG_TUH_VENDOR 0
|
||||||
#define CFG_TUH_XINPUT 1
|
#define CFG_TUH_XINPUT MAX_GAMEPADS
|
||||||
|
|
||||||
// max device support (excluding hub device)
|
// max device support (excluding hub device)
|
||||||
#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1) // hub typically has 4 ports
|
#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1) // hub typically has 4 ports
|
||||||
|
|||||||
@@ -1,197 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info)
|
|
||||||
*/
|
|
||||||
#include "utilities/scaling.h"
|
|
||||||
|
|
||||||
#include "usbd/dinput/DInputDriver.h"
|
|
||||||
#include "descriptors/DInputDescriptors.h"
|
|
||||||
|
|
||||||
#include "usbd/shared/driverhelper.h"
|
|
||||||
|
|
||||||
// Magic byte sequence to enable PS button on PS3
|
|
||||||
static const uint8_t ps3_magic_init_bytes[8] = {0x21, 0x26, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00};
|
|
||||||
|
|
||||||
static bool hid_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, (void *) ps3_magic_init_bytes, sizeof(ps3_magic_init_bytes));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return hidd_control_xfer_cb(rhport, stage, request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DInputDriver::initialize()
|
|
||||||
{
|
|
||||||
dinput_report = {
|
|
||||||
// .report_id = 0,
|
|
||||||
.square_btn = 0, .cross_btn = 0, .circle_btn = 0, .triangle_btn = 0,
|
|
||||||
.l1_btn = 0, .r1_btn = 0, .l2_btn = 0, .r2_btn = 0,
|
|
||||||
.select_btn = 0, .start_btn = 0, .l3_btn = 0, .r3_btn = 0, .ps_btn = 0, .tp_btn = 0,
|
|
||||||
.direction = 0x08,
|
|
||||||
.l_x_axis = DINPUT_JOYSTICK_MID,
|
|
||||||
.l_y_axis = DINPUT_JOYSTICK_MID,
|
|
||||||
.r_x_axis = DINPUT_JOYSTICK_MID,
|
|
||||||
.r_y_axis = DINPUT_JOYSTICK_MID,
|
|
||||||
.right_axis = 0x00, .left_axis = 0x00, .up_axis = 0x00, .down_axis = 0x00,
|
|
||||||
.triangle_axis = 0x00, .circle_axis = 0x00, .cross_axis = 0x00, .square_axis = 0x00,
|
|
||||||
.l1_axis = 0x00, .r1_axis = 0x00, .l2_axis = 0x00, .r2_axis = 0x00
|
|
||||||
};
|
|
||||||
|
|
||||||
class_driver = {
|
|
||||||
#if CFG_TUSB_DEBUG >= 2
|
|
||||||
.name = "HID",
|
|
||||||
#endif
|
|
||||||
.init = hidd_init,
|
|
||||||
.reset = hidd_reset,
|
|
||||||
.open = hidd_open,
|
|
||||||
.control_xfer_cb = hid_control_xfer_cb,
|
|
||||||
.xfer_cb = hidd_xfer_cb,
|
|
||||||
.sof = NULL
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate HID report from gamepad and send to TUSB Device
|
|
||||||
void DInputDriver::process(Gamepad * gamepad, uint8_t * outBuffer)
|
|
||||||
{
|
|
||||||
if (gamepad->state.up) {
|
|
||||||
if (gamepad->state.right) {
|
|
||||||
dinput_report.direction = DINPUT_HAT_UPRIGHT;
|
|
||||||
} else if (gamepad->state.left) {
|
|
||||||
dinput_report.direction = DINPUT_HAT_UPLEFT;
|
|
||||||
} else {
|
|
||||||
dinput_report.direction = DINPUT_HAT_UP;
|
|
||||||
}
|
|
||||||
} else if (gamepad->state.down) {
|
|
||||||
if (gamepad->state.right) {
|
|
||||||
dinput_report.direction = DINPUT_HAT_DOWNRIGHT;
|
|
||||||
} else if (gamepad->state.left) {
|
|
||||||
dinput_report.direction = DINPUT_HAT_DOWNLEFT;
|
|
||||||
} else {
|
|
||||||
dinput_report.direction = DINPUT_HAT_DOWN;
|
|
||||||
}
|
|
||||||
} else if (gamepad->state.left) {
|
|
||||||
dinput_report.direction = DINPUT_HAT_LEFT;
|
|
||||||
} else if (gamepad->state.right) {
|
|
||||||
dinput_report.direction = DINPUT_HAT_RIGHT;
|
|
||||||
} else {
|
|
||||||
dinput_report.direction = DINPUT_HAT_NOTHING;
|
|
||||||
}
|
|
||||||
|
|
||||||
dinput_report.cross_btn = gamepad->state.a ? 1 : 0;
|
|
||||||
dinput_report.circle_btn = gamepad->state.b ? 1 : 0;
|
|
||||||
dinput_report.square_btn = gamepad->state.x ? 1 : 0;
|
|
||||||
dinput_report.triangle_btn = gamepad->state.y ? 1 : 0;
|
|
||||||
dinput_report.l1_btn = gamepad->state.lb ? 1 : 0;
|
|
||||||
dinput_report.r1_btn = gamepad->state.rb ? 1 : 0;
|
|
||||||
dinput_report.l2_btn = gamepad->state.lt > 0 ? 1 : 0;
|
|
||||||
dinput_report.r2_btn = gamepad->state.rt > 0 ? 1 : 0;
|
|
||||||
dinput_report.select_btn = gamepad->state.back ? 1 : 0;
|
|
||||||
dinput_report.start_btn = gamepad->state.start ? 1 : 0;
|
|
||||||
dinput_report.l3_btn = gamepad->state.l3 ? 1 : 0;
|
|
||||||
dinput_report.r3_btn = gamepad->state.r3 ? 1 : 0;
|
|
||||||
dinput_report.ps_btn = gamepad->state.sys ? 1 : 0;
|
|
||||||
dinput_report.tp_btn = gamepad->state.misc ? 1 : 0;
|
|
||||||
|
|
||||||
dinput_report.cross_axis = gamepad->state.a ? 0xFF : 0x00;
|
|
||||||
dinput_report.circle_axis = gamepad->state.b ? 0xFF : 0x00;
|
|
||||||
dinput_report.square_axis = gamepad->state.x ? 0xFF : 0x00;
|
|
||||||
dinput_report.triangle_axis = gamepad->state.y ? 0xFF : 0x00;
|
|
||||||
dinput_report.l1_axis = gamepad->state.lb ? 0xFF : 0x00;
|
|
||||||
dinput_report.r1_axis = gamepad->state.rb ? 0xFF : 0x00;
|
|
||||||
|
|
||||||
dinput_report.l2_axis = gamepad->state.lt;
|
|
||||||
dinput_report.r2_axis = gamepad->state.rt;
|
|
||||||
|
|
||||||
dinput_report.l_x_axis = scale_int16_to_uint8(gamepad->state.lx, false);
|
|
||||||
dinput_report.l_y_axis = scale_int16_to_uint8(gamepad->state.ly, true);
|
|
||||||
dinput_report.r_x_axis = scale_int16_to_uint8(gamepad->state.rx, false);
|
|
||||||
dinput_report.r_y_axis = scale_int16_to_uint8(gamepad->state.ry, true);
|
|
||||||
|
|
||||||
// Wake up TinyUSB device
|
|
||||||
if (tud_suspended())
|
|
||||||
tud_remote_wakeup();
|
|
||||||
|
|
||||||
void * report = &dinput_report;
|
|
||||||
uint16_t report_size = sizeof(dinput_report);
|
|
||||||
// if (memcmp(last_report, report, report_size) != 0)
|
|
||||||
// {
|
|
||||||
// HID ready + report sent, copy previous report
|
|
||||||
if (tud_hid_ready() && tud_hid_report(0, report, report_size) == true ) {
|
|
||||||
memcpy(last_report, report, report_size);
|
|
||||||
}
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
// tud_hid_get_report_cb
|
|
||||||
uint16_t DInputDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
|
|
||||||
{
|
|
||||||
memcpy(buffer, &dinput_report, sizeof(DInputReport));
|
|
||||||
return sizeof(DInputReport);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only PS4 does anything with set report
|
|
||||||
void DInputDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize)
|
|
||||||
{
|
|
||||||
// testing things, I'll have a usb sniffer soon so this will get figured out then
|
|
||||||
|
|
||||||
// DInputOutReport dinput_out_report = {0};
|
|
||||||
// memcpy(&dinput_out_report, buffer, sizeof(dinput_out_report));
|
|
||||||
|
|
||||||
// // gamepadOut.out_state.rrumble = dinput_out_report.rumble.right_motor_on ? 0xFF : 0x00;
|
|
||||||
// // gamepadOut.out_state.lrumble = gamepadOut.out_state.rrumble = dinput_out_report.rumble.left_motor_force;
|
|
||||||
|
|
||||||
// // if (dinput_out_report.rumble.left_motor_force > 0)
|
|
||||||
// if (dinput_out_report.led->time_enabled > 0)
|
|
||||||
// gamepadOut.out_state.lrumble = gamepadOut.out_state.rrumble = 0xFF;
|
|
||||||
// if (dinput_out_report.led->duty_length > 0)
|
|
||||||
// gamepadOut.out_state.lrumble = gamepadOut.out_state.rrumble = 0xFF;
|
|
||||||
// if (dinput_out_report.led->enabled > 0)
|
|
||||||
// gamepadOut.out_state.lrumble = gamepadOut.out_state.rrumble = 0xFF;
|
|
||||||
// if (dinput_out_report.led->duty_off > 0)
|
|
||||||
// gamepadOut.out_state.lrumble = gamepadOut.out_state.rrumble = 0xFF;
|
|
||||||
// if (dinput_out_report.led->duty_on > 0)
|
|
||||||
// gamepadOut.out_state.lrumble = gamepadOut.out_state.rrumble = 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only XboxOG and Xbox One use vendor control xfer cb
|
|
||||||
bool DInputDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint16_t * DInputDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid)
|
|
||||||
{
|
|
||||||
const char *value = (const char *)dinput_string_descriptors[index];
|
|
||||||
return getStringDescriptor(value, index); // getStringDescriptor returns a static array
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * DInputDriver::get_descriptor_device_cb()
|
|
||||||
{
|
|
||||||
return dinput_device_descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * DInputDriver::get_hid_descriptor_report_cb(uint8_t itf)
|
|
||||||
{
|
|
||||||
return dinput_report_descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * DInputDriver::get_descriptor_configuration_cb(uint8_t index)
|
|
||||||
{
|
|
||||||
return dinput_configuration_descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * DInputDriver::get_descriptor_device_qualifier_cb()
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t DInputDriver::GetJoystickMidValue()
|
|
||||||
{
|
|
||||||
return DINPUT_JOYSTICK_MID << 8;
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _HID_DRIVER_H_
|
|
||||||
#define _HID_DRIVER_H_
|
|
||||||
|
|
||||||
#include "usbd/gpdriver.h"
|
|
||||||
#include "descriptors/DInputDescriptors.h"
|
|
||||||
#include "descriptors/PS3Descriptors.h"
|
|
||||||
|
|
||||||
class DInputDriver : public GPDriver {
|
|
||||||
public:
|
|
||||||
virtual void initialize();
|
|
||||||
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
|
|
||||||
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
|
|
||||||
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
|
|
||||||
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
|
|
||||||
virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid);
|
|
||||||
virtual const uint8_t * get_descriptor_device_cb();
|
|
||||||
virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ;
|
|
||||||
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
|
|
||||||
virtual const uint8_t * get_descriptor_device_qualifier_cb();
|
|
||||||
virtual uint16_t GetJoystickMidValue();
|
|
||||||
private:
|
|
||||||
uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { };
|
|
||||||
|
|
||||||
DInputReport dinput_report;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // _HID_DRIVER_H_
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
#include "usbd/drivermanager.h"
|
|
||||||
|
|
||||||
// #include "net/NetDriver.h"
|
|
||||||
// #include "keyboard/KeyboardDriver.h"
|
|
||||||
|
|
||||||
#include "usbd/hid/HIDDriver.h"
|
|
||||||
#include "usbd/psclassic/PSClassicDriver.h"
|
|
||||||
#include "usbd/switch/SwitchDriver.h"
|
|
||||||
#include "usbd/xboxog/XboxOriginalDriver.h"
|
|
||||||
#include "usbd/xinput/XInputDriver.h"
|
|
||||||
#include "usbd/usbserial/USBSerialDriver.h"
|
|
||||||
|
|
||||||
void DriverManager::setup(InputMode mode)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
// case INPUT_MODE_CONFIG:
|
|
||||||
// driver = new NetDriver();
|
|
||||||
// break;
|
|
||||||
// case INPUT_MODE_KEYBOARD:
|
|
||||||
// driver = new KeyboardDriver();
|
|
||||||
// break;
|
|
||||||
case INPUT_MODE_HID:
|
|
||||||
driver = new HIDDriver();
|
|
||||||
break;
|
|
||||||
case INPUT_MODE_PSCLASSIC:
|
|
||||||
driver = new PSClassicDriver();
|
|
||||||
break;
|
|
||||||
case INPUT_MODE_SWITCH:
|
|
||||||
driver = new SwitchDriver();
|
|
||||||
break;
|
|
||||||
case INPUT_MODE_XBOXORIGINAL:
|
|
||||||
driver = new XboxOriginalDriver();
|
|
||||||
break;
|
|
||||||
case INPUT_MODE_XINPUT:
|
|
||||||
driver = new XInputDriver();
|
|
||||||
break;
|
|
||||||
case INPUT_MODE_USBSERIAL:
|
|
||||||
driver = new USBSerialDriver();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize our chosen driver
|
|
||||||
driver->initialize();
|
|
||||||
|
|
||||||
// Start the TinyUSB Device functionality
|
|
||||||
tud_init(TUD_OPT_RHPORT);
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
#ifndef _DRIVERMANAGER_H
|
|
||||||
#define _DRIVERMANAGER_H
|
|
||||||
|
|
||||||
#include "usbd/gpdriver.h"
|
|
||||||
#include "input_mode.h"
|
|
||||||
|
|
||||||
class GPDriver;
|
|
||||||
|
|
||||||
class DriverManager {
|
|
||||||
public:
|
|
||||||
DriverManager(DriverManager const&) = delete;
|
|
||||||
void operator=(DriverManager const&) = delete;
|
|
||||||
static DriverManager& getInstance() {// Thread-safe storage ensures cross-thread talk
|
|
||||||
static DriverManager instance; // Guaranteed to be destroyed. // Instantiated on first use.
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
GPDriver * getDriver() { return driver; }
|
|
||||||
void setup(InputMode mode);
|
|
||||||
private:
|
|
||||||
DriverManager() {}
|
|
||||||
GPDriver * driver;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _GPDRIVER_H_
|
|
||||||
#define _GPDRIVER_H_
|
|
||||||
|
|
||||||
#include "Gamepad.h"
|
|
||||||
#include "tusb_config.h"
|
|
||||||
|
|
||||||
#include "tusb.h"
|
|
||||||
#include "class/hid/hid.h"
|
|
||||||
#include "device/usbd_pvt.h"
|
|
||||||
|
|
||||||
// Forward declare gamepad
|
|
||||||
class Gamepad;
|
|
||||||
|
|
||||||
//
|
|
||||||
// GP2040-CE USB Device Class Driver
|
|
||||||
//
|
|
||||||
class GPDriver {
|
|
||||||
public:
|
|
||||||
virtual void initialize() = 0;
|
|
||||||
virtual void process(Gamepad * gamepad, uint8_t * outBuffer) = 0;
|
|
||||||
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) = 0;
|
|
||||||
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) = 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;
|
|
||||||
virtual uint16_t GetJoystickMidValue() = 0;
|
|
||||||
const usbd_class_driver_t * get_class_driver() { return &class_driver; }
|
|
||||||
protected:
|
|
||||||
usbd_class_driver_t class_driver;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info)
|
|
||||||
*/
|
|
||||||
#include "utilities/scaling.h"
|
|
||||||
|
|
||||||
#include "usbd/hid/HIDDriver.h"
|
|
||||||
#include "descriptors/HIDDescriptors.h"
|
|
||||||
#include "usbd/shared/driverhelper.h"
|
|
||||||
|
|
||||||
// Magic byte sequence to enable PS button on PS3
|
|
||||||
static const uint8_t ps3_magic_init_bytes[8] = {0x21, 0x26, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00};
|
|
||||||
|
|
||||||
static bool hid_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, (void *) ps3_magic_init_bytes, sizeof(ps3_magic_init_bytes));
|
|
||||||
} else {
|
|
||||||
return hidd_control_xfer_cb(rhport, stage, request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HIDDriver::initialize()
|
|
||||||
{
|
|
||||||
hidReport = {
|
|
||||||
.square_btn = 0, .cross_btn = 0, .circle_btn = 0, .triangle_btn = 0,
|
|
||||||
.l1_btn = 0, .r1_btn = 0, .l2_btn = 0, .r2_btn = 0,
|
|
||||||
.select_btn = 0, .start_btn = 0, .l3_btn = 0, .r3_btn = 0, .ps_btn = 0, .tp_btn = 0,
|
|
||||||
.direction = 0x08,
|
|
||||||
.l_x_axis = HID_JOYSTICK_MID,
|
|
||||||
.l_y_axis = HID_JOYSTICK_MID,
|
|
||||||
.r_x_axis = HID_JOYSTICK_MID,
|
|
||||||
.r_y_axis = HID_JOYSTICK_MID,
|
|
||||||
.right_axis = 0x00, .left_axis = 0x00, .up_axis = 0x00, .down_axis = 0x00,
|
|
||||||
.triangle_axis = 0x00, .circle_axis = 0x00, .cross_axis = 0x00, .square_axis = 0x00,
|
|
||||||
.l1_axis = 0x00, .r1_axis = 0x00, .l2_axis = 0x00, .r2_axis = 0x00
|
|
||||||
};
|
|
||||||
|
|
||||||
class_driver = {
|
|
||||||
#if CFG_TUSB_DEBUG >= 2
|
|
||||||
.name = "HID",
|
|
||||||
#endif
|
|
||||||
.init = hidd_init,
|
|
||||||
.reset = hidd_reset,
|
|
||||||
.open = hidd_open,
|
|
||||||
.control_xfer_cb = hid_control_xfer_cb,
|
|
||||||
.xfer_cb = hidd_xfer_cb,
|
|
||||||
.sof = NULL
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate HID report from gamepad and send to TUSB Device
|
|
||||||
void HIDDriver::process(Gamepad * gamepad, uint8_t * outBuffer)
|
|
||||||
{
|
|
||||||
if (gamepad->state.up) {
|
|
||||||
if (gamepad->state.right) {
|
|
||||||
hidReport.direction = HID_HAT_UPRIGHT;
|
|
||||||
} else if (gamepad->state.left) {
|
|
||||||
hidReport.direction = HID_HAT_UPLEFT;
|
|
||||||
} else {
|
|
||||||
hidReport.direction = HID_HAT_UP;
|
|
||||||
}
|
|
||||||
} else if (gamepad->state.down) {
|
|
||||||
if (gamepad->state.right) {
|
|
||||||
hidReport.direction = HID_HAT_DOWNRIGHT;
|
|
||||||
} else if (gamepad->state.left) {
|
|
||||||
hidReport.direction = HID_HAT_DOWNLEFT;
|
|
||||||
} else {
|
|
||||||
hidReport.direction = HID_HAT_DOWN;
|
|
||||||
}
|
|
||||||
} else if (gamepad->state.left) {
|
|
||||||
hidReport.direction = HID_HAT_LEFT;
|
|
||||||
} else if (gamepad->state.right) {
|
|
||||||
hidReport.direction = HID_HAT_RIGHT;
|
|
||||||
} else {
|
|
||||||
hidReport.direction = HID_HAT_NOTHING;
|
|
||||||
}
|
|
||||||
|
|
||||||
hidReport.cross_btn = gamepad->state.a ? 1 : 0;
|
|
||||||
hidReport.circle_btn = gamepad->state.b ? 1 : 0;
|
|
||||||
hidReport.square_btn = gamepad->state.x ? 1 : 0;
|
|
||||||
hidReport.triangle_btn = gamepad->state.y ? 1 : 0;
|
|
||||||
hidReport.l1_btn = gamepad->state.lb ? 1 : 0;
|
|
||||||
hidReport.r1_btn = gamepad->state.rb ? 1 : 0;
|
|
||||||
hidReport.l2_btn = gamepad->state.lt > 0 ? 1 : 0;
|
|
||||||
hidReport.r2_btn = gamepad->state.rt > 0 ? 1 : 0;
|
|
||||||
hidReport.select_btn = gamepad->state.back ? 1 : 0;
|
|
||||||
hidReport.start_btn = gamepad->state.start ? 1 : 0;
|
|
||||||
hidReport.l3_btn = gamepad->state.l3 ? 1 : 0;
|
|
||||||
hidReport.r3_btn = gamepad->state.r3 ? 1 : 0;
|
|
||||||
hidReport.ps_btn = gamepad->state.sys ? 1 : 0;
|
|
||||||
hidReport.tp_btn = gamepad->state.misc ? 1 : 0;
|
|
||||||
|
|
||||||
hidReport.cross_axis = gamepad->state.a ? 0xFF : 0x00;
|
|
||||||
hidReport.circle_axis = gamepad->state.b ? 0xFF : 0x00;
|
|
||||||
hidReport.square_axis = gamepad->state.x ? 0xFF : 0x00;
|
|
||||||
hidReport.triangle_axis = gamepad->state.y ? 0xFF : 0x00;
|
|
||||||
hidReport.l1_axis = gamepad->state.lb ? 0xFF : 0x00;
|
|
||||||
hidReport.r1_axis = gamepad->state.rb ? 0xFF : 0x00;
|
|
||||||
|
|
||||||
hidReport.l2_axis = gamepad->state.lt;
|
|
||||||
hidReport.r2_axis = gamepad->state.rt;
|
|
||||||
|
|
||||||
hidReport.l_x_axis = scale_int16_to_uint8(gamepad->state.lx, false);
|
|
||||||
hidReport.l_y_axis = scale_int16_to_uint8(gamepad->state.ly, true);
|
|
||||||
hidReport.r_x_axis = scale_int16_to_uint8(gamepad->state.rx, false);
|
|
||||||
hidReport.r_y_axis = scale_int16_to_uint8(gamepad->state.ry, true);
|
|
||||||
|
|
||||||
// Wake up TinyUSB device
|
|
||||||
if (tud_suspended())
|
|
||||||
tud_remote_wakeup();
|
|
||||||
|
|
||||||
void * report = &hidReport;
|
|
||||||
uint16_t report_size = sizeof(hidReport);
|
|
||||||
if (memcmp(last_report, report, report_size) != 0)
|
|
||||||
{
|
|
||||||
// HID ready + report sent, copy previous report
|
|
||||||
if (tud_hid_ready() && tud_hid_report(0, report, report_size) == true ) {
|
|
||||||
memcpy(last_report, report, report_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// tud_hid_get_report_cb
|
|
||||||
uint16_t HIDDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
|
|
||||||
{
|
|
||||||
memcpy(buffer, &hidReport, sizeof(HIDReport));
|
|
||||||
return sizeof(HIDReport);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only PS4 does anything with set report
|
|
||||||
void HIDDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {}
|
|
||||||
|
|
||||||
// Only XboxOG and Xbox One use vendor control xfer cb
|
|
||||||
bool HIDDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint16_t * HIDDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid)
|
|
||||||
{
|
|
||||||
const char *value = (const char *)hid_string_descriptors[index];
|
|
||||||
return getStringDescriptor(value, index); // getStringDescriptor returns a static array
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * HIDDriver::get_descriptor_device_cb()
|
|
||||||
{
|
|
||||||
return hid_device_descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * HIDDriver::get_hid_descriptor_report_cb(uint8_t itf)
|
|
||||||
{
|
|
||||||
return hid_report_descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * HIDDriver::get_descriptor_configuration_cb(uint8_t index)
|
|
||||||
{
|
|
||||||
return hid_configuration_descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * HIDDriver::get_descriptor_device_qualifier_cb()
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t HIDDriver::GetJoystickMidValue()
|
|
||||||
{
|
|
||||||
return HID_JOYSTICK_MID << 8;
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _HID_DRIVER_H_
|
|
||||||
#define _HID_DRIVER_H_
|
|
||||||
|
|
||||||
#include "usbd/gpdriver.h"
|
|
||||||
#include "descriptors/HIDDescriptors.h"
|
|
||||||
|
|
||||||
class HIDDriver : public GPDriver {
|
|
||||||
public:
|
|
||||||
virtual void initialize();
|
|
||||||
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
|
|
||||||
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
|
|
||||||
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
|
|
||||||
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
|
|
||||||
virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid);
|
|
||||||
virtual const uint8_t * get_descriptor_device_cb();
|
|
||||||
virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ;
|
|
||||||
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
|
|
||||||
virtual const uint8_t * get_descriptor_device_qualifier_cb();
|
|
||||||
virtual uint16_t GetJoystickMidValue();
|
|
||||||
private:
|
|
||||||
uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { };
|
|
||||||
HIDReport hidReport;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // _HID_DRIVER_H_
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
#include "usbd/psclassic/PSClassicDriver.h"
|
|
||||||
#include "usbd/shared/driverhelper.h"
|
|
||||||
|
|
||||||
void PSClassicDriver::initialize() {
|
|
||||||
psClassicReport = {
|
|
||||||
.buttons = 0x0014
|
|
||||||
};
|
|
||||||
|
|
||||||
class_driver = {
|
|
||||||
#if CFG_TUSB_DEBUG >= 2
|
|
||||||
.name = "PSCLASSIC",
|
|
||||||
#endif
|
|
||||||
.init = hidd_init,
|
|
||||||
.reset = hidd_reset,
|
|
||||||
.open = hidd_open,
|
|
||||||
.control_xfer_cb = hidd_control_xfer_cb,
|
|
||||||
.xfer_cb = hidd_xfer_cb,
|
|
||||||
.sof = NULL
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void PSClassicDriver::process(Gamepad * gamepad, uint8_t * outBuffer) {
|
|
||||||
psClassicReport.buttons = PSCLASSIC_MASK_CENTER;
|
|
||||||
|
|
||||||
if (gamepad->state.up) {
|
|
||||||
if (gamepad->state.right)
|
|
||||||
psClassicReport.buttons = PSCLASSIC_MASK_UP_RIGHT;
|
|
||||||
else if (gamepad->state.left)
|
|
||||||
psClassicReport.buttons = PSCLASSIC_MASK_UP_LEFT;
|
|
||||||
else
|
|
||||||
psClassicReport.buttons = PSCLASSIC_MASK_UP;
|
|
||||||
} else if (gamepad->state.down) {
|
|
||||||
if (gamepad->state.right)
|
|
||||||
psClassicReport.buttons = PSCLASSIC_MASK_DOWN_RIGHT;
|
|
||||||
else if (gamepad->state.left)
|
|
||||||
psClassicReport.buttons = PSCLASSIC_MASK_DOWN_LEFT;
|
|
||||||
else
|
|
||||||
psClassicReport.buttons = PSCLASSIC_MASK_DOWN;
|
|
||||||
} else if (gamepad->state.left) {
|
|
||||||
psClassicReport.buttons = PSCLASSIC_MASK_LEFT;
|
|
||||||
} else if (gamepad->state.right) {
|
|
||||||
psClassicReport.buttons = PSCLASSIC_MASK_RIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
psClassicReport.buttons |=
|
|
||||||
(gamepad->state.start ? PSCLASSIC_MASK_START : 0) |
|
|
||||||
(gamepad->state.back ? PSCLASSIC_MASK_SELECT : 0) |
|
|
||||||
(gamepad->state.a ? PSCLASSIC_MASK_CROSS : 0) |
|
|
||||||
(gamepad->state.b ? PSCLASSIC_MASK_CIRCLE : 0) |
|
|
||||||
(gamepad->state.x ? PSCLASSIC_MASK_SQUARE : 0) |
|
|
||||||
(gamepad->state.y ? PSCLASSIC_MASK_TRIANGLE : 0) |
|
|
||||||
(gamepad->state.lb ? PSCLASSIC_MASK_L1 : 0) |
|
|
||||||
(gamepad->state.rb ? PSCLASSIC_MASK_R1 : 0) |
|
|
||||||
(gamepad->state.lt ? PSCLASSIC_MASK_L2 : 0) |
|
|
||||||
(gamepad->state.rt ? PSCLASSIC_MASK_R2 : 0);
|
|
||||||
|
|
||||||
// Wake up TinyUSB device
|
|
||||||
if (tud_suspended())
|
|
||||||
tud_remote_wakeup();
|
|
||||||
|
|
||||||
void * report = &psClassicReport;
|
|
||||||
uint16_t report_size = sizeof(psClassicReport);
|
|
||||||
if (memcmp(last_report, report, report_size) != 0) {
|
|
||||||
// HID ready + report sent, copy previous report
|
|
||||||
if (tud_hid_ready() && tud_hid_report(0, report, report_size) == true ) {
|
|
||||||
memcpy(last_report, report, report_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// tud_hid_get_report_cb
|
|
||||||
uint16_t PSClassicDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) {
|
|
||||||
memcpy(buffer, &psClassicReport, sizeof(PSClassicReport));
|
|
||||||
return sizeof(PSClassicReport);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only PS4 does anything with set report
|
|
||||||
void PSClassicDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {}
|
|
||||||
|
|
||||||
// Only XboxOG and Xbox One use vendor control xfer cb
|
|
||||||
bool PSClassicDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint16_t * PSClassicDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
|
||||||
const char *value = (const char *)psclassic_string_descriptors[index];
|
|
||||||
return getStringDescriptor(value, index); // getStringDescriptor returns a static array
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * PSClassicDriver::get_descriptor_device_cb() {
|
|
||||||
return psclassic_device_descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * PSClassicDriver::get_hid_descriptor_report_cb(uint8_t itf) {
|
|
||||||
return psclassic_report_descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * PSClassicDriver::get_descriptor_configuration_cb(uint8_t index) {
|
|
||||||
return psclassic_configuration_descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * PSClassicDriver::get_descriptor_device_qualifier_cb() {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t PSClassicDriver::GetJoystickMidValue() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PSCLASSIC_DRIVER_H_
|
|
||||||
#define _PSCLASSIC_DRIVER_H_
|
|
||||||
|
|
||||||
#include "usbd/gpdriver.h"
|
|
||||||
#include "descriptors/PSClassicDescriptors.h"
|
|
||||||
|
|
||||||
class PSClassicDriver : public GPDriver {
|
|
||||||
public:
|
|
||||||
virtual void initialize();
|
|
||||||
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
|
|
||||||
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
|
|
||||||
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
|
|
||||||
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
|
|
||||||
virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid);
|
|
||||||
virtual const uint8_t * get_descriptor_device_cb();
|
|
||||||
virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ;
|
|
||||||
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
|
|
||||||
virtual const uint8_t * get_descriptor_device_qualifier_cb();
|
|
||||||
virtual uint16_t GetJoystickMidValue();
|
|
||||||
private:
|
|
||||||
uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { };
|
|
||||||
PSClassicReport psClassicReport;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // _PSCLASSIC_DRIVER_H_
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
#ifndef _DRIVER_HELPER_H_
|
|
||||||
#define _DRIVER_HELPER_H_
|
|
||||||
|
|
||||||
static uint16_t * getStringDescriptor(const char * value, uint8_t index)
|
|
||||||
{
|
|
||||||
static uint16_t descriptorStringBuffer[32]; // Max 64 bytes, 31 unicode characters
|
|
||||||
size_t charCount;
|
|
||||||
if ( index == 0 ) // language always has a character count of 1
|
|
||||||
charCount = 1;
|
|
||||||
else {
|
|
||||||
charCount = strlen(value);
|
|
||||||
if (charCount > 31)
|
|
||||||
charCount = 31;
|
|
||||||
}
|
|
||||||
// Fill descriptionStringBuffer[1] .. [32]
|
|
||||||
for (uint8_t i = 0; i < charCount; i++)
|
|
||||||
descriptorStringBuffer[i + 1] = value[i];
|
|
||||||
|
|
||||||
// first byte (descriptionStringBuffer[0]) is length (including header), second byte is string type
|
|
||||||
descriptorStringBuffer[0] = (0x03 << 8) | (2 * (uint8_t)charCount + 2);
|
|
||||||
|
|
||||||
// Cast temp buffer to final result
|
|
||||||
return descriptorStringBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _DRIVER_HELPER_H_
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
#include "usbd/switch/SwitchDriver.h"
|
|
||||||
#include "usbd/shared/driverhelper.h"
|
|
||||||
|
|
||||||
#include "utilities/scaling.h"
|
|
||||||
|
|
||||||
void SwitchDriver::initialize() {
|
|
||||||
switchReport = {
|
|
||||||
.buttons = 0,
|
|
||||||
.hat = SWITCH_HAT_NOTHING,
|
|
||||||
.lx = SWITCH_JOYSTICK_MID,
|
|
||||||
.ly = SWITCH_JOYSTICK_MID,
|
|
||||||
.rx = SWITCH_JOYSTICK_MID,
|
|
||||||
.ry = SWITCH_JOYSTICK_MID,
|
|
||||||
.vendor = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
class_driver = {
|
|
||||||
#if CFG_TUSB_DEBUG >= 2
|
|
||||||
.name = "SWITCH",
|
|
||||||
#endif
|
|
||||||
.init = hidd_init,
|
|
||||||
.reset = hidd_reset,
|
|
||||||
.open = hidd_open,
|
|
||||||
.control_xfer_cb = hidd_control_xfer_cb,
|
|
||||||
.xfer_cb = hidd_xfer_cb,
|
|
||||||
.sof = NULL
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void SwitchDriver::process(Gamepad * gamepad, uint8_t * outBuffer)
|
|
||||||
{
|
|
||||||
switchReport.hat = SWITCH_HAT_NOTHING;
|
|
||||||
|
|
||||||
if (gamepad->state.up)
|
|
||||||
{
|
|
||||||
if (gamepad->state.right)
|
|
||||||
{
|
|
||||||
switchReport.hat = SWITCH_HAT_UPRIGHT;
|
|
||||||
}
|
|
||||||
else if (gamepad->state.left)
|
|
||||||
{
|
|
||||||
switchReport.hat = SWITCH_HAT_UPLEFT;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switchReport.hat = SWITCH_HAT_UP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (gamepad->state.down)
|
|
||||||
{
|
|
||||||
if (gamepad->state.right)
|
|
||||||
{
|
|
||||||
switchReport.hat = SWITCH_HAT_DOWNRIGHT;
|
|
||||||
}
|
|
||||||
else if (gamepad->state.left)
|
|
||||||
{
|
|
||||||
switchReport.hat = SWITCH_HAT_DOWNLEFT;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switchReport.hat = SWITCH_HAT_DOWN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (gamepad->state.left)
|
|
||||||
{
|
|
||||||
switchReport.hat = SWITCH_HAT_LEFT;
|
|
||||||
}
|
|
||||||
else if (gamepad->state.right)
|
|
||||||
{
|
|
||||||
switchReport.hat = SWITCH_HAT_RIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
switchReport.buttons = 0
|
|
||||||
| (gamepad->state.a ? SWITCH_MASK_B : 0)
|
|
||||||
| (gamepad->state.b ? SWITCH_MASK_A : 0)
|
|
||||||
| (gamepad->state.x ? SWITCH_MASK_Y : 0)
|
|
||||||
| (gamepad->state.y ? SWITCH_MASK_X : 0)
|
|
||||||
| (gamepad->state.lb ? SWITCH_MASK_L : 0)
|
|
||||||
| (gamepad->state.rb ? SWITCH_MASK_R : 0)
|
|
||||||
| (gamepad->state.lt ? SWITCH_MASK_ZL : 0)
|
|
||||||
| (gamepad->state.rt ? SWITCH_MASK_ZR : 0)
|
|
||||||
| (gamepad->state.back ? SWITCH_MASK_MINUS : 0)
|
|
||||||
| (gamepad->state.start ? SWITCH_MASK_PLUS : 0)
|
|
||||||
| (gamepad->state.l3 ? SWITCH_MASK_L3 : 0)
|
|
||||||
| (gamepad->state.r3 ? SWITCH_MASK_R3 : 0)
|
|
||||||
| (gamepad->state.sys ? SWITCH_MASK_HOME : 0)
|
|
||||||
| (gamepad->state.misc ? SWITCH_MASK_CAPTURE : 0)
|
|
||||||
;
|
|
||||||
|
|
||||||
switchReport.lx = scale_int16_to_uint8(gamepad->state.lx, false);
|
|
||||||
switchReport.ly = scale_int16_to_uint8(gamepad->state.ly, true);
|
|
||||||
switchReport.rx = scale_int16_to_uint8(gamepad->state.rx, false);
|
|
||||||
switchReport.ry = scale_int16_to_uint8(gamepad->state.ry, true);
|
|
||||||
|
|
||||||
// switchReport.lx = static_cast<uint8_t>((gamepad->state.lx + 32768) >> 8);
|
|
||||||
// switchReport.ly = static_cast<uint8_t>(((-gamepad->state.ly - 1) + 32768) >> 8);
|
|
||||||
// switchReport.rx = static_cast<uint8_t>((gamepad->state.rx + 32768) >> 8);
|
|
||||||
// switchReport.ry = static_cast<uint8_t>(((-gamepad->state.ry - 1) + 32768) >> 8);
|
|
||||||
|
|
||||||
// Wake up TinyUSB device
|
|
||||||
if (tud_suspended())
|
|
||||||
tud_remote_wakeup();
|
|
||||||
|
|
||||||
void * report = &switchReport;
|
|
||||||
uint16_t report_size = sizeof(switchReport);
|
|
||||||
if (memcmp(last_report, report, report_size) != 0) {
|
|
||||||
// HID ready + report sent, copy previous report
|
|
||||||
if (tud_hid_ready() && tud_hid_report(0, report, report_size) == true ) {
|
|
||||||
memcpy(last_report, report, report_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// tud_hid_get_report_cb
|
|
||||||
uint16_t SwitchDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) {
|
|
||||||
memcpy(buffer, &switchReport, sizeof(SwitchReport));
|
|
||||||
return sizeof(SwitchReport);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only PS4 does anything with set report
|
|
||||||
void SwitchDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {}
|
|
||||||
|
|
||||||
// Only XboxOG and Xbox One use vendor control xfer cb
|
|
||||||
bool SwitchDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint16_t * SwitchDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
|
||||||
const char *value = (const char *)switch_string_descriptors[index];
|
|
||||||
return getStringDescriptor(value, index); // getStringDescriptor returns a static array
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * SwitchDriver::get_descriptor_device_cb() {
|
|
||||||
return switch_device_descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * SwitchDriver::get_hid_descriptor_report_cb(uint8_t itf) {
|
|
||||||
return switch_report_descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * SwitchDriver::get_descriptor_configuration_cb(uint8_t index) {
|
|
||||||
return switch_configuration_descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * SwitchDriver::get_descriptor_device_qualifier_cb() {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t SwitchDriver::GetJoystickMidValue() {
|
|
||||||
return SWITCH_JOYSTICK_MID << 8;
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _SWITCH_DRIVER_H_
|
|
||||||
#define _SWITCH_DRIVER_H_
|
|
||||||
|
|
||||||
#include "usbd/gpdriver.h"
|
|
||||||
#include "descriptors/SwitchDescriptors.h"
|
|
||||||
|
|
||||||
class SwitchDriver : public GPDriver {
|
|
||||||
public:
|
|
||||||
virtual void initialize();
|
|
||||||
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
|
|
||||||
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
|
|
||||||
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
|
|
||||||
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
|
|
||||||
virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid);
|
|
||||||
virtual const uint8_t * get_descriptor_device_cb();
|
|
||||||
virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ;
|
|
||||||
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
|
|
||||||
virtual const uint8_t * get_descriptor_device_qualifier_cb();
|
|
||||||
virtual uint16_t GetJoystickMidValue();
|
|
||||||
private:
|
|
||||||
uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { };
|
|
||||||
SwitchReport switchReport;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // _SWITCH_DRIVER_H_
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2024 Open Stick Community (gp2040-ce.info)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _USBDRIVER_CPP_
|
|
||||||
#define _USBDRIVER_CPP_
|
|
||||||
|
|
||||||
#include "tusb.h"
|
|
||||||
|
|
||||||
#include "usbd/drivermanager.h"
|
|
||||||
|
|
||||||
static bool usb_mounted;
|
|
||||||
static bool usb_suspended;
|
|
||||||
|
|
||||||
bool get_usb_mounted(void)
|
|
||||||
{
|
|
||||||
return usb_mounted;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get_usb_suspended(void)
|
|
||||||
{
|
|
||||||
return usb_suspended;
|
|
||||||
}
|
|
||||||
|
|
||||||
const usbd_class_driver_t *usbd_app_driver_get_cb(uint8_t *driver_count)
|
|
||||||
{
|
|
||||||
*driver_count = 1;
|
|
||||||
return DriverManager::getInstance().getDriver()->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 DriverManager::getInstance().getDriver()->get_report(report_id, report_type, buffer, reqlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoked when received SET_REPORT control request or
|
|
||||||
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
DriverManager::getInstance().getDriver()->set_report(report_id, report_type, buffer, bufsize);
|
|
||||||
tud_hid_report(report_id, buffer, bufsize); // echo back anything we received from host
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoked when device is mounted
|
|
||||||
void tud_mount_cb(void)
|
|
||||||
{
|
|
||||||
usb_mounted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoked when device is unmounted
|
|
||||||
void tud_umount_cb(void)
|
|
||||||
{
|
|
||||||
usb_mounted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoked when usb bus is suspended
|
|
||||||
// remote_wakeup_en : if host allow us to perform remote wakeup
|
|
||||||
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
|
|
||||||
void tud_suspend_cb(bool remote_wakeup_en)
|
|
||||||
{
|
|
||||||
(void)remote_wakeup_en;
|
|
||||||
usb_suspended = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoked when usb bus is resumed
|
|
||||||
void tud_resume_cb(void)
|
|
||||||
{
|
|
||||||
usb_suspended = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vendor Controlled XFER occured
|
|
||||||
bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
|
|
||||||
{
|
|
||||||
return DriverManager::getInstance().getDriver()->vendor_control_xfer_cb(rhport, stage, request);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Invoked when received GET STRING DESCRIPTOR request
|
|
||||||
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
|
|
||||||
uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid)
|
|
||||||
{
|
|
||||||
return DriverManager::getInstance().getDriver()->get_descriptor_string_cb(index, langid);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoked when received GET DEVICE DESCRIPTOR
|
|
||||||
// Application return pointer to descriptor
|
|
||||||
uint8_t const *tud_descriptor_device_cb()
|
|
||||||
{
|
|
||||||
return DriverManager::getInstance().getDriver()->get_descriptor_device_cb();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoked when received GET HID REPORT DESCRIPTOR
|
|
||||||
// Application return pointer to descriptor
|
|
||||||
// Descriptor contents must exist long enough for transfer to complete
|
|
||||||
uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf)
|
|
||||||
{
|
|
||||||
return DriverManager::getInstance().getDriver()->get_hid_descriptor_report_cb(itf);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoked when received GET CONFIGURATION DESCRIPTOR
|
|
||||||
// Application return pointer to descriptor
|
|
||||||
// Descriptor contents must exist long enough for transfer to complete
|
|
||||||
uint8_t const *tud_descriptor_configuration_cb(uint8_t index)
|
|
||||||
{
|
|
||||||
return DriverManager::getInstance().getDriver()->get_descriptor_configuration_cb(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t const* tud_descriptor_device_qualifier_cb()
|
|
||||||
{
|
|
||||||
return DriverManager::getInstance().getDriver()->get_descriptor_device_qualifier_cb();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#ifndef _USB_DRIVER_H_
|
|
||||||
#define _USB_DRIVER_H_
|
|
||||||
|
|
||||||
bool get_usb_mounted(void);
|
|
||||||
bool get_usb_suspended(void);
|
|
||||||
|
|
||||||
#endif // #ifndef _USB_DRIVER_H_
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
#include "stdint.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <tusb.h>
|
|
||||||
#include "device/usbd_pvt.h"
|
|
||||||
#include "class/cdc/cdc_device.h"
|
|
||||||
|
|
||||||
#include "utilities/log.h"
|
|
||||||
|
|
||||||
#include "usbd/usbserial/USBSerialDriver.h"
|
|
||||||
#include "descriptors/USBSerialDescriptors.h"
|
|
||||||
|
|
||||||
void USBSerialDriver::initialize()
|
|
||||||
{
|
|
||||||
#if CFG_TUSB_DEBUG >= 2
|
|
||||||
.name = "UART",
|
|
||||||
#endif
|
|
||||||
class_driver = {
|
|
||||||
.init = cdcd_init,
|
|
||||||
.reset = cdcd_reset,
|
|
||||||
.open = cdcd_open,
|
|
||||||
.control_xfer_cb = cdcd_control_xfer_cb,
|
|
||||||
.xfer_cb = cdcd_xfer_cb,
|
|
||||||
.sof = NULL
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void USBSerialDriver::process(Gamepad * gamepad, uint8_t * outbuffer)
|
|
||||||
{
|
|
||||||
uint32_t bytes_written = tud_cdc_write_str(get_log());
|
|
||||||
|
|
||||||
if (bytes_written == strlen(get_log()))
|
|
||||||
{
|
|
||||||
tud_cdc_write_flush();
|
|
||||||
clear_log();
|
|
||||||
};
|
|
||||||
|
|
||||||
sleep_ms(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t USBSerialDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
|
|
||||||
{
|
|
||||||
return sizeof(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void USBSerialDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize)
|
|
||||||
{}
|
|
||||||
|
|
||||||
bool USBSerialDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint16_t * USBSerialDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid)
|
|
||||||
{
|
|
||||||
(void) langid;
|
|
||||||
size_t chr_count;
|
|
||||||
|
|
||||||
switch ( index )
|
|
||||||
{
|
|
||||||
case STRID_LANGID:
|
|
||||||
memcpy(&_desc_str[1], string_desc_arr[0], 2);
|
|
||||||
chr_count = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STRID_SERIAL:
|
|
||||||
chr_count = board_usb_get_serial(_desc_str + 1, 32);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
|
|
||||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
|
|
||||||
|
|
||||||
if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
|
|
||||||
|
|
||||||
const char *str = string_desc_arr[index];
|
|
||||||
|
|
||||||
// Cap at max char
|
|
||||||
chr_count = strlen(str);
|
|
||||||
size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type
|
|
||||||
if ( chr_count > max_count ) chr_count = max_count;
|
|
||||||
|
|
||||||
// Convert ASCII string into UTF-16
|
|
||||||
for ( size_t i = 0; i < chr_count; i++ ) {
|
|
||||||
_desc_str[1 + i] = str[i];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// first byte is length (including header), second byte is string type
|
|
||||||
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
|
|
||||||
|
|
||||||
return _desc_str;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * USBSerialDriver::get_descriptor_device_cb()
|
|
||||||
{
|
|
||||||
return (uint8_t const *) &usbserial_device_descriptor;;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * USBSerialDriver::get_hid_descriptor_report_cb(uint8_t itf)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * USBSerialDriver::get_descriptor_configuration_cb(uint8_t index)
|
|
||||||
{
|
|
||||||
return usbserial_configuration_descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * USBSerialDriver::get_descriptor_device_qualifier_cb()
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t USBSerialDriver::GetJoystickMidValue()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
#ifndef _UART_PASSTHROUGH_DRIVER_H_
|
|
||||||
#define _UART_PASSTHROUGH_DRIVER_H_
|
|
||||||
|
|
||||||
#include "usbd/gpdriver.h"
|
|
||||||
|
|
||||||
class USBSerialDriver : public GPDriver {
|
|
||||||
public:
|
|
||||||
virtual void initialize();
|
|
||||||
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
|
|
||||||
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
|
|
||||||
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
|
|
||||||
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
|
|
||||||
virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid);
|
|
||||||
virtual const uint8_t * get_descriptor_device_cb();
|
|
||||||
virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf);
|
|
||||||
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
|
|
||||||
virtual const uint8_t * get_descriptor_device_qualifier_cb();
|
|
||||||
virtual uint16_t GetJoystickMidValue();
|
|
||||||
private:
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
#include "usbd/xboxog/XboxOriginalDriver.h"
|
|
||||||
#include "usbd/xboxog/xid/xid.h"
|
|
||||||
#include "usbd/shared/driverhelper.h"
|
|
||||||
|
|
||||||
#include "Gamepad.h"
|
|
||||||
|
|
||||||
void xid_process_rumble_data(USB_XboxGamepad_OutReport_t xid_rumble_data)
|
|
||||||
{
|
|
||||||
gamepadOut.out_state.lrumble = xid_rumble_data.lValue >> 8;
|
|
||||||
gamepadOut.out_state.rrumble = xid_rumble_data.rValue >> 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XboxOriginalDriver::initialize() {
|
|
||||||
xboxOriginalReport = {
|
|
||||||
.dButtons = 0,
|
|
||||||
.A = 0,
|
|
||||||
.B = 0,
|
|
||||||
.X = 0,
|
|
||||||
.Y = 0,
|
|
||||||
.BLACK = 0,
|
|
||||||
.WHITE = 0,
|
|
||||||
.L = 0,
|
|
||||||
.R = 0,
|
|
||||||
.leftStickX = 0,
|
|
||||||
.leftStickY = 0,
|
|
||||||
.rightStickX = 0,
|
|
||||||
.rightStickY = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Copy XID driver to local class driver
|
|
||||||
memcpy(&class_driver, xid_get_driver(), sizeof(usbd_class_driver_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
void XboxOriginalDriver::process(Gamepad * gamepad, uint8_t * outBuffer) {
|
|
||||||
// digital buttons
|
|
||||||
xboxOriginalReport.dButtons = 0
|
|
||||||
| (gamepad->state.up ? XID_DUP : 0)
|
|
||||||
| (gamepad->state.down ? XID_DDOWN : 0)
|
|
||||||
| (gamepad->state.left ? XID_DLEFT : 0)
|
|
||||||
| (gamepad->state.right ? XID_DRIGHT : 0)
|
|
||||||
| (gamepad->state.start ? XID_START : 0)
|
|
||||||
| (gamepad->state.back ? XID_BACK : 0)
|
|
||||||
| (gamepad->state.l3 ? XID_LS : 0)
|
|
||||||
| (gamepad->state.r3 ? XID_RS : 0)
|
|
||||||
;
|
|
||||||
|
|
||||||
// analog buttons - convert to digital
|
|
||||||
xboxOriginalReport.A = (gamepad->state.a ? 0xFF : 0);
|
|
||||||
xboxOriginalReport.B = (gamepad->state.b ? 0xFF : 0);
|
|
||||||
xboxOriginalReport.X = (gamepad->state.x ? 0xFF : 0);
|
|
||||||
xboxOriginalReport.Y = (gamepad->state.y ? 0xFF : 0);
|
|
||||||
xboxOriginalReport.BLACK = (gamepad->state.rb ? 0xFF : 0);
|
|
||||||
xboxOriginalReport.WHITE = (gamepad->state.lb ? 0xFF : 0);
|
|
||||||
|
|
||||||
// analog triggers
|
|
||||||
xboxOriginalReport.L = gamepad->state.lt;
|
|
||||||
xboxOriginalReport.R = gamepad->state.rt;
|
|
||||||
|
|
||||||
// analog sticks
|
|
||||||
xboxOriginalReport.leftStickX = gamepad->state.lx;
|
|
||||||
xboxOriginalReport.leftStickY = gamepad->state.ly;
|
|
||||||
xboxOriginalReport.rightStickX = gamepad->state.rx;
|
|
||||||
xboxOriginalReport.rightStickY = gamepad->state.ry;
|
|
||||||
|
|
||||||
if (tud_suspended())
|
|
||||||
tud_remote_wakeup();
|
|
||||||
|
|
||||||
uint8_t xIndex = xid_get_index_by_type(0, XID_TYPE_GAMECONTROLLER);
|
|
||||||
if (memcmp(last_report, &xboxOriginalReport, sizeof(XboxOriginalReport)) != 0) {
|
|
||||||
if ( xid_send_report(xIndex, &xboxOriginalReport, sizeof(XboxOriginalReport)) == true ) {
|
|
||||||
memcpy(last_report, &xboxOriginalReport, sizeof(XboxOriginalReport));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
USB_XboxGamepad_OutReport_t xpad_rumble_data;
|
|
||||||
|
|
||||||
if (xid_get_report(xIndex, &xpad_rumble_data, sizeof(xpad_rumble_data)))
|
|
||||||
{
|
|
||||||
xid_process_rumble_data(xpad_rumble_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// tud_hid_get_report_cb
|
|
||||||
uint16_t XboxOriginalDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) {
|
|
||||||
memcpy(buffer, &xboxOriginalReport, sizeof(XboxOriginalReport));
|
|
||||||
return sizeof(XboxOriginalReport);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only PS4 does anything with set report
|
|
||||||
void XboxOriginalDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {}
|
|
||||||
|
|
||||||
// Only XboxOG and Xbox One use vendor control xfer cb
|
|
||||||
bool XboxOriginalDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) {
|
|
||||||
return class_driver.control_xfer_cb(rhport, stage, request);
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint16_t * XboxOriginalDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
|
||||||
const char *value = (const char *)xboxoriginal_string_descriptors[index];
|
|
||||||
return getStringDescriptor(value, index); // getStringDescriptor returns a static array
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * XboxOriginalDriver::get_descriptor_device_cb() {
|
|
||||||
return xboxoriginal_device_descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * XboxOriginalDriver::get_hid_descriptor_report_cb(uint8_t itf) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * XboxOriginalDriver::get_descriptor_configuration_cb(uint8_t index) {
|
|
||||||
return xboxoriginal_configuration_descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * XboxOriginalDriver::get_descriptor_device_qualifier_cb() {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t XboxOriginalDriver::GetJoystickMidValue() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _XBOX_ORIGINAL_DRIVER_H_
|
|
||||||
#define _XBOX_ORIGINAL_DRIVER_H_
|
|
||||||
|
|
||||||
#include "usbd/gpdriver.h"
|
|
||||||
#include "descriptors/XboxOriginalDescriptors.h"
|
|
||||||
|
|
||||||
class XboxOriginalDriver : public GPDriver {
|
|
||||||
public:
|
|
||||||
virtual void initialize();
|
|
||||||
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
|
|
||||||
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
|
|
||||||
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
|
|
||||||
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
|
|
||||||
virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid);
|
|
||||||
virtual const uint8_t * get_descriptor_device_cb();
|
|
||||||
virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ;
|
|
||||||
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
|
|
||||||
virtual const uint8_t * get_descriptor_device_qualifier_cb();
|
|
||||||
virtual uint16_t GetJoystickMidValue();
|
|
||||||
private:
|
|
||||||
uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { };
|
|
||||||
XboxOriginalReport xboxOriginalReport;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // _XBOX_ORIGINAL_DRIVER_H_
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2023 Ryzee119
|
|
||||||
|
|
||||||
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.
|
|
||||||
@@ -1,257 +0,0 @@
|
|||||||
#include "usbd/xboxog/xid/xid.h"
|
|
||||||
|
|
||||||
bool duke_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, xid_interface_t *p_xid);
|
|
||||||
bool steelbattalion_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, xid_interface_t *p_xid);
|
|
||||||
bool xremote_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, xid_interface_t *p_xid);
|
|
||||||
|
|
||||||
#define MAX_XIDS (XID_DUKE + XID_STEELBATTALION + XID_XREMOTE)
|
|
||||||
|
|
||||||
CFG_TUSB_MEM_SECTION static xid_interface_t _xid_itf[MAX_XIDS];
|
|
||||||
|
|
||||||
static inline int8_t get_index_by_itfnum(uint8_t itf_num)
|
|
||||||
{
|
|
||||||
for (uint8_t i = 0; i < MAX_XIDS; i++)
|
|
||||||
{
|
|
||||||
if (itf_num == _xid_itf[i].itf_num)
|
|
||||||
return i;
|
|
||||||
//Xremote has two interfaces. Handle is separately.
|
|
||||||
if (_xid_itf[i].type == XID_TYPE_XREMOTE)
|
|
||||||
{
|
|
||||||
if (itf_num == _xid_itf[i].itf_num + 1)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int8_t get_index_by_ep_addr(uint8_t ep_addr)
|
|
||||||
{
|
|
||||||
for (uint8_t i = 0; i < MAX_XIDS; i++)
|
|
||||||
{
|
|
||||||
if (ep_addr == _xid_itf[i].ep_in)
|
|
||||||
return i;
|
|
||||||
|
|
||||||
if (ep_addr == _xid_itf[i].ep_out)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline xid_interface_t *find_available_interface()
|
|
||||||
{
|
|
||||||
for (uint8_t i = 0; i < MAX_XIDS; i++)
|
|
||||||
{
|
|
||||||
if (_xid_itf[i].ep_in == 0)
|
|
||||||
return &_xid_itf[i];
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void xid_init(void)
|
|
||||||
{
|
|
||||||
|
|
||||||
//#define MAX_XIDS (XID_DUKE + XID_STEELBATTALION + XID_XREMOTE)
|
|
||||||
tu_memclr(_xid_itf, sizeof(_xid_itf));
|
|
||||||
for (uint8_t i = 0; i < MAX_XIDS; i++)
|
|
||||||
{
|
|
||||||
_xid_itf[i].type = (i < (XID_DUKE)) ? XID_TYPE_GAMECONTROLLER :
|
|
||||||
(i < (XID_DUKE + XID_STEELBATTALION)) ? XID_TYPE_STEELBATTALION :
|
|
||||||
(i < (XID_DUKE + XID_STEELBATTALION + XID_XREMOTE)) ? XID_TYPE_XREMOTE : 0xFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 == XID_INTERFACE_CLASS, 0);
|
|
||||||
TU_VERIFY(itf_desc->bInterfaceSubClass == XID_INTERFACE_SUBCLASS, 0);
|
|
||||||
|
|
||||||
xid_interface_t *p_xid = find_available_interface();
|
|
||||||
TU_ASSERT(p_xid != NULL, 0);
|
|
||||||
|
|
||||||
uint16_t const drv_len = (p_xid->type == XID_TYPE_GAMECONTROLLER) ? TUD_XID_DUKE_DESC_LEN :
|
|
||||||
(p_xid->type == XID_TYPE_STEELBATTALION) ? TUD_XID_SB_DESC_LEN :
|
|
||||||
(p_xid->type == XID_TYPE_XREMOTE) ? TUD_XID_XREMOTE_DESC_LEN : 0;
|
|
||||||
TU_ASSERT(max_len >= drv_len, 0);
|
|
||||||
|
|
||||||
p_xid->itf_num = itf_desc->bInterfaceNumber;
|
|
||||||
|
|
||||||
tusb_desc_endpoint_t *ep_desc;
|
|
||||||
ep_desc = (tusb_desc_endpoint_t *)tu_desc_next(itf_desc);
|
|
||||||
if (tu_desc_type(ep_desc) == TUSB_DESC_ENDPOINT)
|
|
||||||
{
|
|
||||||
usbd_edpt_open(rhport, ep_desc);
|
|
||||||
(ep_desc->bEndpointAddress & 0x80) ? (p_xid->ep_in = ep_desc->bEndpointAddress) :
|
|
||||||
(p_xid->ep_out = ep_desc->bEndpointAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
TU_VERIFY(itf_desc->bNumEndpoints >= 2, drv_len);
|
|
||||||
ep_desc = (tusb_desc_endpoint_t *)tu_desc_next(ep_desc);
|
|
||||||
if (tu_desc_type(ep_desc) == TUSB_DESC_ENDPOINT)
|
|
||||||
{
|
|
||||||
usbd_edpt_open(rhport, ep_desc);
|
|
||||||
(ep_desc->bEndpointAddress & 0x80) ? (p_xid->ep_in = ep_desc->bEndpointAddress) :
|
|
||||||
(p_xid->ep_out = ep_desc->bEndpointAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
return drv_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int8_t xid_get_index_by_type(uint8_t type_index, xid_type_t type)
|
|
||||||
{
|
|
||||||
uint8_t _type_index = 0;
|
|
||||||
for (uint8_t i = 0; i < MAX_XIDS; i++)
|
|
||||||
{
|
|
||||||
if (_xid_itf[i].type == type)
|
|
||||||
{
|
|
||||||
if (_type_index == type_index)
|
|
||||||
return i;
|
|
||||||
_type_index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool xid_get_report(uint8_t index, void *report, uint16_t len)
|
|
||||||
{
|
|
||||||
TU_VERIFY(index < MAX_XIDS, false);
|
|
||||||
TU_VERIFY(_xid_itf[index].ep_out != 0, false);
|
|
||||||
TU_VERIFY(len < XID_MAX_PACKET_SIZE, false);
|
|
||||||
|
|
||||||
memcpy(report, _xid_itf[index].out, len);
|
|
||||||
|
|
||||||
//Queue request on out endpoint
|
|
||||||
//Most games send to control pipe, but some send to out pipe. THPSX2 atleast
|
|
||||||
if (tud_ready() && !usbd_edpt_busy(TUD_OPT_RHPORT, _xid_itf[index].ep_out))
|
|
||||||
{
|
|
||||||
usbd_edpt_xfer(TUD_OPT_RHPORT, _xid_itf[index].ep_out, _xid_itf[index].ep_out_buff, len);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool xid_send_report_ready(uint8_t index)
|
|
||||||
{
|
|
||||||
TU_VERIFY(index < MAX_XIDS, false);
|
|
||||||
TU_VERIFY(_xid_itf[index].ep_in != 0, false);
|
|
||||||
return (tud_ready() && !usbd_edpt_busy(TUD_OPT_RHPORT, _xid_itf[index].ep_in));
|
|
||||||
}
|
|
||||||
bool xid_send_report(uint8_t index, void *report, uint16_t len)
|
|
||||||
{
|
|
||||||
TU_VERIFY(len < XID_MAX_PACKET_SIZE, false);
|
|
||||||
TU_VERIFY(index < MAX_XIDS, false);
|
|
||||||
TU_VERIFY(_xid_itf[index].ep_in != 0, false);
|
|
||||||
TU_VERIFY(xid_send_report_ready(index), false);
|
|
||||||
|
|
||||||
if (tud_suspended())
|
|
||||||
tud_remote_wakeup();
|
|
||||||
|
|
||||||
//Maintain a local copy of the report
|
|
||||||
memcpy(_xid_itf[index].in, report, len);
|
|
||||||
|
|
||||||
//Send it to the host
|
|
||||||
return usbd_edpt_xfer(TUD_OPT_RHPORT, _xid_itf[index].ep_in, _xid_itf[index].in, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool xid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
|
|
||||||
{
|
|
||||||
(void)rhport;
|
|
||||||
uint8_t index = get_index_by_ep_addr(ep_addr);
|
|
||||||
|
|
||||||
TU_VERIFY(result == XFER_RESULT_SUCCESS, true);
|
|
||||||
TU_VERIFY(index != -1, true);
|
|
||||||
TU_VERIFY(xferred_bytes < XID_MAX_PACKET_SIZE, true);
|
|
||||||
|
|
||||||
if (ep_addr == _xid_itf[index].ep_out)
|
|
||||||
{
|
|
||||||
memcpy(_xid_itf[index].out, _xid_itf[index].ep_out_buff, MIN(xferred_bytes, sizeof( _xid_itf[index].ep_out_buff)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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_index_by_itfnum((uint8_t)request->wIndex);
|
|
||||||
TU_VERIFY(index != -1, false);
|
|
||||||
|
|
||||||
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, _xid_itf[index].in, MIN(request->wLength, sizeof(_xid_itf[index].in)));
|
|
||||||
}
|
|
||||||
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, _xid_itf[index].ep_out_buff, MIN(request->wLength, sizeof(_xid_itf[index].ep_out_buff)));
|
|
||||||
}
|
|
||||||
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(_xid_itf[index].out, _xid_itf[index].ep_out_buff, MIN(request->wLength, sizeof(_xid_itf[index].out)));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (_xid_itf[index].type)
|
|
||||||
{
|
|
||||||
case XID_TYPE_GAMECONTROLLER:
|
|
||||||
ret = duke_control_xfer(rhport, stage, request, &_xid_itf[index]);
|
|
||||||
break;
|
|
||||||
case XID_TYPE_STEELBATTALION:
|
|
||||||
ret = steelbattalion_control_xfer(rhport, stage, request, &_xid_itf[index]);
|
|
||||||
break;
|
|
||||||
case XID_TYPE_XREMOTE:
|
|
||||||
ret = xremote_control_xfer(rhport, stage, request, &_xid_itf[index]);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const usbd_class_driver_t xid_driver =
|
|
||||||
{
|
|
||||||
#if CFG_TUSB_DEBUG >= 2
|
|
||||||
.name = "XID DRIVER (DUKE,SB OR XREMOTE)",
|
|
||||||
#endif
|
|
||||||
.init = xid_init,
|
|
||||||
.reset = xid_reset,
|
|
||||||
.open = xid_open,
|
|
||||||
.control_xfer_cb = xid_control_xfer_cb,
|
|
||||||
.xfer_cb = xid_xfer_cb,
|
|
||||||
.sof = NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
const usbd_class_driver_t *xid_get_driver()
|
|
||||||
{
|
|
||||||
return &xid_driver;
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
#ifndef XID_H_
|
|
||||||
#define XID_H_
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <tusb.h>
|
|
||||||
#include <device/usbd_pvt.h>
|
|
||||||
|
|
||||||
#include "usbd/xboxog/xid/xid_gamepad.h"
|
|
||||||
#include "usbd/xboxog/xid/xid_remote.h"
|
|
||||||
#include "usbd/xboxog/xid/xid_steelbattalion.h"
|
|
||||||
|
|
||||||
#define XID_DUKE 1
|
|
||||||
#define XID_STEELBATTALION 0
|
|
||||||
#define XID_XREMOTE 0
|
|
||||||
#define MSC_XMU 0
|
|
||||||
|
|
||||||
#define XID_INTERFACE_CLASS 0x58
|
|
||||||
#define XID_INTERFACE_SUBCLASS 0x42
|
|
||||||
#define XID_MAX_PACKET_SIZE 32
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
XID_TYPE_GAMECONTROLLER,
|
|
||||||
XID_TYPE_STEELBATTALION,
|
|
||||||
XID_TYPE_XREMOTE,
|
|
||||||
} xid_type_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t itf_num;
|
|
||||||
xid_type_t type;
|
|
||||||
uint8_t ep_in;
|
|
||||||
uint8_t ep_out;
|
|
||||||
CFG_TUSB_MEM_ALIGN uint8_t ep_out_buff[XID_MAX_PACKET_SIZE];
|
|
||||||
CFG_TUSB_MEM_ALIGN uint8_t in[XID_MAX_PACKET_SIZE];
|
|
||||||
CFG_TUSB_MEM_ALIGN uint8_t out[XID_MAX_PACKET_SIZE];
|
|
||||||
} xid_interface_t;
|
|
||||||
|
|
||||||
int8_t xid_get_index_by_type(uint8_t type_index, xid_type_t type);
|
|
||||||
bool xid_get_report(uint8_t index, void *report, uint16_t len);
|
|
||||||
bool xid_send_report_ready(uint8_t index);
|
|
||||||
bool xid_send_report(uint8_t index, void *report, uint16_t len);
|
|
||||||
const usbd_class_driver_t *xid_get_driver();
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif //XID_H_
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#include "usbd/xboxog/xid/xid.h"
|
|
||||||
|
|
||||||
uint8_t *xremote_get_rom()
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
#ifndef XID_DRIVER_H_
|
|
||||||
#define XID_DRIVER_H_
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <tusb.h>
|
|
||||||
#include <device/usbd_pvt.h>
|
|
||||||
#include "usbd/xboxog/xid/xid.h"
|
|
||||||
|
|
||||||
static const tusb_desc_device_t XID_DESC_DEVICE =
|
|
||||||
{
|
|
||||||
.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
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
#if (XID_DUKE >= 1)
|
|
||||||
ITF_NUM_XID_DUKE,
|
|
||||||
#endif
|
|
||||||
#if (XID_STEELBATTALION >= 1)
|
|
||||||
ITF_NUM_XID_STEELBATTALION,
|
|
||||||
#endif
|
|
||||||
#if (XID_XREMOTE >= 1)
|
|
||||||
ITF_NUM_XID_XREMOTE,
|
|
||||||
ITF_NUM_XID_XREMOTE_ROM,
|
|
||||||
#endif
|
|
||||||
#if (MSC_XMU >= 1)
|
|
||||||
ITF_NUM_MSC,
|
|
||||||
#endif
|
|
||||||
XID_ITF_NUM_TOTAL
|
|
||||||
};
|
|
||||||
|
|
||||||
#define XID_CONFIG_TOTAL_LEN \
|
|
||||||
(TUD_CONFIG_DESC_LEN) + \
|
|
||||||
(TUD_XID_DUKE_DESC_LEN * XID_DUKE) + \
|
|
||||||
(TUD_XID_SB_DESC_LEN * XID_STEELBATTALION) + \
|
|
||||||
(TUD_XID_XREMOTE_DESC_LEN * XID_XREMOTE) + \
|
|
||||||
(TUD_MSC_DESC_LEN * MSC_XMU)
|
|
||||||
|
|
||||||
static uint8_t const XID_DESC_CONFIGURATION[] =
|
|
||||||
{
|
|
||||||
// Config number, interface count, string index, total length, attribute, power in mA
|
|
||||||
TUD_CONFIG_DESCRIPTOR(1, XID_ITF_NUM_TOTAL, 0, XID_CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 500),
|
|
||||||
|
|
||||||
#if (XID_DUKE >= 1)
|
|
||||||
TUD_XID_DUKE_DESCRIPTOR(ITF_NUM_XID_DUKE, ITF_NUM_XID_DUKE + 1, 0x80 | (ITF_NUM_XID_DUKE + 1)),
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (XID_STEELBATTALION >= 1)
|
|
||||||
TUD_XID_SB_DESCRIPTOR(ITF_NUM_XID_STEELBATTALION, ITF_NUM_XID_STEELBATTALION + 1, 0x80 | (ITF_NUM_XID_STEELBATTALION + 1)),
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (XID_XREMOTE >= 1)
|
|
||||||
TUD_XID_XREMOTE_DESCRIPTOR(ITF_NUM_XID_XREMOTE, 0x80 | (ITF_NUM_XID_XREMOTE + 1)),
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (CFG_TUD_MSC >= 1)
|
|
||||||
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, ITF_NUM_MSC + 1, 0x80 | (ITF_NUM_MSC + 1), 64),
|
|
||||||
#endif
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif //XID_DRIVER_H_
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
#include "usbd/xboxog/xid/xid_driver.h"
|
|
||||||
|
|
||||||
bool duke_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, xid_interface_t *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 *)DUKE_DESC_XID, sizeof(DUKE_DESC_XID));
|
|
||||||
}
|
|
||||||
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 *)DUKE_CAPABILITIES_IN, sizeof(DUKE_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 *)DUKE_CAPABILITIES_OUT, sizeof(DUKE_CAPABILITIES_OUT));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
#ifndef XID_DUKE_H_
|
|
||||||
#define XID_DUKE_H_
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <tusb.h>
|
|
||||||
|
|
||||||
/* Digital Button Masks */
|
|
||||||
#define XID_DUP (1 << 0)
|
|
||||||
#define XID_DDOWN (1 << 1)
|
|
||||||
#define XID_DLEFT (1 << 2)
|
|
||||||
#define XID_DRIGHT (1 << 3)
|
|
||||||
#define XID_START (1 << 4)
|
|
||||||
#define XID_BACK (1 << 5)
|
|
||||||
#define XID_LS (1 << 6)
|
|
||||||
#define XID_RS (1 << 7)
|
|
||||||
|
|
||||||
typedef struct __attribute__((packed))
|
|
||||||
{
|
|
||||||
uint8_t zero;
|
|
||||||
uint8_t bLength;
|
|
||||||
uint8_t dButtons;
|
|
||||||
uint8_t reserved;
|
|
||||||
uint8_t A;
|
|
||||||
uint8_t B;
|
|
||||||
uint8_t X;
|
|
||||||
uint8_t Y;
|
|
||||||
uint8_t BLACK;
|
|
||||||
uint8_t WHITE;
|
|
||||||
uint8_t L;
|
|
||||||
uint8_t R;
|
|
||||||
int16_t leftStickX;
|
|
||||||
int16_t leftStickY;
|
|
||||||
int16_t rightStickX;
|
|
||||||
int16_t rightStickY;
|
|
||||||
} USB_XboxGamepad_InReport_t;
|
|
||||||
|
|
||||||
typedef struct __attribute__((packed))
|
|
||||||
{
|
|
||||||
uint8_t zero;
|
|
||||||
uint8_t bLength;
|
|
||||||
uint16_t lValue;
|
|
||||||
uint16_t rValue;
|
|
||||||
} USB_XboxGamepad_OutReport_t;
|
|
||||||
|
|
||||||
#define TUD_XID_DUKE_DESC_LEN (9+7+7)
|
|
||||||
|
|
||||||
#define TUD_XID_DUKE_DESCRIPTOR(_itfnum, _epout, _epin) \
|
|
||||||
/* Interface */\
|
|
||||||
9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, XID_INTERFACE_CLASS, XID_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 DUKE_DESC_XID[] = {
|
|
||||||
0x10,
|
|
||||||
0x42,
|
|
||||||
0x00, 0x01,
|
|
||||||
0x01,
|
|
||||||
0x02,
|
|
||||||
0x14,
|
|
||||||
0x06,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t DUKE_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 DUKE_CAPABILITIES_OUT[] = {
|
|
||||||
0x00,
|
|
||||||
0x06,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
#include "usbd/xboxog/xid/xid_driver.h"
|
|
||||||
|
|
||||||
uint8_t *xremote_get_rom();
|
|
||||||
|
|
||||||
bool xremote_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, xid_interface_t *p_xid)
|
|
||||||
{
|
|
||||||
if (request->bmRequestType == 0xC1 && request->bRequest == 0x06 && request->wValue == 0x4200)
|
|
||||||
{
|
|
||||||
if (stage == CONTROL_STAGE_SETUP)
|
|
||||||
{
|
|
||||||
TU_LOG1("Sending REMOTE_DESC_XID\r\n");
|
|
||||||
tud_control_xfer(rhport, request, (void *)REMOTE_DESC_XID, sizeof(REMOTE_DESC_XID));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//INFO PACKET (Interface 1)
|
|
||||||
else 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");
|
|
||||||
uint8_t *rom = xremote_get_rom();
|
|
||||||
if (rom == NULL)
|
|
||||||
{
|
|
||||||
return false; //STALL
|
|
||||||
}
|
|
||||||
tud_control_xfer(rhport, request, &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)
|
|
||||||
{
|
|
||||||
uint8_t *rom = xremote_get_rom();
|
|
||||||
if (rom == NULL)
|
|
||||||
{
|
|
||||||
return false; //STALL
|
|
||||||
}
|
|
||||||
tud_control_xfer(rhport, request, &rom[request->wValue * 1024], request->wLength);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
#ifndef XID_REMOTE_H_
|
|
||||||
#define XID_REMOTE_H_
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <tusb.h>
|
|
||||||
|
|
||||||
#define XID_XREMOTE_ROM_CLASS 0x59
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
XREMOTE_SELECT = 0x0A0B,
|
|
||||||
XREMOTE_UP = 0x0AA6,
|
|
||||||
XREMOTE_DOWN = 0x0AA7,
|
|
||||||
XREMOTE_RIGHT = 0x0AA8,
|
|
||||||
XREMOTE_LEFT = 0x0AA9,
|
|
||||||
XREMOTE_INFO = 0x0AC3,
|
|
||||||
XREMOTE_NINE = 0x0AC6,
|
|
||||||
XREMOTE_EIGHT = 0x0AC7,
|
|
||||||
XREMOTE_SEVEN = 0x0AC8,
|
|
||||||
XREMOTE_SIX = 0x0AC9,
|
|
||||||
XREMOTE_FIVE = 0x0ACA,
|
|
||||||
XREMOTE_FOUR = 0x0ACB,
|
|
||||||
XREMOTE_THREE = 0x0ACC,
|
|
||||||
XREMOTE_TWO = 0x0ACD,
|
|
||||||
XREMOTE_ONE = 0x0ACE,
|
|
||||||
XREMOTE_ZERO = 0x0ACF,
|
|
||||||
XREMOTE_DISPLAY = 0x0AD5,
|
|
||||||
XREMOTE_BACK = 0x0AD8,
|
|
||||||
XREMOTE_SKIP_MINUS = 0x0ADD,
|
|
||||||
XREMOTE_SKIP_PLUS = 0x0ADF,
|
|
||||||
XREMOTE_STOP = 0x0AE0,
|
|
||||||
XREMOTE_REVERSE = 0x0AE2,
|
|
||||||
XREMOTE_FORWARD = 0x0AE3,
|
|
||||||
XREMOTE_TITLE = 0x0AE5,
|
|
||||||
XREMOTE_PAUSE = 0x0AE6,
|
|
||||||
XREMOTE_PLAY = 0x0AEA,
|
|
||||||
XREMOTE_MENU = 0x0AF7,
|
|
||||||
} xremote_buttoncode_t;
|
|
||||||
|
|
||||||
typedef struct __attribute__((packed))
|
|
||||||
{
|
|
||||||
uint8_t zero;
|
|
||||||
uint8_t bLength;
|
|
||||||
xremote_buttoncode_t buttonCode;
|
|
||||||
uint16_t timeElapsed; //ms since last button press
|
|
||||||
} USB_XboxRemote_InReport_t;
|
|
||||||
|
|
||||||
#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_INTERFACE_CLASS, XID_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
|
|
||||||
|
|
||||||
static const uint8_t REMOTE_DESC_XID[] = {
|
|
||||||
0x08,
|
|
||||||
0x42,
|
|
||||||
0x00, 0x01,
|
|
||||||
0x03,
|
|
||||||
0x00,
|
|
||||||
0x06,
|
|
||||||
0x00
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
#include "usbd/xboxog/xid/xid_driver.h"
|
|
||||||
|
|
||||||
bool steelbattalion_control_xfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, xid_interface_t *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 *)STEELBATTALION_DESC_XID, sizeof(STEELBATTALION_DESC_XID));
|
|
||||||
}
|
|
||||||
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 *)STEELBATTALION_CAPABILITIES_IN, sizeof(STEELBATTALION_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 *)STEELBATTALION_CAPABILITIES_OUT, sizeof(STEELBATTALION_CAPABILITIES_OUT));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
#ifndef XID_STEELBATTALION_H_
|
|
||||||
#define XID_STEELBATTALION_H_
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <tusb.h>
|
|
||||||
|
|
||||||
/* https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/blob/master/src/core/hle/XAPI/XapiCxbxr.h */
|
|
||||||
#define CXBX_SBC_GAMEPAD_W0_RIGHTJOYMAINWEAPON 0x0001
|
|
||||||
#define CXBX_SBC_GAMEPAD_W0_RIGHTJOYFIRE 0x0002
|
|
||||||
#define CXBX_SBC_GAMEPAD_W0_RIGHTJOYLOCKON 0x0004
|
|
||||||
#define CXBX_SBC_GAMEPAD_W0_EJECT 0x0008
|
|
||||||
#define CXBX_SBC_GAMEPAD_W0_COCKPITHATCH 0x0010
|
|
||||||
#define CXBX_SBC_GAMEPAD_W0_IGNITION 0x0020
|
|
||||||
#define CXBX_SBC_GAMEPAD_W0_START 0x0040
|
|
||||||
#define CXBX_SBC_GAMEPAD_W0_MULTIMONOPENCLOSE 0x0080
|
|
||||||
#define CXBX_SBC_GAMEPAD_W0_MULTIMONMAPZOOMINOUT 0x0100
|
|
||||||
#define CXBX_SBC_GAMEPAD_W0_MULTIMONMODESELECT 0x0200
|
|
||||||
#define CXBX_SBC_GAMEPAD_W0_MULTIMONSUBMONITOR 0x0400
|
|
||||||
#define CXBX_SBC_GAMEPAD_W0_MAINMONZOOMIN 0x0800
|
|
||||||
#define CXBX_SBC_GAMEPAD_W0_MAINMONZOOMOUT 0x1000
|
|
||||||
#define CXBX_SBC_GAMEPAD_W0_FUNCTIONFSS 0x2000
|
|
||||||
#define CXBX_SBC_GAMEPAD_W0_FUNCTIONMANIPULATOR 0x4000
|
|
||||||
#define CXBX_SBC_GAMEPAD_W0_FUNCTIONLINECOLORCHANGE 0x8000
|
|
||||||
|
|
||||||
#define CXBX_SBC_GAMEPAD_W1_WASHING 0x0001
|
|
||||||
#define CXBX_SBC_GAMEPAD_W1_EXTINGUISHER 0x0002
|
|
||||||
#define CXBX_SBC_GAMEPAD_W1_CHAFF 0x0004
|
|
||||||
#define CXBX_SBC_GAMEPAD_W1_FUNCTIONTANKDETACH 0x0008
|
|
||||||
#define CXBX_SBC_GAMEPAD_W1_FUNCTIONOVERRIDE 0x0010
|
|
||||||
#define CXBX_SBC_GAMEPAD_W1_FUNCTIONNIGHTSCOPE 0x0020
|
|
||||||
#define CXBX_SBC_GAMEPAD_W1_FUNCTIONF1 0x0040
|
|
||||||
#define CXBX_SBC_GAMEPAD_W1_FUNCTIONF2 0x0080
|
|
||||||
#define CXBX_SBC_GAMEPAD_W1_FUNCTIONF3 0x0100
|
|
||||||
#define CXBX_SBC_GAMEPAD_W1_WEAPONCONMAIN 0x0200
|
|
||||||
#define CXBX_SBC_GAMEPAD_W1_WEAPONCONSUB 0x0400
|
|
||||||
#define CXBX_SBC_GAMEPAD_W1_WEAPONCONMAGAZINE 0x0800
|
|
||||||
#define CXBX_SBC_GAMEPAD_W1_COMM1 0x1000
|
|
||||||
#define CXBX_SBC_GAMEPAD_W1_COMM2 0x2000
|
|
||||||
#define CXBX_SBC_GAMEPAD_W1_COMM3 0x4000
|
|
||||||
#define CXBX_SBC_GAMEPAD_W1_COMM4 0x8000
|
|
||||||
|
|
||||||
#define CXBX_SBC_GAMEPAD_W2_COMM5 0x0001
|
|
||||||
#define CXBX_SBC_GAMEPAD_W2_LEFTJOYSIGHTCHANGE 0x0002
|
|
||||||
#define CXBX_SBC_GAMEPAD_W2_TOGGLEFILTERCONTROL 0x0004
|
|
||||||
#define CXBX_SBC_GAMEPAD_W2_TOGGLEOXYGENSUPPLY 0x0008
|
|
||||||
#define CXBX_SBC_GAMEPAD_W2_TOGGLEFUELFLOWRATE 0x0010
|
|
||||||
#define CXBX_SBC_GAMEPAD_W2_TOGGLEBUFFREMATERIAL 0x0020
|
|
||||||
#define CXBX_SBC_GAMEPAD_W2_TOGGLEVTLOCATION 0x0040
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct __attribute__((packed))
|
|
||||||
{
|
|
||||||
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
|
|
||||||
} USB_SteelBattalion_InReport_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
} USB_SteelBattalion_OutReport_t;
|
|
||||||
|
|
||||||
#define TUD_XID_SB_DESC_LEN (9+7+7)
|
|
||||||
|
|
||||||
#define TUD_XID_SB_DESCRIPTOR(_itfnum, _epout, _epin) \
|
|
||||||
/* Interface */\
|
|
||||||
9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, XID_INTERFACE_CLASS, XID_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 STEELBATTALION_DESC_XID[] = {
|
|
||||||
0x10,
|
|
||||||
0x42,
|
|
||||||
0x00, 0x01,
|
|
||||||
0x80,
|
|
||||||
0x01,
|
|
||||||
0x1A,
|
|
||||||
0x16,
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t STEELBATTALION_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 STEELBATTALION_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
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "usbd/xinput/XInputDriver.h"
|
|
||||||
#include "usbd/shared/driverhelper.h"
|
|
||||||
|
|
||||||
#include "Gamepad.h"
|
|
||||||
|
|
||||||
#define XINPUT_OUT_SIZE 32
|
|
||||||
|
|
||||||
uint8_t endpoint_in = 0;
|
|
||||||
uint8_t endpoint_out = 0;
|
|
||||||
uint8_t xinput_out_buffer[XINPUT_OUT_SIZE] = {};
|
|
||||||
|
|
||||||
void xinput_process_rumble_data(const uint8_t* outBuffer)
|
|
||||||
{
|
|
||||||
XInputOutReport out_report;
|
|
||||||
|
|
||||||
memcpy(&out_report, outBuffer, sizeof(XInputOutReport));
|
|
||||||
|
|
||||||
if (out_report.report_type == XBOX_REPORT_TYPE_RUMBLE)
|
|
||||||
{
|
|
||||||
gamepadOut.out_state.lrumble = out_report.lrumble;
|
|
||||||
gamepadOut.out_state.rrumble = out_report.rrumble;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void xinput_init(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void xinput_reset(uint8_t rhport)
|
|
||||||
{
|
|
||||||
(void)rhport;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t xinput_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 xinput_device_control_request(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
|
|
||||||
{
|
|
||||||
(void)rhport;
|
|
||||||
(void)stage;
|
|
||||||
(void)request;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool xinput_control_complete(uint8_t rhport, tusb_control_request_t const *request)
|
|
||||||
{
|
|
||||||
(void)rhport;
|
|
||||||
(void)request;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool xinput_xfer_callback(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
|
|
||||||
{
|
|
||||||
(void)rhport;
|
|
||||||
(void)result;
|
|
||||||
(void)xferred_bytes;
|
|
||||||
|
|
||||||
if (ep_addr == endpoint_out) usbd_edpt_xfer(0, endpoint_out, xinput_out_buffer, XINPUT_OUT_SIZE);
|
|
||||||
|
|
||||||
xinput_process_rumble_data(xinput_out_buffer);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XInputDriver::initialize() {
|
|
||||||
xinputReport = {
|
|
||||||
.report_id = 0,
|
|
||||||
.report_size = XINPUT_ENDPOINT_SIZE,
|
|
||||||
.buttons1 = 0,
|
|
||||||
.buttons2 = 0,
|
|
||||||
.lt = 0,
|
|
||||||
.rt = 0,
|
|
||||||
.lx = 0,
|
|
||||||
.ly = 0,
|
|
||||||
.rx = 0,
|
|
||||||
.ry = 0,
|
|
||||||
._reserved = { },
|
|
||||||
};
|
|
||||||
|
|
||||||
class_driver = {
|
|
||||||
#if CFG_TUSB_DEBUG >= 2
|
|
||||||
.name = "XINPUT",
|
|
||||||
#endif
|
|
||||||
.init = xinput_init,
|
|
||||||
.reset = xinput_reset,
|
|
||||||
.open = xinput_open,
|
|
||||||
.control_xfer_cb = xinput_device_control_request,
|
|
||||||
.xfer_cb = xinput_xfer_callback,
|
|
||||||
.sof = NULL
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void XInputDriver::process(Gamepad * gamepad, uint8_t * outBuffer) {
|
|
||||||
xinputReport.buttons1 = 0
|
|
||||||
| (gamepad->state.up ? XBOX_MASK_UP : 0)
|
|
||||||
| (gamepad->state.down ? XBOX_MASK_DOWN : 0)
|
|
||||||
| (gamepad->state.left ? XBOX_MASK_LEFT : 0)
|
|
||||||
| (gamepad->state.right ? XBOX_MASK_RIGHT : 0)
|
|
||||||
| (gamepad->state.start ? XBOX_MASK_START : 0)
|
|
||||||
| (gamepad->state.back ? XBOX_MASK_BACK : 0)
|
|
||||||
| (gamepad->state.l3 ? XBOX_MASK_LS : 0)
|
|
||||||
| (gamepad->state.r3 ? XBOX_MASK_RS : 0)
|
|
||||||
;
|
|
||||||
|
|
||||||
xinputReport.buttons2 = 0
|
|
||||||
| (gamepad->state.rb ? XBOX_MASK_RB : 0)
|
|
||||||
| (gamepad->state.lb ? XBOX_MASK_LB : 0)
|
|
||||||
| (gamepad->state.sys ? XBOX_MASK_HOME : 0)
|
|
||||||
| (gamepad->state.a ? XBOX_MASK_A : 0)
|
|
||||||
| (gamepad->state.b ? XBOX_MASK_B : 0)
|
|
||||||
| (gamepad->state.x ? XBOX_MASK_X : 0)
|
|
||||||
| (gamepad->state.y ? XBOX_MASK_Y : 0)
|
|
||||||
;
|
|
||||||
|
|
||||||
xinputReport.lt = gamepad->state.lt;
|
|
||||||
xinputReport.rt = gamepad->state.rt;
|
|
||||||
|
|
||||||
xinputReport.lx = gamepad->state.lx;
|
|
||||||
xinputReport.ly = gamepad->state.ly;
|
|
||||||
xinputReport.rx = gamepad->state.rx;
|
|
||||||
xinputReport.ry = gamepad->state.ry;
|
|
||||||
|
|
||||||
// printf("processing rumble\n");
|
|
||||||
|
|
||||||
// compare against previous report and send new
|
|
||||||
if ( memcmp(last_report, &xinputReport, sizeof(XInputReport)) != 0) {
|
|
||||||
if ( tud_ready() && // Is the device ready?
|
|
||||||
(endpoint_in != 0) && (!usbd_edpt_busy(0, endpoint_in)) ) // Is the IN endpoint available?
|
|
||||||
{
|
|
||||||
usbd_edpt_claim(0, endpoint_in); // Take control of IN endpoint
|
|
||||||
usbd_edpt_xfer(0, endpoint_in, (uint8_t *)&xinputReport, sizeof(XInputReport)); // Send report buffer
|
|
||||||
usbd_edpt_release(0, endpoint_in); // Release control of IN endpoint
|
|
||||||
memcpy(last_report, &xinputReport, sizeof(XInputReport)); // save if we sent it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for player LEDs
|
|
||||||
if (tud_ready() &&
|
|
||||||
(endpoint_out != 0) && (!usbd_edpt_busy(0, endpoint_out)))
|
|
||||||
{
|
|
||||||
usbd_edpt_claim(0, endpoint_out); // Take control of OUT endpoint
|
|
||||||
usbd_edpt_xfer(0, endpoint_out, outBuffer, XINPUT_OUT_SIZE); // Retrieve report buffer
|
|
||||||
usbd_edpt_release(0, endpoint_out); // Release control of OUT endpoint
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// tud_hid_get_report_cb
|
|
||||||
uint16_t XInputDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) {
|
|
||||||
memcpy(buffer, &xinputReport, sizeof(XInputReport));
|
|
||||||
return sizeof(XInputReport);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only PS4 does anything with set report
|
|
||||||
void XInputDriver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {}
|
|
||||||
|
|
||||||
// Only XboxOG and Xbox One use vendor control xfer cb
|
|
||||||
bool XInputDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint16_t * XInputDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
|
||||||
const char *value = (const char *)xinput_string_descriptors[index];
|
|
||||||
return getStringDescriptor(value, index); // getStringDescriptor returns a static array
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * XInputDriver::get_descriptor_device_cb() {
|
|
||||||
return xinput_device_descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * XInputDriver::get_hid_descriptor_report_cb(uint8_t itf) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * XInputDriver::get_descriptor_configuration_cb(uint8_t index) {
|
|
||||||
return xinput_configuration_descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * XInputDriver::get_descriptor_device_qualifier_cb() {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t XInputDriver::GetJoystickMidValue() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2024 OpenStickCommunity (gp2040-ce.info)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _XINPUT_DRIVER_H_
|
|
||||||
#define _XINPUT_DRIVER_H_
|
|
||||||
|
|
||||||
#include "usbd/gpdriver.h"
|
|
||||||
#include "descriptors/XInputDescriptors.h"
|
|
||||||
|
|
||||||
class XInputDriver : public GPDriver {
|
|
||||||
public:
|
|
||||||
virtual void initialize();
|
|
||||||
virtual void process(Gamepad * gamepad, uint8_t * outBuffer);
|
|
||||||
virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen);
|
|
||||||
virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize);
|
|
||||||
virtual bool vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);
|
|
||||||
virtual const uint16_t * get_descriptor_string_cb(uint8_t index, uint16_t langid);
|
|
||||||
virtual const uint8_t * get_descriptor_device_cb();
|
|
||||||
virtual const uint8_t * get_hid_descriptor_report_cb(uint8_t itf) ;
|
|
||||||
virtual const uint8_t * get_descriptor_configuration_cb(uint8_t index);
|
|
||||||
virtual const uint8_t * get_descriptor_device_qualifier_cb();
|
|
||||||
virtual uint16_t GetJoystickMidValue();
|
|
||||||
private:
|
|
||||||
uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { };
|
|
||||||
XInputReport xinputReport;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
23
src/usbh/GPHostDriver.h
Normal file
23
src/usbh/GPHostDriver.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef _GPHOSTDRIVER_H_
|
||||||
|
#define _GPHOSTDRIVER_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "host/usbh.h" // needed so xinput_host will build
|
||||||
|
#include "xinput_host.h"
|
||||||
|
#include "tusb_gamepad.h"
|
||||||
|
|
||||||
|
#include "usbh/shared/shared.h"
|
||||||
|
|
||||||
|
class GPHostDriver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~GPHostDriver() = default;
|
||||||
|
|
||||||
|
virtual void init(uint8_t player_id, uint8_t dev_addr, uint8_t instance) = 0;
|
||||||
|
virtual void process_hid_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) = 0;
|
||||||
|
virtual void process_xinput_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, xinputh_interface_t const* report, uint16_t len) = 0;
|
||||||
|
virtual void hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) = 0;
|
||||||
|
virtual bool send_fb_data(const Gamepad* gamepad, uint8_t dev_addr, uint8_t instance) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _GPHOSTDRIVER_H_
|
||||||
113
src/usbh/n64usb/N64USB.cpp
Normal file
113
src/usbh/n64usb/N64USB.cpp
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#include "tusb.h"
|
||||||
|
|
||||||
|
#include "usbh/shared/scaling.h"
|
||||||
|
#include "usbh/n64usb/N64USB.h"
|
||||||
|
|
||||||
|
void N64USB::init(uint8_t player_id, uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
n64usb.player_id = player_id;
|
||||||
|
tuh_hid_receive_report(dev_addr, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void N64USB::update_gamepad(Gamepad* gamepad, const N64USBReport* n64_data)
|
||||||
|
{
|
||||||
|
gamepad->reset_pad(gamepad);
|
||||||
|
|
||||||
|
uint8_t n64_dpad = n64_data->buttons & N64_DPAD_MASK;
|
||||||
|
|
||||||
|
switch(n64_dpad)
|
||||||
|
{
|
||||||
|
case N64_DPAD_MASK_UP:
|
||||||
|
gamepad->buttons.up = true;
|
||||||
|
break;
|
||||||
|
case N64_DPAD_MASK_UP_RIGHT:
|
||||||
|
gamepad->buttons.up = true;
|
||||||
|
gamepad->buttons.right = true;
|
||||||
|
break;
|
||||||
|
case N64_DPAD_MASK_RIGHT:
|
||||||
|
gamepad->buttons.right = true;
|
||||||
|
break;
|
||||||
|
case N64_DPAD_MASK_RIGHT_DOWN:
|
||||||
|
gamepad->buttons.right = true;
|
||||||
|
gamepad->buttons.down = true;
|
||||||
|
break;
|
||||||
|
case N64_DPAD_MASK_DOWN:
|
||||||
|
gamepad->buttons.down = true;
|
||||||
|
break;
|
||||||
|
case N64_DPAD_MASK_DOWN_LEFT:
|
||||||
|
gamepad->buttons.down = true;
|
||||||
|
gamepad->buttons.left = true;
|
||||||
|
break;
|
||||||
|
case N64_DPAD_MASK_LEFT:
|
||||||
|
gamepad->buttons.left = true;
|
||||||
|
break;
|
||||||
|
case N64_DPAD_MASK_LEFT_UP:
|
||||||
|
gamepad->buttons.left = true;
|
||||||
|
gamepad->buttons.up = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n64_data->buttons & N64_C_UP_MASK) gamepad->joysticks.ry = INT16_MAX;
|
||||||
|
if (n64_data->buttons & N64_C_DOWN_MASK) gamepad->joysticks.ry = INT16_MIN;
|
||||||
|
if (n64_data->buttons & N64_C_LEFT_MASK) gamepad->joysticks.rx = INT16_MIN;
|
||||||
|
if (n64_data->buttons & N64_C_RIGHT_MASK) gamepad->joysticks.rx = INT16_MAX;
|
||||||
|
|
||||||
|
if (n64_data->buttons & N64_A_MASK) gamepad->buttons.a = true;
|
||||||
|
if (n64_data->buttons & N64_B_MASK) gamepad->buttons.b = true;
|
||||||
|
if (n64_data->buttons & N64_START_MASK) gamepad->buttons.start = true;
|
||||||
|
if (n64_data->buttons & N64_L_MASK) gamepad->buttons.lb = true;
|
||||||
|
if (n64_data->buttons & N64_R_MASK) gamepad->buttons.rb = true;
|
||||||
|
|
||||||
|
if (n64_data->buttons & N64_Z_MASK) gamepad->triggers.r = 0xFF;
|
||||||
|
|
||||||
|
gamepad->joysticks.ly = scale_uint8_to_int16(n64_data->y, true);
|
||||||
|
gamepad->joysticks.lx = scale_uint8_to_int16(n64_data->x, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void N64USB::process_hid_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)len;
|
||||||
|
|
||||||
|
static N64USBReport prev_report = {};
|
||||||
|
|
||||||
|
N64USBReport n64_report;
|
||||||
|
memcpy(&n64_report, report, sizeof(n64_report));
|
||||||
|
|
||||||
|
if (memcmp(&n64_report, &prev_report, sizeof(n64_report)) != 0)
|
||||||
|
{
|
||||||
|
update_gamepad(gamepad, &n64_report);
|
||||||
|
|
||||||
|
prev_report = n64_report;
|
||||||
|
}
|
||||||
|
|
||||||
|
tuh_hid_receive_report(dev_addr, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void N64USB::process_xinput_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, xinputh_interface_t const* report, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)gamepad;
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
(void)report;
|
||||||
|
(void)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void N64USB::hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
(void)report_id;
|
||||||
|
(void)report_type;
|
||||||
|
(void)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool N64USB::send_fb_data(const Gamepad* gamepad, uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
(void)gamepad;
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#ifndef _N64USB_H_
|
#ifndef _N64USB_H_
|
||||||
#define _N64USB_H_
|
#define _N64USB_H_
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "usbh/tusb_hid/shared.h"
|
#include "usbh/GPHostDriver.h"
|
||||||
|
|
||||||
const usb_vid_pid_t n64_devices[] =
|
const usb_vid_pid_t n64_devices[] =
|
||||||
{
|
{
|
||||||
@@ -46,21 +44,24 @@ typedef struct __attribute__((packed))
|
|||||||
uint16_t buttons;
|
uint16_t buttons;
|
||||||
} N64USBReport;
|
} N64USBReport;
|
||||||
|
|
||||||
struct N64USBState
|
struct N64USBState
|
||||||
{
|
{
|
||||||
uint8_t dev_addr = {0};
|
uint8_t player_id = {0};
|
||||||
uint8_t instance = {0};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class N64USB
|
class N64USB: public GPHostDriver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void init(uint8_t dev_addr, uint8_t instance);
|
~N64USB() override {}
|
||||||
void process_report(uint8_t const* report, uint16_t len);
|
|
||||||
bool send_fb_data();
|
virtual void init(uint8_t player_id, uint8_t dev_addr, uint8_t instance);
|
||||||
|
virtual void process_hid_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
|
||||||
|
virtual void process_xinput_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, xinputh_interface_t const* report, uint16_t len);
|
||||||
|
virtual void hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len);
|
||||||
|
virtual bool send_fb_data(const Gamepad* gamepad, uint8_t dev_addr, uint8_t instance);
|
||||||
private:
|
private:
|
||||||
N64USBState n64usb;
|
N64USBState n64usb;
|
||||||
void update_gamepad(const N64USBReport* n64_data);
|
void update_gamepad(Gamepad* gp, const N64USBReport* n64_data);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _N64USB_H_
|
#endif // _N64USB_H_
|
||||||
146
src/usbh/ps3/DInput.cpp
Normal file
146
src/usbh/ps3/DInput.cpp
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#include "tusb.h"
|
||||||
|
#include "class/hid/hid_host.h"
|
||||||
|
|
||||||
|
#include "usbh/ps3/DInput.h"
|
||||||
|
#include "usbh/shared/scaling.h"
|
||||||
|
|
||||||
|
void DInput::init(uint8_t player_id, uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
dinput.player_id = player_id;
|
||||||
|
|
||||||
|
tuh_hid_receive_report(dev_addr, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DInput::update_gamepad(Gamepad* gamepad, const DInputReport* dinput_report)
|
||||||
|
{
|
||||||
|
gamepad->reset_pad(gamepad);
|
||||||
|
|
||||||
|
switch (dinput_report->direction)
|
||||||
|
{
|
||||||
|
case DINPUT_HAT_UP:
|
||||||
|
gamepad->buttons.up = true;
|
||||||
|
break;
|
||||||
|
case DINPUT_HAT_UPRIGHT:
|
||||||
|
gamepad->buttons.up = true;
|
||||||
|
gamepad->buttons.right = true;
|
||||||
|
break;
|
||||||
|
case DINPUT_HAT_RIGHT:
|
||||||
|
gamepad->buttons.right = true;
|
||||||
|
break;
|
||||||
|
case DINPUT_HAT_DOWNRIGHT:
|
||||||
|
gamepad->buttons.right = true;
|
||||||
|
gamepad->buttons.down = true;
|
||||||
|
break;
|
||||||
|
case DINPUT_HAT_DOWN:
|
||||||
|
gamepad->buttons.down = true;
|
||||||
|
break;
|
||||||
|
case DINPUT_HAT_DOWNLEFT:
|
||||||
|
gamepad->buttons.down = true;
|
||||||
|
gamepad->buttons.left = true;
|
||||||
|
break;
|
||||||
|
case DINPUT_HAT_LEFT:
|
||||||
|
gamepad->buttons.left = true;
|
||||||
|
break;
|
||||||
|
case DINPUT_HAT_UPLEFT:
|
||||||
|
gamepad->buttons.up = true;
|
||||||
|
gamepad->buttons.left = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dinput_report->square_btn) gamepad->buttons.x = true;
|
||||||
|
if (dinput_report->triangle_btn) gamepad->buttons.y = true;
|
||||||
|
if (dinput_report->cross_btn) gamepad->buttons.a = true;
|
||||||
|
if (dinput_report->circle_btn) gamepad->buttons.b = true;
|
||||||
|
|
||||||
|
if (dinput_report->select_btn) gamepad->buttons.back = true;
|
||||||
|
if (dinput_report->start_btn) gamepad->buttons.start = true;
|
||||||
|
if (dinput_report->ps_btn) gamepad->buttons.sys = true;
|
||||||
|
|
||||||
|
if (dinput_report->l3_btn) gamepad->buttons.l3 = true;
|
||||||
|
if (dinput_report->r3_btn) gamepad->buttons.r3 = true;
|
||||||
|
|
||||||
|
if (dinput_report->l1_btn) gamepad->buttons.lb = true;
|
||||||
|
if (dinput_report->r1_btn) gamepad->buttons.rb = true;
|
||||||
|
|
||||||
|
if (dinput_report->l2_axis > 0)
|
||||||
|
{
|
||||||
|
gamepad->triggers.l = dinput_report->l2_axis;
|
||||||
|
}
|
||||||
|
else if (dinput_report->l2_btn)
|
||||||
|
{
|
||||||
|
gamepad->triggers.l = 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dinput_report->r2_axis > 0)
|
||||||
|
{
|
||||||
|
gamepad->triggers.r = dinput_report->r2_axis;
|
||||||
|
}
|
||||||
|
else if (dinput_report->r2_btn)
|
||||||
|
{
|
||||||
|
gamepad->triggers.r = 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
gamepad->analog_buttons.up = dinput_report->up_axis;
|
||||||
|
gamepad->analog_buttons.down = dinput_report->down_axis;
|
||||||
|
gamepad->analog_buttons.left = dinput_report->left_axis;
|
||||||
|
gamepad->analog_buttons.right = dinput_report->right_axis;
|
||||||
|
|
||||||
|
gamepad->analog_buttons.x = dinput_report->square_axis;
|
||||||
|
gamepad->analog_buttons.y = dinput_report->triangle_axis;
|
||||||
|
gamepad->analog_buttons.a = dinput_report->cross_axis;
|
||||||
|
gamepad->analog_buttons.b = dinput_report->circle_axis;
|
||||||
|
|
||||||
|
gamepad->analog_buttons.lb = dinput_report->l1_axis;
|
||||||
|
gamepad->analog_buttons.rb = dinput_report->r1_axis;
|
||||||
|
|
||||||
|
gamepad->joysticks.lx = scale_uint8_to_int16(dinput_report->l_x_axis, false);
|
||||||
|
gamepad->joysticks.ly = scale_uint8_to_int16(dinput_report->l_y_axis, true);
|
||||||
|
gamepad->joysticks.rx = scale_uint8_to_int16(dinput_report->r_x_axis, false);
|
||||||
|
gamepad->joysticks.ry = scale_uint8_to_int16(dinput_report->r_y_axis, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DInput::process_hid_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)len;
|
||||||
|
|
||||||
|
static DInputReport prev_report = {};
|
||||||
|
DInputReport dinput_report;
|
||||||
|
memcpy(&dinput_report, report, sizeof(dinput_report));
|
||||||
|
|
||||||
|
if (memcmp(&dinput_report, &prev_report, sizeof(dinput_report)) != 0)
|
||||||
|
{
|
||||||
|
update_gamepad(gamepad, &dinput_report);
|
||||||
|
prev_report = dinput_report;
|
||||||
|
}
|
||||||
|
|
||||||
|
tuh_hid_receive_report(dev_addr, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DInput::process_xinput_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, xinputh_interface_t const* report, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)gamepad;
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
(void)report;
|
||||||
|
(void)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DInput::hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
(void)report_id;
|
||||||
|
(void)report_type;
|
||||||
|
(void)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DInput::send_fb_data(const Gamepad* gamepad, uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
(void)gamepad;
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
38
src/usbh/ps3/DInput.h
Normal file
38
src/usbh/ps3/DInput.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#ifndef _DINPUT_H_
|
||||||
|
#define _DINPUT_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "descriptors/DInputDescriptors.h"
|
||||||
|
|
||||||
|
#include "usbh/GPHostDriver.h"
|
||||||
|
|
||||||
|
const usb_vid_pid_t dinput_devices[] =
|
||||||
|
{
|
||||||
|
{0x044F, 0xB324}, // ThrustMaster Dual Trigger (PS3 mode)
|
||||||
|
{0x0738, 0x8818}, // MadCatz Street Fighter IV Arcade FightStick
|
||||||
|
{0x0810, 0x0003}, // Personal Communication Systems, Inc. Generic
|
||||||
|
{0x146B, 0x0902}, // BigBen Interactive Wired Mini PS3 Game Controller
|
||||||
|
{0x2563, 0x0575} // SHANWAN 2In1 USB Joystick
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DInputState
|
||||||
|
{
|
||||||
|
uint8_t player_id = {0};
|
||||||
|
};
|
||||||
|
|
||||||
|
class DInput : public GPHostDriver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~DInput() override {}
|
||||||
|
|
||||||
|
virtual void init(uint8_t player_id, uint8_t dev_addr, uint8_t instance);
|
||||||
|
virtual void process_hid_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
|
||||||
|
virtual void process_xinput_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, xinputh_interface_t const* report, uint16_t len);
|
||||||
|
virtual void hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len);
|
||||||
|
virtual bool send_fb_data(const Gamepad* gamepad, uint8_t dev_addr, uint8_t instance);
|
||||||
|
private:
|
||||||
|
DInputState dinput;
|
||||||
|
void update_gamepad(Gamepad* gp, const DInputReport* dinput_report);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _DINPUT_H_
|
||||||
340
src/usbh/ps3/Dualshock3.cpp
Normal file
340
src/usbh/ps3/Dualshock3.cpp
Normal file
@@ -0,0 +1,340 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#include "tusb.h"
|
||||||
|
#include "class/hid/hid_host.h"
|
||||||
|
|
||||||
|
#include "usbh/ps3/Dualshock3.h"
|
||||||
|
#include "usbh/shared/scaling.h"
|
||||||
|
|
||||||
|
void Dualshock3::init(uint8_t player_id, uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
dualshock3.player_id = player_id;
|
||||||
|
dualshock3.response_count = 0;
|
||||||
|
dualshock3.reports_enabled = false;
|
||||||
|
|
||||||
|
// tuh_hid_get_report not working correctly?
|
||||||
|
tusb_control_request_t setup_packet =
|
||||||
|
{
|
||||||
|
.bmRequestType = 0xA1,
|
||||||
|
.bRequest = 0x01, // GET_REPORT
|
||||||
|
.wValue = (HID_REPORT_TYPE_FEATURE << 8) | 0xF2,
|
||||||
|
.wIndex = 0x0000,
|
||||||
|
.wLength = 17
|
||||||
|
};
|
||||||
|
|
||||||
|
tuh_xfer_s transfer =
|
||||||
|
{
|
||||||
|
.daddr = dev_addr,
|
||||||
|
.ep_addr = 0x00,
|
||||||
|
.setup = &setup_packet,
|
||||||
|
.buffer = (uint8_t*)&dualshock3.en_buffer,
|
||||||
|
.complete_cb = NULL,
|
||||||
|
.user_data = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
if (tuh_control_xfer(&transfer))
|
||||||
|
{
|
||||||
|
get_report_complete_cb(dev_addr, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tuh_hid_get_report(dev_addr, instance, 0xF2, HID_REPORT_TYPE_FEATURE, &dualshock3.en_buffer, 17);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dualshock3::get_report_complete_cb(uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
if (dualshock3.response_count == 0)
|
||||||
|
{
|
||||||
|
tusb_control_request_t setup_packet =
|
||||||
|
{
|
||||||
|
.bmRequestType = 0xA1,
|
||||||
|
.bRequest = 0x01, // GET_REPORT
|
||||||
|
.wValue = (HID_REPORT_TYPE_FEATURE << 8) | 0xF2,
|
||||||
|
.wIndex = 0x0000,
|
||||||
|
.wLength = 17
|
||||||
|
};
|
||||||
|
|
||||||
|
tuh_xfer_s transfer =
|
||||||
|
{
|
||||||
|
.daddr = dev_addr,
|
||||||
|
.ep_addr = 0x00,
|
||||||
|
.setup = &setup_packet,
|
||||||
|
.buffer = (uint8_t*)&dualshock3.en_buffer,
|
||||||
|
.complete_cb = NULL,
|
||||||
|
.user_data = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
if (tuh_control_xfer(&transfer))
|
||||||
|
{
|
||||||
|
dualshock3.response_count++;
|
||||||
|
get_report_complete_cb(dev_addr, instance);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (dualshock3.response_count == 1)
|
||||||
|
{
|
||||||
|
tusb_control_request_t setup_packet =
|
||||||
|
{
|
||||||
|
.bmRequestType = 0xA1,
|
||||||
|
.bRequest = 0x01, // GET_REPORT
|
||||||
|
.wValue = (HID_REPORT_TYPE_FEATURE << 8) | 0xF2,
|
||||||
|
.wIndex = 0x0000,
|
||||||
|
.wLength = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
tuh_xfer_s transfer =
|
||||||
|
{
|
||||||
|
.daddr = dev_addr,
|
||||||
|
.ep_addr = 0x00,
|
||||||
|
.setup = &setup_packet,
|
||||||
|
.buffer = (uint8_t*)&dualshock3.en_buffer,
|
||||||
|
.complete_cb = NULL,
|
||||||
|
.user_data = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
if (tuh_control_xfer(&transfer))
|
||||||
|
{
|
||||||
|
dualshock3.response_count++;
|
||||||
|
get_report_complete_cb(dev_addr, instance);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (dualshock3.response_count == 2)
|
||||||
|
{
|
||||||
|
dualshock3.response_count++;
|
||||||
|
|
||||||
|
uint8_t default_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
|
||||||
|
};
|
||||||
|
|
||||||
|
memcpy(&dualshock3.out_report, &default_report, sizeof(Dualshock3OutReport));
|
||||||
|
|
||||||
|
dualshock3.out_report.leds_bitmap = 0x1 << (instance + 1);
|
||||||
|
dualshock3.out_report.led[instance].time_enabled = UINT8_MAX;
|
||||||
|
|
||||||
|
tusb_control_request_t setup_packet =
|
||||||
|
{
|
||||||
|
.bmRequestType = 0x21,
|
||||||
|
.bRequest = 0x09, // SET_REPORT
|
||||||
|
.wValue = 0x0201,
|
||||||
|
.wIndex = 0x0000,
|
||||||
|
.wLength = sizeof(Dualshock3OutReport)
|
||||||
|
};
|
||||||
|
|
||||||
|
tuh_xfer_s transfer =
|
||||||
|
{
|
||||||
|
.daddr = dev_addr,
|
||||||
|
.ep_addr = 0x00,
|
||||||
|
.setup = &setup_packet,
|
||||||
|
.buffer = (uint8_t*)&dualshock3.out_report,
|
||||||
|
.complete_cb = NULL,
|
||||||
|
.user_data = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
if (tuh_control_xfer(&transfer))
|
||||||
|
{
|
||||||
|
dualshock3.reports_enabled = true;
|
||||||
|
tuh_hid_receive_report(dev_addr, instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dualshock3::hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
(void)report_id;
|
||||||
|
(void)report_type;
|
||||||
|
(void)len;
|
||||||
|
// if (dualshock3.response_count == 0)
|
||||||
|
// {
|
||||||
|
// if (tuh_hid_get_report(dev_addr, instance, 0xF2, HID_REPORT_TYPE_FEATURE, &dualshock3.en_buffer, 17))
|
||||||
|
// {
|
||||||
|
// dualshock3.response_count++;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else if (dualshock3.response_count == 1)
|
||||||
|
// {
|
||||||
|
// if (tuh_hid_get_report(dev_addr, instance, 0xF5, HID_REPORT_TYPE_FEATURE, &dualshock3.en_buffer, 8))
|
||||||
|
// {
|
||||||
|
// dualshock3.response_count++;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else if (dualshock3.response_count == 2)
|
||||||
|
// {
|
||||||
|
// dualshock3.response_count++;
|
||||||
|
|
||||||
|
// uint8_t default_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
|
||||||
|
// };
|
||||||
|
|
||||||
|
// memcpy(&dualshock3.out_report, &default_report, sizeof(Dualshock3OutReport));
|
||||||
|
|
||||||
|
// dualshock3.out_report.leds_bitmap = 0x1 << (instance + 1);
|
||||||
|
// dualshock3.out_report.led[instance].time_enabled = UINT8_MAX;
|
||||||
|
|
||||||
|
// tusb_control_request_t setup_packet =
|
||||||
|
// {
|
||||||
|
// .bmRequestType = 0x21,
|
||||||
|
// .bRequest = 0x09, // SET_REPORT
|
||||||
|
// .wValue = 0x0201,
|
||||||
|
// .wIndex = 0x0000,
|
||||||
|
// .wLength = sizeof(Dualshock3OutReport)
|
||||||
|
// };
|
||||||
|
|
||||||
|
// tuh_xfer_s transfer =
|
||||||
|
// {
|
||||||
|
// .daddr = dev_addr,
|
||||||
|
// .ep_addr = 0x00,
|
||||||
|
// .setup = &setup_packet,
|
||||||
|
// .buffer = (uint8_t*)&dualshock3.out_report,
|
||||||
|
// .complete_cb = NULL,
|
||||||
|
// .user_data = 0
|
||||||
|
// };
|
||||||
|
|
||||||
|
// if (tuh_control_xfer(&transfer))
|
||||||
|
// {
|
||||||
|
// dualshock3.reports_enabled = true;
|
||||||
|
// tuh_hid_receive_report(dev_addr, instance);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dualshock3::update_gamepad(Gamepad* gamepad, const Dualshock3Report* ds3_data)
|
||||||
|
{
|
||||||
|
gamepad->reset_pad(gamepad);
|
||||||
|
|
||||||
|
if (ds3_data->up) gamepad->buttons.up =true;
|
||||||
|
if (ds3_data->down) gamepad->buttons.down =true;
|
||||||
|
if (ds3_data->left) gamepad->buttons.left =true;
|
||||||
|
if (ds3_data->right) gamepad->buttons.right =true;
|
||||||
|
|
||||||
|
if (ds3_data->square) gamepad->buttons.x = true;
|
||||||
|
if (ds3_data->triangle) gamepad->buttons.y = true;
|
||||||
|
if (ds3_data->cross) gamepad->buttons.a = true;
|
||||||
|
if (ds3_data->circle) gamepad->buttons.b = true;
|
||||||
|
|
||||||
|
if (ds3_data->select) gamepad->buttons.back = true;
|
||||||
|
if (ds3_data->start) gamepad->buttons.start = true;
|
||||||
|
if (ds3_data->ps) gamepad->buttons.sys = true;
|
||||||
|
|
||||||
|
if (ds3_data->l3) gamepad->buttons.l3 = true;
|
||||||
|
if (ds3_data->r3) gamepad->buttons.r3 = true;
|
||||||
|
|
||||||
|
if (ds3_data->l1) gamepad->buttons.lb = true;
|
||||||
|
if (ds3_data->r1) gamepad->buttons.rb = true;
|
||||||
|
|
||||||
|
gamepad->analog_buttons.up = ds3_data->up_axis;
|
||||||
|
gamepad->analog_buttons.down = ds3_data->down_axis;
|
||||||
|
gamepad->analog_buttons.left = ds3_data->left_axis;
|
||||||
|
gamepad->analog_buttons.right = ds3_data->right_axis;
|
||||||
|
|
||||||
|
gamepad->analog_buttons.x = ds3_data->square_axis;
|
||||||
|
gamepad->analog_buttons.y = ds3_data->triangle_axis;
|
||||||
|
gamepad->analog_buttons.a = ds3_data->cross_axis;
|
||||||
|
gamepad->analog_buttons.b = ds3_data->circle_axis;
|
||||||
|
|
||||||
|
gamepad->analog_buttons.lb = ds3_data->l1_axis;
|
||||||
|
gamepad->analog_buttons.rb = ds3_data->r1_axis;
|
||||||
|
|
||||||
|
gamepad->triggers.l = ds3_data->l2_axis;
|
||||||
|
gamepad->triggers.r = ds3_data->r2_axis;
|
||||||
|
|
||||||
|
gamepad->joysticks.lx = scale_uint8_to_int16(ds3_data->left_x, false);
|
||||||
|
gamepad->joysticks.ly = scale_uint8_to_int16(ds3_data->left_y, true);
|
||||||
|
gamepad->joysticks.rx = scale_uint8_to_int16(ds3_data->right_x, false);
|
||||||
|
gamepad->joysticks.ry = scale_uint8_to_int16(ds3_data->right_y, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dualshock3::process_hid_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)len;
|
||||||
|
|
||||||
|
static Dualshock3Report prev_report = {};
|
||||||
|
Dualshock3Report ds3_report;
|
||||||
|
memcpy(&ds3_report, report, sizeof(ds3_report));
|
||||||
|
|
||||||
|
if (memcmp(&ds3_report, &prev_report, sizeof(ds3_report)) != 0)
|
||||||
|
{
|
||||||
|
update_gamepad(gamepad, &ds3_report);
|
||||||
|
prev_report = ds3_report;
|
||||||
|
}
|
||||||
|
|
||||||
|
tuh_hid_receive_report(dev_addr, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dualshock3::process_xinput_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, xinputh_interface_t const* report, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)gamepad;
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
(void)report;
|
||||||
|
(void)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Dualshock3::send_fb_data(const Gamepad* gamepad, uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
(void)instance;
|
||||||
|
|
||||||
|
static absolute_time_t next_allowed_time = {0};
|
||||||
|
absolute_time_t current_time = get_absolute_time();
|
||||||
|
|
||||||
|
if (!dualshock3.reports_enabled)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dualshock3.out_report.rumble.right_duration = (gamepad->rumble.r > 0) ? 20: 0;
|
||||||
|
dualshock3.out_report.rumble.right_motor_on = (gamepad->rumble.r > 0) ? 1 : 0;
|
||||||
|
|
||||||
|
dualshock3.out_report.rumble.left_duration = (gamepad->rumble.l > 0) ? 20 : 0;
|
||||||
|
dualshock3.out_report.rumble.left_motor_force = gamepad->rumble.l;
|
||||||
|
|
||||||
|
if (gamepad->rumble.l > 0 || gamepad->rumble.r > 0 ||
|
||||||
|
absolute_time_diff_us(current_time, next_allowed_time) < 0)
|
||||||
|
{
|
||||||
|
tusb_control_request_t setup_packet =
|
||||||
|
{
|
||||||
|
.bmRequestType = 0x21,
|
||||||
|
.bRequest = 0x09,
|
||||||
|
.wValue = 0x0201,
|
||||||
|
.wIndex = 0x0000,
|
||||||
|
.wLength = sizeof(Dualshock3OutReport)
|
||||||
|
};
|
||||||
|
|
||||||
|
tuh_xfer_s transfer =
|
||||||
|
{
|
||||||
|
.daddr = dev_addr,
|
||||||
|
.ep_addr = 0x00,
|
||||||
|
.setup = &setup_packet,
|
||||||
|
.buffer = (uint8_t*)&dualshock3.out_report,
|
||||||
|
.complete_cb = NULL,
|
||||||
|
.user_data = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
if (tuh_control_xfer(&transfer))
|
||||||
|
{
|
||||||
|
if (gamepad->rumble.l == 0 && gamepad->rumble.r == 0)
|
||||||
|
{
|
||||||
|
next_allowed_time = delayed_by_us(get_absolute_time(), 500000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
39
src/usbh/ps3/Dualshock3.h
Normal file
39
src/usbh/ps3/Dualshock3.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef _DUALSHOCK3_H_
|
||||||
|
#define _DUALSHOCK3_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "descriptors/PS3Descriptors.h"
|
||||||
|
|
||||||
|
#include "usbh/GPHostDriver.h"
|
||||||
|
|
||||||
|
const usb_vid_pid_t ps3_devices[] =
|
||||||
|
{
|
||||||
|
{0x054C, 0x0268}, // Sony Batoh (Dualshock 3)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Dualshock3State
|
||||||
|
{
|
||||||
|
uint8_t player_id {0};
|
||||||
|
bool reports_enabled {false};
|
||||||
|
uint8_t en_buffer[17];
|
||||||
|
Dualshock3OutReport out_report;
|
||||||
|
int response_count {0};
|
||||||
|
};
|
||||||
|
|
||||||
|
class Dualshock3 : public GPHostDriver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~Dualshock3() override {}
|
||||||
|
|
||||||
|
virtual void init(uint8_t player_id, uint8_t dev_addr, uint8_t instance);
|
||||||
|
virtual void process_hid_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
|
||||||
|
virtual void process_xinput_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, xinputh_interface_t const* report, uint16_t len);
|
||||||
|
virtual void hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len);
|
||||||
|
virtual bool send_fb_data(const Gamepad* gamepad, uint8_t dev_addr, uint8_t instance);
|
||||||
|
private:
|
||||||
|
Dualshock3State dualshock3;
|
||||||
|
void update_gamepad(Gamepad* gp, const Dualshock3Report* ds3_data);
|
||||||
|
void get_report_complete_cb(uint8_t dev_addr, uint8_t instance);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
152
src/usbh/ps4/Dualshock4.cpp
Normal file
152
src/usbh/ps4/Dualshock4.cpp
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#include "tusb.h"
|
||||||
|
#include "CRC32.h"
|
||||||
|
|
||||||
|
#include "usbh/ps4/Dualshock4.h"
|
||||||
|
#include "usbh/shared/scaling.h"
|
||||||
|
|
||||||
|
#define REPORT_ID_GAMEPAD_STATE 0x11
|
||||||
|
|
||||||
|
void Dualshock4::init(uint8_t player_id, uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
dualshock4.player_id = player_id;
|
||||||
|
// set_leds();
|
||||||
|
tuh_hid_receive_report(dev_addr, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this DCs the controller, come back to it */
|
||||||
|
bool Dualshock4::set_leds(uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
// see: https://github.com/Hydr8gon/VitaControl
|
||||||
|
|
||||||
|
static uint8_t buffer[79] = {};
|
||||||
|
buffer[0] = 0xA2;
|
||||||
|
buffer[1] = 0x11;
|
||||||
|
buffer[2] = 0xC0;
|
||||||
|
buffer[3] = 0x20;
|
||||||
|
buffer[4] = 0xF3;
|
||||||
|
buffer[5] = 0x04;
|
||||||
|
buffer[9] = led_colors[instance][0];
|
||||||
|
buffer[10] = led_colors[instance][1];
|
||||||
|
buffer[11] = led_colors[instance][2];
|
||||||
|
|
||||||
|
// Calculate the CRC of the data (including the 0xA2 byte) and append it to the end
|
||||||
|
uint32_t crc = CRC32::calculate(buffer, 75);
|
||||||
|
buffer[75] = crc >> 0;
|
||||||
|
buffer[76] = crc >> 8;
|
||||||
|
buffer[77] = crc >> 16;
|
||||||
|
buffer[78] = crc >> 24;
|
||||||
|
|
||||||
|
// Send the write request, omitting the 0xA2 byte
|
||||||
|
dualshock4.leds_set = tuh_hid_send_report(dev_addr, instance, 0, &buffer + 1, sizeof(buffer) - 1);
|
||||||
|
|
||||||
|
return dualshock4.leds_set;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dualshock4::update_gamepad(Gamepad* gamepad, const Dualshock4Report* ds4_data)
|
||||||
|
{
|
||||||
|
gamepad->reset_pad(gamepad);
|
||||||
|
|
||||||
|
switch(ds4_data->dpad)
|
||||||
|
{
|
||||||
|
case PS4_DPAD_MASK_UP:
|
||||||
|
gamepad->buttons.up = true;
|
||||||
|
break;
|
||||||
|
case PS4_DPAD_MASK_UP_RIGHT:
|
||||||
|
gamepad->buttons.up = true;
|
||||||
|
gamepad->buttons.right = true;
|
||||||
|
break;
|
||||||
|
case PS4_DPAD_MASK_RIGHT:
|
||||||
|
gamepad->buttons.right = true;
|
||||||
|
break;
|
||||||
|
case PS4_DPAD_MASK_RIGHT_DOWN:
|
||||||
|
gamepad->buttons.right = true;
|
||||||
|
gamepad->buttons.down = true;
|
||||||
|
break;
|
||||||
|
case PS4_DPAD_MASK_DOWN:
|
||||||
|
gamepad->buttons.down = true;
|
||||||
|
break;
|
||||||
|
case PS4_DPAD_MASK_DOWN_LEFT:
|
||||||
|
gamepad->buttons.down = true;
|
||||||
|
gamepad->buttons.left = true;
|
||||||
|
break;
|
||||||
|
case PS4_DPAD_MASK_LEFT:
|
||||||
|
gamepad->buttons.left = true;
|
||||||
|
break;
|
||||||
|
case PS4_DPAD_MASK_LEFT_UP:
|
||||||
|
gamepad->buttons.left = true;
|
||||||
|
gamepad->buttons.up = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ds4_data->square) gamepad->buttons.x = true;
|
||||||
|
if (ds4_data->cross) gamepad->buttons.a = true;
|
||||||
|
if (ds4_data->circle) gamepad->buttons.b = true;
|
||||||
|
if (ds4_data->triangle) gamepad->buttons.y = true;
|
||||||
|
|
||||||
|
if (ds4_data->share) gamepad->buttons.back = true;
|
||||||
|
if (ds4_data->option) gamepad->buttons.start = true;
|
||||||
|
if (ds4_data->ps) gamepad->buttons.sys = true;
|
||||||
|
if (ds4_data->tpad) gamepad->buttons.misc = true;
|
||||||
|
|
||||||
|
if (ds4_data->l1) gamepad->buttons.lb = true;
|
||||||
|
if (ds4_data->r1) gamepad->buttons.rb = true;
|
||||||
|
|
||||||
|
if (ds4_data->l3) gamepad->buttons.l3 = true;
|
||||||
|
if (ds4_data->r3) gamepad->buttons.r3 = true;
|
||||||
|
|
||||||
|
gamepad->triggers.l = ds4_data->l2_trigger;
|
||||||
|
gamepad->triggers.r = ds4_data->r2_trigger;
|
||||||
|
|
||||||
|
gamepad->joysticks.lx = scale_uint8_to_int16(ds4_data->lx, false);
|
||||||
|
gamepad->joysticks.ly = scale_uint8_to_int16(ds4_data->ly, true);
|
||||||
|
gamepad->joysticks.rx = scale_uint8_to_int16(ds4_data->rx, false);
|
||||||
|
gamepad->joysticks.ry = scale_uint8_to_int16(ds4_data->ry, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dualshock4::process_hid_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)len;
|
||||||
|
|
||||||
|
static Dualshock4Report prev_report = {};
|
||||||
|
Dualshock4Report ds4_report;
|
||||||
|
memcpy(&ds4_report, report, sizeof(ds4_report));
|
||||||
|
|
||||||
|
if (memcmp(&ds4_report, &prev_report, sizeof(ds4_report)) != 0)
|
||||||
|
{
|
||||||
|
update_gamepad(gamepad, &ds4_report);
|
||||||
|
|
||||||
|
prev_report = ds4_report;
|
||||||
|
}
|
||||||
|
|
||||||
|
tuh_hid_receive_report(dev_addr, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dualshock4::process_xinput_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, xinputh_interface_t const* report, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)gamepad;
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
(void)report;
|
||||||
|
(void)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dualshock4::hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
(void)report_id;
|
||||||
|
(void)report_type;
|
||||||
|
(void)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Dualshock4::send_fb_data(const Gamepad* gamepad, uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
Dualshock4OutReport out_report = {0};
|
||||||
|
out_report.set_rumble = 1;
|
||||||
|
out_report.motor_left = gamepad->rumble.l;
|
||||||
|
out_report.motor_right = gamepad->rumble.r;
|
||||||
|
|
||||||
|
return tuh_hid_send_report(dev_addr, instance, 5, &out_report, sizeof(out_report));
|
||||||
|
}
|
||||||
@@ -1,13 +1,9 @@
|
|||||||
#pragma once
|
#ifndef _DUALSHOCK4_H_
|
||||||
|
#define _DUALSHOCK4_H_
|
||||||
#ifndef _PS4_H_
|
|
||||||
#define _PS4_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "usbh/tusb_hid/shared.h"
|
#include "usbh/GPHostDriver.h"
|
||||||
|
|
||||||
#define REPORT_ID_GAMEPAD_STATE 0x11
|
|
||||||
|
|
||||||
const usb_vid_pid_t ps4_devices[] =
|
const usb_vid_pid_t ps4_devices[] =
|
||||||
{
|
{
|
||||||
@@ -28,7 +24,7 @@ static const uint8_t led_colors[][3] =
|
|||||||
{ 0x20, 0x00, 0x20 }, // Pink
|
{ 0x20, 0x00, 0x20 }, // Pink
|
||||||
};
|
};
|
||||||
|
|
||||||
enum dualshock4_dpad_mask
|
enum Dualshock4DpadMask
|
||||||
{
|
{
|
||||||
PS4_DPAD_MASK_UP = 0x00,
|
PS4_DPAD_MASK_UP = 0x00,
|
||||||
PS4_DPAD_MASK_UP_RIGHT = 0x01,
|
PS4_DPAD_MASK_UP_RIGHT = 0x01,
|
||||||
@@ -120,21 +116,24 @@ typedef struct __attribute__((packed))
|
|||||||
|
|
||||||
struct Dualshock4State
|
struct Dualshock4State
|
||||||
{
|
{
|
||||||
uint8_t dev_addr = {0};
|
uint8_t player_id = {0};
|
||||||
uint8_t instance = {0};
|
|
||||||
bool leds_set = {false};
|
bool leds_set = {false};
|
||||||
};
|
};
|
||||||
|
|
||||||
class Dualshock4
|
class Dualshock4 : public GPHostDriver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void init(uint8_t dev_addr, uint8_t instance);
|
~Dualshock4() override {}
|
||||||
void process_report(uint8_t const* report, uint16_t len);
|
|
||||||
bool send_fb_data();
|
virtual void init(uint8_t player_id, uint8_t dev_addr, uint8_t instance);
|
||||||
|
virtual void process_hid_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
|
||||||
|
virtual void process_xinput_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, xinputh_interface_t const* report, uint16_t len);
|
||||||
|
virtual void hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len);
|
||||||
|
virtual bool send_fb_data(const Gamepad* gamepad, uint8_t dev_addr, uint8_t instance);
|
||||||
private:
|
private:
|
||||||
Dualshock4State dualshock4;
|
Dualshock4State dualshock4;
|
||||||
void update_gamepad(const Dualshock4Report* ds4_data);
|
void update_gamepad(Gamepad* gp, const Dualshock4Report* ds4_data);
|
||||||
bool set_leds();
|
bool set_leds(uint8_t dev_addr, uint8_t instance);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _PS4_H_
|
#endif
|
||||||
115
src/usbh/ps5/Dualsense.cpp
Normal file
115
src/usbh/ps5/Dualsense.cpp
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#include "tusb.h"
|
||||||
|
|
||||||
|
#include "usbh/ps5/Dualsense.h"
|
||||||
|
#include "usbh/shared/scaling.h"
|
||||||
|
|
||||||
|
void Dualsense::init(uint8_t player_id, uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
dualsense.player_id = player_id;
|
||||||
|
tuh_hid_receive_report(dev_addr, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dualsense::update_gamepad(Gamepad* gamepad, const DualsenseReport* ds_report)
|
||||||
|
{
|
||||||
|
gamepad->reset_pad(gamepad);
|
||||||
|
|
||||||
|
switch(ds_report->dpad)
|
||||||
|
{
|
||||||
|
case PS5_MASK_DPAD_UP:
|
||||||
|
gamepad->buttons.up = true;
|
||||||
|
break;
|
||||||
|
case PS5_MASK_DPAD_UP_RIGHT:
|
||||||
|
gamepad->buttons.up = true;
|
||||||
|
gamepad->buttons.right = true;
|
||||||
|
break;
|
||||||
|
case PS5_MASK_DPAD_RIGHT:
|
||||||
|
gamepad->buttons.right = true;
|
||||||
|
break;
|
||||||
|
case PS5_MASK_DPAD_RIGHT_DOWN:
|
||||||
|
gamepad->buttons.right = true;
|
||||||
|
gamepad->buttons.down = true;
|
||||||
|
break;
|
||||||
|
case PS5_MASK_DPAD_DOWN:
|
||||||
|
gamepad->buttons.down = true;
|
||||||
|
break;
|
||||||
|
case PS5_MASK_DPAD_DOWN_LEFT:
|
||||||
|
gamepad->buttons.down = true;
|
||||||
|
gamepad->buttons.left = true;
|
||||||
|
break;
|
||||||
|
case PS5_MASK_DPAD_LEFT:
|
||||||
|
gamepad->buttons.left = true;
|
||||||
|
break;
|
||||||
|
case PS5_MASK_DPAD_LEFT_UP:
|
||||||
|
gamepad->buttons.left = true;
|
||||||
|
gamepad->buttons.up = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ds_report->square) gamepad->buttons.x = true;
|
||||||
|
if (ds_report->cross) gamepad->buttons.a = true;
|
||||||
|
if (ds_report->circle) gamepad->buttons.b = true;
|
||||||
|
if (ds_report->triangle) gamepad->buttons.y = true;
|
||||||
|
|
||||||
|
if (ds_report->buttons[0] & PS5_MASK_L1) gamepad->buttons.lb = true;
|
||||||
|
if (ds_report->buttons[0] & PS5_MASK_R1) gamepad->buttons.rb = true;
|
||||||
|
|
||||||
|
if (ds_report->buttons[0] & PS5_MASK_SHARE) gamepad->buttons.back = true;
|
||||||
|
if (ds_report->buttons[0] & PS5_MASK_OPTIONS) gamepad->buttons.start = true;
|
||||||
|
|
||||||
|
if (ds_report->buttons[0] & PS5_MASK_L3) gamepad->buttons.l3 = true;
|
||||||
|
if (ds_report->buttons[0] & PS5_MASK_R3) gamepad->buttons.r3 = true;
|
||||||
|
|
||||||
|
if (ds_report->buttons[1] & PS5_MASK_PS) gamepad->buttons.sys = true;
|
||||||
|
if (ds_report->buttons[1] & PS5_MASK_MIC) gamepad->buttons.misc = true;
|
||||||
|
|
||||||
|
gamepad->triggers.l = ds_report->lt;
|
||||||
|
gamepad->triggers.r = ds_report->rt;
|
||||||
|
|
||||||
|
gamepad->joysticks.lx = scale_uint8_to_int16(ds_report->lx, false);
|
||||||
|
gamepad->joysticks.ly = scale_uint8_to_int16(ds_report->ly, true);
|
||||||
|
gamepad->joysticks.rx = scale_uint8_to_int16(ds_report->rx, false);
|
||||||
|
gamepad->joysticks.ry = scale_uint8_to_int16(ds_report->ry, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dualsense::process_hid_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)len;
|
||||||
|
|
||||||
|
DualsenseReport ds_report;
|
||||||
|
memcpy(&ds_report, report, sizeof(ds_report));
|
||||||
|
update_gamepad(gamepad, &ds_report);
|
||||||
|
tuh_hid_receive_report(dev_addr, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dualsense::process_xinput_report(Gamepad* gp, uint8_t dev_addr, uint8_t instance, xinputh_interface_t const* report, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)gp;
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
(void)report;
|
||||||
|
(void)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dualsense::hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
(void)report_id;
|
||||||
|
(void)report_type;
|
||||||
|
(void)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Dualsense::send_fb_data(const Gamepad* gamepad, uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
// need to figure out if the flags are necessary and how the LEDs work
|
||||||
|
DualsenseOutReport out_report = {0};
|
||||||
|
out_report.valid_flag0 = 0x02; // idk what this means
|
||||||
|
out_report.valid_flag1 = 0x02; // this one either
|
||||||
|
out_report.valid_flag2 = 0x04; // uhhhhh
|
||||||
|
out_report.motor_left = gamepad->rumble.l;
|
||||||
|
out_report.motor_right = gamepad->rumble.r;
|
||||||
|
|
||||||
|
return tuh_hid_send_report(dev_addr, instance, 5, &out_report, sizeof(out_report));
|
||||||
|
}
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
#pragma once
|
#ifndef _DUALSENSE_H_
|
||||||
|
#define _DUALSENSE_H_
|
||||||
#ifndef _PS5_H_
|
|
||||||
#define _PS5_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "usbh/tusb_hid/shared.h"
|
#include "usbh/GPHostDriver.h"
|
||||||
|
|
||||||
const usb_vid_pid_t ps5_devices[] =
|
const usb_vid_pid_t ps5_devices[] =
|
||||||
{
|
{
|
||||||
@@ -131,21 +129,22 @@ struct DualsenseOutReport {
|
|||||||
uint8_t lightbar_blue;
|
uint8_t lightbar_blue;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
struct DualsenseState
|
struct DualsenseState
|
||||||
{
|
{
|
||||||
uint8_t dev_addr = {0};
|
uint8_t player_id = {0};
|
||||||
uint8_t instance = {0};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Dualsense
|
class Dualsense : public GPHostDriver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void init(uint8_t dev_addr, uint8_t instance);
|
virtual void init(uint8_t player_id, uint8_t dev_addr, uint8_t instance);
|
||||||
void process_report(uint8_t const* report, uint16_t len);
|
virtual void process_hid_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
|
||||||
bool send_fb_data();
|
virtual void process_xinput_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, xinputh_interface_t const* report, uint16_t len);
|
||||||
|
virtual void hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len);
|
||||||
|
virtual bool send_fb_data(const Gamepad* gamepad, uint8_t dev_addr, uint8_t instance);
|
||||||
private:
|
private:
|
||||||
DualsenseState dualsense;
|
DualsenseState dualsense;
|
||||||
void update_gamepad(const DualsenseReport* ds_data);
|
void update_gamepad(Gamepad* gp, const DualsenseReport* ds_report);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _PS5_H_
|
#endif // _DUALSENSE_H_
|
||||||
107
src/usbh/psclassic/PSClassic.cpp
Normal file
107
src/usbh/psclassic/PSClassic.cpp
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#include "tusb.h"
|
||||||
|
|
||||||
|
#include "usbh/psclassic/PSClassic.h"
|
||||||
|
|
||||||
|
void PSClassic::init(uint8_t player_id, uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
psclassic.player_id = player_id;
|
||||||
|
tuh_hid_receive_report(dev_addr, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PSClassic::update_gamepad(Gamepad* gamepad, const PSClassicReport* psc_data)
|
||||||
|
{
|
||||||
|
gamepad->reset_pad(gamepad);
|
||||||
|
|
||||||
|
switch (psc_data->buttons & 0x3C00) {
|
||||||
|
case PSCLASSIC_MASK_UP_LEFT:
|
||||||
|
gamepad->buttons.up = true;
|
||||||
|
gamepad->buttons.left = true;
|
||||||
|
break;
|
||||||
|
case PSCLASSIC_MASK_UP:
|
||||||
|
gamepad->buttons.up = true;
|
||||||
|
break;
|
||||||
|
case PSCLASSIC_MASK_UP_RIGHT:
|
||||||
|
gamepad->buttons.up = true;
|
||||||
|
gamepad->buttons.right = true;
|
||||||
|
break;
|
||||||
|
case PSCLASSIC_MASK_LEFT:
|
||||||
|
gamepad->buttons.left = true;
|
||||||
|
break;
|
||||||
|
case PSCLASSIC_MASK_RIGHT:
|
||||||
|
gamepad->buttons.right = true;
|
||||||
|
break;
|
||||||
|
case PSCLASSIC_MASK_DOWN_LEFT:
|
||||||
|
gamepad->buttons.down = true;
|
||||||
|
gamepad->buttons.left = true;
|
||||||
|
break;
|
||||||
|
case PSCLASSIC_MASK_DOWN:
|
||||||
|
gamepad->buttons.down = true;
|
||||||
|
break;
|
||||||
|
case PSCLASSIC_MASK_DOWN_RIGHT:
|
||||||
|
gamepad->buttons.down = true;
|
||||||
|
gamepad->buttons.right = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (psc_data->buttons & PSCLASSIC_MASK_TRIANGLE) gamepad->buttons.y = true;
|
||||||
|
if (psc_data->buttons & PSCLASSIC_MASK_CIRCLE) gamepad->buttons.b = true;
|
||||||
|
if (psc_data->buttons & PSCLASSIC_MASK_CROSS) gamepad->buttons.a = true;
|
||||||
|
if (psc_data->buttons & PSCLASSIC_MASK_SQUARE) gamepad->buttons.x = true;
|
||||||
|
|
||||||
|
if (psc_data->buttons & PSCLASSIC_MASK_L2) gamepad->triggers.l = 0xFF;
|
||||||
|
if (psc_data->buttons & PSCLASSIC_MASK_R2) gamepad->triggers.r = 0xFF;
|
||||||
|
|
||||||
|
if (psc_data->buttons & PSCLASSIC_MASK_L1) gamepad->buttons.lb = true;
|
||||||
|
if (psc_data->buttons & PSCLASSIC_MASK_R1) gamepad->buttons.rb = true;
|
||||||
|
|
||||||
|
if (psc_data->buttons & PSCLASSIC_MASK_SELECT) gamepad->buttons.back = true;
|
||||||
|
if (psc_data->buttons & PSCLASSIC_MASK_START) gamepad->buttons.start = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PSClassic::process_hid_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)len;
|
||||||
|
|
||||||
|
static PSClassicReport prev_report = {};
|
||||||
|
|
||||||
|
PSClassicReport psc_report;
|
||||||
|
memcpy(&psc_report, report, sizeof(psc_report));
|
||||||
|
|
||||||
|
if (memcmp(&psc_report, &prev_report, sizeof(psc_report)) != 0)
|
||||||
|
{
|
||||||
|
update_gamepad(gamepad, &psc_report);
|
||||||
|
|
||||||
|
prev_report = psc_report;
|
||||||
|
}
|
||||||
|
|
||||||
|
tuh_hid_receive_report(dev_addr, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PSClassic::process_xinput_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, xinputh_interface_t const* report, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)gamepad;
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
(void)report;
|
||||||
|
(void)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PSClassic::hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
(void)report_id;
|
||||||
|
(void)report_type;
|
||||||
|
(void)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PSClassic::send_fb_data(const Gamepad* gamepad, uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
(void)gamepad;
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
34
src/usbh/psclassic/PSClassic.h
Normal file
34
src/usbh/psclassic/PSClassic.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#ifndef _PSCLASSIC_H_
|
||||||
|
#define _PSCLASSIC_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "descriptors/PSClassicDescriptors.h"
|
||||||
|
|
||||||
|
#include "usbh/GPHostDriver.h"
|
||||||
|
|
||||||
|
const usb_vid_pid_t psc_devices[] =
|
||||||
|
{
|
||||||
|
{0x054C, 0x0CDA} // psclassic
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PSClassicState
|
||||||
|
{
|
||||||
|
uint8_t player_id = {0};
|
||||||
|
};
|
||||||
|
|
||||||
|
class PSClassic : public GPHostDriver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~PSClassic() override {}
|
||||||
|
|
||||||
|
virtual void init(uint8_t player_id, uint8_t dev_addr, uint8_t instance);
|
||||||
|
virtual void process_hid_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
|
||||||
|
virtual void process_xinput_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, xinputh_interface_t const* report, uint16_t len);
|
||||||
|
virtual void hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len);
|
||||||
|
virtual bool send_fb_data(const Gamepad* gamepad, uint8_t dev_addr, uint8_t instance);
|
||||||
|
private:
|
||||||
|
PSClassicState psclassic;
|
||||||
|
void update_gamepad(Gamepad* gp, const PSClassicReport* psc_data);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _PSCLASSIC_H_
|
||||||
13
src/usbh/shared/hid_class_driver.c
Normal file
13
src/usbh/shared/hid_class_driver.c
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#include "host/usbh.h"
|
||||||
|
#include "host/usbh_pvt.h"
|
||||||
|
#include "class/hid/hid_host.h"
|
||||||
|
#include "usbh/shared/hid_class_driver.h"
|
||||||
|
|
||||||
|
usbh_class_driver_t const usbh_hid_driver =
|
||||||
|
{
|
||||||
|
.init = hidh_init,
|
||||||
|
.open = hidh_open,
|
||||||
|
.set_config = hidh_set_config,
|
||||||
|
.xfer_cb = hidh_xfer_cb,
|
||||||
|
.close = hidh_close
|
||||||
|
};
|
||||||
8
src/usbh/shared/hid_class_driver.h
Normal file
8
src/usbh/shared/hid_class_driver.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef _HID_CLASS_DRIVER_H_
|
||||||
|
#define _HID_CLASS_DRIVER_H_
|
||||||
|
|
||||||
|
extern usbh_class_driver_t const usbh_hid_driver;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,26 +1,4 @@
|
|||||||
#include "utilities/scaling.h"
|
#include "usbh/shared/scaling.h"
|
||||||
|
|
||||||
uint8_t scale_int16_to_uint8(int16_t value, bool invert)
|
|
||||||
{
|
|
||||||
if (value == INT16_MIN && invert)
|
|
||||||
{
|
|
||||||
return UINT8_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (invert)
|
|
||||||
{
|
|
||||||
value = -value;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t scaled_value = static_cast<uint32_t>(value - INT16_MIN) * UINT8_MAX / (INT16_MAX - INT16_MIN);
|
|
||||||
|
|
||||||
if (scaled_value > UINT8_MAX)
|
|
||||||
{
|
|
||||||
scaled_value = UINT8_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
return static_cast<uint8_t>(scaled_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
int16_t scale_uint8_to_int16(uint8_t value, bool invert)
|
int16_t scale_uint8_to_int16(uint8_t value, bool invert)
|
||||||
{
|
{
|
||||||
@@ -1,11 +1,8 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#ifndef _SCALING_H_
|
#ifndef _SCALING_H_
|
||||||
#define _SCALING_H_
|
#define _SCALING_H_
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
uint8_t scale_int16_to_uint8(int16_t value, bool invert);
|
|
||||||
int16_t scale_uint8_to_int16(uint8_t value, bool invert);
|
int16_t scale_uint8_to_int16(uint8_t value, bool invert);
|
||||||
|
|
||||||
#endif // _SCALING_H_
|
#endif // _SCALING_H_
|
||||||
260
src/usbh/switch/SwitchPro.cpp
Normal file
260
src/usbh/switch/SwitchPro.cpp
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <cmath>
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#include "tusb.h"
|
||||||
|
|
||||||
|
#include "usbh/switch/SwitchPro.h"
|
||||||
|
|
||||||
|
void SwitchPro::init(uint8_t player_id, uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
|
||||||
|
switch_pro.player_id = player_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitchPro::send_handshake(uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
if (tuh_hid_send_ready(dev_addr, instance))
|
||||||
|
{
|
||||||
|
uint8_t handshake_command[2] = {CMD_HID, SUBCMD_HANDSHAKE};
|
||||||
|
switch_pro.handshake_sent = tuh_hid_send_report(dev_addr, instance, 0, handshake_command, sizeof(handshake_command));
|
||||||
|
}
|
||||||
|
|
||||||
|
tuh_hid_receive_report(dev_addr, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t SwitchPro::get_output_sequence_counter()
|
||||||
|
{
|
||||||
|
// increments each report, resets to 0 after 15
|
||||||
|
uint8_t counter = switch_pro.output_sequence_counter;
|
||||||
|
switch_pro.output_sequence_counter = (switch_pro.output_sequence_counter + 1) & 0x0F;
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitchPro::disable_timeout(uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
if (tuh_hid_send_ready(dev_addr, instance))
|
||||||
|
{
|
||||||
|
uint8_t disable_timeout_cmd[2] = {CMD_HID, SUBCMD_DISABLE_TIMEOUT};
|
||||||
|
switch_pro.timeout_disabled = tuh_hid_send_report(dev_addr, instance, 0, disable_timeout_cmd, sizeof(disable_timeout_cmd));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitchPro::process_hid_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)len;
|
||||||
|
|
||||||
|
if (!switch_pro.handshake_sent)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (!switch_pro.timeout_disabled)
|
||||||
|
{
|
||||||
|
disable_timeout(dev_addr, instance); // response to handshake
|
||||||
|
tuh_hid_receive_report(dev_addr, instance);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SwitchProReport prev_report = {};
|
||||||
|
|
||||||
|
SwitchProReport switch_report;
|
||||||
|
memcpy(&switch_report, report, sizeof(switch_report));
|
||||||
|
|
||||||
|
if (memcmp(&switch_report, &prev_report, sizeof(switch_report)) != 0)
|
||||||
|
{
|
||||||
|
update_gamepad(gamepad, &switch_report);
|
||||||
|
|
||||||
|
prev_report = switch_report;
|
||||||
|
}
|
||||||
|
|
||||||
|
tuh_hid_receive_report(dev_addr, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t SwitchPro::normalize_axes(uint16_t value)
|
||||||
|
{
|
||||||
|
/* 12bit value from the controller doesnt cover the full 12bit range seemingly
|
||||||
|
doesn't seem completely centered at 2047 so I may be missing something here
|
||||||
|
tried to get as close as possible with the multiplier */
|
||||||
|
|
||||||
|
int32_t normalized_value = (value - 2047) * 22;
|
||||||
|
|
||||||
|
if (normalized_value < INT16_MIN)
|
||||||
|
{
|
||||||
|
normalized_value = INT16_MIN;
|
||||||
|
}
|
||||||
|
else if (normalized_value > INT16_MAX)
|
||||||
|
{
|
||||||
|
normalized_value = INT16_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int16_t)normalized_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitchPro::update_gamepad(Gamepad* gamepad, const SwitchProReport* switch_report)
|
||||||
|
{
|
||||||
|
gamepad->reset_pad(gamepad);
|
||||||
|
|
||||||
|
if (switch_report->up) gamepad->buttons.up =true;
|
||||||
|
if (switch_report->down) gamepad->buttons.down =true;
|
||||||
|
if (switch_report->left) gamepad->buttons.left =true;
|
||||||
|
if (switch_report->right) gamepad->buttons.right =true;
|
||||||
|
|
||||||
|
if (switch_report->y) gamepad->buttons.x = true;
|
||||||
|
if (switch_report->x) gamepad->buttons.y = true;
|
||||||
|
if (switch_report->b) gamepad->buttons.a = true;
|
||||||
|
if (switch_report->a) gamepad->buttons.b = true;
|
||||||
|
|
||||||
|
if (switch_report->minus) gamepad->buttons.back = true;
|
||||||
|
if (switch_report->plus) gamepad->buttons.start = true;
|
||||||
|
if (switch_report->home) gamepad->buttons.sys = true;
|
||||||
|
if (switch_report->capture) gamepad->buttons.misc = true;
|
||||||
|
|
||||||
|
if (switch_report->stickL) gamepad->buttons.l3 = true;
|
||||||
|
if (switch_report->stickR) gamepad->buttons.r3 = true;
|
||||||
|
|
||||||
|
if (switch_report->l) gamepad->buttons.lb = true;
|
||||||
|
if (switch_report->r) gamepad->buttons.rb = true;
|
||||||
|
|
||||||
|
if (switch_report->zl) gamepad->triggers.l = 0xFF;
|
||||||
|
if (switch_report->zr) gamepad->triggers.r = 0xFF;
|
||||||
|
|
||||||
|
gamepad->joysticks.lx = normalize_axes(switch_report->leftX );
|
||||||
|
gamepad->joysticks.ly = normalize_axes(switch_report->leftY );
|
||||||
|
gamepad->joysticks.rx = normalize_axes(switch_report->rightX);
|
||||||
|
gamepad->joysticks.ry = normalize_axes(switch_report->rightY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitchPro::process_xinput_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, xinputh_interface_t const* report, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)gamepad;
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
(void)report;
|
||||||
|
(void)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitchPro::hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
(void)report_id;
|
||||||
|
(void)report_type;
|
||||||
|
(void)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SwitchPro::send_fb_data(const Gamepad* gamepad, uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
if (!switch_pro.handshake_sent)
|
||||||
|
{
|
||||||
|
send_handshake(dev_addr, instance);
|
||||||
|
}
|
||||||
|
else if (!switch_pro.timeout_disabled)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See: https://github.com/Dan611/hid-procon
|
||||||
|
// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering
|
||||||
|
// https://github.com/HisashiKato/USB_Host_Shield_Library_2.0
|
||||||
|
|
||||||
|
SwitchProOutReport report = {};
|
||||||
|
uint8_t report_size = 10;
|
||||||
|
|
||||||
|
report.command = CMD_RUMBLE_ONLY;
|
||||||
|
report.sequence_counter = get_output_sequence_counter();
|
||||||
|
|
||||||
|
if (gamepad->rumble.l > 0)
|
||||||
|
{
|
||||||
|
uint8_t amplitude_l = static_cast<uint8_t>(((gamepad->rumble.l / 255.0f) * 0.8f + 0.5f) * (0xC0 - 0x40) + 0x40);
|
||||||
|
|
||||||
|
report.rumble_l[0] = amplitude_l;
|
||||||
|
report.rumble_l[1] = 0x88;
|
||||||
|
report.rumble_l[2] = amplitude_l / 2;
|
||||||
|
report.rumble_l[3] = 0x61;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
report.rumble_l[0] = 0x00;
|
||||||
|
report.rumble_l[1] = 0x01;
|
||||||
|
report.rumble_l[2] = 0x40;
|
||||||
|
report.rumble_l[3] = 0x40;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamepad->rumble.r > 0)
|
||||||
|
{
|
||||||
|
uint8_t amplitude_r = static_cast<uint8_t>(((gamepad->rumble.r / 255.0f) * 0.8f + 0.5f) * (0xC0 - 0x40) + 0x40);
|
||||||
|
|
||||||
|
report.rumble_r[0] = amplitude_r;
|
||||||
|
report.rumble_r[1] = 0x88;
|
||||||
|
report.rumble_r[2] = amplitude_r / 2;
|
||||||
|
report.rumble_r[3] = 0x61;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
report.rumble_r[0] = 0x00;
|
||||||
|
report.rumble_r[1] = 0x01;
|
||||||
|
report.rumble_r[2] = 0x40;
|
||||||
|
report.rumble_r[3] = 0x40;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!switch_pro.commands_sent)
|
||||||
|
{
|
||||||
|
if (!switch_pro.led_set)
|
||||||
|
{
|
||||||
|
report_size = 12;
|
||||||
|
|
||||||
|
report.command = CMD_AND_RUMBLE;
|
||||||
|
report.sub_command = CMD_LED;
|
||||||
|
report.sub_command_args[0] = switch_pro.player_id;
|
||||||
|
|
||||||
|
switch_pro.led_set = tuh_hid_send_report(dev_addr, instance, 0, &report, report_size);
|
||||||
|
|
||||||
|
return switch_pro.led_set;
|
||||||
|
}
|
||||||
|
else if (!switch_pro.led_home_set)
|
||||||
|
{
|
||||||
|
report_size = 14;
|
||||||
|
|
||||||
|
report.command = CMD_AND_RUMBLE;
|
||||||
|
report.sub_command = CMD_LED_HOME;
|
||||||
|
report.sub_command_args[0] = (0 /* Number of cycles */ << 4) | (true ? 0xF : 0);
|
||||||
|
report.sub_command_args[1] = (0xF /* LED start intensity */ << 4) | 0x0 /* Number of full cycles */;
|
||||||
|
report.sub_command_args[2] = (0xF /* Mini Cycle 1 LED intensity */ << 4) | 0x0 /* Mini Cycle 2 LED intensity */;
|
||||||
|
|
||||||
|
switch_pro.led_home_set = tuh_hid_send_report(dev_addr, instance, 0, &report, report_size);
|
||||||
|
|
||||||
|
return switch_pro.led_home_set;
|
||||||
|
}
|
||||||
|
else if (!switch_pro.full_report_enabled)
|
||||||
|
{
|
||||||
|
report_size = 12;
|
||||||
|
|
||||||
|
report.command = CMD_AND_RUMBLE;
|
||||||
|
report.sub_command = CMD_MODE;
|
||||||
|
report.sub_command_args[0] = SUBCMD_FULL_REPORT_MODE;
|
||||||
|
|
||||||
|
switch_pro.full_report_enabled = tuh_hid_send_report(dev_addr, instance, 0, &report, report_size);
|
||||||
|
|
||||||
|
return switch_pro.full_report_enabled;
|
||||||
|
}
|
||||||
|
else if (!switch_pro.imu_enabled)
|
||||||
|
{
|
||||||
|
report_size = 12;
|
||||||
|
|
||||||
|
report.command = CMD_AND_RUMBLE;
|
||||||
|
report.sub_command = CMD_GYRO;
|
||||||
|
report.sub_command_args[0] = 1 ? 1 : 0;
|
||||||
|
|
||||||
|
switch_pro.imu_enabled = tuh_hid_send_report(dev_addr, instance, 0, &report, report_size);
|
||||||
|
|
||||||
|
return switch_pro.imu_enabled;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch_pro.commands_sent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tuh_hid_send_report(dev_addr, instance, 0, &report, report_size);
|
||||||
|
}
|
||||||
46
src/usbh/switch/SwitchPro.h
Normal file
46
src/usbh/switch/SwitchPro.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#ifndef _SWITCHPRO_H_
|
||||||
|
#define _SWITCHPRO_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "descriptors/SwitchProDescriptors.h"
|
||||||
|
|
||||||
|
#include "usbh/GPHostDriver.h"
|
||||||
|
|
||||||
|
const usb_vid_pid_t switch_pro_devices[] =
|
||||||
|
{
|
||||||
|
{0x057E, 0x2009} // Switch Pro
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SwitchProState
|
||||||
|
{
|
||||||
|
uint8_t player_id = {0};
|
||||||
|
bool handshake_sent {false};
|
||||||
|
bool timeout_disabled {false};
|
||||||
|
bool full_report_enabled {false};
|
||||||
|
bool led_set {false};
|
||||||
|
bool led_home_set {false};
|
||||||
|
bool imu_enabled {false};
|
||||||
|
bool commands_sent {false};
|
||||||
|
uint8_t output_sequence_counter {0};
|
||||||
|
};
|
||||||
|
|
||||||
|
class SwitchPro : public GPHostDriver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~SwitchPro() override {}
|
||||||
|
|
||||||
|
virtual void init(uint8_t player_id, uint8_t dev_addr, uint8_t instance);
|
||||||
|
virtual void process_hid_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
|
||||||
|
virtual void process_xinput_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, xinputh_interface_t const* report, uint16_t len);
|
||||||
|
virtual void hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len);
|
||||||
|
virtual bool send_fb_data(const Gamepad* gamepad, uint8_t dev_addr, uint8_t instance);
|
||||||
|
private:
|
||||||
|
SwitchProState switch_pro;
|
||||||
|
void send_handshake(uint8_t dev_addr, uint8_t instance);
|
||||||
|
void disable_timeout(uint8_t dev_addr, uint8_t instance);
|
||||||
|
uint8_t get_output_sequence_counter();
|
||||||
|
int16_t normalize_axes(uint16_t value);
|
||||||
|
void update_gamepad(Gamepad* gp, const SwitchProReport* switch_pro_data);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _SWITCHPRO_H_
|
||||||
121
src/usbh/switch/SwitchWired.cpp
Normal file
121
src/usbh/switch/SwitchWired.cpp
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#include "pico/time.h"
|
||||||
|
#include "tusb.h"
|
||||||
|
#include "descriptors/SwitchDescriptors.h"
|
||||||
|
|
||||||
|
#include "usbh/switch/SwitchWired.h"
|
||||||
|
#include "usbh/shared/scaling.h"
|
||||||
|
|
||||||
|
void SwitchWired::init(uint8_t player_id, uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
switch_wired.player_id = player_id;
|
||||||
|
tuh_hid_receive_report(dev_addr, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitchWired::process_hid_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)len;
|
||||||
|
|
||||||
|
static SwitchWiredReport prev_report = {};
|
||||||
|
|
||||||
|
SwitchWiredReport switch_report;
|
||||||
|
memcpy(&switch_report, report, sizeof(switch_report));
|
||||||
|
|
||||||
|
if (memcmp(&switch_report, &prev_report, sizeof(switch_report)) != 0)
|
||||||
|
{
|
||||||
|
update_gamepad(gamepad, &switch_report);
|
||||||
|
|
||||||
|
prev_report = switch_report;
|
||||||
|
}
|
||||||
|
|
||||||
|
tuh_hid_receive_report(dev_addr, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitchWired::update_gamepad(Gamepad* gamepad, const SwitchWiredReport* switch_report)
|
||||||
|
{
|
||||||
|
gamepad->reset_pad(gamepad);
|
||||||
|
|
||||||
|
switch (switch_report->dpad)
|
||||||
|
{
|
||||||
|
case SWITCH_HAT_UP:
|
||||||
|
gamepad->buttons.up = true;
|
||||||
|
break;
|
||||||
|
case SWITCH_HAT_UPRIGHT:
|
||||||
|
gamepad->buttons.up = true;
|
||||||
|
gamepad->buttons.right = true;
|
||||||
|
break;
|
||||||
|
case SWITCH_HAT_RIGHT:
|
||||||
|
gamepad->buttons.right = true;
|
||||||
|
break;
|
||||||
|
case SWITCH_HAT_DOWNRIGHT:
|
||||||
|
gamepad->buttons.right = true;
|
||||||
|
gamepad->buttons.down = true;
|
||||||
|
break;
|
||||||
|
case SWITCH_HAT_DOWN:
|
||||||
|
gamepad->buttons.down = true;
|
||||||
|
break;
|
||||||
|
case SWITCH_HAT_DOWNLEFT:
|
||||||
|
gamepad->buttons.down = true;
|
||||||
|
gamepad->buttons.left = true;
|
||||||
|
break;
|
||||||
|
case SWITCH_HAT_LEFT:
|
||||||
|
gamepad->buttons.left = true;
|
||||||
|
break;
|
||||||
|
case SWITCH_HAT_UPLEFT:
|
||||||
|
gamepad->buttons.up = true;
|
||||||
|
gamepad->buttons.left = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switch_report->b) gamepad->buttons.a = true;
|
||||||
|
if (switch_report->a) gamepad->buttons.b = true;
|
||||||
|
if (switch_report->y) gamepad->buttons.x = true;
|
||||||
|
if (switch_report->x) gamepad->buttons.y = true;
|
||||||
|
|
||||||
|
if (switch_report->minus) gamepad->buttons.back = true;
|
||||||
|
if (switch_report->plus) gamepad->buttons.start = true;
|
||||||
|
if (switch_report->l3) gamepad->buttons.l3 = true;
|
||||||
|
if (switch_report->r3) gamepad->buttons.r3 = true;
|
||||||
|
|
||||||
|
if(switch_report->home) gamepad->buttons.sys = true;
|
||||||
|
if(switch_report->capture) gamepad->buttons.misc = true;
|
||||||
|
|
||||||
|
if(switch_report->l) gamepad->buttons.lb = true;
|
||||||
|
if(switch_report->r) gamepad->buttons.rb = true;
|
||||||
|
|
||||||
|
if(switch_report->lz) gamepad->triggers.l = 0xFF;
|
||||||
|
if(switch_report->rz) gamepad->triggers.r = 0xFF;
|
||||||
|
|
||||||
|
gamepad->joysticks.lx = scale_uint8_to_int16(switch_report->lx, false);
|
||||||
|
gamepad->joysticks.ly = scale_uint8_to_int16(switch_report->ly, true);
|
||||||
|
gamepad->joysticks.rx = scale_uint8_to_int16(switch_report->rx, false);
|
||||||
|
gamepad->joysticks.ry = scale_uint8_to_int16(switch_report->ry, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitchWired::process_xinput_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, xinputh_interface_t const* report, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)gamepad;
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
(void)report;
|
||||||
|
(void)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitchWired::hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len)
|
||||||
|
{
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
(void)report_id;
|
||||||
|
(void)report_type;
|
||||||
|
(void)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SwitchWired::send_fb_data(const Gamepad* gamepad, uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
(void)gamepad;
|
||||||
|
(void)dev_addr;
|
||||||
|
(void)instance;
|
||||||
|
|
||||||
|
return true; // not aware of a wired switch gamepad with rumble
|
||||||
|
}
|
||||||
67
src/usbh/switch/SwitchWired.h
Normal file
67
src/usbh/switch/SwitchWired.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#ifndef _SWITCHWIRED_H_
|
||||||
|
#define _SWITCHWIRED_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "usbh/GPHostDriver.h"
|
||||||
|
|
||||||
|
const usb_vid_pid_t switch_wired_devices[] =
|
||||||
|
{
|
||||||
|
{0x20D6, 0xA719}, // PowerA wired
|
||||||
|
{0x20D6, 0xA713}, // PowerA Enhanced wired
|
||||||
|
{0x0F0D, 0x0092} // Hori Pokken wired, I don't have this one so not 100% on if it'll work
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SwitchWiredReport
|
||||||
|
{
|
||||||
|
uint8_t y : 1;
|
||||||
|
uint8_t b : 1;
|
||||||
|
uint8_t a : 1;
|
||||||
|
uint8_t x : 1;
|
||||||
|
|
||||||
|
uint8_t l : 1;
|
||||||
|
uint8_t r : 1;
|
||||||
|
uint8_t lz : 1;
|
||||||
|
uint8_t rz : 1;
|
||||||
|
|
||||||
|
uint8_t minus : 1;
|
||||||
|
uint8_t plus : 1;
|
||||||
|
uint8_t l3 : 1;
|
||||||
|
uint8_t r3 : 1;
|
||||||
|
|
||||||
|
uint8_t home : 1;
|
||||||
|
uint8_t capture : 1;
|
||||||
|
|
||||||
|
uint8_t : 2;
|
||||||
|
|
||||||
|
uint8_t dpad : 4;
|
||||||
|
uint8_t : 4;
|
||||||
|
|
||||||
|
uint8_t lx;
|
||||||
|
uint8_t ly;
|
||||||
|
uint8_t rx;
|
||||||
|
uint8_t ry;
|
||||||
|
}
|
||||||
|
__attribute__((packed));
|
||||||
|
|
||||||
|
struct SwitchWiredState
|
||||||
|
{
|
||||||
|
uint8_t player_id = {0};
|
||||||
|
};
|
||||||
|
|
||||||
|
class SwitchWired : public GPHostDriver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~SwitchWired() override {}
|
||||||
|
|
||||||
|
virtual void init(uint8_t player_id, uint8_t dev_addr, uint8_t instance);
|
||||||
|
virtual void process_hid_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
|
||||||
|
virtual void process_xinput_report(Gamepad* gamepad, uint8_t dev_addr, uint8_t instance, xinputh_interface_t const* report, uint16_t len);
|
||||||
|
virtual void hid_get_report_complete_cb(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len);
|
||||||
|
virtual bool send_fb_data(const Gamepad* gamepad, uint8_t dev_addr, uint8_t instance);
|
||||||
|
private:
|
||||||
|
SwitchWiredState switch_wired;
|
||||||
|
void update_gamepad(Gamepad* gp, const SwitchWiredReport* switch_pro_data);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _SWITCHWIRED_H_
|
||||||
@@ -1,207 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include "pico/stdlib.h"
|
|
||||||
|
|
||||||
#include "tusb.h"
|
|
||||||
#include "host/usbh.h"
|
|
||||||
#include "host/usbh_pvt.h"
|
|
||||||
#include "class/hid/hid_host.h"
|
|
||||||
|
|
||||||
#include "usbh/tusb_hid/shared.h"
|
|
||||||
#include "usbh/tusb_hid/hid_host_app.h"
|
|
||||||
|
|
||||||
#include "usbh/tusb_host_manager.h" // global enum host_mode
|
|
||||||
|
|
||||||
// TODO: make a host driver class for all this
|
|
||||||
|
|
||||||
N64USB* n64usb = nullptr;
|
|
||||||
PSClassic* psclassic = nullptr;
|
|
||||||
Dualshock3* dualshock3 = nullptr;
|
|
||||||
Dualshock4* dualshock4 = nullptr;
|
|
||||||
Dualsense* dualsense = nullptr;
|
|
||||||
SwitchPro* switch_pro = nullptr;
|
|
||||||
SwitchWired* switch_wired = nullptr;
|
|
||||||
|
|
||||||
static bool gamepad_mounted;
|
|
||||||
static uint8_t gamepad_dev_addr = 0;
|
|
||||||
static uint8_t gamepad_instance = 0;
|
|
||||||
|
|
||||||
usbh_class_driver_t const usbh_hid_driver =
|
|
||||||
{
|
|
||||||
.init = hidh_init,
|
|
||||||
.open = hidh_open,
|
|
||||||
.set_config = hidh_set_config,
|
|
||||||
.xfer_cb = hidh_xfer_cb,
|
|
||||||
.close = hidh_close
|
|
||||||
};
|
|
||||||
|
|
||||||
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len)
|
|
||||||
{
|
|
||||||
(void)desc_report;
|
|
||||||
(void)desc_len;
|
|
||||||
|
|
||||||
if (!gamepad_mounted)
|
|
||||||
{
|
|
||||||
gamepad_dev_addr = dev_addr;
|
|
||||||
gamepad_instance = instance;
|
|
||||||
gamepad_mounted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (host_mode == HOST_MODE_HID_SWITCH_PRO && !switch_pro)
|
|
||||||
{
|
|
||||||
switch_pro = new SwitchPro();
|
|
||||||
switch_pro->init(dev_addr, instance);
|
|
||||||
}
|
|
||||||
else if (host_mode == HOST_MODE_HID_SWITCH_WIRED && !switch_wired)
|
|
||||||
{
|
|
||||||
switch_wired = new SwitchWired();
|
|
||||||
switch_wired->init(dev_addr, instance);
|
|
||||||
}
|
|
||||||
else if (host_mode == HOST_MODE_HID_PS3 && !dualshock3)
|
|
||||||
{
|
|
||||||
dualshock3 = new Dualshock3();
|
|
||||||
dualshock3->init(dev_addr, instance);
|
|
||||||
}
|
|
||||||
else if (host_mode == HOST_MODE_HID_PS4 && !dualshock4)
|
|
||||||
{
|
|
||||||
dualshock4 = new Dualshock4();
|
|
||||||
dualshock4->init(dev_addr, instance);
|
|
||||||
}
|
|
||||||
else if (host_mode == HOST_MODE_HID_PS5 && !dualsense)
|
|
||||||
{
|
|
||||||
dualsense = new Dualsense();
|
|
||||||
dualsense->init(dev_addr, instance);
|
|
||||||
}
|
|
||||||
else if (host_mode == HOST_MODE_HID_PSCLASSIC && !psclassic)
|
|
||||||
{
|
|
||||||
psclassic = new PSClassic();
|
|
||||||
psclassic->init(dev_addr, instance);
|
|
||||||
}
|
|
||||||
else if (host_mode == HOST_MODE_HID_N64USB && !n64usb)
|
|
||||||
{
|
|
||||||
n64usb = new N64USB();
|
|
||||||
n64usb->init(dev_addr, instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tuh_hid_receive_report(dev_addr, instance))
|
|
||||||
{
|
|
||||||
printf("Error: cannot request to receive report\r\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
|
|
||||||
{
|
|
||||||
if (gamepad_mounted && gamepad_dev_addr == dev_addr && gamepad_instance == instance)
|
|
||||||
{
|
|
||||||
gamepad_mounted = false;
|
|
||||||
|
|
||||||
if (switch_pro)
|
|
||||||
{
|
|
||||||
delete switch_pro;
|
|
||||||
switch_pro = nullptr;
|
|
||||||
}
|
|
||||||
if (switch_wired)
|
|
||||||
{
|
|
||||||
delete switch_wired;
|
|
||||||
switch_wired = nullptr;
|
|
||||||
}
|
|
||||||
if (n64usb)
|
|
||||||
{
|
|
||||||
delete n64usb;
|
|
||||||
n64usb = nullptr;
|
|
||||||
}
|
|
||||||
if (psclassic)
|
|
||||||
{
|
|
||||||
delete psclassic;
|
|
||||||
psclassic = nullptr;
|
|
||||||
}
|
|
||||||
if (dualshock3)
|
|
||||||
{
|
|
||||||
delete dualshock3;
|
|
||||||
dualshock3 = nullptr;
|
|
||||||
}
|
|
||||||
if (dualshock4)
|
|
||||||
{
|
|
||||||
delete dualshock4;
|
|
||||||
dualshock4 = nullptr;
|
|
||||||
}
|
|
||||||
if (dualsense)
|
|
||||||
{
|
|
||||||
delete dualsense;
|
|
||||||
dualsense = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoked when received report from device via interrupt endpoint
|
|
||||||
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
|
|
||||||
{
|
|
||||||
switch(host_mode)
|
|
||||||
{
|
|
||||||
case HOST_MODE_HID_PSCLASSIC:
|
|
||||||
psclassic->process_report(report, len);
|
|
||||||
break;
|
|
||||||
case HOST_MODE_HID_PS3:
|
|
||||||
dualshock3->process_report(report, len);
|
|
||||||
break;
|
|
||||||
case HOST_MODE_HID_PS4:
|
|
||||||
dualshock4->process_report(report, len);
|
|
||||||
break;
|
|
||||||
case HOST_MODE_HID_PS5:
|
|
||||||
dualsense->process_report(report, len);
|
|
||||||
break;
|
|
||||||
case HOST_MODE_HID_SWITCH_PRO:
|
|
||||||
switch_pro->process_report(report, len);
|
|
||||||
break;
|
|
||||||
case HOST_MODE_HID_SWITCH_WIRED:
|
|
||||||
switch_wired->process_report(report, len);
|
|
||||||
break;
|
|
||||||
case HOST_MODE_HID_N64USB:
|
|
||||||
n64usb->process_report(report, len);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !tuh_hid_receive_report(dev_addr, instance) )
|
|
||||||
{
|
|
||||||
printf("Error: cannot request to receive report\r\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool send_fb_data_to_hid_gamepad()
|
|
||||||
{
|
|
||||||
if (!gamepad_mounted)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool rumble_sent = false;
|
|
||||||
|
|
||||||
if (tuh_hid_send_ready)
|
|
||||||
{
|
|
||||||
switch(host_mode)
|
|
||||||
{
|
|
||||||
case HOST_MODE_HID_PSCLASSIC:
|
|
||||||
rumble_sent = psclassic->send_fb_data();
|
|
||||||
break;
|
|
||||||
case HOST_MODE_HID_PS3:
|
|
||||||
rumble_sent = dualshock3->send_fb_data();
|
|
||||||
break;
|
|
||||||
case HOST_MODE_HID_PS4:
|
|
||||||
rumble_sent = dualshock4->send_fb_data();
|
|
||||||
break;
|
|
||||||
case HOST_MODE_HID_PS5:
|
|
||||||
rumble_sent = dualsense->send_fb_data();
|
|
||||||
break;
|
|
||||||
case HOST_MODE_HID_SWITCH_PRO:
|
|
||||||
rumble_sent = switch_pro->send_fb_data();
|
|
||||||
break;
|
|
||||||
case HOST_MODE_HID_SWITCH_WIRED:
|
|
||||||
rumble_sent = switch_wired->send_fb_data();
|
|
||||||
break;
|
|
||||||
case HOST_MODE_HID_N64USB:
|
|
||||||
rumble_sent = n64usb->send_fb_data();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rumble_sent;
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
#ifndef _HID_HOST_APP_H_
|
|
||||||
#define _HID_HOST_APP_H_
|
|
||||||
|
|
||||||
#include "usbh/tusb_hid/n64usb.h"
|
|
||||||
#include "usbh/tusb_hid/psclassic.h"
|
|
||||||
#include "usbh/tusb_hid/ps3.h"
|
|
||||||
#include "usbh/tusb_hid/ps4.h"
|
|
||||||
#include "usbh/tusb_hid/ps5.h"
|
|
||||||
#include "usbh/tusb_hid/switch_pro.h"
|
|
||||||
#include "usbh/tusb_hid/switch_wired.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern usbh_class_driver_t const usbh_hid_driver;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool send_fb_data_to_hid_gamepad();
|
|
||||||
|
|
||||||
#endif // _HID_HOST_APP_H_
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include "pico/stdlib.h"
|
|
||||||
#include "tusb.h"
|
|
||||||
|
|
||||||
#include "utilities/scaling.h"
|
|
||||||
|
|
||||||
#include "usbh/tusb_hid/n64usb.h"
|
|
||||||
|
|
||||||
#include "Gamepad.h"
|
|
||||||
|
|
||||||
void N64USB::init(uint8_t dev_addr, uint8_t instance)
|
|
||||||
{
|
|
||||||
n64usb.dev_addr = dev_addr;
|
|
||||||
n64usb.instance = instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void N64USB::update_gamepad(const N64USBReport* n64_data)
|
|
||||||
{
|
|
||||||
gamepad.reset_state();
|
|
||||||
|
|
||||||
uint8_t n64_dpad = n64_data->buttons & N64_DPAD_MASK;
|
|
||||||
|
|
||||||
switch(n64_dpad)
|
|
||||||
{
|
|
||||||
case N64_DPAD_MASK_UP:
|
|
||||||
gamepad.state.up = true;
|
|
||||||
break;
|
|
||||||
case N64_DPAD_MASK_UP_RIGHT:
|
|
||||||
gamepad.state.up = true;
|
|
||||||
gamepad.state.right = true;
|
|
||||||
break;
|
|
||||||
case N64_DPAD_MASK_RIGHT:
|
|
||||||
gamepad.state.right = true;
|
|
||||||
break;
|
|
||||||
case N64_DPAD_MASK_RIGHT_DOWN:
|
|
||||||
gamepad.state.right = true;
|
|
||||||
gamepad.state.down = true;
|
|
||||||
break;
|
|
||||||
case N64_DPAD_MASK_DOWN:
|
|
||||||
gamepad.state.down = true;
|
|
||||||
break;
|
|
||||||
case N64_DPAD_MASK_DOWN_LEFT:
|
|
||||||
gamepad.state.down = true;
|
|
||||||
gamepad.state.left = true;
|
|
||||||
break;
|
|
||||||
case N64_DPAD_MASK_LEFT:
|
|
||||||
gamepad.state.left = true;
|
|
||||||
break;
|
|
||||||
case N64_DPAD_MASK_LEFT_UP:
|
|
||||||
gamepad.state.left = true;
|
|
||||||
gamepad.state.up = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n64_data->buttons & N64_C_UP_MASK) gamepad.state.ry = INT16_MAX;
|
|
||||||
if (n64_data->buttons & N64_C_DOWN_MASK) gamepad.state.ry = INT16_MIN;
|
|
||||||
if (n64_data->buttons & N64_C_LEFT_MASK) gamepad.state.rx = INT16_MIN;
|
|
||||||
if (n64_data->buttons & N64_C_RIGHT_MASK) gamepad.state.rx = INT16_MAX;
|
|
||||||
|
|
||||||
if (n64_data->buttons & N64_A_MASK) gamepad.state.a = true;
|
|
||||||
if (n64_data->buttons & N64_B_MASK) gamepad.state.b = true;
|
|
||||||
if (n64_data->buttons & N64_START_MASK) gamepad.state.start = true;
|
|
||||||
if (n64_data->buttons & N64_L_MASK) gamepad.state.lb = true;
|
|
||||||
if (n64_data->buttons & N64_R_MASK) gamepad.state.rb = true;
|
|
||||||
|
|
||||||
if (n64_data->buttons & N64_Z_MASK) gamepad.state.rt = 0xFF;
|
|
||||||
|
|
||||||
gamepad.state.ly = scale_uint8_to_int16(n64_data->y, true);
|
|
||||||
gamepad.state.lx = scale_uint8_to_int16(n64_data->x, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void N64USB::process_report(uint8_t const* report, uint16_t len)
|
|
||||||
{
|
|
||||||
static N64USBReport prev_report = { 0 };
|
|
||||||
|
|
||||||
N64USBReport n64_report;
|
|
||||||
memcpy(&n64_report, report, sizeof(n64_report));
|
|
||||||
|
|
||||||
if (memcmp(&n64_report, &prev_report, sizeof(n64_report)) != 0)
|
|
||||||
{
|
|
||||||
update_gamepad(&n64_report);
|
|
||||||
|
|
||||||
prev_report = n64_report;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool N64USB::send_fb_data()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@@ -1,221 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "pico/stdlib.h"
|
|
||||||
|
|
||||||
#include "tusb.h"
|
|
||||||
#include "class/hid/hid_host.h"
|
|
||||||
|
|
||||||
#include "utilities/scaling.h"
|
|
||||||
#include "Gamepad.h"
|
|
||||||
|
|
||||||
#include "usbh/tusb_hid/ps3.h"
|
|
||||||
|
|
||||||
#include "utilities/log.h"
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
/* this only works for DInput currently, no DS3 */
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
void Dualshock3::init(uint8_t dev_addr, uint8_t instance)
|
|
||||||
{
|
|
||||||
dualshock3.dev_addr = dev_addr;
|
|
||||||
dualshock3.instance = instance;
|
|
||||||
|
|
||||||
uint16_t vid, pid;
|
|
||||||
tuh_vid_pid_get(dualshock3.dev_addr, &vid, &pid);
|
|
||||||
if (vid == 0x054C && pid == 0x0268) dualshock3.sixaxis = true;
|
|
||||||
|
|
||||||
if (enable_reports())
|
|
||||||
{
|
|
||||||
// log("reports enabled, addr: %02X inst: %02X", dev_addr, instance);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// log("report enable failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Dualshock3::enable_reports()
|
|
||||||
{
|
|
||||||
// uint8_t cmd_buf[4];
|
|
||||||
// cmd_buf[0] = 0x42;
|
|
||||||
// cmd_buf[1] = 0x0c;
|
|
||||||
// cmd_buf[2] = 0x00;
|
|
||||||
// cmd_buf[3] = 0x00;
|
|
||||||
|
|
||||||
// // if (tuh_hid_send_ready)
|
|
||||||
// // {
|
|
||||||
// dualshock3.report_enabled = tuh_hid_set_report(dualshock3.dev_addr, dualshock3.instance, 0xF4, HID_REPORT_TYPE_FEATURE, &cmd_buf, sizeof(cmd_buf));
|
|
||||||
// // }
|
|
||||||
|
|
||||||
static uint8_t buffer[5] = {};
|
|
||||||
buffer[0] = 0xF4;
|
|
||||||
buffer[1] = 0x42;
|
|
||||||
buffer[2] = 0x03;
|
|
||||||
buffer[3] = 0x00;
|
|
||||||
buffer[4] = 0x00;
|
|
||||||
|
|
||||||
dualshock3.report_enabled = tuh_hid_set_report(dualshock3.dev_addr, dualshock3.instance, 0, HID_REPORT_TYPE_FEATURE, buffer, sizeof(buffer));
|
|
||||||
|
|
||||||
tuh_hid_send_report(dualshock3.dev_addr, dualshock3.instance, 0, buffer, sizeof(buffer));
|
|
||||||
|
|
||||||
if (dualshock3.report_enabled)
|
|
||||||
{
|
|
||||||
tuh_hid_receive_report(dualshock3.dev_addr, dualshock3.instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dualshock3.report_enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dualshock3::update_gamepad_dinput(const DInputReport* dinput_report)
|
|
||||||
{
|
|
||||||
gamepad.reset_state();
|
|
||||||
|
|
||||||
switch (dinput_report->direction)
|
|
||||||
{
|
|
||||||
case DINPUT_HAT_UP:
|
|
||||||
gamepad.state.up = true;
|
|
||||||
break;
|
|
||||||
case DINPUT_HAT_UPRIGHT:
|
|
||||||
gamepad.state.up = true;
|
|
||||||
gamepad.state.right = true;
|
|
||||||
break;
|
|
||||||
case DINPUT_HAT_RIGHT:
|
|
||||||
gamepad.state.right = true;
|
|
||||||
break;
|
|
||||||
case DINPUT_HAT_DOWNRIGHT:
|
|
||||||
gamepad.state.right = true;
|
|
||||||
gamepad.state.down = true;
|
|
||||||
break;
|
|
||||||
case DINPUT_HAT_DOWN:
|
|
||||||
gamepad.state.down = true;
|
|
||||||
break;
|
|
||||||
case DINPUT_HAT_DOWNLEFT:
|
|
||||||
gamepad.state.down = true;
|
|
||||||
gamepad.state.left = true;
|
|
||||||
break;
|
|
||||||
case DINPUT_HAT_LEFT:
|
|
||||||
gamepad.state.left = true;
|
|
||||||
break;
|
|
||||||
case DINPUT_HAT_UPLEFT:
|
|
||||||
gamepad.state.up = true;
|
|
||||||
gamepad.state.left = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dinput_report->square_btn) gamepad.state.x = true;
|
|
||||||
if (dinput_report->triangle_btn) gamepad.state.y = true;
|
|
||||||
if (dinput_report->cross_btn) gamepad.state.a = true;
|
|
||||||
if (dinput_report->circle_btn) gamepad.state.b = true;
|
|
||||||
|
|
||||||
if (dinput_report->select_btn) gamepad.state.back = true;
|
|
||||||
if (dinput_report->start_btn) gamepad.state.start = true;
|
|
||||||
if (dinput_report->ps_btn) gamepad.state.sys = true;
|
|
||||||
|
|
||||||
if (dinput_report->l3_btn) gamepad.state.l3 = true;
|
|
||||||
if (dinput_report->r3_btn) gamepad.state.r3 = true;
|
|
||||||
|
|
||||||
if (dinput_report->l1_btn) gamepad.state.lb = true;
|
|
||||||
if (dinput_report->r1_btn) gamepad.state.rb = true;
|
|
||||||
|
|
||||||
if (dinput_report->l2_btn) gamepad.state.lt = 0xFF;
|
|
||||||
if (dinput_report->r2_btn) gamepad.state.rt = 0xFF;
|
|
||||||
|
|
||||||
gamepad.state.lx = scale_uint8_to_int16(dinput_report->l_x_axis, false);
|
|
||||||
gamepad.state.ly = scale_uint8_to_int16(dinput_report->l_y_axis, true);
|
|
||||||
gamepad.state.rx = scale_uint8_to_int16(dinput_report->r_x_axis, false);
|
|
||||||
gamepad.state.ry = scale_uint8_to_int16(dinput_report->r_y_axis, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dualshock3::update_gamepad(const Dualshock3Report* ds3_data)
|
|
||||||
{
|
|
||||||
gamepad.reset_state();
|
|
||||||
|
|
||||||
if (ds3_data->up) gamepad.state.up =true;
|
|
||||||
if (ds3_data->down) gamepad.state.down =true;
|
|
||||||
if (ds3_data->left) gamepad.state.left =true;
|
|
||||||
if (ds3_data->right) gamepad.state.right =true;
|
|
||||||
|
|
||||||
if (ds3_data->square) gamepad.state.x = true;
|
|
||||||
if (ds3_data->triangle) gamepad.state.y = true;
|
|
||||||
if (ds3_data->cross) gamepad.state.a = true;
|
|
||||||
if (ds3_data->circle) gamepad.state.b = true;
|
|
||||||
|
|
||||||
if (ds3_data->select) gamepad.state.back = true;
|
|
||||||
if (ds3_data->start) gamepad.state.start = true;
|
|
||||||
if (ds3_data->ps) gamepad.state.sys = true;
|
|
||||||
|
|
||||||
if (ds3_data->l3) gamepad.state.l3 = true;
|
|
||||||
if (ds3_data->r3) gamepad.state.r3 = true;
|
|
||||||
|
|
||||||
if (ds3_data->l1) gamepad.state.lb = true;
|
|
||||||
if (ds3_data->r1) gamepad.state.rb = true;
|
|
||||||
|
|
||||||
if (ds3_data->l2) gamepad.state.lt = 0xFF;
|
|
||||||
if (ds3_data->r2) gamepad.state.rt = 0xFF;
|
|
||||||
|
|
||||||
gamepad.state.lx = scale_uint8_to_int16(ds3_data->left_x, false);
|
|
||||||
gamepad.state.ly = scale_uint8_to_int16(ds3_data->left_y, true);
|
|
||||||
gamepad.state.rx = scale_uint8_to_int16(ds3_data->right_x, false);
|
|
||||||
gamepad.state.ry = scale_uint8_to_int16(ds3_data->right_y, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dualshock3::process_report(uint8_t const* report, uint16_t len)
|
|
||||||
{
|
|
||||||
// if (report[0] != 0x01) return;
|
|
||||||
|
|
||||||
// print hex values
|
|
||||||
// char hex_buffer[len * 3];
|
|
||||||
// for (int i = 0; i < len; i++)
|
|
||||||
// {
|
|
||||||
// sprintf(hex_buffer + (i * 3), "%02X ", report[i]); // Convert byte to hexadecimal string
|
|
||||||
// }
|
|
||||||
// log(hex_buffer);
|
|
||||||
|
|
||||||
if (!dualshock3.sixaxis)
|
|
||||||
{
|
|
||||||
static DInputReport prev_report = {0};
|
|
||||||
DInputReport dinput_report;
|
|
||||||
memcpy(&dinput_report, report, sizeof(dinput_report));
|
|
||||||
update_gamepad_dinput(&dinput_report);
|
|
||||||
prev_report = dinput_report;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
static Dualshock3Report prev_report = { 0 };
|
|
||||||
Dualshock3Report ds3_report;
|
|
||||||
memcpy(&ds3_report, report, sizeof(ds3_report));
|
|
||||||
update_gamepad(&ds3_report);
|
|
||||||
prev_report = ds3_report;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Dualshock3::send_fb_data()
|
|
||||||
{
|
|
||||||
uint8_t default_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
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sixaxis_output_report output_report;
|
|
||||||
|
|
||||||
memcpy(&output_report, default_report, sizeof(output_report));
|
|
||||||
|
|
||||||
// default_output_report.leds_bitmap |= 0x1 << (dualshock3.instance+1);
|
|
||||||
output_report.leds_bitmap = 0x02;
|
|
||||||
// output_report.led->time_enabled = 0xFF;
|
|
||||||
// output_report.led->duty_on = 0xFF;
|
|
||||||
|
|
||||||
output_report.rumble.right_duration = UINT8_MAX / 2;
|
|
||||||
if (gamepadOut.out_state.rrumble > 0) output_report.rumble.right_motor_on = 1;
|
|
||||||
|
|
||||||
output_report.rumble.left_duration = UINT8_MAX / 2;
|
|
||||||
output_report.rumble.left_motor_force = gamepadOut.out_state.lrumble;
|
|
||||||
|
|
||||||
return tuh_hid_send_report(dualshock3.dev_addr, dualshock3.instance, 0x1, &output_report, sizeof(output_report));
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#ifndef _PS3_H_
|
|
||||||
#define _PS3_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "usbh/tusb_hid/shared.h"
|
|
||||||
#include "descriptors/PS3Descriptors.h"
|
|
||||||
#include "descriptors/DInputDescriptors.h"
|
|
||||||
|
|
||||||
#define PS3_REPORT_BUFFER_SIZE 48
|
|
||||||
|
|
||||||
const usb_vid_pid_t ps3_devices[] =
|
|
||||||
{
|
|
||||||
{0x054C, 0x0268}, // Sony Batoh (Dualshock 3)
|
|
||||||
// {0x045E, 0x028E}, // Voyee generic "P3", won't work, IDs are for a 360 controller (dumb)
|
|
||||||
{0x044F, 0xB324}, // ThrustMaster Dual Trigger (PS3 mode)
|
|
||||||
{0x0738, 0x8818}, // MadCatz Street Fighter IV Arcade FightStick
|
|
||||||
{0x0810, 0x0003}, // Personal Communication Systems, Inc. Generic
|
|
||||||
{0x146B, 0x0902} // BigBen Interactive Wired Mini PS3 Game Controller
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Dualshock3State
|
|
||||||
{
|
|
||||||
bool report_enabled {false};
|
|
||||||
bool sixaxis {false};
|
|
||||||
uint8_t dev_addr = {0};
|
|
||||||
uint8_t instance = {0};
|
|
||||||
};
|
|
||||||
|
|
||||||
class Dualshock3
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void init(uint8_t dev_addr, uint8_t instance);
|
|
||||||
void process_report(uint8_t const* report, uint16_t len);
|
|
||||||
bool send_fb_data();
|
|
||||||
|
|
||||||
private:
|
|
||||||
Dualshock3State dualshock3;
|
|
||||||
|
|
||||||
bool enable_reports();
|
|
||||||
void reset_state();
|
|
||||||
void update_gamepad(const Dualshock3Report* ds3_data);
|
|
||||||
void update_gamepad_dinput(const DInputReport* dinput_report);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // _PS3_H_
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include "pico/stdlib.h"
|
|
||||||
#include "tusb.h"
|
|
||||||
#include "CRC32.h"
|
|
||||||
|
|
||||||
#include "usbh/tusb_hid/ps4.h"
|
|
||||||
|
|
||||||
#include "utilities/scaling.h"
|
|
||||||
|
|
||||||
#include "Gamepad.h"
|
|
||||||
|
|
||||||
void Dualshock4::init(uint8_t dev_addr, uint8_t instance)
|
|
||||||
{
|
|
||||||
dualshock4.dev_addr = dev_addr;
|
|
||||||
dualshock4.instance = instance;
|
|
||||||
// set_leds();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* this DCs the controller, come back to it */
|
|
||||||
bool Dualshock4::set_leds()
|
|
||||||
{
|
|
||||||
// see: https://github.com/Hydr8gon/VitaControl
|
|
||||||
|
|
||||||
static uint8_t buffer[79] = {};
|
|
||||||
buffer[0] = 0xA2;
|
|
||||||
buffer[1] = 0x11;
|
|
||||||
buffer[2] = 0xC0;
|
|
||||||
buffer[3] = 0x20;
|
|
||||||
buffer[4] = 0xF3;
|
|
||||||
buffer[5] = 0x04;
|
|
||||||
buffer[9] = led_colors[dualshock4.instance][0];
|
|
||||||
buffer[10] = led_colors[dualshock4.instance][1];
|
|
||||||
buffer[11] = led_colors[dualshock4.instance][2];
|
|
||||||
|
|
||||||
// Calculate the CRC of the data (including the 0xA2 byte) and append it to the end
|
|
||||||
uint32_t crc = CRC32::calculate(buffer, 75);
|
|
||||||
buffer[75] = crc >> 0;
|
|
||||||
buffer[76] = crc >> 8;
|
|
||||||
buffer[77] = crc >> 16;
|
|
||||||
buffer[78] = crc >> 24;
|
|
||||||
|
|
||||||
// Send the write request, omitting the 0xA2 byte
|
|
||||||
dualshock4.leds_set = tuh_hid_send_report(dualshock4.dev_addr, dualshock4.instance, 0, &buffer + 1, sizeof(buffer) - 1);
|
|
||||||
|
|
||||||
return dualshock4.leds_set;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dualshock4::update_gamepad(const Dualshock4Report* ds4_data)
|
|
||||||
{
|
|
||||||
gamepad.reset_state();
|
|
||||||
|
|
||||||
switch(ds4_data->dpad)
|
|
||||||
{
|
|
||||||
case PS4_DPAD_MASK_UP:
|
|
||||||
gamepad.state.up = true;
|
|
||||||
break;
|
|
||||||
case PS4_DPAD_MASK_UP_RIGHT:
|
|
||||||
gamepad.state.up = true;
|
|
||||||
gamepad.state.right = true;
|
|
||||||
break;
|
|
||||||
case PS4_DPAD_MASK_RIGHT:
|
|
||||||
gamepad.state.right = true;
|
|
||||||
break;
|
|
||||||
case PS4_DPAD_MASK_RIGHT_DOWN:
|
|
||||||
gamepad.state.right = true;
|
|
||||||
gamepad.state.down = true;
|
|
||||||
break;
|
|
||||||
case PS4_DPAD_MASK_DOWN:
|
|
||||||
gamepad.state.down = true;
|
|
||||||
break;
|
|
||||||
case PS4_DPAD_MASK_DOWN_LEFT:
|
|
||||||
gamepad.state.down = true;
|
|
||||||
gamepad.state.left = true;
|
|
||||||
break;
|
|
||||||
case PS4_DPAD_MASK_LEFT:
|
|
||||||
gamepad.state.left = true;
|
|
||||||
break;
|
|
||||||
case PS4_DPAD_MASK_LEFT_UP:
|
|
||||||
gamepad.state.left = true;
|
|
||||||
gamepad.state.up = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ds4_data->square) gamepad.state.x = true;
|
|
||||||
if (ds4_data->cross) gamepad.state.a = true;
|
|
||||||
if (ds4_data->circle) gamepad.state.b = true;
|
|
||||||
if (ds4_data->triangle) gamepad.state.y = true;
|
|
||||||
|
|
||||||
if (ds4_data->share) gamepad.state.back = true;
|
|
||||||
if (ds4_data->option) gamepad.state.start = true;
|
|
||||||
if (ds4_data->ps) gamepad.state.sys = true;
|
|
||||||
if (ds4_data->tpad) gamepad.state.misc = true;
|
|
||||||
|
|
||||||
if (ds4_data->l1) gamepad.state.lb = true;
|
|
||||||
if (ds4_data->r1) gamepad.state.rb = true;
|
|
||||||
|
|
||||||
if (ds4_data->l3) gamepad.state.l3 = true;
|
|
||||||
if (ds4_data->r3) gamepad.state.r3 = true;
|
|
||||||
|
|
||||||
gamepad.state.lt = ds4_data->l2_trigger;
|
|
||||||
gamepad.state.rt = ds4_data->r2_trigger;
|
|
||||||
|
|
||||||
gamepad.state.lx = scale_uint8_to_int16(ds4_data->lx, false);
|
|
||||||
gamepad.state.ly = scale_uint8_to_int16(ds4_data->ly, true);
|
|
||||||
gamepad.state.rx = scale_uint8_to_int16(ds4_data->rx, false);
|
|
||||||
gamepad.state.ry = scale_uint8_to_int16(ds4_data->ry, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dualshock4::process_report(uint8_t const* report, uint16_t len)
|
|
||||||
{
|
|
||||||
// if (report[0] != REPORT_ID_GAMEPAD_STATE)
|
|
||||||
// {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
static Dualshock4Report prev_report = { 0 };
|
|
||||||
|
|
||||||
Dualshock4Report ds4_report;
|
|
||||||
|
|
||||||
memcpy(&ds4_report, report, sizeof(ds4_report));
|
|
||||||
|
|
||||||
if (memcmp(&ds4_report, &prev_report, sizeof(ds4_report)) != 0)
|
|
||||||
{
|
|
||||||
update_gamepad(&ds4_report);
|
|
||||||
|
|
||||||
prev_report = ds4_report;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Dualshock4::send_fb_data()
|
|
||||||
{
|
|
||||||
Dualshock4OutReport output_report = {0};
|
|
||||||
output_report.set_rumble = 1;
|
|
||||||
output_report.motor_left = gamepadOut.out_state.lrumble;
|
|
||||||
output_report.motor_right = gamepadOut.out_state.rrumble;
|
|
||||||
|
|
||||||
return tuh_hid_send_report(dualshock4.dev_addr, dualshock4.instance, 5, &output_report, sizeof(output_report));
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include "pico/stdlib.h"
|
|
||||||
#include "tusb.h"
|
|
||||||
|
|
||||||
#include "usbh/tusb_hid/ps5.h"
|
|
||||||
#include "utilities/scaling.h"
|
|
||||||
|
|
||||||
#include "Gamepad.h"
|
|
||||||
|
|
||||||
void Dualsense::init(uint8_t dev_addr, uint8_t instance)
|
|
||||||
{
|
|
||||||
dualsense.dev_addr = dev_addr;
|
|
||||||
dualsense.instance = instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dualsense::update_gamepad(const DualsenseReport* ds_data)
|
|
||||||
{
|
|
||||||
gamepad.reset_state();
|
|
||||||
|
|
||||||
switch(ds_data->dpad)
|
|
||||||
{
|
|
||||||
case PS5_MASK_DPAD_UP:
|
|
||||||
gamepad.state.up = true;
|
|
||||||
break;
|
|
||||||
case PS5_MASK_DPAD_UP_RIGHT:
|
|
||||||
gamepad.state.up = true;
|
|
||||||
gamepad.state.right = true;
|
|
||||||
break;
|
|
||||||
case PS5_MASK_DPAD_RIGHT:
|
|
||||||
gamepad.state.right = true;
|
|
||||||
break;
|
|
||||||
case PS5_MASK_DPAD_RIGHT_DOWN:
|
|
||||||
gamepad.state.right = true;
|
|
||||||
gamepad.state.down = true;
|
|
||||||
break;
|
|
||||||
case PS5_MASK_DPAD_DOWN:
|
|
||||||
gamepad.state.down = true;
|
|
||||||
break;
|
|
||||||
case PS5_MASK_DPAD_DOWN_LEFT:
|
|
||||||
gamepad.state.down = true;
|
|
||||||
gamepad.state.left = true;
|
|
||||||
break;
|
|
||||||
case PS5_MASK_DPAD_LEFT:
|
|
||||||
gamepad.state.left = true;
|
|
||||||
break;
|
|
||||||
case PS5_MASK_DPAD_LEFT_UP:
|
|
||||||
gamepad.state.left = true;
|
|
||||||
gamepad.state.up = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ds_data->square) gamepad.state.x = true;
|
|
||||||
if (ds_data->cross) gamepad.state.a = true;
|
|
||||||
if (ds_data->circle) gamepad.state.b = true;
|
|
||||||
if (ds_data->triangle) gamepad.state.y = true;
|
|
||||||
|
|
||||||
if (ds_data->buttons[0] & PS5_MASK_L1) gamepad.state.lb = true;
|
|
||||||
if (ds_data->buttons[0] & PS5_MASK_R1) gamepad.state.rb = true;
|
|
||||||
|
|
||||||
if (ds_data->buttons[0] & PS5_MASK_SHARE) gamepad.state.back = true;
|
|
||||||
if (ds_data->buttons[0] & PS5_MASK_OPTIONS) gamepad.state.start = true;
|
|
||||||
|
|
||||||
if (ds_data->buttons[0] & PS5_MASK_L3) gamepad.state.l3 = true;
|
|
||||||
if (ds_data->buttons[0] & PS5_MASK_R3) gamepad.state.r3 = true;
|
|
||||||
|
|
||||||
if (ds_data->buttons[1] & PS5_MASK_PS) gamepad.state.sys = true;
|
|
||||||
if (ds_data->buttons[1] & PS5_MASK_MIC) gamepad.state.misc = true;
|
|
||||||
|
|
||||||
gamepad.state.lt = ds_data->lt;
|
|
||||||
gamepad.state.rt = ds_data->rt;
|
|
||||||
|
|
||||||
gamepad.state.lx = scale_uint8_to_int16(ds_data->lx, false);
|
|
||||||
gamepad.state.ly = scale_uint8_to_int16(ds_data->ly, true);
|
|
||||||
gamepad.state.rx = scale_uint8_to_int16(ds_data->rx, false);
|
|
||||||
gamepad.state.ry = scale_uint8_to_int16(ds_data->ry, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* not much point in comparing changes unless we only look at buttons */
|
|
||||||
void Dualsense::process_report(uint8_t const* report, uint16_t len)
|
|
||||||
{
|
|
||||||
// static DualsenseReport prev_report = { 0 };
|
|
||||||
|
|
||||||
DualsenseReport ds_report;
|
|
||||||
memcpy(&ds_report, report, sizeof(ds_report));
|
|
||||||
|
|
||||||
// if (memcmp(&ds_report, &prev_report, sizeof(ds_report)) != 0)
|
|
||||||
// {
|
|
||||||
update_gamepad(&ds_report);
|
|
||||||
|
|
||||||
// prev_report = ds_report;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Dualsense::send_fb_data()
|
|
||||||
{
|
|
||||||
// need to figure out if the flags are necessary and how the LEDs work
|
|
||||||
DualsenseOutReport output_report = {0};
|
|
||||||
output_report.valid_flag0 = 0x02; // idk what this means
|
|
||||||
output_report.valid_flag1 = 0x02; // this one either
|
|
||||||
output_report.valid_flag2 = 0x04; // uhhhhh
|
|
||||||
output_report.motor_left = gamepadOut.out_state.lrumble;
|
|
||||||
output_report.motor_right = gamepadOut.out_state.rrumble;
|
|
||||||
|
|
||||||
return tuh_hid_send_report(dualsense.dev_addr, dualsense.instance, 5, &output_report, sizeof(output_report));
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include "pico/stdlib.h"
|
|
||||||
#include "tusb.h"
|
|
||||||
|
|
||||||
#include "usbh/tusb_hid/psclassic.h"
|
|
||||||
// #include "usbh/tusb_hid/ps4.h"
|
|
||||||
|
|
||||||
#include "Gamepad.h"
|
|
||||||
|
|
||||||
void PSClassic::init(uint8_t dev_addr, uint8_t instance)
|
|
||||||
{
|
|
||||||
psclassic.dev_addr = dev_addr;
|
|
||||||
psclassic.instance = instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PSClassic::update_gamepad(const PSClassicReport* psc_data)
|
|
||||||
{
|
|
||||||
gamepad.reset_state();
|
|
||||||
|
|
||||||
switch (psc_data->buttons & 0x3C00) {
|
|
||||||
case PSCLASSIC_MASK_UP_LEFT:
|
|
||||||
gamepad.state.up = true;
|
|
||||||
gamepad.state.left = true;
|
|
||||||
break;
|
|
||||||
case PSCLASSIC_MASK_UP:
|
|
||||||
gamepad.state.up = true;
|
|
||||||
break;
|
|
||||||
case PSCLASSIC_MASK_UP_RIGHT:
|
|
||||||
gamepad.state.up = true;
|
|
||||||
gamepad.state.right = true;
|
|
||||||
break;
|
|
||||||
case PSCLASSIC_MASK_LEFT:
|
|
||||||
gamepad.state.left = true;
|
|
||||||
break;
|
|
||||||
case PSCLASSIC_MASK_RIGHT:
|
|
||||||
gamepad.state.right = true;
|
|
||||||
break;
|
|
||||||
case PSCLASSIC_MASK_DOWN_LEFT:
|
|
||||||
gamepad.state.down = true;
|
|
||||||
gamepad.state.left = true;
|
|
||||||
break;
|
|
||||||
case PSCLASSIC_MASK_DOWN:
|
|
||||||
gamepad.state.down = true;
|
|
||||||
break;
|
|
||||||
case PSCLASSIC_MASK_DOWN_RIGHT:
|
|
||||||
gamepad.state.down = true;
|
|
||||||
gamepad.state.right = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (psc_data->buttons & PSCLASSIC_MASK_TRIANGLE) gamepad.state.y = true;
|
|
||||||
if (psc_data->buttons & PSCLASSIC_MASK_CIRCLE) gamepad.state.b = true;
|
|
||||||
if (psc_data->buttons & PSCLASSIC_MASK_CROSS) gamepad.state.a = true;
|
|
||||||
if (psc_data->buttons & PSCLASSIC_MASK_SQUARE) gamepad.state.x = true;
|
|
||||||
|
|
||||||
if (psc_data->buttons & PSCLASSIC_MASK_L2) gamepad.state.lt = 0xFF;
|
|
||||||
if (psc_data->buttons & PSCLASSIC_MASK_R2) gamepad.state.rt = 0xFF;
|
|
||||||
|
|
||||||
if (psc_data->buttons & PSCLASSIC_MASK_L1) gamepad.state.lb = true;
|
|
||||||
if (psc_data->buttons & PSCLASSIC_MASK_R1) gamepad.state.rb = true;
|
|
||||||
|
|
||||||
if (psc_data->buttons & PSCLASSIC_MASK_SELECT) gamepad.state.back = true;
|
|
||||||
if (psc_data->buttons & PSCLASSIC_MASK_START) gamepad.state.start = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PSClassic::process_report(uint8_t const* report, uint16_t len)
|
|
||||||
{
|
|
||||||
static PSClassicReport prev_report = { 0 };
|
|
||||||
|
|
||||||
PSClassicReport psc_report;
|
|
||||||
memcpy(&psc_report, report, sizeof(psc_report));
|
|
||||||
|
|
||||||
if (memcmp(&psc_report, &prev_report, sizeof(psc_report)) != 0)
|
|
||||||
{
|
|
||||||
update_gamepad(&psc_report);
|
|
||||||
|
|
||||||
prev_report = psc_report;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PSClassic::send_fb_data()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#ifndef _PSCLASSIC_H_
|
|
||||||
#define _PSCLASSIC_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "usbh/tusb_hid/shared.h"
|
|
||||||
|
|
||||||
#include "descriptors/PSClassicDescriptors.h"
|
|
||||||
|
|
||||||
const usb_vid_pid_t psc_devices[] =
|
|
||||||
{
|
|
||||||
{0x054C, 0x0CDA} // psclassic
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PSClassicState
|
|
||||||
{
|
|
||||||
uint8_t dev_addr = {0};
|
|
||||||
uint8_t instance = {0};
|
|
||||||
};
|
|
||||||
|
|
||||||
class PSClassic
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void init(uint8_t dev_addr, uint8_t instance);
|
|
||||||
void process_report(uint8_t const* report, uint16_t len);
|
|
||||||
bool send_fb_data();
|
|
||||||
private:
|
|
||||||
PSClassicState psclassic;
|
|
||||||
void update_gamepad(const PSClassicReport* psc_data);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // _PSCLASSIC_H_
|
|
||||||
@@ -1,266 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include "pico/stdlib.h"
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#include "tusb.h"
|
|
||||||
|
|
||||||
#include "usbh/tusb_hid/switch_pro.h"
|
|
||||||
|
|
||||||
#include "Gamepad.h"
|
|
||||||
|
|
||||||
// commands
|
|
||||||
#define CMD_HID 0x80
|
|
||||||
#define SUBCMD_HANDSHAKE 0x02
|
|
||||||
#define SUBCMD_DISABLE_TIMEOUT 0x04
|
|
||||||
|
|
||||||
// out report commands
|
|
||||||
#define CMD_RUMBLE_ONLY 0x10
|
|
||||||
#define CMD_AND_RUMBLE 0x01
|
|
||||||
|
|
||||||
// out report subcommands
|
|
||||||
#define CMD_LED 0x30
|
|
||||||
#define CMD_LED_HOME 0x38
|
|
||||||
#define CMD_GYRO 0x40
|
|
||||||
#define CMD_MODE 0x03
|
|
||||||
#define SUBCMD_FULL_REPORT_MODE 0x30
|
|
||||||
|
|
||||||
void SwitchPro::init(uint8_t dev_addr, uint8_t instance)
|
|
||||||
{
|
|
||||||
reset_state();
|
|
||||||
|
|
||||||
switch_pro.dev_addr = dev_addr;
|
|
||||||
switch_pro.instance = instance;
|
|
||||||
|
|
||||||
if (tuh_hid_send_ready)
|
|
||||||
{
|
|
||||||
uint8_t handshake_command[2] = {CMD_HID, SUBCMD_HANDSHAKE};
|
|
||||||
switch_pro.handshake_sent = tuh_hid_send_report(switch_pro.dev_addr, switch_pro.instance, 0, handshake_command, sizeof(handshake_command));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SwitchPro::reset_state()
|
|
||||||
{
|
|
||||||
switch_pro.handshake_sent = false;
|
|
||||||
switch_pro.timeout_disabled = false;
|
|
||||||
switch_pro.full_report_enabled = false;
|
|
||||||
switch_pro.led_set = false;
|
|
||||||
switch_pro.led_home_set = false;
|
|
||||||
switch_pro.imu_enabled = false;
|
|
||||||
switch_pro.dev_addr = 0;
|
|
||||||
switch_pro.instance = 0;
|
|
||||||
switch_pro.output_sequence_counter = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t SwitchPro::get_output_sequence_counter()
|
|
||||||
{
|
|
||||||
// increments each report, resets to 0 after 15
|
|
||||||
uint8_t counter = switch_pro.output_sequence_counter;
|
|
||||||
switch_pro.output_sequence_counter = (switch_pro.output_sequence_counter + 1) & 0x0F;
|
|
||||||
return counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SwitchPro::disable_timeout()
|
|
||||||
{
|
|
||||||
uint8_t disable_timeout_command[2] = {CMD_HID, SUBCMD_DISABLE_TIMEOUT};
|
|
||||||
|
|
||||||
if (tuh_hid_send_ready)
|
|
||||||
{
|
|
||||||
switch_pro.timeout_disabled = tuh_hid_send_report(switch_pro.dev_addr, switch_pro.instance, 0, disable_timeout_command, sizeof(disable_timeout_command));
|
|
||||||
}
|
|
||||||
|
|
||||||
return switch_pro.timeout_disabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SwitchPro::process_report(uint8_t const* report, uint16_t len)
|
|
||||||
{
|
|
||||||
if (switch_pro.handshake_sent)
|
|
||||||
{
|
|
||||||
// this is here to the respond to handshake, doesn't seem to work otherwise
|
|
||||||
if (!switch_pro.timeout_disabled)
|
|
||||||
{
|
|
||||||
disable_timeout();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static SwitchProReport prev_report = {0};
|
|
||||||
|
|
||||||
SwitchProReport switch_report;
|
|
||||||
memcpy(&switch_report, report, sizeof(switch_report));
|
|
||||||
|
|
||||||
if (memcmp(&switch_report, &prev_report, sizeof(switch_report)) != 0)
|
|
||||||
{
|
|
||||||
update_gamepad(&switch_report);
|
|
||||||
|
|
||||||
prev_report = switch_report;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int16_t SwitchPro::normalize_axes(uint16_t value)
|
|
||||||
{
|
|
||||||
/* 12bit value from the controller doesnt cover the full 12bit range seemingly
|
|
||||||
doesn't seem completely centered at 2047 so I may be missing something here
|
|
||||||
tried to get as close as possible with the multiplier */
|
|
||||||
|
|
||||||
int32_t normalized_value = (value - 2047) * 22;
|
|
||||||
|
|
||||||
if (normalized_value < -32768)
|
|
||||||
{
|
|
||||||
normalized_value = -32768;
|
|
||||||
}
|
|
||||||
else if (normalized_value > 32767)
|
|
||||||
{
|
|
||||||
normalized_value = 32767;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (int16_t)normalized_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SwitchPro::update_gamepad(const SwitchProReport* switch_report)
|
|
||||||
{
|
|
||||||
gamepad.reset_state();
|
|
||||||
|
|
||||||
if (switch_report->up) gamepad.state.up =true;
|
|
||||||
if (switch_report->down) gamepad.state.down =true;
|
|
||||||
if (switch_report->left) gamepad.state.left =true;
|
|
||||||
if (switch_report->right) gamepad.state.right =true;
|
|
||||||
|
|
||||||
if (switch_report->y) gamepad.state.x = true;
|
|
||||||
if (switch_report->x) gamepad.state.y = true;
|
|
||||||
if (switch_report->b) gamepad.state.a = true;
|
|
||||||
if (switch_report->a) gamepad.state.b = true;
|
|
||||||
|
|
||||||
if (switch_report->minus) gamepad.state.back = true;
|
|
||||||
if (switch_report->plus) gamepad.state.start = true;
|
|
||||||
if (switch_report->home) gamepad.state.sys = true;
|
|
||||||
if (switch_report->capture) gamepad.state.misc = true;
|
|
||||||
|
|
||||||
if (switch_report->stickL) gamepad.state.l3 = true;
|
|
||||||
if (switch_report->stickR) gamepad.state.r3 = true;
|
|
||||||
|
|
||||||
if (switch_report->l) gamepad.state.lb = true;
|
|
||||||
if (switch_report->r) gamepad.state.rb = true;
|
|
||||||
|
|
||||||
if (switch_report->zl) gamepad.state.lt = 0xFF;
|
|
||||||
if (switch_report->zr) gamepad.state.rt = 0xFF;
|
|
||||||
|
|
||||||
gamepad.state.lx = normalize_axes(switch_report->leftX );
|
|
||||||
gamepad.state.ly = normalize_axes(switch_report->leftY );
|
|
||||||
gamepad.state.rx = normalize_axes(switch_report->rightX);
|
|
||||||
gamepad.state.ry = normalize_axes(switch_report->rightY);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SwitchPro::send_fb_data()
|
|
||||||
{
|
|
||||||
if (!switch_pro.handshake_sent || !switch_pro.timeout_disabled)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// See: https://github.com/Dan611/hid-procon
|
|
||||||
// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering
|
|
||||||
// https://github.com/HisashiKato/USB_Host_Shield_Library_2.0
|
|
||||||
|
|
||||||
uint8_t buffer[14] = { 0 };
|
|
||||||
uint8_t report_size = 10;
|
|
||||||
|
|
||||||
buffer[1] = get_output_sequence_counter();
|
|
||||||
|
|
||||||
// whoever came up with hd rumble is some kind of sick freak, I'm just guessing here
|
|
||||||
|
|
||||||
if (gamepadOut.out_state.lrumble > 0)
|
|
||||||
{
|
|
||||||
// full on
|
|
||||||
// buffer[2] = 0x28;
|
|
||||||
// buffer[3] = 0x88;
|
|
||||||
// buffer[4] = 0x60;
|
|
||||||
// buffer[5] = 0x61;
|
|
||||||
|
|
||||||
// uint8_t amplitude_l = static_cast<uint8_t>((gamepadOut.out_state.lrumble / 255.0) * (0xC0 - 0x40) + 0x40);
|
|
||||||
uint8_t amplitude_l = static_cast<uint8_t>(((gamepadOut.out_state.lrumble / 255.0f) * 0.8f + 0.5f) * (0xC0 - 0x40) + 0x40);
|
|
||||||
|
|
||||||
buffer[2] = amplitude_l;
|
|
||||||
buffer[3] = 0x88;
|
|
||||||
buffer[4] = amplitude_l / 2;
|
|
||||||
buffer[5] = 0x61;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
buffer[2] = 0x00;
|
|
||||||
buffer[3] = 0x01;
|
|
||||||
buffer[4] = 0x40;
|
|
||||||
buffer[5] = 0x40;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gamepadOut.out_state.rrumble > 0)
|
|
||||||
{
|
|
||||||
// full on
|
|
||||||
// buffer[6] = 0x28;
|
|
||||||
// buffer[7] = 0x88;
|
|
||||||
// buffer[8] = 0x60;
|
|
||||||
// buffer[9] = 0x61;
|
|
||||||
|
|
||||||
// uint8_t amplitude_r = static_cast<uint8_t>((gamepadOut.out_state.rrumble / 255.0) * (0xC0 - 0x40) + 0x40);
|
|
||||||
uint8_t amplitude_r = static_cast<uint8_t>(((gamepadOut.out_state.rrumble / 255.0f) * 0.8f + 0.5f) * (0xC0 - 0x40) + 0x40);
|
|
||||||
|
|
||||||
buffer[6] = amplitude_r;
|
|
||||||
buffer[7] = 0x88;
|
|
||||||
buffer[8] = amplitude_r / 2;
|
|
||||||
buffer[9] = 0x61;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
buffer[6] = 0x00;
|
|
||||||
buffer[7] = 0x01;
|
|
||||||
buffer[8] = 0x40;
|
|
||||||
buffer[9] = 0x40;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!switch_pro.commands_sent)
|
|
||||||
{
|
|
||||||
buffer[0] = CMD_AND_RUMBLE;
|
|
||||||
|
|
||||||
if (!switch_pro.led_set)
|
|
||||||
{
|
|
||||||
report_size = 12;
|
|
||||||
buffer[10] = CMD_LED;
|
|
||||||
buffer[11] = 0x01;
|
|
||||||
switch_pro.led_set = tuh_hid_send_report(switch_pro.dev_addr, switch_pro.instance, 0, &buffer, report_size);
|
|
||||||
return switch_pro.led_set;
|
|
||||||
}
|
|
||||||
else if (!switch_pro.led_home_set)
|
|
||||||
{
|
|
||||||
report_size = 14;
|
|
||||||
buffer[10] = CMD_LED_HOME;
|
|
||||||
buffer[11] = (0 /* Number of cycles */ << 4) | (true ? 0xF : 0);
|
|
||||||
buffer[12] = (0xF /* LED start intensity */ << 4) | 0x0 /* Number of full cycles */;
|
|
||||||
buffer[13] = (0xF /* Mini Cycle 1 LED intensity */ << 4) | 0x0 /* Mini Cycle 2 LED intensity */;
|
|
||||||
switch_pro.led_home_set = tuh_hid_send_report(switch_pro.dev_addr, switch_pro.instance, 0, &buffer, report_size);
|
|
||||||
return switch_pro.led_home_set;
|
|
||||||
}
|
|
||||||
else if (!switch_pro.full_report_enabled)
|
|
||||||
{
|
|
||||||
report_size = 12;
|
|
||||||
buffer[10] = CMD_MODE;
|
|
||||||
buffer[11] = SUBCMD_FULL_REPORT_MODE;
|
|
||||||
switch_pro.full_report_enabled = tuh_hid_send_report(switch_pro.dev_addr, switch_pro.instance, 0, &buffer, report_size);
|
|
||||||
return switch_pro.full_report_enabled;
|
|
||||||
}
|
|
||||||
else if (!switch_pro.imu_enabled)
|
|
||||||
{
|
|
||||||
report_size = 12;
|
|
||||||
buffer[10] = CMD_GYRO;
|
|
||||||
buffer[11] = 1 ? 1 : 0;
|
|
||||||
switch_pro.imu_enabled = tuh_hid_send_report(switch_pro.dev_addr, switch_pro.instance, 0, &buffer, report_size);
|
|
||||||
return switch_pro.imu_enabled;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch_pro.commands_sent = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer[0] = CMD_RUMBLE_ONLY;
|
|
||||||
|
|
||||||
return tuh_hid_send_report(switch_pro.dev_addr, switch_pro.instance, 0, &buffer, report_size);
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#ifndef _SWITCH_PRO_H_
|
|
||||||
#define _SWITCH_PRO_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "usbh/tusb_hid/shared.h"
|
|
||||||
|
|
||||||
const usb_vid_pid_t switch_pro_devices[] =
|
|
||||||
{
|
|
||||||
{0x057E, 0x2009} // Switch Pro
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SwitchProReport
|
|
||||||
{
|
|
||||||
uint8_t reportId;
|
|
||||||
uint8_t timer;
|
|
||||||
|
|
||||||
uint8_t connInfo : 4;
|
|
||||||
uint8_t battery : 4;
|
|
||||||
|
|
||||||
uint8_t y : 1;
|
|
||||||
uint8_t x : 1;
|
|
||||||
uint8_t b : 1;
|
|
||||||
uint8_t a : 1;
|
|
||||||
uint8_t : 2;
|
|
||||||
uint8_t r : 1;
|
|
||||||
uint8_t zr : 1;
|
|
||||||
|
|
||||||
uint8_t minus : 1;
|
|
||||||
uint8_t plus : 1;
|
|
||||||
uint8_t stickR : 1;
|
|
||||||
uint8_t stickL : 1;
|
|
||||||
uint8_t home : 1;
|
|
||||||
uint8_t capture : 1;
|
|
||||||
uint8_t : 0;
|
|
||||||
|
|
||||||
uint8_t down : 1;
|
|
||||||
uint8_t up : 1;
|
|
||||||
uint8_t right : 1;
|
|
||||||
uint8_t left : 1;
|
|
||||||
uint8_t : 2;
|
|
||||||
uint8_t l : 1;
|
|
||||||
uint8_t zl : 1;
|
|
||||||
|
|
||||||
uint16_t leftX : 12;
|
|
||||||
uint16_t leftY : 12;
|
|
||||||
uint16_t rightX : 12;
|
|
||||||
uint16_t rightY : 12;
|
|
||||||
|
|
||||||
uint8_t vibrator;
|
|
||||||
|
|
||||||
uint16_t accelerX;
|
|
||||||
uint16_t accelerY;
|
|
||||||
uint16_t accelerZ;
|
|
||||||
|
|
||||||
uint16_t velocityX;
|
|
||||||
uint16_t velocityY;
|
|
||||||
uint16_t velocityZ;
|
|
||||||
}
|
|
||||||
__attribute__((packed));
|
|
||||||
|
|
||||||
struct SwitchProState
|
|
||||||
{
|
|
||||||
bool handshake_sent {false};
|
|
||||||
bool timeout_disabled {false};
|
|
||||||
bool full_report_enabled {false};
|
|
||||||
bool led_set {false};
|
|
||||||
bool led_home_set {false};
|
|
||||||
bool imu_enabled {false};
|
|
||||||
bool commands_sent {false};
|
|
||||||
uint8_t output_sequence_counter {0};
|
|
||||||
uint8_t dev_addr = {0};
|
|
||||||
uint8_t instance = {0};
|
|
||||||
};
|
|
||||||
|
|
||||||
class SwitchPro
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void init(uint8_t dev_addr, uint8_t instance);
|
|
||||||
void process_report(uint8_t const* report, uint16_t len);
|
|
||||||
bool send_fb_data();
|
|
||||||
|
|
||||||
private:
|
|
||||||
SwitchProState switch_pro;
|
|
||||||
|
|
||||||
bool disable_timeout();
|
|
||||||
void reset_state();
|
|
||||||
uint8_t get_output_sequence_counter();
|
|
||||||
int16_t normalize_axes(uint16_t value);
|
|
||||||
void update_gamepad(const SwitchProReport* switch_pro_data);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // _SWITCH_PRO_H_
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include "pico/stdlib.h"
|
|
||||||
#include "pico/time.h"
|
|
||||||
|
|
||||||
#include "tusb.h"
|
|
||||||
|
|
||||||
#include "utilities/scaling.h"
|
|
||||||
#include "descriptors/SwitchDescriptors.h"
|
|
||||||
#include "usbh/tusb_hid/switch_wired.h"
|
|
||||||
|
|
||||||
#include "Gamepad.h"
|
|
||||||
|
|
||||||
void SwitchWired::init(uint8_t dev_addr, uint8_t instance)
|
|
||||||
{
|
|
||||||
reset_state();
|
|
||||||
switch_wired.dev_addr = dev_addr;
|
|
||||||
switch_wired.instance = instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SwitchWired::reset_state()
|
|
||||||
{
|
|
||||||
switch_wired.dev_addr = 0;
|
|
||||||
switch_wired.instance = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SwitchWired::process_report(uint8_t const* report, uint16_t len)
|
|
||||||
{
|
|
||||||
static SwitchWiredReport prev_report = {0};
|
|
||||||
|
|
||||||
SwitchWiredReport switch_report;
|
|
||||||
memcpy(&switch_report, report, sizeof(switch_report));
|
|
||||||
|
|
||||||
if (memcmp(&switch_report, &prev_report, sizeof(switch_report)) != 0)
|
|
||||||
{
|
|
||||||
update_gamepad(&switch_report);
|
|
||||||
|
|
||||||
prev_report = switch_report;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SwitchWired::update_gamepad(const SwitchWiredReport* switch_report)
|
|
||||||
{
|
|
||||||
gamepad.reset_state();
|
|
||||||
|
|
||||||
switch (switch_report->dpad)
|
|
||||||
{
|
|
||||||
case SWITCH_HAT_UP:
|
|
||||||
gamepad.state.up = true;
|
|
||||||
break;
|
|
||||||
case SWITCH_HAT_UPRIGHT:
|
|
||||||
gamepad.state.up = true;
|
|
||||||
gamepad.state.right = true;
|
|
||||||
break;
|
|
||||||
case SWITCH_HAT_RIGHT:
|
|
||||||
gamepad.state.right = true;
|
|
||||||
break;
|
|
||||||
case SWITCH_HAT_DOWNRIGHT:
|
|
||||||
gamepad.state.right = true;
|
|
||||||
gamepad.state.down = true;
|
|
||||||
break;
|
|
||||||
case SWITCH_HAT_DOWN:
|
|
||||||
gamepad.state.down = true;
|
|
||||||
break;
|
|
||||||
case SWITCH_HAT_DOWNLEFT:
|
|
||||||
gamepad.state.down = true;
|
|
||||||
gamepad.state.left = true;
|
|
||||||
break;
|
|
||||||
case SWITCH_HAT_LEFT:
|
|
||||||
gamepad.state.left = true;
|
|
||||||
break;
|
|
||||||
case SWITCH_HAT_UPLEFT:
|
|
||||||
gamepad.state.up = true;
|
|
||||||
gamepad.state.left = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (switch_report->b) gamepad.state.a = true;
|
|
||||||
if (switch_report->a) gamepad.state.b = true;
|
|
||||||
if (switch_report->y) gamepad.state.x = true;
|
|
||||||
if (switch_report->x) gamepad.state.y = true;
|
|
||||||
|
|
||||||
if (switch_report->minus) gamepad.state.back = true;
|
|
||||||
if (switch_report->plus) gamepad.state.start = true;
|
|
||||||
if (switch_report->l3) gamepad.state.l3 = true;
|
|
||||||
if (switch_report->r3) gamepad.state.r3 = true;
|
|
||||||
|
|
||||||
if(switch_report->home) gamepad.state.sys = true;
|
|
||||||
if(switch_report->capture) gamepad.state.misc = true;
|
|
||||||
|
|
||||||
if(switch_report->l) gamepad.state.lb = true;
|
|
||||||
if(switch_report->r) gamepad.state.rb = true;
|
|
||||||
|
|
||||||
if(switch_report->lz) gamepad.state.lt = 0xFF;
|
|
||||||
if(switch_report->rz) gamepad.state.rt = 0xFF;
|
|
||||||
|
|
||||||
gamepad.state.lx = scale_uint8_to_int16(switch_report->lx, false);
|
|
||||||
gamepad.state.ly = scale_uint8_to_int16(switch_report->ly, true);
|
|
||||||
gamepad.state.rx = scale_uint8_to_int16(switch_report->rx, false);
|
|
||||||
gamepad.state.ry = scale_uint8_to_int16(switch_report->ry, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SwitchWired::send_fb_data()
|
|
||||||
{
|
|
||||||
// mine doesn't have rumble motors, not sure what goes here
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#ifndef _SWITCH_WIRED_H_
|
|
||||||
#define _SWITCH_WIRED_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "usbh/tusb_hid/shared.h"
|
|
||||||
|
|
||||||
const usb_vid_pid_t switch_wired_devices[] =
|
|
||||||
{
|
|
||||||
{0x20D6, 0xA719}, // PowerA wired
|
|
||||||
{0x0F0D, 0x0092} // Hori Pokken wired, I don't have this one so not 100% on if it'll work
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SwitchWiredReport
|
|
||||||
{
|
|
||||||
uint8_t y : 1;
|
|
||||||
uint8_t b : 1;
|
|
||||||
uint8_t a : 1;
|
|
||||||
uint8_t x : 1;
|
|
||||||
|
|
||||||
uint8_t l : 1;
|
|
||||||
uint8_t r : 1;
|
|
||||||
uint8_t lz : 1;
|
|
||||||
uint8_t rz : 1;
|
|
||||||
|
|
||||||
uint8_t minus : 1;
|
|
||||||
uint8_t plus : 1;
|
|
||||||
uint8_t l3 : 1;
|
|
||||||
uint8_t r3 : 1;
|
|
||||||
|
|
||||||
uint8_t home : 1;
|
|
||||||
uint8_t capture : 1;
|
|
||||||
|
|
||||||
uint8_t : 2;
|
|
||||||
|
|
||||||
uint8_t dpad : 4;
|
|
||||||
uint8_t : 4;
|
|
||||||
|
|
||||||
uint8_t lx;
|
|
||||||
uint8_t ly;
|
|
||||||
uint8_t rx;
|
|
||||||
uint8_t ry;
|
|
||||||
}
|
|
||||||
__attribute__((packed));
|
|
||||||
|
|
||||||
struct SwitchWiredState
|
|
||||||
{
|
|
||||||
uint8_t dev_addr = {0};
|
|
||||||
uint8_t instance = {0};
|
|
||||||
};
|
|
||||||
|
|
||||||
class SwitchWired
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void init(uint8_t dev_addr, uint8_t instance);
|
|
||||||
void process_report(uint8_t const* report, uint16_t len);
|
|
||||||
bool send_fb_data();
|
|
||||||
|
|
||||||
private:
|
|
||||||
SwitchWiredState switch_wired;
|
|
||||||
|
|
||||||
void reset_state();
|
|
||||||
void update_gamepad(const SwitchWiredReport* switch_pro_data);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // _SWITCH_WIRED_H_
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user