aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2020-07-11 12:28:50 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2020-08-14 19:12:23 +0300
commit0e5969320ee96fbbf7edde7c0c789217a83f0b9b (patch)
treeff140daf8af9bb59ed003c326721ebe641a4790e
parent3c85e6273257158c8ac4112fe257a354fe3ff318 (diff)
downloadhid-tmff2-0e5969320ee96fbbf7edde7c0c789217a83f0b9b.tar.gz
hid-tmff2-0e5969320ee96fbbf7edde7c0c789217a83f0b9b.zip
Pushing changes from testing to master
-rw-r--r--.clangd/index/hid-tm.h.7821369EC83FE7C8.idxbin1326 -> 0 bytes
-rw-r--r--.clangd/index/hid-tmff2.c.9B4690F7E401243F.idxbin10340 -> 0 bytes
-rw-r--r--.clangd/index/hid-tmt300rs.c.43A658324E8CEF81.idxbin10460 -> 0 bytes
-rw-r--r--.clangd/index/hid-tmt300rs.h.3CC3B1B35D0BBA1F.idxbin2640 -> 0 bytes
-rw-r--r--.clangd/index/usbhid.h.D54214605C1BF4CF.idxbin3044 -> 0 bytes
-rw-r--r--.gitingore3
-rw-r--r--Init.pcapngbin0 -> 6992 bytes
-rw-r--r--Module.symvers0
-rw-r--r--README.md18
-rw-r--r--README.md.orig56
-rw-r--r--force-effects.txt166
-rw-r--r--hid-tmt300rs.c564
-rw-r--r--hid-tmt300rs.h16
-rw-r--r--t150init.pcapngbin0 -> 6772 bytes
14 files changed, 693 insertions, 130 deletions
diff --git a/.clangd/index/hid-tm.h.7821369EC83FE7C8.idx b/.clangd/index/hid-tm.h.7821369EC83FE7C8.idx
deleted file mode 100644
index 926efd2..0000000
--- a/.clangd/index/hid-tm.h.7821369EC83FE7C8.idx
+++ /dev/null
Binary files differ
diff --git a/.clangd/index/hid-tmff2.c.9B4690F7E401243F.idx b/.clangd/index/hid-tmff2.c.9B4690F7E401243F.idx
deleted file mode 100644
index 8585493..0000000
--- a/.clangd/index/hid-tmff2.c.9B4690F7E401243F.idx
+++ /dev/null
Binary files differ
diff --git a/.clangd/index/hid-tmt300rs.c.43A658324E8CEF81.idx b/.clangd/index/hid-tmt300rs.c.43A658324E8CEF81.idx
deleted file mode 100644
index 3de5e8d..0000000
--- a/.clangd/index/hid-tmt300rs.c.43A658324E8CEF81.idx
+++ /dev/null
Binary files differ
diff --git a/.clangd/index/hid-tmt300rs.h.3CC3B1B35D0BBA1F.idx b/.clangd/index/hid-tmt300rs.h.3CC3B1B35D0BBA1F.idx
deleted file mode 100644
index 5522235..0000000
--- a/.clangd/index/hid-tmt300rs.h.3CC3B1B35D0BBA1F.idx
+++ /dev/null
Binary files differ
diff --git a/.clangd/index/usbhid.h.D54214605C1BF4CF.idx b/.clangd/index/usbhid.h.D54214605C1BF4CF.idx
deleted file mode 100644
index 6a7514a..0000000
--- a/.clangd/index/usbhid.h.D54214605C1BF4CF.idx
+++ /dev/null
Binary files differ
diff --git a/.gitingore b/.gitingore
deleted file mode 100644
index 64bbd39..0000000
--- a/.gitingore
+++ /dev/null
@@ -1,3 +0,0 @@
-*.ko
-*.o
-*.mod*
diff --git a/Init.pcapng b/Init.pcapng
new file mode 100644
index 0000000..3a395ef
--- /dev/null
+++ b/Init.pcapng
Binary files differ
diff --git a/Module.symvers b/Module.symvers
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Module.symvers
diff --git a/README.md b/README.md
index c866177..65994c0 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,10 @@
# Linux kernel module for the Thrustmaster T300RS wheel
## Current state
-Playable. Dynamic updating of effects isn't baked into the wheel quite as
-well as I'd hoped, and so the driver in its current state doesn't really
-support it. At some point in the future I'd like to add it to the feature
-list, but it will need a lot more research and might take a while.
-
-One other issue is that if you have the T3PA pedals, the clutch doesn't seem
-to be registered by most(all?) games. It is registered and works as expected
-in jstest and jstest-gtk, no clue what that is about.
+Playable. I've made some improvements to the dynamic updating of effects, and
+while still far for perfect, the experience is slowly getting better and better.
+Some drawbacks include missing dynamic updating of ramp effects and in some
+games inconsistent pedal mapping. Meaning that all pedals should be detected in games, but may be mapped incorrectly.
Anycase, **this version is usable in most force feedback games, supports
rangesetting as well as gain and autocentering along with most force feedback effects.**
@@ -22,11 +18,11 @@ With that in mind,
## Installation
+ Unplug wheel from computer
-+ `git clone this-repo`
++ `git clone https://github.com/Kimplul/hid-tmff2.git`
+ `make`
+ `sudo make install`
+ Plug wheel back in
-+ reboot (not strictly necessary, but recommended)
++ reboot (not strictly necessary, but definitely recommended)
Done!
@@ -41,7 +37,7 @@ Write a value between 0 and 1080 to
Use the default evdev ways, i.e. https://www.kernel.org/doc/html/v5.1/input/ff.html
-+ Currently there is support for this driver in oversteer(https://github.com/berarma/oversteer), and ffbwrap(https://github.com/berarma/ffbtools) should work.
++ Currently there is support for this driver in oversteer(https://github.com/berarma/oversteer), and ffbwrap(https://github.com/berarma/ffbtools) should work just fine.
+ If the wheel has a deadzone in games, you can set up a udev rule:
`/etc/udev/rules.d/99-joydev.rules`
diff --git a/README.md.orig b/README.md.orig
deleted file mode 100644
index f1353ef..0000000
--- a/README.md.orig
+++ /dev/null
@@ -1,56 +0,0 @@
-# Linux kernel module for the Thrustmaster T300RS wheel
-
-## Current state
-Playable. Dynamic updating of effects isn't baked into the wheel quite as
-well as I'd hoped, and so the driver in its current state doesn't really
-support it. At some point in the future I'd like to add it to the feature
-list, but it will need a lot more research and might take a while.
-
-One other issue is that if you have the T3PA pedals, the clutch doesn't seem
-to be registered by most(all?) games. It is registered and works as expected
-in jstest and jstest-gtk, no clue what that is about.
-
-Anycase, **this version is usable in most force feedback games, supports
-rangesetting as well as gain and autocentering along with most force feedback effects.**
-## Small note
-
-While I haven't personally come across any crashes or lockups with this
-version, I can't promise that they won't occur under any circumstances.
-
-With that in mind,
-
-## Installation
-
-+ Unplug wheel from computer
-+ `git clone this-repo`
-+ `make`
-+ `sudo make install`
-+ Plug wheel back in
-+ reboot (not strictly necessary, but recommended)
-
-Done!
-
-## Additional tidbits
-
-+ Change range:
-
-Write a value between 0 and 65535 to
-/sys/bus/devices/XXXX:044F:B66E.XXX/range
-
-+ Change autocenter and gain:
-
-Use the default evdev ways, i.e. https://www.kernel.org/doc/html/v5.1/input/ff.html
-
-<<<<<<< HEAD
- + Currently there is no support for this driver in oversteer(https://github.com/berarma/oversteer), but ffbwrap(https://github.com/berarma/ffbtools) should work.
- + If the wheel has a deadzone in games, you can set up a udev rule:
- `/etc/udev/rules.d/99-joydev.rules`:
- `SUBSYSTEM=="input", ATTRS{idVendor}=="044f", ATTRS{idProduct}=="b66e"
-
- RUN+="/usr/bin/evdev-joystick --evdev %E{DEVNAME} --deadzone 0"`
- This should make sure that the wheel behaves like you'd want from a
- wheel.
-=======
-+ Currently there is no support for this driver in oversteer(https://github.com/berarma/oversteer).
-I opened a pull request to add support(to some degree) for this driver to ffbtools(https://github.com/berarma/ffbtools), but until it gets merged I have a repo here: https://github.com/Kimplul/ffbtools
->>>>>>> 8dcb9edbc14b9709e6b0d8b567211e4252191b1e
diff --git a/force-effects.txt b/force-effects.txt
index 6c205f7..bd5b8d1 100644
--- a/force-effects.txt
+++ b/force-effects.txt
@@ -53,15 +53,14 @@ FF_CONSTANT:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- Modifying: (It may be possible to modify the effects all at once, not sure)
- (In any case, so far I only investigated the constant modifiers)
+ Modifying: (For dynamic updating of effects)
Direction: n/a
Constant force:
60 00 - standard header
01 - ID
0a - modify constant force
- 05 16 - constant force
+ 05 16 - constant force ***
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
@@ -75,7 +74,7 @@ FF_CONSTANT:
attack_length 81,
fade_level 88,
fade_length 84 )
- 63 04 - value attribute should be set to
+ 63 04 - value attribute should be set to ?***?
00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
@@ -91,6 +90,9 @@ FF_CONSTANT:
00 00 00 00 00 00 00 00 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:
+ Not supported?
+
FF_RAMP:
(Why on earth is it this difficult to figure out how a fucking ramp works?)
@@ -117,6 +119,40 @@ FF_RAMP:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ Modifying:
+ Sweet baby jesus
+ I'll figure this out later
+
+ Envelope:
+ 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
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 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
+ 01 - ID
+ 4e 08 - ?
+ 01 00 - time in milliseconds
+ 05 41 - ?
+ 01 00 - 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 00 00 00 00 00 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:
+ Not supported?
+
FF_SPRING:
Init:
60 00 - standard header
@@ -137,6 +173,9 @@ FF_SPRING:
00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ Modifying:
+ Same as under
+
FF_DAMPER + FF_FRICTION + FF_INERTIA:
Init:
60 00 - standard header
@@ -155,6 +194,51 @@ FF_DAMPER + FF_FRICTION + FF_INERTIA:
00 ff ff - end of init
00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+ Modifying:
+ positive coefficient:
+ 60 00
+ 02 - ID
+ 0e 41
+ 64 35 - value, signed (between 00 00 and 01 80?)
+ 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+ negative coefficient:
+ 60 00
+ 02 - ID
+ 0e 42
+ 64 35 - value, signed (between 00 00 and ff 7f?)
+ 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+ deadband/offset:
+ 60 00
+ 02 - ID
+ 0e 4c
+ 64 35 - deadband (right?) (deadband + offset) (fe ff means no deadband)
+ 00 00 - deadband (left?) (deadband + 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
+
+ Duration:
+ 60 00 - standard header
+ 01 - ID
+ 49 06 41 - modify timing?
+ 6c 20 - length 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 00 00
+
+ Offset:
+ Not supported?
FF_PERIODIC:
60 00 - standard header
@@ -182,6 +266,80 @@ FF_PERIODIC:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ Modifying:
+ magnitude:
+ 60 00
+ 02 - ID
+ 0e 01
+ 64 35 - value, signed (between 00 00 and ff 7f?)
+ 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 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:
+ 60 00
+ 02 - ID
+ 0e 04
+ 64 35 - value, signed (between 00 00 and ff 7f?)
+ 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 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 02
+ 64 35 - value, signed (between 80 01 and ff 7f?)
+ 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 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, signed (between 00 00 and I guess ff 7f?) (max value in
+ wireshark is 0d 07, but I don't know if that's a driver or program issue)
+ 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 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:
+ 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
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 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
+ 01 - ID
+ 4e 08 - ?
+ 01 00 - time in milliseconds
+ 05 41 - ?
+ 01 00 - 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 00 00 00 00 00 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:
+ Not supported?
+
+
FF_AUTOCENTER:
60 08 - header plus settings?
03 - set autocenter force
diff --git a/hid-tmt300rs.c b/hid-tmt300rs.c
index 8287042..a8c4c0f 100644
--- a/hid-tmt300rs.c
+++ b/hid-tmt300rs.c
@@ -36,7 +36,7 @@ static int t300rs_send_int(struct input_dev *dev, u8 *send_buffer, int *trans){
struct usb_interface *usbif;
struct usb_host_endpoint *ep;
struct urb *urb = usb_alloc_urb(0, GFP_ATOMIC);
-
+
t300rs = t300rs_get_device(hdev);
if(!t300rs){
hid_err(hdev, "could not get device\n");
@@ -96,26 +96,475 @@ static int t300rs_stop_effect(struct t300rs_device_entry *t300rs, struct t300rs_
}
static void t300rs_fill_envelope(u8 *send_buffer, int i, s16 level, u16 duration, struct ff_envelope *envelope){
+ u16 le_attack_level, le_attack_length, le_fade_level, le_fade_length;
u16 attack_length = (duration * envelope->attack_length) / 0x7fff;
u16 attack_level = (level * envelope->attack_level) / 0x7fff;
u16 fade_length = (duration * envelope->fade_length) / 0x7fff;
u16 fade_level = (level * envelope->fade_level) / 0x7fff;
- attack_length = cpu_to_le16(attack_length);
- attack_level = cpu_to_le16(attack_level);
- fade_length = cpu_to_le16(fade_length);
- fade_level = cpu_to_le16(fade_level);
+ le_attack_length = cpu_to_le16(attack_length);
+ le_attack_level = cpu_to_le16(attack_level);
+ le_fade_length = cpu_to_le16(fade_length);
+ le_fade_level = cpu_to_le16(fade_level);
+
+ send_buffer[i ] = le_attack_length & 0xff;
+ send_buffer[i + 1] = le_attack_length >> 8;
+ send_buffer[i + 2] = le_attack_level & 0xff;
+ send_buffer[i + 3] = le_attack_level >> 8;
+ send_buffer[i + 4] = le_fade_length & 0xff;
+ send_buffer[i + 5] = le_fade_length >> 8;
+ send_buffer[i + 6] = le_fade_level & 0xff;
+ send_buffer[i + 7] = le_fade_level >> 8;
+}
+
+static int t300rs_modify_periodic_envelope(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state, u8 *send_buffer){
+ struct ff_effect effect = state->effect;
+ struct ff_effect old = state->old;
+ struct ff_periodic_effect periodic = effect.u.periodic;
+ struct ff_periodic_effect periodic_old = old.u.periodic;
+ struct ff_envelope envelope = periodic.envelope;
+ struct ff_envelope envelope_old = periodic_old.envelope;
+ u16 duration, attack_length, attack_level, fade_length, fade_level;
+ u16 le_attack_length, le_attack_level, le_fade_length, le_fade_level;
+ s16 level;
+ int ret = 0, trans;
+
+ level = (periodic.magnitude * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;
+
+ if(effect.replay.length == 0){
+ duration = 0xffff;
+ } else {
+ duration = effect.replay.length;
+ }
+
+ 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;
+
+ le_attack_length = cpu_to_le16(attack_length);
+ le_attack_level = cpu_to_le16(attack_level);
+ le_fade_length = cpu_to_le16(fade_length);
+ le_fade_level = cpu_to_le16(fade_level);
+
+ send_buffer[0] = 0x60;
+ send_buffer[2] = effect.id + 1;
+ send_buffer[3] = 0x31;
+
+ if(envelope.attack_length != envelope_old.attack_length){
+ send_buffer[4] = 0x81;
+
+ send_buffer[5] = le_attack_length & 0xff;
+ send_buffer[6] = le_attack_length >> 8;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying constant effect\n");
+ goto error;
+ }
+ }
+
+ if(envelope.attack_level != envelope_old.attack_level){
+ send_buffer[4] = 0x82;
+
+ send_buffer[5] = le_attack_level & 0xff;
+ send_buffer[6] = le_attack_level >> 8;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying constant effect\n");
+ goto error;
+ }
+ }
+
+ if(envelope.fade_length != envelope_old.fade_length){
+ send_buffer[4] = 0x84;
+
+ send_buffer[5] = le_fade_length & 0xff;
+ send_buffer[6] = le_fade_length >> 8;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying constant effect\n");
+ goto error;
+ }
+ }
+
+ if(envelope.fade_level != envelope_old.fade_level){
+ send_buffer[4] = 0x88;
+
+ send_buffer[5] = le_fade_level & 0xff;
+ send_buffer[6] = le_fade_level >> 8;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying constant effect\n");
+ goto error;
+ }
+ }
+
+error:
+ memset(send_buffer, 0, T300RS_BUFFER_LENGTH);
+ return ret;
+}
+static int t300rs_modify_constant_envelope(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state, u8 *send_buffer){
+ struct ff_effect effect = state->effect;
+ struct ff_effect old = state->old;
+ struct ff_constant_effect constant = effect.u.constant;
+ struct ff_constant_effect constant_old = old.u.constant;
+ struct ff_envelope envelope = constant.envelope;
+ struct ff_envelope envelope_old = constant_old.envelope;
+ u16 duration, attack_length, attack_level, fade_length, fade_level;
+ u16 le_attack_length, le_attack_level, le_fade_length, le_fade_level;
+ s16 level;
+ int ret = 0, trans;
+
+ level = (constant.level * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;
+
+ if(effect.replay.length == 0){
+ duration = 0xffff;
+ } else {
+ duration = effect.replay.length;
+ }
+
+ 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;
+
+ le_attack_length = cpu_to_le16(attack_length);
+ le_attack_level = cpu_to_le16(attack_level);
+ le_fade_length = cpu_to_le16(fade_length);
+ le_fade_level = cpu_to_le16(fade_level);
+
+ send_buffer[0] = 0x60;
+ send_buffer[2] = effect.id + 1;
+ send_buffer[3] = 0x31;
+
+ if(envelope.attack_length != envelope_old.attack_length){
+ send_buffer[4] = 0x81;
+
+ send_buffer[5] = le_attack_length & 0xff;
+ send_buffer[6] = le_attack_length >> 8;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying constant effect\n");
+ goto error;
+ }
+ }
+
+ if(envelope.attack_level != envelope_old.attack_level){
+ send_buffer[4] = 0x82;
+
+ send_buffer[5] = le_attack_level & 0xff;
+ send_buffer[6] = le_attack_level >> 8;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying constant effect\n");
+ goto error;
+ }
+ }
+
+ if(envelope.fade_length != envelope_old.fade_length){
+ send_buffer[4] = 0x84;
- send_buffer[i ] = attack_length & 0xff;
- send_buffer[i + 1] = attack_length >> 8;
- send_buffer[i + 2] = attack_level & 0xff;
- send_buffer[i + 3] = attack_level >> 8;
- send_buffer[i + 4] = fade_length & 0xff;
- send_buffer[i + 5] = fade_length >> 8;
- send_buffer[i + 6] = fade_level & 0xff;
- send_buffer[i + 7] = fade_level >> 8;
+ send_buffer[5] = le_fade_length & 0xff;
+ send_buffer[6] = le_fade_length >> 8;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying constant effect\n");
+ goto error;
+ }
+ }
+
+ if(envelope.fade_level != envelope_old.fade_level){
+ send_buffer[4] = 0x88;
+
+ send_buffer[5] = le_fade_level & 0xff;
+ send_buffer[6] = le_fade_level >> 8;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying constant effect\n");
+ goto error;
+ }
+ }
+
+error:
+ memset(send_buffer, 0, T300RS_BUFFER_LENGTH);
+ return ret;
}
+static int t300rs_modify_duration(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state, u8 *send_buffer){
+ struct ff_effect effect = state->effect;
+ struct ff_effect old = state->old;
+ u16 duration, le_duration;
+ int ret = 0, trans;
+
+ if(effect.replay.length == 0){
+ duration = 0xffff;
+ } else {
+ duration = effect.replay.length;
+ }
+
+ le_duration = cpu_to_le16(duration);
+
+ if(effect.replay.length != old.replay.length){
+ send_buffer[0] = 0x60;
+ send_buffer[2] = effect.id + 1;
+ send_buffer[3] = 0x49;
+ send_buffer[5] = 0x41;
+
+ send_buffer[6] = le_duration & 0xff;
+ send_buffer[7] = le_duration >> 8;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying duration\n");
+ goto error;
+ }
+ }
+error:
+ memset(send_buffer, 0, T300RS_BUFFER_LENGTH);
+ return ret;
+}
+
+static int t300rs_modify_constant(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state, u8 *send_buffer){
+ struct ff_effect effect = state->effect;
+ struct ff_effect old = state->old;
+ struct ff_constant_effect constant = effect.u.constant;
+ struct ff_constant_effect constant_old = old.u.constant;
+ int ret, trans;
+
+ if(constant.level != constant_old.level){
+ s16 level, le_level;
+
+ level = (constant.level * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;
+ le_level = cpu_to_le16(level);
+
+ send_buffer[0] = 0x60;
+ send_buffer[2] = effect.id + 1;
+ send_buffer[3] = 0x0a;
+
+ send_buffer[4] = le_level & 0xff;
+ send_buffer[5] = le_level >> 8;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying constant effect\n");
+ goto error;
+ }
+
+ memset(send_buffer, 0, T300RS_BUFFER_LENGTH);
+ }
+
+ ret = t300rs_modify_constant_envelope(t300rs, state, send_buffer);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying constant envelope\n");
+ goto error;
+ }
+
+ ret = t300rs_modify_duration(t300rs, state, send_buffer);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying constant duration\n");
+ goto error;
+ }
+
+error:
+ kfree(send_buffer);
+ return ret;
+}
+
+static int t300rs_modify_damper(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state, u8 *send_buffer){
+ struct ff_effect effect = state->effect;
+ struct ff_effect old = state->old;
+ struct ff_condition_effect damper = effect.u.condition[0];
+ struct ff_condition_effect damper_old = old.u.condition[0];
+ int ret, trans;
+
+ if(damper.right_coeff != damper_old.right_coeff){
+ s16 le_coeff = cpu_to_le16(damper.right_coeff);
+
+ send_buffer[0] = 0x60;
+ send_buffer[2] = effect.id + 1;
+ send_buffer[3] = 0x0e;
+ send_buffer[4] = 0x41;
+
+ send_buffer[5] = le_coeff & 0xff;
+ send_buffer[6] = le_coeff >> 8;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying damper rc\n");
+ goto error;
+ }
+
+ memset(send_buffer, 0, T300RS_BUFFER_LENGTH);
+ }
+
+ if(damper.left_coeff != damper_old.left_coeff){
+ s16 le_coeff = cpu_to_le16(damper.left_coeff);
+
+ send_buffer[0] = 0x60;
+ send_buffer[2] = effect.id + 1;
+ send_buffer[3] = 0x0e;
+ send_buffer[4] = 0x42;
+
+ send_buffer[5] = le_coeff & 0xff;
+ send_buffer[6] = le_coeff >> 8;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying damper lc\n");
+ }
+
+ memset(send_buffer, 0, T300RS_BUFFER_LENGTH);
+ }
+
+ if((damper.deadband != damper_old.deadband) ||
+ (damper.center != damper_old.center)){
+ u16 le_deadband_right = cpu_to_le16(0xfffe - damper.deadband - damper.center);
+ u16 le_deadband_left = cpu_to_le16(0xfffe - damper.deadband + damper.center);
+
+ send_buffer[0] = 0x60;
+ send_buffer[2] = effect.id + 1;
+ send_buffer[3] = 0x0e;
+ send_buffer[4] = 0x4c;
+
+ send_buffer[5] = le_deadband_right & 0xff;
+ send_buffer[6] = le_deadband_right >> 8;
+
+ send_buffer[7] = le_deadband_left & 0xff;
+ send_buffer[8] = le_deadband_left >> 8;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying damper deadband\n");
+ }
+
+ memset(send_buffer, 0, T300RS_BUFFER_LENGTH);
+ }
+
+ ret = t300rs_modify_duration(t300rs, state, send_buffer);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying constant duration\n");
+ goto error;
+ }
+
+error:
+ kfree(send_buffer);
+ return ret;
+}
+
+
+static int t300rs_modify_periodic(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state, u8 *send_buffer){
+ struct ff_effect effect = state->effect;
+ struct ff_effect old = state->old;
+ struct ff_periodic_effect periodic = effect.u.periodic;
+ struct ff_periodic_effect periodic_old = old.u.periodic;
+ int ret, trans;
+
+ if(periodic.magnitude != periodic_old.magnitude){
+ s16 level, le_level;
+
+ level = (periodic.magnitude * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;
+ le_level = cpu_to_le16(level);
+
+ send_buffer[0] = 0x60;
+ send_buffer[2] = effect.id + 1;
+ send_buffer[3] = 0x0e;
+ send_buffer[4] = 0x01;
+
+ send_buffer[5] = le_level & 0xff;
+ send_buffer[6] = le_level >> 8;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying periodic magnitude\n");
+ goto error;
+ }
+
+ memset(send_buffer, 0, T300RS_BUFFER_LENGTH);
+ }
+
+ if(periodic.offset != periodic_old.offset){
+ s16 le_offset = cpu_to_le16(periodic.offset);
+
+ send_buffer[0] = 0x60;
+ send_buffer[2] = effect.id + 1;
+ send_buffer[3] = 0x0e;
+ send_buffer[4] = 0x04;
+
+ send_buffer[5] = le_offset & 0xff;
+ send_buffer[6] = le_offset >> 8;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying periodic offset\n");
+ }
+
+ memset(send_buffer, 0, T300RS_BUFFER_LENGTH);
+ }
+
+ if(periodic.phase != periodic_old.phase){
+ s16 le_phase = cpu_to_le16(periodic.phase);
+
+ send_buffer[0] = 0x60;
+ send_buffer[2] = effect.id + 1;
+ send_buffer[3] = 0x0e;
+ send_buffer[4] = 0x02;
+
+ send_buffer[5] = le_phase & 0xff;
+ send_buffer[6] = le_phase >> 8;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying periodic phase\n");
+ }
+
+ memset(send_buffer, 0, T300RS_BUFFER_LENGTH);
+ }
+
+ if(periodic.period != periodic_old.period){
+ s16 le_period = cpu_to_le16(periodic.period);
+
+ send_buffer[0] = 0x60;
+ send_buffer[2] = effect.id + 1;
+ send_buffer[3] = 0x0e;
+ send_buffer[4] = 0x08;
+
+ send_buffer[5] = le_period & 0xff;
+ send_buffer[6] = le_period >> 8;
+
+ ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying periodic period\n");
+ }
+
+ memset(send_buffer, 0, T300RS_BUFFER_LENGTH);
+ }
+
+ ret = t300rs_modify_periodic_envelope(t300rs, state, send_buffer);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying constant envelope\n");
+ goto error;
+ }
+
+ ret = t300rs_modify_duration(t300rs, state, send_buffer);
+ if(ret){
+ hid_err(t300rs->hdev, "failed modifying constant duration\n");
+ goto error;
+ }
+
+error:
+ kfree(send_buffer);
+ return ret;
+}
+
+
static int t300rs_upload_constant(struct t300rs_device_entry *t300rs, struct t300rs_effect_state *state){
u8 *send_buffer = kzalloc(T300RS_BUFFER_LENGTH, GFP_ATOMIC);
struct ff_effect effect = state->effect;
@@ -124,15 +573,16 @@ static int t300rs_upload_constant(struct t300rs_device_entry *t300rs, struct t30
u16 duration, le_offset, le_duration;
int ret, trans;
-
- /* currently this driver doesn't support dynamic effect updating quite like
- * many games would assume. There's not a huge drawback to this method, the
- * wheel maybe feels a bit more jittery because of this but it's not a
- * massive downside. At some point in the future I'd like to improve the
- * dynamic updating, but this will do for now.
- * */
- if(test_bit(FF_EFFECT_PLAYING, &state->flags)){
- t300rs_stop_effect(t300rs, state);
+
+ /* some games, such as DiRT Rally 2 have a weird feeling to them, sort of
+ * like the wheel pulls just a bit to the right or left and then it just
+ * stops. I wouldn't be surprised if it's got something to do with the
+ * constant envelope, but right now I don't know. */
+
+ if(test_bit(FF_EFFECT_PLAYING, &state->flags) &&
+ test_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags)){
+ __clear_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags);
+ return t300rs_modify_constant(t300rs, state, send_buffer);
}
level = (constant.level * fixp_sin16(effect.direction * 360 / 0x10000)) / 0x7fff;
@@ -172,10 +622,6 @@ static int t300rs_upload_constant(struct t300rs_device_entry *t300rs, struct t30
hid_err(t300rs->hdev, "failed uploading constant effect\n");
}
- if(test_bit(FF_EFFECT_PLAYING, &state->flags)){
- t300rs_play_effect(t300rs, state);
- }
-
kfree(send_buffer);
return ret;
}
@@ -262,8 +708,10 @@ static int t300rs_upload_spring(struct t300rs_device_entry *t300rs, struct t300r
u16 duration, le_right_coeff, le_left_coeff, le_deadband_right, le_deadband_left,
le_duration, le_offset;
- if(test_bit(FF_EFFECT_PLAYING, &state->flags)){
- t300rs_stop_effect(t300rs, state);
+ if(test_bit(FF_EFFECT_PLAYING, &state->flags) &&
+ test_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags)){
+ __clear_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags);
+ return t300rs_modify_damper(t300rs, state, send_buffer);
}
if(effect.replay.length == 0){
@@ -314,10 +762,6 @@ static int t300rs_upload_spring(struct t300rs_device_entry *t300rs, struct t300r
hid_err(t300rs->hdev, "failed uploading spring\n");
}
- if(test_bit(FF_EFFECT_PLAYING, &state->flags)){
- t300rs_play_effect(t300rs, state);
- }
-
kfree(send_buffer);
return ret;
}
@@ -331,8 +775,10 @@ static int t300rs_upload_damper(struct t300rs_device_entry *t300rs, struct t300r
u16 duration, le_right_coeff, le_left_coeff, le_deadband_right, le_deadband_left,
le_duration, le_offset;
- if(test_bit(FF_EFFECT_PLAYING, &state->flags)){
- t300rs_stop_effect(t300rs, state);
+ if(test_bit(FF_EFFECT_PLAYING, &state->flags) &&
+ test_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags)){
+ __clear_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags);
+ return t300rs_modify_damper(t300rs, state, send_buffer);
}
if(effect.replay.length == 0){
@@ -383,10 +829,6 @@ static int t300rs_upload_damper(struct t300rs_device_entry *t300rs, struct t300r
hid_err(t300rs->hdev, "failed uploading spring\n");
}
- if(test_bit(FF_EFFECT_PLAYING, &state->flags)){
- t300rs_play_effect(t300rs, state);
- }
-
kfree(send_buffer);
return ret;
}
@@ -399,8 +841,10 @@ static int t300rs_upload_periodic(struct t300rs_device_entry *t300rs, struct t30
u16 duration, magnitude, le_magnitude, le_phase, le_period, le_offset, le_duration;
s16 le_periodic_offset;
- if(test_bit(FF_EFFECT_PLAYING, &state->flags)){
- t300rs_stop_effect(t300rs, state);
+ if(test_bit(FF_EFFECT_PLAYING, &state->flags) &&
+ test_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags)){
+ __clear_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags);
+ return t300rs_modify_periodic(t300rs, state, send_buffer);
}
if(effect.replay.length == 0){
@@ -456,10 +900,6 @@ static int t300rs_upload_periodic(struct t300rs_device_entry *t300rs, struct t30
hid_err(t300rs->hdev, "failed uploading periodic effect");
}
- if(test_bit(FF_EFFECT_PLAYING, &state->flags)){
- t300rs_play_effect(t300rs, state);
- }
-
kfree(send_buffer);
return ret;
}
@@ -493,10 +933,13 @@ static int t300rs_timer_helper(struct t300rs_device_entry *t300rs){
state = &t300rs->states[effect_id];
- if(test_bit(FF_EFFECT_PLAYING, &state->flags)){
- if((jiffies_now - state->start_time) >= state->effect.replay.length){
+ if(test_bit(FF_EFFECT_PLAYING, &state->flags) && state->effect.replay.length){
+ if((jiffies_now - state->start_time) >= state->effect.replay.length){
__clear_bit(FF_EFFECT_PLAYING, &state->flags);
+ /* lazy bum fix? */
+ __clear_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags);
+
if(state->count){
__set_bit(FF_EFFECT_QUEUE_START, &state->flags);
}
@@ -582,6 +1025,10 @@ static int t300rs_upload(struct input_dev *dev, struct ff_effect *effect, struct
spin_lock_irqsave(&t300rs->lock, t300rs->lock_flags);
state->effect = *effect;
+ if(old){
+ state->old = *old;
+ __set_bit(FF_EFFECT_QUEUE_UPDATE, &state->flags);
+ }
__set_bit(FF_EFFECT_QUEUE_UPLOAD, &state->flags);
spin_unlock_irqrestore(&t300rs->lock, t300rs->lock_flags);
@@ -601,11 +1048,12 @@ static int t300rs_play(struct input_dev *dev, int effect_id, int value){
spin_lock_irqsave(&t300rs->lock, t300rs->lock_flags);
if(value > 0){
+ /*
if(test_bit(FF_EFFECT_QUEUE_START, &state->flags)){
__set_bit(FF_EFFECT_QUEUE_STOP, &state->flags);
} else {
t300rs->effects_used++;
- }
+ }*/
state->count = value;
state->start_time = JIFFIES2MS(jiffies);
@@ -631,21 +1079,28 @@ static ssize_t t300rs_range_store(struct device *dev, struct device_attribute *a
struct t300rs_device_entry *t300rs;
u8 *send_buffer = kzalloc(T300RS_BUFFER_LENGTH, GFP_ATOMIC);
u16 range = simple_strtoul(buf, NULL, 10);
+ u16 le_range;
int ret, trans;
t300rs = t300rs_get_device(hdev);
- if(range < 0x097b){
- range = 0x097b;
+ if(range < 40){
+ range = 40;
}
- range = cpu_to_le16(range);
+ if(range > 1080){
+ range = 1080;
+ }
+
+ range *= 0x3c;
+
+ le_range = cpu_to_le16(range);
send_buffer[0] = 0x60;
send_buffer[1] = 0x08;
send_buffer[2] = 0x11;
- send_buffer[3] = range & 0xff;
- send_buffer[4] = range >> 8;
+ send_buffer[3] = le_range & 0xff;
+ send_buffer[4] = le_range >> 8;
ret = t300rs_send_int(t300rs->input_dev, send_buffer, &trans);
if(ret){
@@ -653,7 +1108,7 @@ static ssize_t t300rs_range_store(struct device *dev, struct device_attribute *a
return -1;
}
- t300rs->range = range;
+ t300rs->range = range / 0x3c;
kfree(send_buffer);
return count;
}
@@ -798,7 +1253,7 @@ int t300rs_init(struct hid_device *hdev, const signed short *ff_bits){
struct usb_device *usbdev = interface_to_usbdev(usbif);
struct hid_report *report;
struct ff_device *ff;
- char range[10] = "54000"; /* approx 900 degress */
+ char range[10] = "1080"; /* max */
int i, ret;
drv_data = hid_get_drvdata(hdev);
@@ -829,6 +1284,7 @@ int t300rs_init(struct hid_device *hdev, const signed short *ff_bits){
}
spin_lock_init(&t300rs->lock);
+ spin_lock_init(&data_lock);
drv_data->device_props = t300rs;
diff --git a/hid-tmt300rs.h b/hid-tmt300rs.h
index ccdea78..e5bb58d 100644
--- a/hid-tmt300rs.h
+++ b/hid-tmt300rs.h
@@ -7,12 +7,19 @@
#define T300RS_MAX_EFFECTS 16
#define T300RS_BUFFER_LENGTH 64
-#define DEFAULT_TIMER_PERIOD 4 /* the wheel seems to be bad at stuff*/
+/* the wheel seems to only be capable of processing a certain number of
+ * interrupts per second, and if this value is too low the kernel urb buffer(or
+ * some buffer at least) fills up. Optimally I would figure out some way to
+ * space out the interrupts so that they all leave at regular intervals, but for
+ * now this is good enough, go slow enough that everything works.
+ * */
+#define DEFAULT_TIMER_PERIOD 8
#define FF_EFFECT_QUEUE_UPLOAD 0
#define FF_EFFECT_QUEUE_START 1
#define FF_EFFECT_QUEUE_STOP 2
#define FF_EFFECT_PLAYING 3
+#define FF_EFFECT_QUEUE_UPDATE 4
#define CLAMP_VALUE_U16(x) ((unsigned short)((x) > 0xffff ? 0xffff : (x)))
#define SCALE_VALUE_U16(x, bits) (CLAMP_VALUE_U16(x) >> (16 - bits))
@@ -21,6 +28,9 @@
spinlock_t lock;
unsigned long lock_flags;
+spinlock_t data_lock;
+unsigned long data_flags;
+
static int timer_msecs = DEFAULT_TIMER_PERIOD;
static const signed short t300rs_ff_effects[] = {
@@ -43,6 +53,8 @@ static const signed short t300rs_ff_effects[] = {
struct t300rs_effect_state {
struct ff_effect effect;
+ struct ff_effect old;
+ bool old_set;
unsigned long flags;
unsigned long start_time;
unsigned long count;
@@ -75,7 +87,7 @@ struct t300rs_data{
void *device_props;
};
-static __u8 t300rs_rdesc_fixed[] = {0x05, 0x01, 0x09, 0x04, 0xa1, 0x01, 0x09, 0x01, 0xa1, 0x00, 0x85, 0x07, 0x09, 0x30, 0x15, 0x00, 0x27, 0xff, 0xff, 0x00, 0x00, 0x35, 0x00, 0x47, 0xff, 0xff, 0x00, 0x00, 0x75, 0x10, 0x95, 0x01, 0x81, 0x02, 0x09, 0x31, 0x26, 0xff, 0x03, 0x46, 0xff, 0x03, 0x81, 0x02, 0x09, 0x35, 0x81, 0x02, 0x09, 0x36, 0x81, 0x02, 0x81, 0x03, 0x05, 0x09, 0x19, 0x01, 0x29, 0x0d, 0x25, 0x01, 0x45, 0x01, 0x75, 0x01, 0x95, 0x0d, 0x81, 0x02, 0x75, 0x0b, 0x95, 0x01, 0x81, 0x03, 0x05, 0x01, 0x09, 0x39, 0x25, 0x07, 0x46, 0x3b, 0x01, 0x55, 0x00, 0x65, 0x14, 0x75, 0x04, 0x81, 0x42, 0x65, 0x00, 0x81, 0x03, 0x85, 0x0a, 0x06, 0x00, 0xff, 0x09, 0x0a, 0x75, 0x08, 0x95, 0x3f, 0x26, 0xff, 0x7f, 0x16, 0x00, 0x80, 0x46, 0xff, 0x7f, 0x36, 0x00, 0x80, 0x91, 0x02, 0x85, 0x02, 0x09, 0x02, 0x81, 0x02, 0x09, 0x14, 0x85, 0x14, 0x81, 0x02, 0xc0, 0xc0,};
+static __u8 t300rs_rdesc_fixed[] = {0x05, 0x01, 0x09, 0x04, 0xa1, 0x01, 0x09, 0x01, 0xa1, 0x00, 0x85, 0x07, 0x09, 0x30, 0x15, 0x00, 0x27, 0xff, 0xff, 0x00, 0x00, 0x35, 0x00, 0x47, 0xff, 0xff, 0x00, 0x00, 0x75, 0x10, 0x95, 0x01, 0x81, 0x02, 0x09, 0x35, 0x26, 0xff, 0x03, 0x46, 0xff, 0x03, 0x81, 0x02, 0x09, 0x32, 0x81, 0x02, 0x09, 0x31, 0x81, 0x02, 0x81, 0x03, 0x05, 0x09, 0x19, 0x01, 0x29, 0x0d, 0x25, 0x01, 0x45, 0x01, 0x75, 0x01, 0x95, 0x0d, 0x81, 0x02, 0x75, 0x0b, 0x95, 0x01, 0x81, 0x03, 0x05, 0x01, 0x09, 0x39, 0x25, 0x07, 0x46, 0x3b, 0x01, 0x55, 0x00, 0x65, 0x14, 0x75, 0x04, 0x81, 0x42, 0x65, 0x00, 0x81, 0x03, 0x85, 0x0a, 0x06, 0x00, 0xff, 0x09, 0x0a, 0x75, 0x08, 0x95, 0x3f, 0x26, 0xff, 0x7f, 0x16, 0x00, 0x80, 0x46, 0xff, 0x7f, 0x36, 0x00, 0x80, 0x91, 0x02, 0x85, 0x02, 0x09, 0x02, 0x81, 0x02, 0x09, 0x14, 0x85, 0x14, 0x81, 0x02, 0xc0, 0xc0,};
static u8 spring_values[] = {
0xa6, 0x6a, 0xa6, 0x6a, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xdf, 0x58, 0xa6, 0x6a, 0x06
diff --git a/t150init.pcapng b/t150init.pcapng
new file mode 100644
index 0000000..bb71e52
--- /dev/null
+++ b/t150init.pcapng
Binary files differ