Skip to content

Commit

Permalink
Merge branch 'main' into CI_Update
Browse files Browse the repository at this point in the history
  • Loading branch information
arntsonl authored Oct 9, 2024
2 parents 2d16215 + a23b7df commit 6e1f132
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 79 deletions.
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ endif()
cmake_minimum_required(VERSION 3.13)
include(CMakePrintHelpers)

# enable compile commands for use by IDE autocompletion
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)


# initialize the SDK based on PICO_SDK_PATH
# note: this must happen before project()
include(pico_sdk_import.cmake)
Expand Down
21 changes: 11 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Full documentation can be found at [https://gp2040-ce.info](https://gp2040-ce.in
## Features

- Select from 13 input modes including X-Input, Nintendo Switch, Playstation 4/5, Xbox One, D-Input, and Keyboard
- Input latency average of 0.76ms in Xinput and 0.91ms for Playstation 5.
- Input latency average of 0.76ms in Xinput and 0.90ms for Playstation 5.
- Multiple SOCD cleaning modes - Up Priority (a.k.a. Stickless), Neutral, and Second Input Priority.
- Left and Right stick emulation via D-pad inputs as well as dedicated toggle switches.
- Dual direction via D-pad + LS/RS.
Expand All @@ -53,17 +53,18 @@ Visit the [GP2040-CE Usage](https://gp2040-ce.info/usage) page for more details.

Input latency is tested using the methodology outlined at [WydD's inputlag.science website](https://inputlag.science/controller/methodology), using the default 1000 Hz (1 ms) polling rate in the firmware. You can read more about the setup we use to conduct latency testing [HERE](https://github.com/OpenStickCommunity/Site/blob/main/latency_testing/README.md) if you are interested in testing for yourself or would just like to know more about the devices used to do the testing.

| Version | Mode | Poll Rate | Min | Max | Avg | Stdev | % on time | %1f skip | %2f skip |
| ------- | ------------ | --------- | ------- | ------- | ------- | ------- | --------- | -------- | -------- |
| v0.7.9 | Xinput | 1 ms | 0.45 ms | 1.28 ms | 0.76 ms | 0.24 ms | 98.48% | 1.52% | 0% |
| v0.7.9 | Switch | 1 ms | 0.41 ms | 1.23 ms | 0.72 ms | 0.24 ms | 98.53% | 1.47% | 0% |
| v0.7.9 | Dinput (PS3) | 1 ms | 0.44 ms | 1.27 ms | 0.75 ms | 0.24 ms | 98.49% | 1.51% | 0% |
| v0.7.9 | PS4 | 1 ms | 0.55 ms | 2.26 ms | 0.90 ms | 0.32 ms | 98.21% | 1.79% | 0% |
| v0.7.9 | PS5 | 1 ms | 0.55 ms | 2.33 ms | 0.91 ms | 0.33 ms | 98.18% | 1.82% | 0% |
| Version | Mode | Poll Rate | Min | Max | Avg | Stdev | % on time | %1f skip | %2f skip |
| ------- | ------- | --------- | ------- | ------- | ------- | ------- | --------- | -------- | -------- |
| v0.7.10 | Xinput | 1 ms | 0.45 ms | 1.28 ms | 0.76 ms | 0.24 ms | 98.48% | 1.52% | 0% |
| v0.7.10 | Switch | 1 ms | 0.41 ms | 1.22 ms | 0.73 ms | 0.24 ms | 98.52% | 1.48% | 0% |
| v0.7.10 | HID USB | 1 ms | 0.42 ms | 1.24 ms | 0.73 ms | 0.24 ms | 98.53% | 1.47% | 0% |
| v0.7.10 | PS3 | 1 ms | 0.52 ms | 1.33 ms | 0.82 ms | 0.24 ms | 98.38% | 1.62% | 0% |
| v0.7.10 | PS4 | 1 ms | 0.55 ms | 2.38 ms | 0.91 ms | 0.31 ms | 98.19% | 1.81% | 0% |
| v0.7.10 | PS5 | 1 ms | 0.55 ms | 2.38 ms | 0.90 ms | 0.31 ms | 98.20% | 1.80% | 0% |

Full results can be found in the [GP2040-CE v0.7.9 Firmware Latency Test Results](https://github.com/OpenStickCommunity/Site/raw/main/latency_testing/GP2040-CE_Firmware_Latency_Test_Results_v0.7.9.xlsx) .xlsx Sheet.
Full results can be found in the [GP2040-CE v0.7.10 Firmware Latency Test Results](https://github.com/OpenStickCommunity/Site/raw/main/latency_testing/GP2040-CE_Firmware_Latency_Test_Results_v0.7.10.xlsx) .xlsx Sheet.

Results from v0.7.8 can be found [HERE](https://github.com/OpenStickCommunity/Site/raw/main/latency_testing/GP2040-CE_Firmware_Latency_Test_Results_v0.7.8.xlsx). Previous results can be found in the `latency_testing` folder.
Results from v0.7.9 can be found [HERE](https://github.com/OpenStickCommunity/Site/raw/main/latency_testing/GP2040-CE_Firmware_Latency_Test_Results_v0.7.9.xlsx). Previous results can be found in the `latency_testing` folder.

## Support

Expand Down
32 changes: 23 additions & 9 deletions configs/RP2040AdvancedBreakoutBoardUSBPassthrough/BoardConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,21 @@
#define KEY_BUTTON_A2 HID_KEY_F2 // A2 | ~ | Capture | ~ | 14 | ~ |
#define KEY_BUTTON_FN -1 // Hotkey Function |

#define BOARD_LEDS_PIN 4
#define USB_PERIPHERAL_ENABLED 1

#define USB_PERIPHERAL_PIN_DPLUS 23
#define USB_PERIPHERAL_PIN_ORDER 0

#define LED_BRIGHTNESS_MAXIMUM 50
#define DEFAULT_INPUT_MODE_R1 INPUT_MODE_XBONE
#define DEFAULT_INPUT_MODE_B4 INPUT_MODE_PS5
#define DEFAULT_PS5AUTHENTICATION_TYPE INPUT_MODE_AUTH_TYPE_USB

#define BOARD_LEDS_PIN 4
#define LED_BRIGHTNESS_MAXIMUM 100
#define LED_BRIGHTNESS_STEPS 5
#define LED_FORMAT LED_FORMAT_GRB
#define LEDS_PER_PIXEL 1
#define LEDS_BASE_ANIMATION_INDEX 1
#define LEDS_DPAD_LEFT 0
#define LEDS_DPAD_DOWN 1
#define LEDS_DPAD_RIGHT 2
Expand All @@ -78,18 +89,21 @@
#define LEDS_BUTTON_B2 9
#define LEDS_BUTTON_R2 10
#define LEDS_BUTTON_L2 11
#define LEDS_BUTTON_A1 12
#define LEDS_BUTTON_L3 13
#define LEDS_BUTTON_R3 14
#define LEDS_BUTTON_A2 15

#define HAS_I2C_DISPLAY 1
#define I2C0_ENABLED 1
#define I2C0_PIN_SDA 0
#define I2C0_PIN_SCL 1
#define DISPLAY_I2C_BLOCK i2c0

#define USB_PERIPHERAL_ENABLED 1
#define USB_PERIPHERAL_PIN_DPLUS 23
#define BUTTON_LAYOUT BUTTON_LAYOUT_STICKLESS
#define BUTTON_LAYOUT_RIGHT BUTTON_LAYOUT_STICKLESSB
#define SPLASH_MODE SPLASH_MODE_STATIC
#define SPLASH_DURATION 3000

#define DEFAULT_INPUT_MODE_R1 INPUT_MODE_XBONE
#define DEFAULT_INPUT_MODE_B4 INPUT_MODE_PS5
#define DEFAULT_PS5AUTHENTICATION_TYPE INPUT_MODE_AUTH_TYPE_USB
// Keyboard Host enabled by default
#define KEYBOARD_HOST_ENABLED 1

#endif
19 changes: 7 additions & 12 deletions headers/addons/keyboard_host_listener.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,10 @@ class KeyboardHostListener : public USBListener {
virtual void get_report_complete(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, uint16_t len) {}
void process();
private:
GamepadState _keyboard_host_state;
bool _keyboard_host_enabled;
uint8_t getKeycodeFromModifier(uint8_t modifier);
void preprocess_report();
void process_kbd_report(uint8_t dev_addr, hid_keyboard_report_t const *report);
void process_mouse_report(uint8_t dev_addr, hid_mouse_report_t const *report);

KeyboardButtonMapping _keyboard_host_mapDpadUp;
KeyboardButtonMapping _keyboard_host_mapDpadDown;
KeyboardButtonMapping _keyboard_host_mapDpadLeft;
Expand All @@ -62,22 +59,20 @@ class KeyboardHostListener : public USBListener {
KeyboardButtonMapping _keyboard_host_mapButtonA2;
KeyboardButtonMapping _keyboard_host_mapButtonA3;
KeyboardButtonMapping _keyboard_host_mapButtonA4;

GamepadState _keyboard_host_state;
bool _keyboard_host_mounted;
uint8_t _keyboard_dev_addr;
uint8_t _keyboard_instance;

bool _mouse_host_enabled;
bool _mouse_host_mounted;
uint8_t _mouse_dev_addr;
uint8_t _mouse_instance;

uint16_t mouseLeftMapping;
uint16_t mouseMiddleMapping;
uint16_t mouseRightMapping;

int16_t mouseX = 0;
int16_t mouseY = 0;
int16_t mouseZ = 0;
bool mouseActive = false;
int16_t mouseX;
int16_t mouseY;
int16_t mouseZ;
bool mouseActive;
};

#endif // _KeyboardHost_H_
4 changes: 2 additions & 2 deletions proto/config.proto
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ message SliderOptions
optional int32 deprecatedPinSliderTwo = 3 [deprecated = true];
optional DpadMode deprecatedModeOne = 4 [deprecated = true];
optional DpadMode deprecatedModeTwo = 5 [deprecated = true];
optional DpadMode deprecatedModeDefault = 6;
optional DpadMode deprecatedModeDefault = 6 [deprecated = true];
}

message SOCDSliderOptions
Expand Down Expand Up @@ -794,7 +794,7 @@ message AddonOptions
optional OnBoardLedOptions onBoardLedOptions = 2;
optional AnalogOptions analogOptions = 3;
optional TurboOptions turboOptions = 4;
optional SliderOptions deprecatedSliderOptions = 5;
optional SliderOptions deprecatedSliderOptions = 5 [deprecated = true];
optional ReverseOptions reverseOptions = 6;
optional AnalogADS1219Options analogADS1219Options = 7;
optional DualDirectionalOptions dualDirectionalOptions = 8;
Expand Down
10 changes: 8 additions & 2 deletions src/addons/analog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ void AnalogInput::setup() {

void AnalogInput::process() {
Gamepad * gamepad = Storage::getInstance().GetGamepad();

uint16_t joystickMid = GAMEPAD_JOYSTICK_MID;
if ( DriverManager::getInstance().getDriver() != nullptr ) {
joystickMid = DriverManager::getInstance().getDriver()->GetJoystickMidValue();
}

for(int i = 0; i < ADC_COUNT; i++) {
// Read X-Axis
if (isValidPin(adc_pairs[i].x_pin)) {
Expand Down Expand Up @@ -109,15 +115,15 @@ void AnalogInput::process() {
}

if (adc_pairs[i].analog_dpad == DpadMode::DPAD_MODE_LEFT_ANALOG) {
if ( DriverManager::getInstance().getDriver()->GetJoystickMidValue() == 0x8000 ) {
if ( joystickMid == 0x8000 ) {
gamepad->state.lx = static_cast<uint16_t>(std::ceil(65535.0f * adc_pairs[i].x_value));
gamepad->state.ly = static_cast<uint16_t>(std::ceil(65535.0f * adc_pairs[i].y_value));
} else { // 0x7FFF
gamepad->state.lx = static_cast<uint16_t>(65535.0f * adc_pairs[i].x_value);
gamepad->state.ly = static_cast<uint16_t>(65535.0f * adc_pairs[i].y_value);
}
} else if (adc_pairs[i].analog_dpad == DpadMode::DPAD_MODE_RIGHT_ANALOG) {
if ( DriverManager::getInstance().getDriver()->GetJoystickMidValue() == 0x8000 ) {
if ( joystickMid == 0x8000 ) {
gamepad->state.rx = static_cast<uint16_t>(std::ceil(65535.0f * adc_pairs[i].x_value));
gamepad->state.ry = static_cast<uint16_t>(std::ceil(65535.0f * adc_pairs[i].y_value));
} else { // 0x7FFF
Expand Down
80 changes: 40 additions & 40 deletions src/addons/keyboard_host_listener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include "storagemanager.h"
#include "class/hid/hid_host.h"

#define DEV_ADDR_NONE 0xFF

void KeyboardHostListener::setup() {
const KeyboardHostOptions& keyboardHostOptions = Storage::getInstance().getAddonOptions().keyboardHostOptions;
const KeyboardMapping& keyboardMapping = keyboardHostOptions.mapping;
Expand Down Expand Up @@ -50,22 +52,23 @@ void KeyboardHostListener::setup() {
mouseMiddleMapping = keyboardHostOptions.mouseMiddle;
mouseRightMapping = keyboardHostOptions.mouseRight;

_keyboard_host_enabled = false;
_keyboard_dev_addr = 0;
_keyboard_host_mounted = false;
_keyboard_dev_addr = DEV_ADDR_NONE;
_keyboard_instance = 0;

_mouse_host_enabled = false;
_mouse_dev_addr = 0;
_mouse_host_mounted = false;
_mouse_dev_addr = DEV_ADDR_NONE;
_mouse_instance = 0;

mouseX = 0;
mouseY = 0;
mouseZ = 0;
mouseActive = false;
}

void KeyboardHostListener::process() {
Gamepad *gamepad = Storage::getInstance().GetGamepad();
if (_keyboard_host_enabled || _mouse_host_enabled) {
if (_keyboard_host_mounted == true || _mouse_host_mounted == true) {
gamepad->state.dpad |= _keyboard_host_state.dpad;
gamepad->state.buttons |= _keyboard_host_state.buttons;
gamepad->state.lx |= _keyboard_host_state.lx;
Expand All @@ -78,66 +81,60 @@ void KeyboardHostListener::process() {
}
}

gamepad->auxState.sensors.mouse.enabled = _mouse_host_enabled;
gamepad->auxState.sensors.mouse.active = mouseActive;
if (_mouse_host_enabled && mouseActive) {
gamepad->auxState.sensors.mouse.x = mouseX;
gamepad->auxState.sensors.mouse.y = mouseY;
gamepad->auxState.sensors.mouse.z = mouseZ;
if ( _mouse_host_mounted == true ) {
gamepad->auxState.sensors.mouse.active = mouseActive;
if ( mouseActive == true ) {
gamepad->auxState.sensors.mouse.active = true;
gamepad->auxState.sensors.mouse.x = mouseX;
gamepad->auxState.sensors.mouse.y = mouseY;
gamepad->auxState.sensors.mouse.z = mouseZ;
mouseActive = false;
}
}
mouseActive = false;
}

void KeyboardHostListener::mount(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) {
// Interface protocol (hid_interface_protocol_enum_t)
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);

// tuh_hid_report_received_cb() will be invoked when report is available
if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) {
if (_keyboard_host_mounted == false && itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) {
_keyboard_host_mounted = true;
_keyboard_dev_addr = dev_addr;
_keyboard_instance = instance;
_keyboard_host_enabled = true;
} else if (itf_protocol == HID_ITF_PROTOCOL_MOUSE) {
} else if (_mouse_host_mounted == false && itf_protocol == HID_ITF_PROTOCOL_MOUSE) {
Gamepad *gamepad = Storage::getInstance().GetGamepad();
gamepad->auxState.sensors.mouse.enabled = true;
_mouse_host_mounted = true;
_mouse_dev_addr = dev_addr;
_mouse_instance = instance;
_mouse_host_enabled = true;
} else {
return;
}
}

void KeyboardHostListener::unmount(uint8_t dev_addr) {
if ( _keyboard_dev_addr == dev_addr ) {
_keyboard_host_enabled = false;
_keyboard_dev_addr = 0;
if ( _keyboard_host_mounted == true && _keyboard_dev_addr == dev_addr ) {
_keyboard_host_mounted = false;
_keyboard_dev_addr = DEV_ADDR_NONE;
_keyboard_instance = 0;
} else if ( _mouse_dev_addr == dev_addr ) {
_mouse_host_enabled = false;
_mouse_dev_addr = 0;
} else if ( _mouse_host_mounted == true && _mouse_dev_addr == dev_addr ) {
Gamepad *gamepad = Storage::getInstance().GetGamepad();
gamepad->auxState.sensors.mouse.enabled = false;
_mouse_host_mounted = false;
_mouse_dev_addr = DEV_ADDR_NONE;
_mouse_instance = 0;
}
}

void KeyboardHostListener::report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len){
if (
( _keyboard_host_enabled == false || _keyboard_dev_addr != dev_addr || _keyboard_instance != instance )
&&
( _mouse_host_enabled == false || _mouse_dev_addr != dev_addr || _mouse_instance != instance )
)
return; // do nothing if we haven't mounted

// Interface protocol (hid_interface_protocol_enum_t)
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);

preprocess_report();
// do nothing if we haven't mounted
if ( _keyboard_host_mounted == false && _mouse_host_mounted == false )
return;

// tuh_hid_report_received_cb() will be invoked when report is available
if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) {
if ( _keyboard_host_mounted == true && _keyboard_dev_addr == dev_addr && _keyboard_instance == instance ) {
process_kbd_report(dev_addr, (hid_keyboard_report_t const*) report );
} else if (itf_protocol == HID_ITF_PROTOCOL_MOUSE) {
} else if ( _mouse_host_mounted == true && _mouse_dev_addr == dev_addr && _mouse_instance == instance) {
process_mouse_report(dev_addr, (hid_mouse_report_t const*) report );
} else {
return;
}
}

Expand Down Expand Up @@ -171,12 +168,13 @@ void KeyboardHostListener::preprocess_report()
_keyboard_host_state.ry = joystickMid;
_keyboard_host_state.lt = 0;
_keyboard_host_state.rt = 0;

}

// convert hid keycode to ascii and print via usb device CDC (ignore non-printable)
void KeyboardHostListener::process_kbd_report(uint8_t dev_addr, hid_keyboard_report_t const *report)
{
preprocess_report();

// make this 13 instead of 7 to include modifier bitfields from hid_keyboard_modifier_bm_t
for(uint8_t i=0; i<13; i++)
{
Expand Down Expand Up @@ -223,6 +221,8 @@ void KeyboardHostListener::process_kbd_report(uint8_t dev_addr, hid_keyboard_rep

void KeyboardHostListener::process_mouse_report(uint8_t dev_addr, hid_mouse_report_t const * report)
{
preprocess_report();

//------------- button state -------------//
_keyboard_host_state.buttons |=
(report->buttons & MOUSE_BUTTON_LEFT ? mouseLeftMapping : _keyboard_host_state.buttons)
Expand Down
4 changes: 2 additions & 2 deletions src/drivers/ps4/PS4Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,13 +245,13 @@ void PS4Driver::process(Gamepad * gamepad) {
} else if (pointOneTouched && touchpadData.p1.unpressed) {
pointOneTouched = false;
}
if (!pointTwoTouched && touchpadData.p2.unpressed) {
if (!pointTwoTouched && !touchpadData.p2.unpressed) {
touchCounter = (touchCounter < PS4_TP_MAX_COUNT ? touchCounter+1 : 0);

touchpadData.p2.counter = touchCounter;

pointTwoTouched = true;
} else if (pointTwoTouched && touchpadData.p1.unpressed) {
} else if (pointTwoTouched && touchpadData.p2.unpressed) {
pointTwoTouched = false;
}
ps4Report.touchpad_data = touchpadData;
Expand Down
1 change: 1 addition & 0 deletions www/src/Locales/zh-CN/HomePage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
'header-text': '欢迎来到 GP2040-CE 网页配置器',
'latest-text': '最新:{{version}}',
'memory-flash-text': '闪存',
'memory-board-text': '板载闪存',
'memory-header-text': '内存 (KB)',
'memory-heap-text': '堆',
'memory-static-allocations-text': '静态分配',
Expand Down
4 changes: 2 additions & 2 deletions www/src/Locales/zh-CN/SettingsPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export default {
'xbone-mode-text':
'<span>补充信息:</span>Xbox One 模式需要 USB 主机(USB Host)连接和 USB 加密狗才能正确认证。',
'xinput-mode-text':
'<span>补充信息:</span> Xbox 360 模式可以在没有身份验证或连接USB加密狗的情况下工作。',
'<span>补充信息:</span>Xinput 可以在没有认证的情况下在PC上运行。如果您想在 Xbox 360 上使用它,请选择USB验证并连接合适的加密狗。',
'hotkey-settings-label': '快捷键设置',
'hotkey-settings-sub-header':
'<strong>Fn</strong> 组合映射在<link_pinmap>引脚映射</link_pinmap>页面提供了一个可映射的Function按键。 要选择 <strong>Fn</strong> 组合映射选项,请同时按住 Function 按键和其他快捷键。<br />此外, 可从下拉列表中选择 <strong>None</strong> 以取消分配按钮',
Expand Down Expand Up @@ -138,7 +138,7 @@ export default {
},
'forced-setup-mode-modal-title': '强制设置模式警告',
'forced-setup-mode-modal-body':
'如果保存后重新启动到控制器模式,您将无法再访问网页配置。 如果你完全理解并打算解锁保存按钮,请在下方键入 "<strong>{{warningCheckText}}</strong>" 。 单击取消将还原此设置并保存。',
'如果您在保存后重新启动到控制器模式,您将无法再访问网页配置。如果您完全理解并同意这一点,请在下方键入 "<strong>{{warningCheckText}}</strong>" 以解锁保存按钮。 点击“取消”将恢复此设置并保存。',
'4-way-joystick-mode-label': '4向摇杆模式',
'lock-hotkeys-label': '锁定快捷键',
'keyboard-mapping-header-text': '键盘映射',
Expand Down

0 comments on commit 6e1f132

Please sign in to comment.