--- /dev/null
+#!/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)