Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix DualShock3 rumble intensity by removing overflow and adjusting motor set… #163

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

GorillaDaddy
Copy link

@GorillaDaddy GorillaDaddy commented Dec 23, 2024

I got a ps3 controller today, and was disappointed that the

DualShock 3 rumble didn't work.

In the Bloopair code for emulating a Wii U Pro Controller using a PS3 (DualShock 3) controller, the function responsible for sending rumble (vibration) data to the DS3 has a line:

rep.left_motor_force = ds_data->rumble * 64;

and similarly:

rep.right_motor_force = ds_data->rumble;
where ds_data->rumble is presumably an 8-bit value (0–255). Here’s the problem:

Because the big motor value is multiplied by 64 and stored in an 8-bit field, it constantly overflows, often ending up as zero or a small fraction of the intended force. Meanwhile, the small motor is being driven incorrectly as a full 0–255 range instead of a simple on/off. The result is that the controller hardly rumbles, or rumbles inconsistently.

Left Motor Overflow

The left motor field (left_motor_force) is also just an 8-bit value (0–255).
If ds_data->rumble is larger than 3 or 4, multiplying by 64 immediately overflows in 8 bits.
For example, if ds_data->rumble is 4, 4×64=256 which is 0x100, but in an 8-bit field that becomes 0x00.

If ds_data->rumble is 5, 5×64=320, which modulo 256 becomes 64—an unexpected, relatively weak vibration level.

As a result, the large motor (which is the more powerful motor in the DualShock 3) never gets its intended full range of rumble.

Most values are converted to either 0 or small values, causing the “weak” rumble effect.

Small Motor Misuse

The right motor in a DualShock 3 (the “small” motor) effectively supports on/off states rather than a full 0–255 range. Yet the code assigns it the direct ds_data->rumble value. If ds_data->rumble is large, you’re effectively trying to pass a high value to a motor that only wants 0 or 1.
This doesn’t necessarily break things, but it’s not how Sony’s official HID docs typically implement DS3 rumble. The small motor should be 0 or 1, plus a duration—while the big motor uses a 0–255 force value.

Duration

Both motors also have a duration field. In the snippet it’s set to 1, which is extremely short. Typically you’d set that to something like 0xFF for indefinite rumble. Otherwise, the DS3 might shut off the motor after the short duration expires.

Fixes #73

@GorillaDaddy GorillaDaddy changed the title Fix DualShock3 rumble intensity by removing overflow and adjusting motor set… Fix DualShock3 rumble intensity by removing overflow and adjusting motor set… Fixes #17 Dec 23, 2024
@GorillaDaddy GorillaDaddy changed the title Fix DualShock3 rumble intensity by removing overflow and adjusting motor set… Fixes #17 Fix DualShock3 rumble intensity by removing overflow and adjusting motor set… Dec 23, 2024
@GaryOderNichts
Copy link
Owner

The Wii U Pro Controller only supports turning the rumble motor on and off. Wii U games try to work around this by repeatedly turning the motor on and off with a specific frequency.
Hence ds_data->rumble is a boolean value and is either 1 or 0. Multiplying this value by 64 is done to increase the intensity for the big motor, as otherwise the rumble is barely noticeable. This value will never overflow as it will be either 0 or 64 in the end.

The duration is set to 1, since most games will output several rumble packets per second anyways. I remember experimenting with setting this value to 0xFF, which sometimes caused the rumble motor to be on continuously even after it was supposed to stop.

@GorillaDaddy
Copy link
Author

30_bloopair.zip

I'm attaching a newer 30_bloopair.rpx so you can try it with your dualshock 3. Rumble now works where it didn't before.

I think a duration of 1 on the Dualshock3 is only like 20ms. As you said, the WiiU expects rumble to be either on or off. Hence, 0xff duration which just turns the rumble on without a timeout on the Dualshock3. Yes, it should rumble continuously, until the WiiU tells it to stop rumbling. Just as the WiiU intends. I played a couple of games yesterday, and didn't have the problem of the rumble motor being on continuously. If this later becomes a problem, it's an easy fix. Think of the DualShock3 duration as a watchdog timeout for rumble.

I think the WiiU's ds_data->rumble isn't always 0 or 1. If it is any value > 3, the multiplying by 64 overflow will get weird.

I assumed that WiiU rumble is 0 to 255, some sort of linear increase in physical rumble power, corresponding to the DualShock3's. Just passing the WiiU 8-bit value to the Dualshock3 seems to work correctly.

p.s. The rpx I sent also fixes the triggers, but that's another issue I've yet to commit.

@GaryOderNichts
Copy link
Owner

Rumble currently works for me, but it is very faint as mentioned in #73.
Increasing the duration does make it much stronger, since the motors have more time to spin up.
I'm fine with making the duration 0xFF, if this works without issues.

ds_data->rumble is set based on a 1-bit bitfield which is sent to the Pro Controller. It can only be 0 or 1.

uint8_t rumble : 1;

Maybe the multiplier could be turned in to a configurable option though.

@GaryOderNichts
Copy link
Owner

I'm fine with making the duration 0xFF, if this works without issues.

Update: I was able to get the rumble motor stuck multiple times, by hovering over apps in the Wii U menu.
Maybe simply increasing the duration to something like 5 or 10 would be better. Most titles will send multiple rumble packets for a longer rumble patterns anyways.

@GorillaDaddy
Copy link
Author

Thanks for explaining the binary rumble value in the main header, I didn't know that.

Given the binary on/off for WiiU rumble: I changed it just to max out the rumble on both ds3 motors and turn them off based on that wiiu flag. And changed the ds3 rumble duration to a second (which should eliminate it staying on/rumbling unintentionally). Normally it should get turned off before then by the WiiU, the one-second duration is just a watchdog/off timer. A future configurable option might be the ds3 rumble intensity (now at max). I saw there is a volume in the WiiU's native controller configuration (where you can disable rumble), and maybe we could use that volume value as the rumble strength?

I do suspect that there is some WiiU rumble intensity setting in those 7 unused bits of the packet, but I haven't experimented. I don't have a WiiU Pro Controller. The WiiU Gamepad rumble is super weak.

I didn't sleep much last night, and have a Christmas luncheon thing to attend, but I will get around soon to making another commit with what seems to be working now.

30_bloopair.zip

@GaryOderNichts
Copy link
Owner

I saw there is a volume in the WiiU's native controller configuration (where you can disable rumble), and maybe we could use that volume value as the rumble strength?

Bloopair comes with a configuration system which is used by Koopair. So this could be a configurable option in Koopair.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

The rumble values of DS3 controller is not 100% correct
2 participants