]> git.neil.brown.name Git - plato.git/commitdiff
Add lib/vibra.py
authorNeilBrown <neilb@suse.de>
Sat, 21 Apr 2012 21:54:35 +0000 (07:54 +1000)
committerNeilBrown <neilb@suse.de>
Sat, 21 Apr 2012 21:54:35 +0000 (07:54 +1000)
The vibrator in the GTA04 is presented as an input device with
the 'rumble' force-feedback effect.
This python module provides easy access.

Signed-off-by: NeilBrown <neilb@suse.de>
lib/vibra.py [new file with mode: 0644]

diff --git a/lib/vibra.py b/lib/vibra.py
new file mode 100644 (file)
index 0000000..7d154c4
--- /dev/null
@@ -0,0 +1,129 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2011 Neil Brown <neilb@suse.de>
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; either version 2 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License along
+#    with this program; if not, write to the Free Software Foundation, Inc.,
+#    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import fcntl, struct, array
+
+#
+# There are two steps to creating a rumble effect
+# 1/ describe the effect and give it to the driver using an
+#    ioctl.
+#   There a 3 paramaters:
+#     strength:  from 0 to 0xffff - this code takes a value from 0 to
+#                                   1 and scales it
+#     duration: milliseconds
+#     delay until start: milliseconds.
+#
+# 2/ write a request to play a specific effect.
+#
+# It is possible to have multiple effects active.  If they have
+# different delays they will start at different times.
+# This demo shows combining 3 non-overlapping effects to make
+# a simple vibration pattern
+#
+# An effect is created with f.new_vibe(strength, duration, delay)
+# That effect can then be started with 'play' and stopped with 'stop'.
+
+# EVIOCRMFF = _IOW('E', 0x81, int)
+# dir: 2  WRITE = 1 == 0x40000
+# size 14  4
+# type 8  'E' == 0x45
+# nr: 8   0x81
+#
+EVIOCRMFF = 0x40044581
+# EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect))
+EVIOCSFF = 0x402c4580
+class Vibra:
+    def __init__(self, file = "/dev/input/rumble"):
+        self.f = open(file, "r+")
+
+    def close(self):
+        self.f.close()
+
+    def new_vibe(self, strength, length, delay):
+        # strength is from 0 to 1
+        # length and delay are in millisecs
+        # this is 'struct ff_effect' from "linux/input.h"
+        effect = struct.pack('HhHHHHHxxHH',
+                             0x50, -1, 0, # FF_RUMBLE, id, direction
+                             0, 0,        # trigger (button interval)
+                             length, delay,
+                             int(strength * 0xFFFF), 0)
+        a = array.array('h', effect)
+        fcntl.ioctl(self.f, EVIOCSFF, a, True)
+        return a[1]
+        id = a[1]
+        return (ev_play, ev_stop)
+
+    def multi_vibe(self, length, repeats = 1, delay = None, strength = 1):
+        start = 0
+        if delay == None:
+            delay = length
+        v = []
+        for i in range(0, repeats):
+            v.append(self.new_vibe(strength, length, start))
+            start += length + delay
+        return v
+
+    def play(self, id):
+        # this is 'struct input_event': sec, nsec, type, code, value
+        if type(id) == tuple or type(id) == list:
+            ev_play = ''
+            for i in id:
+                ev_play = ev_play + struct.pack('LLHHi', 0, 0, 0x15, i, 1)
+        else:
+            ev_play = struct.pack('LLHHi', 0, 0, 0x15, id, 1)
+        self.f.write(ev_play)
+        self.f.flush()
+
+    def stop(self, id):
+        # this is 'struct input_event': sec, nsec, type, code, value
+        if type(id) == tuple or type(id) == list:
+            ev_stop = ''
+            for i in id:
+                ev_stop = ev_stop + struct.pack('LLHHi', 0, 0, 0x15, i, 0)
+        else:
+            ev_stop = struct.pack('LLHHi', 0, 0, 0x15, id, 0)
+        self.f.write(ev_stop)
+        self.f.flush()
+
+    def forget(self, id):
+        if type(id) == tuple or type(id) == list:
+            for i in id:
+                fcntl.ioctl(self.f, EVIOCRMFF, i)
+        else:
+            fcntl.ioctl(self.f, EVIOCRMFF, id)
+
+if __name__ == '__main__':
+    import time
+    f = Vibra("/dev/input/rumble")
+
+    # rumble for 300ms, pause for 100ms, rumble for 300ms, pause for 200ms
+    # then half-speed rumble for 600ms
+    p1 = f.new_vibe(1, 300, 0)
+    p2 = f.new_vibe(1, 300,400)
+    p3 = f.new_vibe(0.5, 600, 900)
+
+    f.play((p1, p2, p3))
+
+    time.sleep(2)
+    f.forget((p1, p2, p3))
+
+    # 14 consecutives 200ms rumbles with 100ms gaps
+    f.play(f.multi_vibe(200, 14, delay=100))
+
+    time.sleep(5)