[RFC 5/11] Linux FF: Linux effect parameters: time parameters

Elias Vanderstuyft elias.vds at gmail.com
Sun Mar 9 05:38:06 CDT 2014


On Wed, Mar 5, 2014 at 4:03 PM, Andrew Eikum <aeikum at codeweavers.com> wrote:
> On Tue, Mar 04, 2014 at 08:20:09PM +0100, Elias Vanderstuyft wrote:
>>     So change in dinput/effect_linuxinput.c:488 :
>>         This->effect.u.periodic.period = tsp->dwPeriod / 1000;
>>     to :
>>         if (0 < tsp->dwPeriod && tsp->dwPeriod <= 1000)
>>             This->effect.u.periodic.period = 1;
>>         else
>>             This->effect.u.periodic.period = tsp->dwPeriod / 1000;
>>
>
> Seems good. While we're here, any reason not to use round(3) instead
> of always rounding down in the >1000 case?

That's a good question, the reason is that I want to avoid floating
point arithmetic (round(3)).
But you also have to see this in perspective:
The behaviour of my code is indeed inconsistent around the dwPeriod ==
1000 +- 500 region (in respect with higher values of dwPeriod), but
this is practically irrelevant: a dwPeriod of 1000 means 1ms; a period
of a periodic effect should be minimum 2*sampleperiod, so this
inconsistency will only be perceived (and I'm even not sure a human
would perceive this) when the Linux FF driver has a sampleperiod of
0.5ms, and this is unlikely (lowest value I have seen is 8ms). (Except
maybe for realtime systems like real-motion simulators, but in that
case, I don't think DInput (or other software) will be used as low
level interface, it's more likely that would be implemented in
hardware.)

So can I leave it as I suggested before?

>
>> b)  Anticipate if dwPeriod < 0, otherwise periodic.period will
>> incorrectly wrap around because it's unsigned.
>>     We can choose to let periodic.period be proportional to:
>>     - 0    (driver will generate EINVAL)
>>     - abs(dwPeriod)    (no error, and is mathematically more correct)
>
> DWORDs are usually treated as unsigned.

Thanks for clarifying, I'll fix it.
For some odd reason, I remembered them as signed 32bit values ;)

My code should then become:
    if (tsp->dwPeriod && tsp->dwPeriod <= 1000)
        This->effect.u.periodic.period = 1;
    else
        This->effect.u.periodic.period = tsp->dwPeriod / 1000;

> Is this how Windows behaves
> for massive dwPeriod? I would expect E_INVALIDARG, since it's out of
> the range [0,36000).

I think you're mixing up dwPeriod with dwPhase. The range of dwPeriod
is not defined in MSDN.

>
>>     So, change in dinput/effect_linuxinput.c:191 :
>>         if (dwFlags & DIEP_DURATION) {
>>             peff->dwDuration = (DWORD)This->effect.replay.length * 1000;
>>         }
>>     to :
>>         if (dwFlags & DIEP_DURATION) {
>>             peff->dwDuration = (This->effect.replay.length ?
>> (DWORD)This->effect.replay.length * 1000 : -1);
>>         }
>>
>>     And change in dinput/effect_linuxinput.c:424 :
>>         if (dwFlags & DIEP_DURATION)
>>             This->effect.replay.length = peff->dwDuration / 1000;
>>     to :
>>         if (dwFlags & DIEP_DURATION) {
>>             if (peff->dwDuration == -1)
>>                 This->effect.replay.length = 0; // Infinity
>>             else if (peff->dwDuration > 1000)
>>                 This->effect.replay.length = peff->dwDuration / 1000;
>>             else
>>                 This->effect.replay.length = 1; // Smallest non-zero value
>>         }
>>
>
> This seems okay, though again, maybe use round().

Again, practically an inconsistency in duration at the 1ms bound, will
not be perceivable, see my comment above.

> You should also use
> INFINITE instead of -1.

OK.

Maybe we should also change all occurrences of 10000 in a force
context to DI_FFNOMINALMAX, in the whole FF dinput implementation?


Elias



More information about the wine-devel mailing list