ffbtools icon indicating copy to clipboard operation
ffbtools copied to clipboard

Length 0 instead of 0xFFFF for infinite effect duration.

Open groybe opened this issue 4 years ago • 36 comments

Name of the game: Fedit Steam ID: No Steam Game version: 1.0 Game Type (native/proton/wine): Wine Proton/Wine version: wine-7.2 (Staging) Wheel Model: OpenFFBoard (https://github.com/Ultrawipf/OpenFFBoard) Compatibility Mode: None Distribution: Fedora 34 Kernel version: 5.16.12-100

Force Feedback present: No Symptoms or Special Notes: Fedit (also I tried Richard Burns Rally) My wheel recieves length as 0 instead of 0xFFFF for infinite effect duration.

I used rohitab api monitor to confirm that dinput out of fedit sends 0xFFFF so I guess this might not be a wine issue. At this point I'm lost. Can anyone point me where to look next?

Native program Tux racer appears to work although only in one direction but I think that's a whole other issue.

The creator of OpenFFboard has confirmed it arrives at the OpenFFBoard itself as 0xFFFF on a windows machine. They seem to think it is a linux issue. My G25 wheel gets sent 0 as length but seems to just accept this and play the effect anyways. Should the openFFBoard handle this the same way? I'm not sure this would be to standards?

The log on wine staging is empty for some reason. But the wrapper is working. I've added a length overwrite here and it works.

Log from wine lutris-5.7-11-x86_64 000034473776 > UPLOAD id:2 dir:15681 length:0 delay:0 type:CONSTANT level:-8192 attack_length:0 attack_level:32000 fade_length:0 fade_level:32000

Thanks for anyone who takes the time to look at this.

groybe avatar Mar 17 '22 02:03 groybe

The Linux FF API is different to Windows. The Linux source code has this comment:

All duration values are expressed in ms. Values above 32767 ms (0x7fff) should not be used and have unspecified results.

So using 0xFFFF can give unexpected results, it could even work but it's not following the API specs.

Infinite effect duration is requested with replay.length = 0.

Proton 7.0 has switched to a new input API implementation and has issues with wheels and FF. Wine might have similar issues in case they've switched to this new implementation.

berarma avatar Mar 17 '22 12:03 berarma

Thanks for the quick response. Ah that might ruin the author of OpenFFBoard's plans for compatibility of universal drivers across windows and linux.

Anyways I have a dirty fix using your wrapper here. https://github.com/groybe/ffbtools/tree/OpenFFBoard_fix

Thanks again!

groybe avatar Mar 18 '22 01:03 groybe

I changed the behaviour in the OpenFFBoard firmware back to treating 0xffff and 0 as infinite. The PID standard is not fully clear about if the maximum or 0 is treated as infinite. Check the definitions page of the PID document. That indicates to me that it is likely the max value. Never seen anything on windows send 0. Windows always uses the maximum but also no game would send 0 it seems so its probably best to treat both as infinite for compatibility reasons.

But there are currently other issues. I can't get FFB at all to work on my linux machine at the moment to test it.

Maybe someone here has an idea. dmesg always reports implement() called with too large value 4 (n: 1)! which hints at core-hid.c and sometimes when an effect should be loaded it reports upload request failed.

device reports 0 simultaneous effects
pid_block_load failed 60 times
upload request failed

But the device never receives an effect request at all for some reason so it could be a descriptor interpretation problem on linux. Linux seems very strict about what fields must be present in the descriptor in what order with which values while on windows the descriptor defines what capabilities the device has and the OS sends reports accordingly.

Ultrawipf avatar Mar 18 '22 10:03 Ultrawipf

Hi @Ultrawipf. I was following your work some time ago. I'm glad you're still working on it. It's very interesting and I hope I can get to try it sometime and perhaps help.

I didn't know about the PID document, it isn't in the usb.org index of documents. Logitech wheels don't use it and I don't know any wheels using it. In any case, that's for the USB interface, we're comparing the Windows and Linux interfaces, at a higher level of abstraction.

The PID document is fundamentally done by Microsoft so it may have similarities with DInput on Windows.

I haven't found any Linux documentation that says 0 is infinite duration but it's implied by drivers and Wine. Search "infinite" in this discussion in the Wine mailing list.

About the other issues, I don't know how you are interfacing with the OpenFFBoard firmware. I guess you would need a driver or use hidraw. Maybe I don't know enough about USB and its implementation on Linux, though.

berarma avatar Mar 18 '22 12:03 berarma

Currently debugging the linux handling of the device memory management reports. It seems like windows does not really care about those reports while on linux it is quite important. There was indeed a bug in the pool and block load report replies causing a 1 byte offset causing it not to detect the device managed memory flag (if it is not 1 hid-pidff.c seems to fail immediately). The device is now detected again and effects can be sent but there are still some things to fix.

Also the "autocentering detection" is a bit weird causing some workarounds for other games to break again. Not sure if it was ever common to have a preset spring effect for autocentering. Never seen that before.

If you have some sources to look into about the lower level device management (pool report, block load report, effect creation sequences on linux) it would be nice to look into. The effect setup sequencing does not follow the windows order so thats something i need to look into for now.

Ultrawipf avatar Mar 18 '22 16:03 Ultrawipf

The Linux FF API is different to Windows. The Linux source code has this comment:

All duration values are expressed in ms. Values above 32767 ms (0x7fff) should not be used and have unspecified results.

So using 0xFFFF can give unexpected results, it could even work but it's not following the API specs.

I checked again and indeed in our firmware the maximum valid range is until 0x7fff but windows will send 0xffff as infinite. According to the PID document the "maximum of a range" is infinite so for a 16b value that might actually be 0xffff here and not the maximum of the defined valid range of a value which is 0x7fff then.

Ultrawipf avatar Apr 24 '22 21:04 Ultrawipf

The differences between OS level APIs and firmware APIs should be handled by drivers I guess. That's what the Logitech drivers do, I don't know what the PID driver does.

berarma avatar Apr 25 '22 11:04 berarma

I changed the behaviour in the OpenFFBoard firmware back to treating 0xffff and 0 as infinite. The PID standard is not fully clear about if the maximum or 0 is treated as infinite. Check the definitions page of the PID document. That indicates to me that it is likely the max value. Never seen anything on windows send 0. Windows always uses the maximum but also no game would send 0 it seems so its probably best to treat both as infinite for compatibility reasons.

But there are currently other issues. I can't get FFB at all to work on my linux machine at the moment to test it.

Maybe someone here has an idea. dmesg always reports implement() called with too large value 4 (n: 1)! which hints at core-hid.c and sometimes when an effect should be loaded it reports upload request failed.

device reports 0 simultaneous effects
pid_block_load failed 60 times
upload request failed

But the device never receives an effect request at all for some reason so it could be a descriptor interpretation problem on linux. Linux seems very strict about what fields must be present in the descriptor in what order with which values while on windows the descriptor defines what capabilities the device has and the OS sends reports accordingly.

you have no idea how long i've been searching the internet to find someone who came across that implement error. i've been neck deep in Linux Force Feedback weeds all month, and I came across this repo fairly early, but I didn't take the time to read the issues.

I have a SimXperience Accuforce V2 wheel, which also uses the generic kernel pidff driver. And while tools like ffbtest will work just fine, it wasn't working through wine.

I too have noticed that implement error. but i sort of moved on from it because i think it was a bit of a red herring, or atleast not my biggest issue. i think it only applies to certain effects, i think Rumble, but don't quote me on that. Which would make sense if more common wheels that only have limited common effects, don't see that error.

the biggest issue was the -1 coming from wine dinput into SDL. i put a few lines to set replay.length to SHRT_MAX and i could get ForceTest.exe to play effects.

atleast better. i still think there are other issues i'm working through.

i started a wine thread but now i'm unsure whether or not wine should be sending SHRT_MAX or if SDL should understand and handle the -1.

Spacefreak18 avatar Aug 28 '22 21:08 Spacefreak18

I too have noticed that implement error. but i sort of moved on from it because i think it was a bit of a red herring, or atleast not my biggest issue. i think it only applies to certain effects, i think Rumble, but don't quote me on that. Which would make sense if more common wheels that only have limited common effects, don't see that error.

I guess it would affect any effect the uses infinite duration. In my case it was Constant Force but I've only tried Richard Burns Rally.

Also looking at the work around I was using here I had a problem with the wheel not listening to a negative direction but direction based on degrees was ok. I forget why this was. I think it was the wheel's handling of it too.

groybe avatar Aug 29 '22 00:08 groybe

I just read your post over at Wine forum. Yeah now I remember wine 7 doesn't work for me. So you're not the only one. https://bugs.winehq.org/show_bug.cgi?id=52714

groybe avatar Aug 29 '22 00:08 groybe

i actually just looked again, and i do see that implement error regardless of the effect. but it's just a warning, and the effect still plays. i'll need to investigate further to see if that's causing the problems i'm seeing, which i may create another thread for.

i also looked at your "override length" addition to the ffbwrapper. It'll just set the length to 0xFFFF when it is enabled, so even if the effect had some other reasonable value, it'll just be ignored. i guess most applications will not use values that are non-zero and not max?

Spacefreak18 avatar Aug 29 '22 05:08 Spacefreak18

I think on other effects like sine and rumble the duration would matter yeah. So it really would only work with a game that constantly updates the effect. I guess that would be how most games would use constant force where the duration is really irrelevant as long as it has at least some.

Most of this is over my head though.

groybe avatar Aug 29 '22 06:08 groybe

I have a SimXperience Accuforce V2 wheel, which also uses the generic kernel pidff driver. And while tools like ffbtest will work just fine, it wasn't working through wine.

Does it work with Wine/Proton 6? There were some breaking changes in Wine/Proton 7.

It would be interesting to know more about other PID compatible wheels. More testing would probably help fix bugs unconvered until now. I see there might be discrepancies as to what the different Linux FF drivers understand as infinite. Wine/Proton/SDL might have get caught by these discrepancies.

berarma avatar Aug 29 '22 10:08 berarma

berama, i've read that too but I just can't replicate that. I can get wine 7 to work with the version in debian and with the latest from git. As long as i patch SDL with the -1 issue here.

Now, of course, whe I use proton i have to force it to use the system version of SDL by specifiying SDL_DYNAMIC_API=/usr/local/lib/libSDL2.

This is a very confusing landscape, with a lot of moving parts, wine potentially changing backends does not help the matter. I was constantly playing with a registry key in wine (DisableHidraw) thinking that had something to do with it.

Spacefreak18 avatar Aug 29 '22 14:08 Spacefreak18

Here's a link to the patch i'm using on SDL right now if anyone finds it helpful. https://gist.github.com/Spacefreak18/50e27015bdfeb1c9a4da7d3e1b03dff5

Spacefreak18 avatar Sep 03 '22 15:09 Spacefreak18

I changed the behaviour in the OpenFFBoard firmware back to treating 0xffff and 0 as infinite. The PID standard is not fully clear about if the maximum or 0 is treated as infinite. Check the definitions page of the PID document. That indicates to me that it is likely the max value. Never seen anything on windows send 0. Windows always uses the maximum but also no game would send 0 it seems so its probably best to treat both as infinite for compatibility reasons.

But there are currently other issues. I can't get FFB at all to work on my linux machine at the moment to test it.

Maybe someone here has an idea. dmesg always reports implement() called with too large value 4 (n: 1)! which hints at core-hid.c and sometimes when an effect should be loaded it reports upload request failed.

device reports 0 simultaneous effects
pid_block_load failed 60 times
upload request failed

But the device never receives an effect request at all for some reason so it could be a descriptor interpretation problem on linux. Linux seems very strict about what fields must be present in the descriptor in what order with which values while on windows the descriptor defines what capabilities the device has and the OS sends reports accordingly.

also, i think that upload request failed, could be related to the fix of --update-fix in the ffbwrapper. Have you tried that?

Spacefreak18 avatar Sep 03 '22 17:09 Spacefreak18

I changed the behaviour in the OpenFFBoard firmware back to treating 0xffff and 0 as infinite. The PID standard is not fully clear about if the maximum or 0 is treated as infinite. Check the definitions page of the PID document. That indicates to me that it is likely the max value. Never seen anything on windows send 0. Windows always uses the maximum but also no game would send 0 it seems so its probably best to treat both as infinite for compatibility reasons. But there are currently other issues. I can't get FFB at all to work on my linux machine at the moment to test it. Maybe someone here has an idea. dmesg always reports implement() called with too large value 4 (n: 1)! which hints at core-hid.c and sometimes when an effect should be loaded it reports upload request failed.

device reports 0 simultaneous effects
pid_block_load failed 60 times
upload request failed

But the device never receives an effect request at all for some reason so it could be a descriptor interpretation problem on linux. Linux seems very strict about what fields must be present in the descriptor in what order with which values while on windows the descriptor defines what capabilities the device has and the OS sends reports accordingly.

also, i think that upload request failed, could be related to the fix of --update-fix in the ffbwrapper. Have you tried that?

The "--update-fix" option was added to work around a bug in kernels prior to 5.8. The symptoms are very similar to what's described here. Please, see https://github.com/ValveSoftware/Proton/issues/2366#issuecomment-618727311

With kernels 5.8 and newer there shouldn't be a need for this work around unless another similar issue has arised. Stable kernels with updates after that should have the fix too as stated in the linked post.

berarma avatar Sep 06 '22 13:09 berarma

I'm going to try to keep this thread on topic and only talk about the infinite effect duration. In short, i thought update fix was doing something, but it was really just a difference in wine 5 vs wine 7.

Also, there is an obvious error in the first patch i made, but this has made me more certain that the bug here is within wine not SDL though that is where I've been writing this patch.

Previously when the SDL effect came in as -1 I was setting the length to the maximum value of a signed short, in the Linux Kernel source code, it is an unsigned short. I made an updated patch here.

That's what was causing the issue of the effects just stopping that i reported on the previous thread.

In my patch I went ahead and put some logic to set other values to their maxes, but just the adjusting the lengths should be sufficient to atlest get effects to play, they may be inaccurate, I don't know.

Which brings me to the larger issue...

It clearly has to be a wine bug, let's take a simple constant force effect as an example. replay length is an unsigned short, and constant force level is a signed short in the linux kernel. So for the length, obviously if -1 is passed to SDL, it would be an invalid value to pass to the linux kernel effect, so we can just force it to the SHRT_MAX. But we can't do the same for the constant force level setting, it being an unsigned short in the linux kernel, -1 is actually a valid value.

edited for clarity hopefully.

edit: i just read again that values above 0x7fff are unspecified, so now i really don't know what to do. and setting an unsigned short to -1, should set it to max.

edit: i'll study what's going on some more, but i should add that with that patch i made, not only do effects play, i did 3 full laps with the Accuforce v2 in Assetto Corsa on Linux!

Spacefreak18 avatar Sep 09 '22 15:09 Spacefreak18

The Linux FF API is different to Windows. The Linux source code has this comment:

All duration values are expressed in ms. Values above 32767 ms (0x7fff) should not be used and have unspecified results.

So using 0xFFFF can give unexpected results, it could even work but it's not following the API specs.

I checked again and indeed in our firmware the maximum valid range is until 0x7fff but windows will send 0xffff as infinite. According to the PID document the "maximum of a range" is infinite so for a 16b value that might actually be 0xffff here and not the maximum of the defined valid range of a value which is 0x7fff then.

i think what my findings are showing is that there is atleast one other PID device in the wild that is expecting 0xffff as infinite rather than 0x7fff.

Where does the 0x7fff come from other than those comments in the linux source code?

Spacefreak18 avatar Sep 09 '22 15:09 Spacefreak18

I think we're mixing PID docs and the Linux API. While infinite is defined as the max in the PID docs, that's not how it's defined in the Linux API. So 0x7FFF is not infinite.

I came to the conclusion that 0 was infinite for the Linux API from code in the Logitech driver. I don't think it's written anywhere except in code.

After taking a look at the PID module it seems as if it didn't translate the Linux API infinite value (0) to the PID infinite value (0xFFFF). Someone else should confirm this.

Double checking what I said is more than welcome.

berarma avatar Sep 09 '22 19:09 berarma

Shouldn't the Linux API be driver agnostic?

I feel like the PID Document is implying that 0xFFFF is infinite since it would be the max for an unsigned short.

Are you implying hid-pidff.c should transate the zero to 0xffff? It wouldn't make sense to ever have an effect with zero length I'm guessing.

Spacefreak18 avatar Sep 09 '22 20:09 Spacefreak18

Are you implying hid-pidff.c should transate the zero to 0xffff? It wouldn't make sense to ever have an effect with zero length I'm guessing.

Yes. It doesn't make any sense, that's why it's a good value to represent infinite. If other drivers are using 0 as infinite, the pidff driver should do the same I guess.

berarma avatar Sep 09 '22 22:09 berarma

I went ahead and submitted this as a patch to the kernel, it looks like it may get accepted.

https://lkml.org/lkml/2022/10/2/99

Spacefreak18 avatar Oct 06 '22 05:10 Spacefreak18

I went ahead and submitted this as a patch to the kernel, it looks like it may get accepted.

https://lkml.org/lkml/2022/10/2/99

Good. It's now clear there wasn't a consensus on how infinite was represented but Wine has favoured 0 as inifinite. I just checked Dirt Rally, a native port by Feral and it uses 0x7FFF for duration. They probably got confused too and decided to use the longest possible value. It doesn't really matter when you're updating effects periodically every fraction of a second.

Fixing this might allow using several high-end DD wheels. I'd love to have a list of the wheel models that would suddenly work. Fixing the iforce module would also fix some older wheels.

Thanks!

berarma avatar Oct 06 '22 08:10 berarma

The value will depend on the range defined in the HID descriptor. In our firmware and most other devices it is defined as

0x09,0x50,         //    Usage Duration
0x09,0x54,         //    Usage Trigger Repeat Interval. Unused
0x09,0x51,         //    Usage Sample Period
0x09,0xA7,         //    Usage Start Delay
0x15,0x00,         //    Logical Minimum 0
0x26,0xFF,0x7F,    //    Logical Maximum 7FFFh (32767d)

so 0 to 0x7fff and windows games will send 0xffff as infinite. So for example if a device defines the range as only 8 bits the maximum should also only be 0xff for compatibility.

In general many things in the linux implementation are very strict disregarding the descriptor and won't be compatible with all devices. It fails when optional fields the device doesn't even support are missing or in a different order like the trigger interval/buttons. The whole point of the descriptor is to report to the computer how the expected reports should be structured and what it supports. Never seen a modern device use the triggers or custom force effects but if you leave it out of the descriptor because its not supported it will not work outside of windows.

Ultrawipf avatar Oct 07 '22 06:10 Ultrawipf

Leaving the Windows side aside for the moment, Wine will still send 0, but for your firmware, based on that descriptor, you'd have to set 0x7fff for infinite.

Will 0x7fff create an infinite length effect in your firmware?

If so, I think I can modify my patch to read the value at 0x26 in the descriptor and use it to set infinite on 0 length effects.

It'll be a 16 bit value so I have no idea how it will work on a device that wants to use an 8 bit value there.

As for Windows, does it send 0xffff to your device to indicate an infinite length effect? Thereby ignoring your descriptor? What's the behavior then?

Spacefreak18 avatar Oct 07 '22 16:10 Spacefreak18

Will 0x7fff create an infinite length effect in your firmware?

At the moment no. Only 0xffff and 0 but it could be modified to >= 0x7fff in case thats a valid value too. Not sure if 0x7fff as infinite would be the standard or not. I never ran into issues with that yet and have always only seen 0xffff for 16b 0-0x7fff duration ranges.

If so, I think I can modify my patch to read the value at 0x26 in the descriptor and use it to set infinite on 0 length effects.

It'll be a 16 bit value so I have no idea how it will work on a device that wants to use an 8 bit value there.

As for Windows, does it send 0xffff to your device to indicate an infinite length effect? Thereby ignoring your descriptor? What's the behavior then?

Yes it does. I have tested the behaviour with fedit which is an old microsoft FFB effect testing tool and iracing wheelcheck. Both send 0xffff when infinite.

Simucube also defines a 0 to 32767 range in their descriptor and also seems to receive 0xffff in the usb packet so i would assume at least according to Microsofts dinput infinite is not the highest value defined in the descriptor but the highest value of the datatype.

Ultrawipf avatar Oct 08 '22 11:10 Ultrawipf

I'm going to try to keep this thread on topic and only talk about the infinite effect duration. In short, i thought update fix was doing something, but it was really just a difference in wine 5 vs wine 7.

Also, there is an obvious error in the first patch i made, but this has made me more certain that the bug here is within wine not SDL though that is where I've been writing this patch.

Previously when the SDL effect came in as -1 I was setting the length to the maximum value of a signed short, in the Linux Kernel source code, it is an unsigned short. I made an updated patch here.

That's what was causing the issue of the effects just stopping that i reported on the previous thread.

In my patch I went ahead and put some logic to set other values to their maxes, but just the adjusting the lengths should be sufficient to atlest get effects to play, they may be inaccurate, I don't know.

Which brings me to the larger issue...

It clearly has to be a wine bug, let's take a simple constant force effect as an example. replay length is an unsigned short, and constant force level is a signed short in the linux kernel. So for the length, obviously if -1 is passed to SDL, it would be an invalid value to pass to the linux kernel effect, so we can just force it to the SHRT_MAX. But we can't do the same for the constant force level setting, it being an unsigned short in the linux kernel, -1 is actually a valid value.

edited for clarity hopefully.

edit: i just read again that values above 0x7fff are unspecified, so now i really don't know what to do. and setting an unsigned short to -1, should set it to max.

edit: i'll study what's going on some more, but i should add that with that patch i made, not only do effects play, i did 3 full laps with the Accuforce v2 in Assetto Corsa on Linux!

Is Assetto Corsa working on wine 7 for you? I still need to use wine 6 for Richard Burns Rally so now I'm thinking there is a separate issue specific to RBR.

groybe avatar Oct 13 '22 14:10 groybe

I'm going to try to keep this thread on topic and only talk about the infinite effect duration. In short, i thought update fix was doing something, but it was really just a difference in wine 5 vs wine 7. Also, there is an obvious error in the first patch i made, but this has made me more certain that the bug here is within wine not SDL though that is where I've been writing this patch. Previously when the SDL effect came in as -1 I was setting the length to the maximum value of a signed short, in the Linux Kernel source code, it is an unsigned short. I made an updated patch here. That's what was causing the issue of the effects just stopping that i reported on the previous thread. In my patch I went ahead and put some logic to set other values to their maxes, but just the adjusting the lengths should be sufficient to atlest get effects to play, they may be inaccurate, I don't know. Which brings me to the larger issue... It clearly has to be a wine bug, let's take a simple constant force effect as an example. replay length is an unsigned short, and constant force level is a signed short in the linux kernel. So for the length, obviously if -1 is passed to SDL, it would be an invalid value to pass to the linux kernel effect, so we can just force it to the SHRT_MAX. But we can't do the same for the constant force level setting, it being an unsigned short in the linux kernel, -1 is actually a valid value. edited for clarity hopefully. edit: i just read again that values above 0x7fff are unspecified, so now i really don't know what to do. and setting an unsigned short to -1, should set it to max. edit: i'll study what's going on some more, but i should add that with that patch i made, not only do effects play, i did 3 full laps with the Accuforce v2 in Assetto Corsa on Linux!

Is Assetto Corsa working on wine 7 for you? I still need to use wine 6 for Richard Burns Rally so now I'm thinking there is a separate issue specific to RBR.

Wine 7 breaks ForceFeedback for me, even with the above mentioned patch. And I'm pretty sure it's inside Wine. I tried changine winesys backends, etc, with no results.

The guide I used to install Assetto Corsa, suggested installing to a Proton 5 prefix, and then upgrading to a Proton 6.3 prefix, and that is what I am currently using.

I tried upgrading all the way to Proton 7 and that broke Assetto Corsa completely too for me. But I didn't try much. I also had problems installing dotnet into 7.

In short, 7 breaks a lot of things for me, that I'm ignoring for the moment.

https://github.com/berarma/ffbtools/issues/27

Spacefreak18 avatar Oct 13 '22 21:10 Spacefreak18

Ah. I was reading some people over at the WIneHQ Bugzilla were having some success with 7 but it's gone quiet over there now. Wine 6 for now then :)

groybe avatar Oct 15 '22 07:10 groybe