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

Rumble doesn't work on Stadia controller #974

Closed
asweintraub opened this issue Apr 22, 2024 · 5 comments
Closed

Rumble doesn't work on Stadia controller #974

asweintraub opened this issue Apr 22, 2024 · 5 comments
Labels
v24.04 Fixed, will be in v24.04 release

Comments

@asweintraub
Copy link

BlueRetro firmware version

1.9.1 and 24.04 beta 21

BlueRetro firmware specification

HW1

BlueRetro firmware variant

Universal

BlueRetro hardware type

External adapter with detachable cord

Manufacturer

blue-retro.com

System used

Nintendo 64

Bluetooth controller brand & name

Google Stadia

What is problem? (only list ONE problem per report)

Vibrations don't work with the Stadia controller.

Previous bugs for this issue were closed, so reopening here.

I don't have a linux machine set up to pull the HID report from the controller, but assuming this HID report is correct, the issue seems to be that USAGE_PAGE16 is not handled in a way that supports the Stadia controller's HID report.

In particular, it looks like the Stadia controller is sending
0x06, 0x0F, 0x00, // Usage Page (PID Page)
instead of
0x05, 0x0F, // Usage Page (PID Page)
which would be properly handled with the existing code.

I'm going to see if I can get a dev environment set up to test this, but I think changing the USAGE_PAGE16 code to the following might fix the problem:

hid_stack[hid_stack_idx].usage_page = *desc;
desc += 2;

What did you expect to happen?

I would expect vibrations to work with the Stadia controller.

Attach files like logs or Bluetooth traces here

No response

@darthcloud
Copy link
Owner

darthcloud commented Apr 23, 2024

I'm very open to receiving PRs ;) Hopefully this help a bit:

Usage page is only stored as a 8bits value in the hid_parser stack:

struct hid_stack_element {
uint32_t report_size;
uint32_t report_cnt;
int32_t logical_min;
int32_t logical_max;
uint8_t usage_page;
};

Would make sense to upgrade it to 32bits since everything else is that, including the global structure used in all other module:

struct hid_usage {
uint32_t usage_page;
uint32_t usage;
uint32_t flags;
uint32_t bit_offset;
uint32_t bit_size;
int32_t logical_min;
int32_t logical_max;
};

You would need to cast the pointer to uint16_t * to grab the full value.

hid_stack[hid_stack_idx].usage_page = *(uint16_t *)desc;;
desc += 2;

Then after that you would likely need to edit the generic rumble code to support that usage_page/usage combination:

void hid_fb_from_generic(struct generic_fb *fb_data, struct bt_data *bt_data) {
struct generic_rumble *rumble = (struct generic_rumble *)bt_data->base.output;
rumble->report_size = 0;
uint32_t bytes_count = 0;
uint32_t tmp_value = 0;
uint32_t offset = 0;
uint32_t counter = 0;
bool is_rumble_usage = false;
for (uint32_t i = 0; i < bt_data->reports[RUMBLE].usage_cnt; i++)
{
is_rumble_usage = false;
switch (bt_data->reports[RUMBLE].usages[i].usage)
{
case 0x50: /* Duration */
bytes_count = (bt_data->reports[RUMBLE].usages[i].bit_size + 7) / 8;
rumble->report_size += bytes_count;
if (fb_data->state) {
tmp_value = bt_data->reports[RUMBLE].usages[i].logical_max;
}
else {
tmp_value = bt_data->reports[RUMBLE].usages[i].logical_min;
}
is_rumble_usage = true;
break;
case 0x70: /* Magnitude */
case 0x97: /* Enable Actuators */
bytes_count = (bt_data->reports[RUMBLE].usages[i].bit_size + 7) / 8;
rumble->report_size += bytes_count;
if (fb_data->state) {
tmp_value = bt_data->reports[RUMBLE].usages[i].logical_max * RUMBLE_ON_MULTIPLIER;
}
else {
tmp_value = bt_data->reports[RUMBLE].usages[i].logical_min;
}
is_rumble_usage = true;
break;
case 0x7C: /* Loop Count */
bytes_count = (bt_data->reports[RUMBLE].usages[i].bit_size + 7) / 8;
rumble->report_size += bytes_count;
if (fb_data->state) {
if (fb_data->cycles) {
tmp_value = fb_data->cycles;
}
else {
tmp_value = bt_data->reports[RUMBLE].usages[i].logical_max;
}
}
else {
tmp_value = bt_data->reports[RUMBLE].usages[i].logical_min;
}
is_rumble_usage = true;
break;
case 0xA7: /* Start Delay */
bytes_count = (bt_data->reports[RUMBLE].usages[i].bit_size + 7) / 8;
rumble->report_size += bytes_count;
tmp_value = fb_data->start;
is_rumble_usage = true;
break;
}
if (is_rumble_usage) {
counter = 0;
while(tmp_value)
{
rumble->state[offset++] = tmp_value;
tmp_value >>= 8;
counter++;
}
for (uint32_t refill = counter; refill < bytes_count; refill++) {
rumble->state[offset++] = 0;
}
}
}
rumble->report_id = bt_data->reports[RUMBLE].id;
}

@asweintraub
Copy link
Author

Thanks for the pointers! I probably won't have time to get around to this for a few weeks, since I don't have the ESP-IDF environment set up and will be quite busy. That said, it looks like a good idea to support 32-bit usage pages, so I'll give that a shot when I have the chance.

Either way, it looks as if the values are little-endian, so 0x06, 0x0F, 0x00 should be synonymous with 0x05, 0x0F, meaning we shouldn't have to modify anything else for this to work with Stadia. In fact, the largest usage page I can find in the HID docs is 0x91, so switching this to 32-bits (instead of dropping the extra bytes) is good for future-proofing, but otherwise unnecessary.

@darthcloud
Copy link
Owner

Yes indeed it was simply the same value using a bigger sized var.

Rumble.work now!

https://github.com/darthcloud/BlueRetro/actions/runs/8808673421

@darthcloud darthcloud added the v24.04 Fixed, will be in v24.04 release label Apr 24, 2024
@asweintraub
Copy link
Author

Nice! I didn't realize you had already merged the fix in. I modified the code earlier today but wasn't able to test it until just now. Thank you!

@darthcloud
Copy link
Owner

Fixed in v24.04

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
v24.04 Fixed, will be in v24.04 release
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants