From b63283a213f7cbf279d03e3d88a962dd1ab9793e Mon Sep 17 00:00:00 2001
From: James Meyer <james.meyer@operamail.com>
Date: Wed, 7 Dec 2011 13:41:34 -0600
Subject: powermate_myth: add ability to control the FE using a geffen
 powermate.

---
 abs/core/powermate_myth/PKGBUILD          |  16 +++
 abs/core/powermate_myth/powermate-myth.py | 214 ++++++++++++++++++++++++++++++
 abs/core/powermate_myth/powermate.py      | 106 +++++++++++++++
 3 files changed, 336 insertions(+)
 create mode 100644 abs/core/powermate_myth/PKGBUILD
 create mode 100644 abs/core/powermate_myth/powermate-myth.py
 create mode 100644 abs/core/powermate_myth/powermate.py

diff --git a/abs/core/powermate_myth/PKGBUILD b/abs/core/powermate_myth/PKGBUILD
new file mode 100644
index 0000000..1581477
--- /dev/null
+++ b/abs/core/powermate_myth/PKGBUILD
@@ -0,0 +1,16 @@
+pkgname=powermate_myth
+pkgver=1.0
+pkgrel=1
+arch=('i686')
+pkgdesc="Provides support and sample program for using the powermate with mtythv"
+url=""
+depends=(python2 xdotool)
+source=(powermate-myth.py  powermate.py)
+
+build() {
+  cd $startdir/src
+  install -D -m0755 powermate.py  $startdir/pkg/usr/LH/bin/powermate.py
+  install -D -m0755 powermate-myth.py  $startdir/pkg/usr/LH/bin/powermate-myth.py
+}
+md5sums=('44a03725355ed53d9f81099923d94329'
+         '90bed7b80570ad6e63ebff827830e14b')
diff --git a/abs/core/powermate_myth/powermate-myth.py b/abs/core/powermate_myth/powermate-myth.py
new file mode 100644
index 0000000..85e5165
--- /dev/null
+++ b/abs/core/powermate_myth/powermate-myth.py
@@ -0,0 +1,214 @@
+#!/usr/bin/python2
+
+import powermate
+import time
+import os
+
+EVENT_BUTTON_PRESS = 1
+EVENT_RELATIVE_MOTION = 2
+
+
+button_pressed = False
+single_tap = False
+mode = "nav"
+
+current_event=(0,0,time.time())
+last_event=current_event
+skipped_event = 0
+pressed_time = 0
+button_held = False
+led_brightness = 255
+#pm = powermate.PowerMate("/dev/powermate")
+
+pm = powermate.PowerMate()
+pm.SetLEDState(led_brightness,0,0,0,0)
+
+
+def runcmd(cmd):
+#    print cmd
+    os.system(cmd)
+
+
+def volume_action(action):
+    global mode
+    global led_brightness
+    if action == "L" :
+        print "Volume down"
+
+    if action == "R" :
+        print "Volume UP"
+
+    if action == "tap" :
+        print "toggle mute"
+
+    if action == "double_tap" :
+        mode = "nav"
+        led_brightness = 500
+        print "mode is now nav"
+
+    return
+
+
+def nav_action(action):
+    global mode
+    global led_brightness
+    keycmd = '''xdotool search --name "Mythtv Frontend" key %s'''
+    if action == "L" :
+        #print "prev"
+       cmd =  keycmd %"Up"
+       runcmd(cmd)
+
+    if action == "R" :
+        #print "next"
+        cmd =  keycmd %"Down"
+        runcmd(cmd)
+
+    if action == "LP" :
+        #print "back"
+        cmd =  keycmd %"Left"
+        runcmd(cmd)
+
+    if action == "RP" :
+        #print "tab"
+        cmd =  keycmd %"Right"
+        runcmd(cmd)
+
+
+    if action == "tap" :
+        #print "select"
+        cmd =  keycmd %"Return"
+        runcmd(cmd)
+
+    if action == "double_tap" :
+        mode = "volume"
+        led_brightness = 10
+        print "mode is now vol"
+
+    if action == "button_held" :
+        cmd =  keycmd %"Escape"
+        runcmd(cmd)
+
+
+
+    return
+
+
+
+
+def act_on_event(action):
+
+    if mode == "volume":
+        volume_action(action)
+
+    elif mode == "nav":
+        nav_action(action)
+
+
+
+
+event_stack=[current_event]
+while 1:
+        #process_events = True
+        reset_lastevent = False
+	event = pm.WaitForEvent(2)
+       # print event
+        if event:
+            #event that happens after every button push, can be thrown away.
+            if event[2] == 0:
+                continue
+
+
+        elif single_tap:
+            pressed_diff = time.time() - pressed_time
+            #This takes care of the holding down the button for X amount of time
+            #print event,  button_pressed, pressed_diff, current_event
+            #if pressed_diff >= 2 and button_pressed and current_event[0] == EVENT_BUTTON_PRESS:
+            if pressed_diff >= 2 and button_pressed :
+                act_on_event("button_held")
+                single_tap = False
+                pressed_time = 0
+                button_pressed = False
+                last_event_time = time.time()
+                last_event=(0,0,time.time())
+                pm.SetLEDState(led_brightness,0,0,0,0)
+                #print "resetting last event:",  last_event
+
+
+           #This handles a single press of the button.
+            elif not button_pressed :
+                act_on_event("tap")
+                single_tap = False
+                last_event_time = time.time()
+                last_event=(0,0,time.time())
+
+        if event:
+            #print "processing:" , event
+            current_event = event[2],event[4],time.time()
+
+            last_event_time = last_event[2]
+            current_event_time = current_event[2]
+
+            last_event_only = last_event[0], last_event[1]
+            current_event_only = current_event[0], current_event[1]
+
+            repeat_rate = 10
+            repeat_time = .50
+
+            if last_event_only == current_event_only and  current_event[0] == EVENT_RELATIVE_MOTION :
+                #check for time diff
+                event_time_diff = current_event_time - last_event_time
+
+                if  skipped_event <= repeat_rate and event_time_diff <= repeat_time:
+                    skipped_event = skipped_event + 1
+                    #print "skipped a repeat event : %s" %skipped_event
+                    continue
+            #event occured, reset skip counter
+            skipped_event = 0
+
+            #rotate dial
+            if current_event[0] == EVENT_RELATIVE_MOTION:
+                reset_lastevent = True
+                single_tap = False
+                if current_event[1] >= 0 :
+                    if button_pressed :
+                        #print "dial turned Counter clockwise and button is pressed"
+                        act_on_event("RP")
+                    else:
+                        #print "dial turned Counter clockwise"
+                        act_on_event("R")
+
+                if current_event[1]  <=0 :
+                    if button_pressed :
+                        #print "dial turned clockwise and button is pressed"
+                        act_on_event("LP")
+                    else:
+                        #print "dial turned clockwise"
+                        act_on_event("L")
+
+
+            #button was pushed
+            if current_event[0] == EVENT_BUTTON_PRESS :
+                pm.SetLEDState(0,0,0,0,0)
+                if current_event[1] == 1:
+                    button_pressed = True
+                    pressed_time = current_event_time
+                    tap_diff = current_event_time - last_event_time
+                    #double tap
+                    if tap_diff < 0.2 and last_event[0] == EVENT_BUTTON_PRESS:
+                        act_on_event("double_tap")
+                        single_tap = False
+                    else:
+                        single_tap = True
+                        reset_lastevent = True
+
+                #button was released
+                elif current_event[1] == 0:
+                    button_pressed = False
+                    pressed_time  = 0
+                    pm.SetLEDState(led_brightness,0,0,0,0)
+
+        if reset_lastevent:
+            last_event = current_event
+
+
+
diff --git a/abs/core/powermate_myth/powermate.py b/abs/core/powermate_myth/powermate.py
new file mode 100644
index 0000000..8e40078
--- /dev/null
+++ b/abs/core/powermate_myth/powermate.py
@@ -0,0 +1,106 @@
+#!/usr/bin/env python
+
+import select
+import os
+import fcntl
+import struct
+import exceptions
+
+#struct input_event {
+#        struct timeval time; = {long seconds, long microseconds}
+#        unsigned short type;
+#        unsigned short code;
+#        unsigned int value;
+#};
+
+input_event_struct = "@llHHi"
+input_event_size = struct.calcsize(input_event_struct)
+
+EVENT_BUTTON_PRESS = 1
+EVENT_RELATIVE_MOTION = 2
+RELATIVE_AXES_DIAL = 7
+BUTTON_MISC = 0x100
+
+def report(x):
+    sys.stderr.write(x + "\n")
+
+class PowerMate:
+    def __init__(self, filename = None):
+        self.handle = -1
+        if filename:
+            if not self.OpenDevice(filename):
+                raise exceptions.RuntimeError, 'Unable to find powermate'
+        else:
+            ok = 0
+            for d in range(0, 16):
+                if self.OpenDevice("/dev/input/event%d" % d):
+                    ok = 1
+                    break
+            if not ok:
+                raise exceptions.RuntimeError, 'Unable to find powermate'
+        self.poll = select.poll()
+        self.poll.register(self.handle, select.POLLIN)
+        self.event_queue = [] # queue used to reduce kernel/userspace context switching
+
+    def __del__(self):
+        if self.handle >= 0:
+            self.poll.unregister(self.handle)
+            os.close(self.handle)
+            self.handle = -1
+            del self.poll
+
+    def OpenDevice(self, filename):
+        try:
+            self.handle = os.open(filename, os.O_RDWR)
+            if self.handle < 0:
+                return 0
+            name = fcntl.ioctl(self.handle, 0x80ff4506, chr(0) * 256) # read device name
+            name = name.replace(chr(0), '')
+            if name == 'Griffin PowerMate' or name == 'Griffin SoundKnob':
+                fcntl.fcntl(self.handle, fcntl.F_SETFL, os.O_NDELAY)
+                return 1
+            os.close(self.handle)
+            self.handle = -1
+            return 0
+        except exceptions.OSError:
+            return 0
+
+    def WaitForEvent(self, timeout): # timeout in seconds
+        if len(self.event_queue) > 0:
+            return self.event_queue.pop(0)
+        if self.handle < 0:
+            return None
+        r = self.poll.poll(int(timeout*100))
+        if len(r) == 0:
+            return None
+        return self.GetEvent()
+
+    def GetEvent(self): # only call when descriptor is readable
+        if self.handle < 0:
+            return None
+        try:
+            data = os.read(self.handle, input_event_size * 32)
+            while data != '':
+                self.event_queue.append(struct.unpack(input_event_struct, data[0:input_event_size]))
+                data = data[input_event_size:]
+            return self.event_queue.pop(0)
+        except exceptions.OSError, e: # Errno 11: Resource temporarily unavailable
+            #if e.errno == 19: # device has been disconnected
+            #    report("PowerMate disconnected! Urgent!");
+            return None
+
+    def SetLEDState(self, static_brightness, pulse_speed, pulse_table, pulse_on_sleep, pulse_on_wake):
+        static_brightness &= 0xff;
+        if pulse_speed < 0:
+            pulse_speed = 0
+        if pulse_speed > 510:
+            pulse_speed = 510
+        if pulse_table < 0:
+            pulse_table = 0
+        if pulse_table > 2:
+            pulse_table = 2
+        pulse_on_sleep = not not pulse_on_sleep # not not = convert to 0/1
+        pulse_on_wake  = not not pulse_on_wake
+        magic = static_brightness | (pulse_speed << 8) | (pulse_table << 17) | (pulse_on_sleep << 19) | (pulse_on_wake << 20)
+        data = struct.pack(input_event_struct, 0, 0, 0x04, 0x01, magic)
+        os.write(self.handle, data)
-- 
cgit v0.12

