We are currently migrating Bugzilla to GitHub issues.
Any changes made to the bug tracker now will be lost, so please do not post new bugs or make changes to them.
When we're done, all bug URLs will redirect to their equivalent location on the new bug tracker.

Bug 5033 - Wired Switch Pro controller inconsistently rumbles in SDL 2.0.12
Summary: Wired Switch Pro controller inconsistently rumbles in SDL 2.0.12
Status: NEW
Alias: None
Product: SDL
Classification: Unclassified
Component: haptic (show other bugs)
Version: 2.0.12
Hardware: All All
: P2 major
Assignee: Ryan C. Gordon
QA Contact: Sam Lantinga
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-03-15 18:02 UTC by RustyM
Modified: 2020-06-15 21:34 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description RustyM 2020-03-15 18:02:25 UTC
In the latest release version of SDL 2.0.12 the Switch Pro controller rumbles inconsistently. Despite a fixed rumble strength and duration used, the rumbles will sometimes go much longer and sometimes rumble surprisingly strong.

I’m seeing this issue on macOS 10.12.6 and Windows 10.
It happens with the 2.0.12 release and the latest tip (changeset 13625).

I can see this issue in my own code and with testgamecontroller. To make it happen with testgamecontroller, attach a Switch Pro controller and press the left or right triggers a few times. The first few rumbles will be short, but soon after the rumble will continue even after the trigger is released.

The stronger rumble I see more often in my own code. I've also seen it happen inside testgamecontroller, but I'm not sure how to do it consistently yet. I suspect the "strong rumble" is some queueing that's being fired all at once as it catches up.

My own code is rumbling both the left and right haptic devices at the same time, instead of independently:

Uint16 low_frequency_rumble = 65535;
Uint16 high_frequency_rumble = 65535;
Uint32 duration_ms = 250;
SDL_GameControllerRumble(gameController, low_frequency_rumble, high_frequency_rumble, duration_ms);
Comment 1 RustyM 2020-06-15 21:34:24 UTC
I’ve been working on this more lately since this bug is preventing me from moving to 2.0.12

Just discovered this issue ONLY happens when a Switch Pro controller is wired. Over Bluetooth I haven’t seen it happen on Windows or Mac. With that in mind, I started looking into “changeset 13765”:

    Don't send rumble packets too quickly to Nintendo Switch Pro controllers over Bluetooth
    https://hg.libsdl.org/SDL/rev/0b12c0e43e6c 

This change happened 4 weeks after I found this bug, so it’s not the cause. Moreover, I think it provides a clue to a partial solution:

    /* How often you have to refresh a long duration rumble to keep the motors running */
    #define RUMBLE_REFRESH_FREQUENCY_MS 40

I’m guessing this rumble refresh timer was figured out over Bluetooth. So I split this into two defines:

    /* How often you have to refresh a long duration rumble to keep the motors running */
    #define RUMBLE_REFRESH_FREQUENCY_MS_BLUETOOTH 40

    /* Wired controllers require a longer refresh duration or they'll sometimes continue to rumble beyond the stop call */
    #define RUMBLE_REFRESH_FREQUENCY_MS_WIRED 1000

Through experimentation I found the 1000 ms wired refresh rate. 1050 ms wasn’t enough to keep a long rumble going over a Wired connection. Then later on in the code I added a check for m_bUsingBluetooth:

    SDL_TICKS_PASSED(SDL_GetTicks(), ctx->m_unRumbleSent + (ctx->m_bUsingBluetooth ? RUMBLE_REFRESH_FREQUENCY_MS_BLUETOOTH : RUMBLE_REFRESH_FREQUENCY_MS_WIRED))) {

These two changes to "SDK_hidapi_switch.c" fix the inconsistent rumble in many cases. I haven’t been able to replicate the issue in “testgamecontroller” anymore. Unfortunately it still happens in my own code, though far less frequently.

I can’t yet get it to happen consistently, but I think it has something to do with complex uses of SDL_GameControllerRumble(). Perhaps when I tell a long rumble to stop, and then soon after start a new rumble, the wires get crossed somewhere? Like it queues up a call to stop a rumble or refresh a rumble and it gets confused or some buffer doesn’t get cleared? The results of the bug is what I listed in my original post: Sometimes a rumble told to “stop”, doesn’t actually stop and continues longer than it should. And then sometimes just after this a surprisingly strong rumble happens.