diff options
| -rw-r--r-- | docs/FFBEFFECTS.md | 621 | ||||
| -rw-r--r-- | src/tmt300rs/hid-tmt300rs.c | 574 |
2 files changed, 670 insertions, 525 deletions
diff --git a/docs/FFBEFFECTS.md b/docs/FFBEFFECTS.md index 93dbb80..a9a313a 100644 --- a/docs/FFBEFFECTS.md +++ b/docs/FFBEFFECTS.md @@ -43,7 +43,7 @@ have model specific peculiarities, though. ### Stopping/removing (why are they rolled into one?) ``` - 60 00 - standard header + 60 00 - standard header 01 - ID 89 - playing options 00 - stop @@ -99,7 +99,7 @@ have model specific peculiarities, though. ``` ## FF_AUTOCENTER: -``` +``` 60 08 - header plus settings? 03 - set autocenter force 8f 02 - force (between ff ff and 00 00) @@ -110,7 +110,7 @@ have model specific peculiarities, though. ``` ## FF_GAIN: -``` +``` 60 02 - header plus gain? bf - gain (between ff and 00) 00 00 00 00 00 00 00 00 00 00 00 00 00 @@ -130,7 +130,8 @@ have model specific peculiarities, though. 00 00 - attack_level *** 00 00 - fade_length 00 00 - fade_level *** - 00 4f - ? + 00 - effect type? + 4f f7 17 - time in milliseconds, unsigned 00 00 07 00 - offset from start(?) @@ -142,7 +143,21 @@ have model specific peculiarities, though. ### Modifying (For dynamic updating of effects) -#### Direction: ``N/A`` +``` +4th byte 5th byte hex +00001010 0a - magnitude +01001001 49 - duration / offset / duration + offset +00110001 10000001 31 81 - envelope attack length +00110001 10000010 31 82 - envelope attack level +00110001 10000100 31 84 - envelope fade length +00110001 10001000 31 88 - envelope fade level +00101001 29 - envelope (all) +00101010 2a - magnitude + envelope +01101010 6a - magnitude + envelope + offset +00110010 32 - magnitude + envelope attack length & level +01110010 72 - magnitude + envelope attack length & level + duration +01101010 6a - magnitude + envelope + duration + offset +``` #### Constant force: ``` @@ -158,15 +173,28 @@ have model specific peculiarities, though. #### Envelope: ``` +envelope attack/fade level/length: + multiple values can be updated with one packet + 60 00 - standard header 01 - ID - 31 - modify envelope - 84 - ID of envelope attribute ( attack_level 82, - attack_length 81, - fade_level 88, - fade_length 84 ) - 63 04 - value attribute should be set to ?***? - 00 00 00 00 00 00 00 00 00 + 31 85 + e8 03 - attack length + dc 05 - fade length + 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +envelope (all): + 60 00 - standard header + 01 - ID + 29 + e8 03 - attack length + cc 0c - attack level + dc 05 - fade length + cc 0c - fade level + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 @@ -176,28 +204,133 @@ have model specific peculiarities, though. ``` 60 00 - standard header 01 - ID - 49 00 41 - modify timing? - 6c 20 - length in milliseconds - 00 00 00 00 00 00 00 00 + 49 + 00 - effect type? + 45 - update type + 88 13 - duration in milliseconds + 00 00 - offset in milliseconds + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ``` -#### Offset: `N/A` +#### Combined: +``` +magnitude + envelope: + 60 00 - standard header + 01 - ID + 2a + fd 3f - magnitude + e8 03 - attack length + cc 0c - attack level + dc 05 - fade length + cc 0c - fade level + 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +magnitude + envelope attack length & level + duration: + 60 00 - standard header + 01 - ID + 72 + fd 3f - magnitude + 83 - envelope update type + e8 03 - attack length + cc 0c - attack level + 00 - effect type? + 41 - update type + 88 13 - duration + 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +magnitude + envelope + duration + offset: + 60 00 - standard header + 01 - ID + 6a + fd 3f - magnitude + e8 03 - attack length + cc 0c - attack level + dc 05 - fade length + cc 0c - fade level + 00 - effect type? + 45 - update type + 88 13 - duration + 00 00 - offset + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +``` ## FF_RAMP -Ramps seem to follow triangle wave parameters. +``` +00001110 00000001 0e 01 - slope +00001110 00000010 0e 02 - center +01001001 49 - invert +00001110 00000011 0e 03 - slope + center +01001110 00000001 4e 01 - slope + invert +01001110 00000011 4e 03 - slope + center + invert +01001110 00001000 4e 08 - duration +01001001 49 - offset +01001110 00001000 4e 08 - duration + offset +00110001 10000001 31 81 - envelope attack length +00110001 10000010 31 82 - envelope attack level +00110001 10000100 31 84 - envelope fade length +00110001 10001000 31 88 - envelope fade level +00101001 29 - envelope (all) +01110110 00000011 76 03 - envelope attack & fade length + slope + center + invert +00101110 00000011 2e 03 - envelope + slope + center + invert +01101110 00001011 6e 0b - duration + offset + envelope + slope + center + invert +``` + +### Notes + +#### Invert + +There is a bug in the Windows driver during the Ramp effect update. +If the update requires inverting the effect and the duration or the offset is +not changed, the effect just stops. + +This can be fixed by adding the `update type` byte with the value of `40`. + +Affected examples: + - slope + invert + - slope + center + invert + - invert + - envelope attack & fade length + slope + center + invert + - envelope + slope + center + invert + +Example: +``` +Invalid: + 60 00 - standard header + 01 - ID + 49 + 05 - effect type? + 00 <- missing "update type" + [...] + +Valid: + 60 00 - standard header + 01 - ID + 49 + 05 - effect type? + 40 - update type <- correct update type + [...] +``` + ### Init: ``` 60 00 - standard header 01 - ID 6b - new ramp effect - f6 7f - difference *** - fe ff - level? *** (level = (if end_level > start_level, end_level, else - start_level) - difference?) (signed) + f6 7f - slope *** abs(start - stop) / 2 + fe ff - center *** (start + end) / 2 (signed) 00 00 f7 17 - time 00 80 - some kind of marker @@ -216,53 +349,200 @@ Ramps seem to follow triangle wave parameters. ``` ### Modifying: + ``` +center: 60 00 - standard header 01 - ID - 0e - ??? - 03 - ramp? - e3 04 - difference? - 7d 75 - "level"? - 05 - ???? + 0e 02 + 1e 40 - center + 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +slope + invert: + This packet is affected by the "invert" driver bug. See Notes above. + + 60 00 - standard header + 01 - ID + 4e 01 + 20 00 - slope + 04 - effect type? (invert) 04 or 05 + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +slope + center + invert: + This packet is affected by the "invert" driver bug. See Notes above. + + 60 00 - standard header + 01 - ID + 4e 03 + 06 00 - slope + 25 40 - center + 04 - effect type? (invert) 04 or 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ``` -#### Envelope: +#### Duration, offset, invert: + ``` +duration: 60 00 - standard header 01 - ID - 31 - modify envelope - 84 - ID of envelope attribute ( attack_level 82, - attack_length 81, - fade_level 88, - fade_length 84 ) - 63 04 - value attribute should be set to - 00 00 00 00 00 00 00 00 00 + 4e 08 + 88 13 - duration + 04 - effect type? must reflect the actual inversion 04 or 05 + 41 - update type, see Update type section + 88 13 - duration + 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +offset: + 60 00 - standard header + 01 - ID + 49 + 04 - effect type? must reflect the actual inversion 04 or 05 + 44 - update type, see Update type section + 00 00 - offset + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +duration + offset: + 60 00 - standard header + 01 - ID + 4e 08 + 88 13 - duration + 04 - effect type? must reflect the actual inversion 04 or 05 + 45 - update type, see Update type section + 88 13 - duration + 00 00 - offset + 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +dir + offset: + 60 00 - standard header + 01 - ID + 49 + 05 - effect type? must reflect the actual inversion 04 or 05 + 44 - update type, see Update type section + 00 00 - offset + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +invert: + This packet is affected by the "invert" driver bug. See Notes above. + + 60 00 - standard header + 01 - ID + 49 + 05 - effect type? invert 04 or 05 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ``` -#### Duration: -``` - 60 00 +#### Envelope: + +``` +envelope attack/fade level/length: + multiple values can be updated with one packet + + 60 00 - standard header 01 - ID - 4e - ? - 08 - ? - 01 00 - time in milliseconds - 05 - ? - 41 - ? - 01 00 - time in milliseconds - 00 00 00 00 00 + 31 85 + d0 07 - attack length + dc 05 - fade length + 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +envelope (all): + 60 00 - standard header + 01 - ID + 29 + d0 07 - attack length + 69 34 - attack level + dc 05 - fade length + 32 1a - fade level + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ``` -#### Offset: `N/A` +#### Combined: + +``` +envelope attack & fade length + slope + center + invert: + This packet is affected by the "invert" driver bug. See Notes above. + + 60 00 - standard header + 01 - ID + 76 03 + 06 00 - slope + 25 40 - center + 85 - envelope update type + d0 07 - attack length + dc 05 - fade length + 04 - effect type? (invert) 04 or 05 + 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +envelope + slope + center + invert: + This packet is affected by the "invert" driver bug. See Notes above. + + 60 00 - standard header + 01 - ID + 6e 03 + 06 00 - slope + 25 40 - center + d0 07 - attack length + 69 34 - attack level + dc 05 - fade length + 32 1a - fade level + 04 - effect type? (invert) 04 or 05 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +duration + offset + envelope + slope + center + invert: + 60 00 - standard header + 01 - ID + 6e 0b + 06 00 - slope + 25 40 - center + 88 13 - length + d0 07 - attack length + 69 34 - attack level + dc 05 - fade length + 32 1a - fade level + 04 - effect type? (invert) 04 or 05 + 45 - update type, see Update type section + 88 13 - length 2 + 00 00 - offset + 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +``` ## FF_DAMPER + FF_FRICTION + FF_INERTIA + FF_SPRING: ### Init: @@ -305,7 +585,7 @@ Ramps seem to follow triangle wave parameters. 4th byte 5th byte hex 00001110 01000001 0e 41 positive coefficient 00001110 01000010 0e 42 negative coefficient -00001110 01000011 0e 43 both coefficint +00001110 01000011 0e 43 both coefficient 00001110 01001100 0e 4c right and left deadband 00001110 01010000 0e 50 positive saturation 00001110 01100000 0e 60 negative saturation @@ -348,7 +628,7 @@ The order of the fields are defined in the `all effect specific parameters + dur positive and negative coefficient: 60 00 01 - ID - 0e 43 + 0e 43 ab 67 - right coefficient, signed, between 01 80 (-32767) and fc 7f (32764) 50 18 - left coefficient, signed, between 01 80 (-32767) and fc 7f (32764) 00 00 00 00 00 00 00 @@ -425,7 +705,7 @@ The order of the fields are defined in the `all effect specific parameters + dur fd 5f - positive saturation fd 5f - negative saturation 06 - effect type (condition)? - 45 - update type, see below + 45 - update type, see Update type section 10 27 - length in milliseconds 00 00 - offset in milliseconds 00 00 00 00 00 00 00 00 00 00 @@ -435,22 +715,12 @@ The order of the fields are defined in the `all effect specific parameters + dur ``` ### Duration: - -Update type: - -``` -6th byte hex -01000001 41 length -01000100 44 offset -01000101 45 length + offset -``` - ``` 60 00 - standard header 01 - ID 49 06 - effect type (condition)? - 45 - update type + 45 - update type, see Update type section 6c 20 - length in milliseconds 00 00 - offset in milliseconds 00 00 00 00 00 00 @@ -459,11 +729,10 @@ Update type: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ``` -### Offset: `N/A` - ## FF_PERIODIC: + ### Init -``` +``` 60 00 - standard header 01 - ID 6b - new periodic effect @@ -472,7 +741,7 @@ Update type: 00 00 - phase (left/right) between 00 00 and 4a f7 (32586) meaning is 0 to ~359 deg phase shift in 5b steps e8 03 - period between 00 00 and ff ff (in milliseconds) - 00 80 + 00 80 00 00 - attack_length 00 00 - attack_level *** 00 00 - fade_length @@ -492,8 +761,27 @@ Update type: ``` ### Modifying: + +``` +4th byte 5th byte hex +00001110 00000001 0e 01 - magnitude +00001110 00000010 0e 02 - offset +00001110 00000100 0e 04 - phase +00001110 00001000 0e 08 - period +00001110 00001111 0e 0f - magnitude + offset + phase + period +01001001 49 - duration / offset / duration + offset +00110001 10000001 31 81 - envelope attack length +00110001 10000010 31 82 - envelope attack level +00110001 10000100 31 84 - envelope fade length +00110001 10001000 31 88 - envelope fade level +00101001 29 - envelope (all) +00101110 00001111 2e 0f - magnitude + offset + phase + period + envelope +00110110 00001111 36 0f - magnitude + offset + phase + period + envelope attack length & level +01101110 00001111 6e 0f - magnitude + offset + phase + period + envelope + duration + offset ``` - magnitude: + +``` +magnitude: 60 00 02 - ID 0e 01 @@ -503,118 +791,183 @@ Update type: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - offset of effect: +magnitude + offset + phase + period: 60 00 - 02 - ID - 0e 02 - 64 35 - value, between ff bf (-16385) and fd 3f (16381) - 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - - phase: - 60 00 - 02 - ID - 0e 04 - 64 35 - value, between 00 00 and 4a f7 (32586) in 5b steps + 01 - ID + 0e 0f + dd 3f - magnitude, between 00 00 and fc 7f (32764) + cb 0c - offset, between ff bf (-16385) and fd 3f (16381) + 5a 00 - phase, between 00 00 and 4a f7 (32586) in 5b steps meaning is 0 to 359 deg phase shift - 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - - period: - 60 00 - 02 - ID - 0e 08 - 64 35 - value, between 00 00 and ff ff (in milliseconds) - 00 00 00 00 00 00 00 00 00 + f8 2a - period, between 00 00 and ff ff (in milliseconds) + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ``` -### Envelope: +#### Envelope: ``` +envelope attack/fade level/length: + multiple values can be updated with one packet + 60 00 - standard header 01 - ID - 31 - modify envelope - 84 - ID of envelope attribute ( attack_level 82, - attack_length 81, - fade_level 88, - fade_length 84 ) - 63 04 - value attribute should be set to - 00 00 00 00 00 00 00 00 00 + 31 85 + d0 07 - attack length + dc 05 - fade length + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -``` -### Duration: -``` - Square: - 60 00 +envelope (all): + 60 00 - standard header 01 - ID - 49 - ? - 01 - Effect type - 41 - ? - 4e 0c - Time in milliseconds - 00 00 00 00 00 00 00 00 + 29 + d0 07 - attack length + 69 34 - attack level + dc 05 - fade length + 32 1a - fade level + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +``` - Sine: +#### Duration: +``` 60 00 01 - ID - 49 - ? - 03 - Effect type - 41 - ? - ec 13 - Time in milliseconds - 00 00 00 00 00 00 00 00 + 49 + 03 - effect type 01 - Square + 02 - Triangle + 03 - Sine + 04 - Sawtooth up + 05 - Sawtooth down + 45 - update type, see Update type section + 74 27 - duration + 00 00 - offset + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +``` - Triangle: +#### Combined + +``` +magnitude + offset + phase + period + envelope: 60 00 01 - ID - 49 - ? - 02 - Effect type - 41 - ? - 4e 0c - Time in milliseconds - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 2e 0f + dd 3f - magnitude, between 00 00 and fc 7f (32764) + cb 0c - offset + 5a 00 - phase + f8 2a - period + dc 05 - attack length + 30 73 - attack level + e8 03 - fade length + 30 73 - fade level + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - Sawtooth up: +magnitude + offset + phase + period + envelope attack length & level: 60 00 01 - ID - 49 - ? - 04 - Effect type - 41 - ? - 4e 0c - Time in milliseconds - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 36 0f + dd 3f - magnitude + cb 0c - offset + 5a 00 - phase + f8 2a - period + 83 - envelope update type + e8 03 - attack length + cc 0c - attack level + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - Sawtooth down: +magnitude + offset + phase + period + envelope + duration + offset: 60 00 01 - ID - 49 - ? - 05 - Effect type - 41 - ? - ec 13 - Time in milliseconds - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 6e 0f + dd 3f - magnitude + cb 0c - offset + 5a 00 - phase + f8 2a - period + cc 0c - attack length + e8 03 - attack level + dc 05 - fade length + cc 0c - fade level + 03 - effect type 01 - Square + 02 - Triangle + 03 - Sine + 04 - Sawtooth up + 05 - Sawtooth down + 45 - update type, see Update type section + 74 27 - duration + 00 00 - offset + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ``` -### Offset: `N/A ?` + +## Envelope + +Envelope related parameters are the same across all the effects. The only +difference is which effect specific parameters are used during the calculations. + +Damper, Friction, Inertia, and Spring do not support envelope. + +### attack length + +between 0 and 65535 + +On Windows, it has a minimum value depending on how far is the target from the +attack/fade level. This means that in case of an envelope that goes from zero +to max has the minimum length of 256ms. + +```length = abs((effectval * 32768 / effectmax - level) / 128)``` + +`effectval` is the current value of an effect specific parameter + +`effectmax` is the maximum value of `effectval` + +`level` is the current value of the attack/fade level + +Used parameters for each effect: + +| Effect | Parameter | +|----------|-----------| +| Constant | Strength | +| Periodic | Magnitude | +| Ramp | Slope | + +### attack level + +between 0 and 32764 + +### fade length + +between 0 and 65535 + +Uses the same calculation as attack length. + +### fade level + +between 0 and 32764 + + +## Update type + +``` +binary hex +01000001 41 duration +01000100 44 offset +01000101 45 duration + offset +``` ## PS4 Input `rdesc` ``` diff --git a/src/tmt300rs/hid-tmt300rs.c b/src/tmt300rs/hid-tmt300rs.c index 40be801..2f3e0e8 100644 --- a/src/tmt300rs/hid-tmt300rs.c +++ b/src/tmt300rs/hid-tmt300rs.c @@ -335,6 +335,16 @@ static u8 condition_values[] = { 0xff, 0xfe, 0xff }; +static int16_t t300rs_calculate_constant_level(int16_t level, uint16_t direction) +{ + level = (level * fixp_sin16(direction * 360 / 0x10000)) / 0x7fff; + + /* the Windows driver uses the range [-16385;16381] */ + level = level / 2; + + return level; +} + static void t300rs_calculate_periodic_values(struct ff_effect *effect) { struct ff_periodic_effect *periodic = &effect->u.periodic; @@ -369,7 +379,7 @@ static uint16_t t300rs_condition_max_saturation(uint16_t effect_type) return 0x7ffc; } -static uint16_t t300rs_condition_effect_type(uint16_t effect_type) +static uint8_t t300rs_condition_effect_type(uint16_t effect_type) { if(effect_type == FF_SPRING) return 0x06; @@ -419,6 +429,24 @@ static void t300rs_calculate_deadband(int16_t *out_rband, int16_t *out_lband, *out_lband = clamp(offset - (deadband / 2), -0x7fff, 0x7fff); } +static void t300rs_calculate_ramp_parameters(uint16_t *out_slope, + int16_t *out_center, + uint8_t *out_invert, + struct ff_effect *effect) +{ + struct ff_ramp_effect *ramp = &effect->u.ramp; + + int16_t start_level, end_level; + + start_level = (ramp->start_level * fixp_sin16(effect->direction * 360 / 0x10000)) / 0x7fff; + end_level = (ramp->end_level * fixp_sin16(effect->direction * 360 / 0x10000)) / 0x7fff; + + *out_slope = abs(start_level - end_level) / 2; + *out_center = (start_level + end_level) / 2; + + *out_invert = (start_level < end_level) ? 0x04 : 0x05; +} + int t300rs_send_buf(struct t300rs_device_entry *t300rs, u8 *send_buffer, size_t len) { int i; @@ -501,17 +529,23 @@ int t300rs_stop_effect(void *data, struct tmff2_effect_state *state) } static void t300rs_fill_envelope(struct t300rs_packet_envelope *packet_envelope, - int16_t level, uint16_t duration, struct ff_envelope *envelope) + struct ff_envelope *envelope) { - uint16_t attack_length = (duration * envelope->attack_length) / 0x7fff; - uint16_t attack_level = (level * envelope->attack_level) / 0x7fff; - uint16_t fade_length = (duration * envelope->fade_length) / 0x7fff; - uint16_t fade_level = (level * envelope->fade_level) / 0x7fff; + // Note: Minimal length limitations are not enforced, + // as testing shows that the wheel can handle lower values well + packet_envelope->attack_length = cpu_to_le16(envelope->attack_length); + packet_envelope->attack_level = cpu_to_le16(envelope->attack_level); + packet_envelope->fade_length = cpu_to_le16(envelope->fade_length); + packet_envelope->fade_level = cpu_to_le16(envelope->fade_level); +} - packet_envelope->attack_length = cpu_to_le16(attack_length); - packet_envelope->attack_level = cpu_to_le16(attack_level); - packet_envelope->fade_length = cpu_to_le16(fade_length); - packet_envelope->fade_level = cpu_to_le16(fade_level); +static int t300rs_is_envelope_changed(struct ff_envelope *new, + struct ff_envelope *old) +{ + return new->attack_length != old->attack_length + || new->attack_level != old->attack_level + || new->fade_length != old->fade_length + || new->fade_level != old->fade_level; } static void t300rs_fill_timing(struct t300rs_packet_timing *packet_timing, @@ -524,178 +558,6 @@ static void t300rs_fill_timing(struct t300rs_packet_timing *packet_timing, packet_timing->end_marker = 0xffff; } -static int t300rs_update_envelope(struct t300rs_device_entry *t300rs, - struct tmff2_effect_state *state, - int16_t level, - uint16_t duration, - uint8_t id, - struct ff_envelope envelope, - struct ff_envelope envelope_old - ) -{ - struct __packed t300rs_packet_mod_envelope { - struct t300rs_packet_header header; - uint8_t attribute; - uint16_t value; - } *packet_mod_envelope = (struct t300rs_packet_mod_envelope *)t300rs->send_buffer; - - uint16_t attack_length, attack_level, fade_length, fade_level; - int ret = 0; - - duration = duration - 1; - - attack_length = (duration * envelope.attack_length) / 0x7fff; - attack_level = (level * envelope.attack_level) / 0x7fff; - fade_length = (duration * envelope.fade_length) / 0x7fff; - fade_level = (level * envelope.fade_level) / 0x7fff; - - if (envelope.attack_length != envelope_old.attack_length) { - t300rs_fill_header(&packet_mod_envelope->header, id, 0x31); - packet_mod_envelope->attribute = 0x81; - packet_mod_envelope->value = cpu_to_le16(attack_length); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying effect envelope\n"); - goto error; - } - } - - if (envelope.attack_level != envelope_old.attack_level) { - t300rs_fill_header(&packet_mod_envelope->header, id, 0x31); - packet_mod_envelope->attribute = 0x82; - packet_mod_envelope->value = cpu_to_le16(attack_level); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying effect envelope\n"); - goto error; - } - } - - if (envelope.fade_length != envelope_old.fade_length) { - t300rs_fill_header(&packet_mod_envelope->header, id, 0x31); - packet_mod_envelope->attribute = 0x84; - packet_mod_envelope->value = cpu_to_le16(fade_length); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying effect envelope\n"); - goto error; - } - } - - if (envelope.fade_level != envelope_old.fade_level) { - t300rs_fill_header(&packet_mod_envelope->header, id, 0x31); - packet_mod_envelope->attribute = 0x88; - packet_mod_envelope->value = cpu_to_le16(fade_level); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying effect envelope\n"); - goto error; - } - } - -error: - return ret; -} - -static int t300rs_update_simple_duration(struct t300rs_device_entry *t300rs, - struct tmff2_effect_state *state, unsigned type) -{ - struct ff_effect effect = state->effect; - struct __packed t300rs_packet_mod_duration { - struct t300rs_packet_header header; - uint16_t marker; - uint16_t duration; - } *packet_mod_duration = (struct t300rs_packet_mod_duration *)t300rs->send_buffer; - - uint16_t duration; - int ret = 0; - - duration = effect.replay.length - 1; - - t300rs_fill_header(&packet_mod_duration->header, effect.id, 0x49); - packet_mod_duration->marker = cpu_to_le16(0x4100 + type); - packet_mod_duration->duration = cpu_to_le16(duration); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying duration\n"); - goto error; - } - -error: - return ret; -} - -static int t300rs_update_periodic_duration(struct t300rs_device_entry *t300rs, - struct tmff2_effect_state *state, unsigned type) -{ - struct ff_effect effect = state->effect; - struct __packed t300rs_packet_mod_duration { - struct t300rs_packet_header header; - uint8_t type; - uint8_t marker; - uint16_t duration; - } *packet_mod_duration = (struct t300rs_packet_mod_duration *)t300rs->send_buffer; - - uint16_t duration; - int ret = 0; - - duration = effect.replay.length - 1; - - t300rs_fill_header(&packet_mod_duration->header, effect.id, 0x49); - packet_mod_duration->type = type; - packet_mod_duration->marker = 0x41; - packet_mod_duration->duration = cpu_to_le16(duration); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying duration\n"); - goto error; - } - -error: - return ret; -} - -static int t300rs_update_ramp_duration(struct t300rs_device_entry *t300rs, - struct tmff2_effect_state *state) -{ - struct ff_effect effect = state->effect; - struct __packed t300rs_packet_mod_duration { - struct t300rs_packet_header header; - uint8_t marker0; - uint16_t duration0; - uint8_t marker1; - uint8_t marker2; - uint16_t duration1; - } *packet_mod_duration = (struct t300rs_packet_mod_duration *)t300rs->send_buffer; - - uint16_t duration; - int ret = 0; - - duration = effect.replay.length - 1; - - t300rs_fill_header(&packet_mod_duration->header, effect.id, 0x4e); - packet_mod_duration->marker0 = 0x08; - packet_mod_duration->duration0 = cpu_to_le16(duration); - packet_mod_duration->marker1 = 0x05; - packet_mod_duration->marker2 = 0x41; - packet_mod_duration->duration1 = cpu_to_le16(duration); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying duration\n"); - goto error; - } - -error: - return ret; -} - static int t300rs_update_constant(struct t300rs_device_entry *t300rs, struct tmff2_effect_state *state) { @@ -705,49 +567,44 @@ static int t300rs_update_constant(struct t300rs_device_entry *t300rs, struct ff_constant_effect constant_old = old.u.constant; struct __packed t300rs_packet_mod_constant { struct t300rs_packet_header header; - uint16_t level; + uint16_t magnitude; + struct t300rs_packet_envelope envelope; + uint8_t effect_type; + uint8_t update_type; + uint16_t duration; + uint16_t offset; } *packet_mod_constant = (struct t300rs_packet_mod_constant *)t300rs->send_buffer; - int ret; - int16_t level; - level = (constant.level * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; - /* the Windows driver uses the range [-16385;16381] */ - level = level / 2; + int ret = 0; + int16_t level, old_level; + uint16_t length, old_length; - if ((constant.level != constant_old.level) || (effect.direction != old.direction)) { + level = t300rs_calculate_constant_level(constant.level, effect.direction); + old_level = t300rs_calculate_constant_level(constant_old.level, old.direction); - t300rs_fill_header(&packet_mod_constant->header, effect.id, 0x0a); - packet_mod_constant->level = cpu_to_le16(level); + length = effect.replay.length - 1; + old_length = old.replay.length - 1; - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying constant effect\n"); - goto error; - } + if (!t300rs_is_envelope_changed(&constant.envelope, &constant_old.envelope) + && level == old_level + && length == old_length + && effect.replay.delay == old.replay.delay) + return ret; - } + t300rs_fill_header(&packet_mod_constant->header, effect.id, 0x6a); + packet_mod_constant->magnitude = cpu_to_le16(level); - ret = t300rs_update_envelope(t300rs, - state, - level, - effect.replay.length, - effect.id, - constant.envelope, - constant_old.envelope - ); + t300rs_fill_envelope(&packet_mod_constant->envelope, &constant.envelope); - if (ret) { - hid_err(t300rs->hdev, "failed modifying constant envelope\n"); - goto error; - } + packet_mod_constant->effect_type = 0x00; + packet_mod_constant->update_type = 0x45; + packet_mod_constant->duration = cpu_to_le16(length); + packet_mod_constant->offset = cpu_to_le16(effect.replay.delay); - ret = t300rs_update_simple_duration(t300rs, state, 0x00); - if (ret) { - hid_err(t300rs->hdev, "failed modifying constant duration\n"); - goto error; - } + ret = t300rs_send_int(t300rs); + if (ret) + hid_err(t300rs->hdev, "failed modifying constant effect\n"); -error: return ret; } @@ -760,64 +617,54 @@ static int t300rs_update_ramp(struct t300rs_device_entry *t300rs, struct ff_ramp_effect ramp_old = old.u.ramp; struct __packed t300rs_packet_mod_ramp { struct t300rs_packet_header header; - uint8_t attribute; - uint16_t difference; - uint16_t level; + uint8_t type; + uint16_t slope; + uint16_t center; + uint16_t length; + struct t300rs_packet_envelope envelope; + uint8_t effect_type; + uint8_t update_type; + uint16_t length2; + uint16_t offset; } *packet_mod_ramp = (struct t300rs_packet_mod_ramp *)t300rs->send_buffer; - int ret; - - uint16_t difference, top, bottom; - int16_t level; - - top = ramp.end_level > ramp.start_level ? ramp.end_level : ramp.start_level; - bottom = ramp.end_level > ramp.start_level ? ramp.start_level : ramp.end_level; - - - difference = ((top - bottom) * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; - - - level = (top * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; + int ret = 0; - if ((ramp.start_level != ramp_old.start_level) - || (ramp.end_level != ramp_old.end_level) - || (effect.direction != old.direction)) { + uint8_t invert, old_invert; + uint16_t slope, old_slope, length, old_length; + int16_t center, old_center; - t300rs_fill_header(&packet_mod_ramp->header, effect.id, 0x0e); - packet_mod_ramp->attribute = 0x03; - packet_mod_ramp->difference = cpu_to_le16(difference); - packet_mod_ramp->level = cpu_to_le16(level); + t300rs_calculate_ramp_parameters(&slope, ¢er, &invert, &effect); + t300rs_calculate_ramp_parameters(&old_slope, &old_center, &old_invert, &old); - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying ramp effect\n"); - goto error; - } + length = effect.replay.length - 1; + old_length = old.replay.length - 1; - } + if (!t300rs_is_envelope_changed(&ramp.envelope, &ramp_old.envelope) + && slope == old_slope + && center == old_center + && invert == old_invert + && length == old_length + && effect.replay.delay == old.replay.delay) + return ret; - ret = t300rs_update_envelope(t300rs, - state, - level, - effect.replay.length, - effect.id, - ramp.envelope, - ramp_old.envelope - ); + t300rs_fill_header(&packet_mod_ramp->header, effect.id, 0x6e); + packet_mod_ramp->type = 0x0b; + packet_mod_ramp->slope = cpu_to_le16(slope); + packet_mod_ramp->center = cpu_to_le16(center); + packet_mod_ramp->length = cpu_to_le16(length); + t300rs_fill_envelope(&packet_mod_ramp->envelope, &ramp.envelope); - if (ret) { - hid_err(t300rs->hdev, "failed modifying ramp envelope\n"); - goto error; - } + packet_mod_ramp->effect_type = invert; + packet_mod_ramp->update_type = 0x45; + packet_mod_ramp->length2 = packet_mod_ramp->length; + packet_mod_ramp->offset = cpu_to_le16(effect.replay.delay); - ret = t300rs_update_ramp_duration(t300rs, state); - if (ret) { - hid_err(t300rs->hdev, "failed modifying ramp duration\n"); - goto error; - } + ret = t300rs_send_int(t300rs); + if (ret) + hid_err(t300rs->hdev, "failed modifying ramp effect\n"); -error: return ret; } @@ -869,32 +716,32 @@ static int t300rs_update_condition(struct t300rs_device_entry *t300rs, duration = effect.replay.length - 1; duration_old = old.replay.length - 1; - if (right_coeff != right_coeff_old - || left_coeff != left_coeff_old - || right_deadband != right_deadband_old - || left_deadband != left_deadband_old - || right_sat != right_sat_old - || left_sat != left_sat_old - || duration != duration_old - || effect.replay.delay != old.replay.delay) { + if (right_coeff == right_coeff_old + && left_coeff == left_coeff_old + && right_deadband == right_deadband_old + && left_deadband == left_deadband_old + && right_sat == right_sat_old + && left_sat == left_sat_old + && duration == duration_old + && effect.replay.delay == old.replay.delay) + return ret; - packet_mod_condition->right_coeff = cpu_to_le16(right_coeff); - packet_mod_condition->left_coeff = cpu_to_le16(left_coeff); - packet_mod_condition->right_deadband = cpu_to_le16(right_deadband); - packet_mod_condition->left_deadband = cpu_to_le16(left_deadband); - packet_mod_condition->right_saturation = cpu_to_le16(right_sat); - packet_mod_condition->left_saturation = cpu_to_le16(left_sat); - packet_mod_condition->effect_type = 0x06; - packet_mod_condition->update_type = 0x45; - packet_mod_condition->duration = cpu_to_le16(duration); - packet_mod_condition->delay = cpu_to_le16(effect.replay.delay); + packet_mod_condition->right_coeff = cpu_to_le16(right_coeff); + packet_mod_condition->left_coeff = cpu_to_le16(left_coeff); + packet_mod_condition->right_deadband = cpu_to_le16(right_deadband); + packet_mod_condition->left_deadband = cpu_to_le16(left_deadband); + packet_mod_condition->right_saturation = cpu_to_le16(right_sat); + packet_mod_condition->left_saturation = cpu_to_le16(left_sat); + packet_mod_condition->effect_type = 0x06; + packet_mod_condition->update_type = 0x45; + packet_mod_condition->duration = cpu_to_le16(duration); + packet_mod_condition->delay = cpu_to_le16(effect.replay.delay); - t300rs_fill_header(&packet_mod_condition->header, effect.id, 0x4c); + t300rs_fill_header(&packet_mod_condition->header, effect.id, 0x4c); - ret = t300rs_send_int(t300rs); - if (ret) - hid_err(t300rs->hdev, "failed modifying condition effect\n"); - } + ret = t300rs_send_int(t300rs); + if (ret) + hid_err(t300rs->hdev, "failed modifying condition effect\n"); return ret; } @@ -906,103 +753,58 @@ static int t300rs_update_periodic(struct t300rs_device_entry *t300rs, struct ff_effect old = state->old; struct __packed t300rs_packet_mod_periodic { struct t300rs_packet_header header; - uint8_t attribute; - uint16_t value; + uint8_t type; + uint16_t magnitude; + uint16_t offset; + uint16_t phase; + uint16_t period; + struct t300rs_packet_envelope envelope; + uint8_t effect_type; + uint8_t update_type; + uint16_t duration; + uint16_t play_offset; } *packet_mod_periodic = (struct t300rs_packet_mod_periodic *)t300rs->send_buffer; struct ff_periodic_effect periodic, periodic_old; - int ret; - uint16_t phase; - int16_t magnitude; + int ret = 0; + uint16_t length, old_length; t300rs_calculate_periodic_values(&effect); periodic = effect.u.periodic; - magnitude = periodic.magnitude; - phase = periodic.phase; t300rs_calculate_periodic_values(&old); periodic_old = old.u.periodic; - if ((periodic.magnitude != periodic_old.magnitude) - || (effect.direction != old.direction)) { - - t300rs_fill_header(&packet_mod_periodic->header, effect.id, 0x0e); - packet_mod_periodic->attribute = 0x01; - packet_mod_periodic->value = cpu_to_le16(magnitude); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying periodic magnitude\n"); - goto error; - } - - } - - if (periodic.offset != periodic_old.offset) { - uint16_t offset = periodic.offset; - - t300rs_fill_header(&packet_mod_periodic->header, effect.id, 0x0e); - packet_mod_periodic->attribute = 0x02; - packet_mod_periodic->value = cpu_to_le16(offset); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying periodic offset\n"); - goto error; - } - - } - - if (periodic.phase != periodic_old.phase) { - - t300rs_fill_header(&packet_mod_periodic->header, effect.id, 0x0e); - packet_mod_periodic->attribute = 0x04; - packet_mod_periodic->value = cpu_to_le16(phase); + length = effect.replay.length - 1; + old_length = old.replay.length - 1; - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying periodic phase\n"); - goto error; - } - - } - - if (periodic.period != periodic_old.period) { - int16_t period = periodic.period; - - t300rs_fill_header(&packet_mod_periodic->header, effect.id, 0x0e); - packet_mod_periodic->attribute = 0x08; - packet_mod_periodic->value = cpu_to_le16(period); - - ret = t300rs_send_int(t300rs); - if (ret) { - hid_err(t300rs->hdev, "failed modifying periodic period\n"); - goto error; - } + if (!t300rs_is_envelope_changed(&periodic.envelope, &periodic_old.envelope) + && periodic.magnitude == periodic_old.magnitude + && periodic.offset == periodic_old.offset + && periodic.phase == periodic_old.phase + && periodic.period == periodic_old.period + && length == old_length + && effect.replay.delay == old.replay.delay) + return ret; - } + t300rs_fill_header(&packet_mod_periodic->header, effect.id, 0x6e); + packet_mod_periodic->type = 0x0f; + packet_mod_periodic->magnitude = cpu_to_le16(periodic.magnitude); + packet_mod_periodic->offset = cpu_to_le16(periodic.offset); + packet_mod_periodic->phase = cpu_to_le16(periodic.phase); + packet_mod_periodic->period = cpu_to_le16(periodic.period); - ret = t300rs_update_envelope(t300rs, - state, - magnitude, - effect.replay.length, - effect.id, - periodic.envelope, - periodic_old.envelope - ); + t300rs_fill_envelope(&packet_mod_periodic->envelope, &periodic.envelope); - if (ret) { - hid_err(t300rs->hdev, "failed modifying periodic envelope\n"); - goto error; - } + packet_mod_periodic->effect_type = periodic.waveform - 0x57; + packet_mod_periodic->update_type = 0x45; + packet_mod_periodic->duration = cpu_to_le16(length); + packet_mod_periodic->play_offset = cpu_to_le16(effect.replay.delay); - ret = t300rs_update_periodic_duration(t300rs, state, periodic.waveform - 0x57); - if (ret) { - hid_err(t300rs->hdev, "failed modifying periodic duration\n"); - goto error; - } + ret = t300rs_send_int(t300rs); + if (ret) + hid_err(t300rs->hdev, "failed modifying periodic effect\n"); -error: return ret; } @@ -1024,9 +826,7 @@ static int t300rs_upload_constant(struct t300rs_device_entry *t300rs, int ret; - level = (constant.level * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; - /* the Windows driver uses the range [-16385;16381] */ - level = level / 2; + level = t300rs_calculate_constant_level(constant.level, effect.direction); duration = effect.replay.length - 1; offset = effect.replay.delay; @@ -1035,8 +835,7 @@ static int t300rs_upload_constant(struct t300rs_device_entry *t300rs, packet_constant->level = cpu_to_le16(level); - t300rs_fill_envelope(&packet_constant->envelope, level, duration, - &constant.envelope); + t300rs_fill_envelope(&packet_constant->envelope, &constant.envelope); t300rs_fill_timing(&packet_constant->timing, duration, offset); ret = t300rs_send_int(t300rs); @@ -1053,43 +852,37 @@ static int t300rs_upload_ramp(struct t300rs_device_entry *t300rs, struct ff_ramp_effect ramp = state->effect.u.ramp; struct __packed t300rs_packet_ramp { struct t300rs_packet_header header; - uint16_t difference; - uint16_t level; + uint16_t slope; + uint16_t center; uint8_t zero1[2]; uint16_t duration; uint16_t marker; struct t300rs_packet_envelope envelope; - uint8_t direction; + uint8_t invert; struct t300rs_packet_timing timing; } *packet_ramp = (struct t300rs_packet_ramp *)t300rs->send_buffer; int ret; - uint16_t difference, offset, top, bottom, duration; - int16_t level; - - duration = effect.replay.length - 1; - - top = ramp.end_level > ramp.start_level ? ramp.end_level : ramp.start_level; - bottom = ramp.end_level > ramp.start_level ? ramp.start_level : ramp.end_level; + uint8_t invert; + uint16_t slope, offset, duration; + int16_t center; + t300rs_calculate_ramp_parameters(&slope, ¢er, &invert, &effect); - difference = ((top - bottom) * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; - level = (top * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff; + duration = effect.replay.length - 1; offset = effect.replay.delay; - t300rs_fill_header(&packet_ramp->header, effect.id, 0x6b); - packet_ramp->difference = cpu_to_le16(difference); - packet_ramp->level = cpu_to_le16(level); + packet_ramp->slope = cpu_to_le16(slope); + packet_ramp->center = cpu_to_le16(center); packet_ramp->duration = cpu_to_le16(duration); packet_ramp->marker = cpu_to_le16(0x8000); - t300rs_fill_envelope(&packet_ramp->envelope, level, duration, - &ramp.envelope); + t300rs_fill_envelope(&packet_ramp->envelope, &ramp.envelope); - packet_ramp->direction = ramp.end_level > ramp.start_level ? 0x04 : 0x05; + packet_ramp->invert = invert; t300rs_fill_timing(&packet_ramp->timing, duration, offset); ret = t300rs_send_int(t300rs); @@ -1203,8 +996,7 @@ static int t300rs_upload_periodic(struct t300rs_device_entry *t300rs, packet_periodic->marker = cpu_to_le16(0x8000); - t300rs_fill_envelope(&packet_periodic->envelope, magnitude, duration, - &periodic.envelope); + t300rs_fill_envelope(&packet_periodic->envelope, &periodic.envelope); packet_periodic->waveform = periodic.waveform - 0x57; |
