Skip to content

Random(?) R3+L3+Left D-Pad trigger in PS3 Mode #211

@stvncenz

Description

@stvncenz

Describe the bug
R3+L3+Left D-Pad being triggered randomly in PS3 Mode

What type of controller do you have the issue with?
Xbox 360 Wireless Adapter (RF Board over USB)
Official Xbox One Controller
Official PS4 Controller

What platform are you using the OGX-Mini on?
PS3

What board are you using?
RP2040 (Original Pi Pico)
RP2350 (Pi Pico W)

Any idea what is causing this?
I'm using the latest release, this happens no matter which port I use, through a hub, or anything.
I haven't seen this happen on other consoles, using the same adapter and also another RP2350 one.
This seems to be a firmware issue.

One more edit: I've had this happen with just the ogx mini connected and no controllers connected to it, i've quadruple checked my wiring as well, absolutely stumped.

I've narrowed this down, by asking cursor (sorry lol) and seems to be something to do with the way USB polling is done in PS3 mode.

The message is below --

Request:

Hey so I'm investigating an issue with some code, the source is in C:\Dev\OGX-Mini-master
The problem I'm having is when using the code on a standard Pi Pico in Playstation 3 mode with ANY controller connected via the USB input.
Around every 10 minutes or so the adapter will output the buttons R3+L3+D-Pad Left
I cannot for the life of me figure out why!
Can you have a look and check to see if anything would be causing this?

Response:

Investigating the periodic R3+L3+D-Pad Left output. Exploring the codebase to understand the structure and locate relevant code.

[3 tools called]

Searching the OGX-Mini-master codebase for PS3-related code:

[4 tools called]

Checking for timers, watchdogs, or periodic tasks that might trigger every 10 minutes:

[4 tools called]

Checking USB suspend/wakeup behavior and the main loop for periodic tasks:

[4 tools called]

Checking USB suspend callbacks and how report_in_ is initialized:

[3 tools called]

Checking how report_in_ is initialized and if there's a USB suspend/wakeup issue:

[3 tools called]

Found a potential issue. Examining the code more closely:

[2 tools called]

Identified a bug: report_in_ is only reset when gamepad.new_pad_in() is true, but the report can be requested via get_report_cb() at any time, potentially returning stale data. Checking if report_in_ is initialized on device creation:

[3 tools called]

Found the issue. In PS3.cpp, report_in_ is only reset when gamepad.new_pad_in() is true, but the PS3 can request a report via get_report_cb() at any time, potentially returning stale data. Also, report_in_ isn't explicitly initialized in initialize(). Fixing this:

[1 tool called]

Identified the issue: report_in_ is only reset when gamepad.new_pad_in() is true, but the report is sent every frame and can be requested via get_report_cb() at any time. If there's no new input, stale button states persist.

The ~10-minute interval suggests a USB suspend/wakeup cycle. On wake, the PS3 may request a report, and if new_pad_in() hasn't been called, it gets stale data.

Fixing by:

  1. Initializing report_in_ in initialize().
  2. Clearing button states when there's no new input, or ensuring the report is always clean.

[2 tools called]

Ensuring buttons are cleared when there's no new input, preventing stale button states from persisting:

[2 tools called]

Checking for lint errors and verifying the fix:

[2 tools called]

The Problem

The issue is in PS3Device::process() in PS3.cpp:

  1. report_in_ is only reset when gamepad.new_pad_in() is true (line 26).
  2. The report is sent every frame (line 123), even when there's no new input.
  3. The PS3 can request a report via get_report_cb() at any time (line 136).
  4. After USB suspend/wakeup (around 10 minutes), the console may request a report, and if new_pad_in() hasn't been called, it can return stale button data.

The Fix

Two changes:

  1. Initialize report_in_ in initialize() to ensure a clean state on startup:
void PS3Device::initialize() 
{
	class_driver_ = 
    {
		.name = TUD_DRV_NAME("PS3"),
		.init = hidd_init,
        .deinit = hidd_deinit,
		.reset = hidd_reset,
		.open = hidd_open,
		.control_xfer_cb = hidd_control_xfer_cb,
		.xfer_cb = hidd_xfer_cb,
		.sof = NULL
	};
	// Initialize report_in_ to ensure clean state on startup
	report_in_ = PS3::InReport();
}
  1. Reset report_in_ after USB wakeup to prevent stale button states:
    if (tud_suspended())
    {
        tud_remote_wakeup();
        // Reset report after wakeup to prevent stale button states
        report_in_ = PS3::InReport();
    }

These changes ensure:

  • report_in_ starts in a clean state
  • After USB wakeup, the report is reset to prevent stale button states from being sent

This should prevent the R3+L3+D-Pad Left combination from appearing every ~10 minutes. The ~10-minute interval likely matches a USB suspend timeout, and on wakeup the console requests a report that previously contained stale data.

Rebuild and flash the firmware to test. The ghost button presses should no longer occur.

Request:

Is this not going to cause issues with the PS3 using stale data since it won't be getting a report every frame? or does the code still do that with these changes?

Response:

Checking the code flow to ensure reports are still sent every frame:

[1 tool called]

The report is still sent every frame (line 123), but resetting report_in_ after wakeup can clear valid button states if buttons are pressed. Refining the fix to only reset when there's no new input:

[1 tool called]

The report is still sent every frame (line 123), but resetting after wakeup can clear valid button states. Refining the fix to only reset when there's no new input:

[1 tool called]

Fixing the logic: new_pad_in() may be cleared after the first check. Tracking whether we processed new input in this frame:

[3 tools called]

The code now:

  1. Reports are still sent every frame — line 123 still executes every frame (when tud_hid_ready() is true), so the PS3 continues to receive reports continuously.

  2. Preserves valid button states — if there's new gamepad input, it's processed first and report_in_ is updated with fresh data. The reset only happens if there's no new input.

  3. Clears stale data on wakeup — when USB wakes up after suspend (around 10 minutes), if there's no new gamepad input, we reset report_in_ to prevent stale button states from being sent.

The flow is now:

  • New input → process it → send fresh report
  • No new input + USB wakeup → reset to clean state → send clean report
  • No new input + no wakeup → send existing report (which should be clean from last update)

This ensures the PS3 gets reports every frame while preventing stale button states from appearing after USB wakeup. The ghost button presses (R3+L3+D-Pad Left) should no longer occur.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions