summaryrefslogtreecommitdiff
path: root/gr-wxgui/python/wxgui/powermate.py
diff options
context:
space:
mode:
Diffstat (limited to 'gr-wxgui/python/wxgui/powermate.py')
-rw-r--r--gr-wxgui/python/wxgui/powermate.py448
1 files changed, 0 insertions, 448 deletions
diff --git a/gr-wxgui/python/wxgui/powermate.py b/gr-wxgui/python/wxgui/powermate.py
deleted file mode 100644
index 7c324c5d95..0000000000
--- a/gr-wxgui/python/wxgui/powermate.py
+++ /dev/null
@@ -1,448 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2005 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio 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 3, or (at your option)
-# any later version.
-#
-# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-#
-
-"""
-Handler for Griffin PowerMate, Contour ShuttlePro & ShuttleXpress USB knobs
-
-This is Linux and wxPython specific.
-"""
-
-import os
-import sys
-import struct
-import exceptions
-import threading
-import wx
-from gnuradio import gru
-
-imported_ok = True
-
-try:
- import select
- import fcntl
-except ImportError:
- imported_ok = False
-
-
-# First a little bit of background:
-#
-# The Griffin PowerMate has
-# * a single knob which rotates
-# * a single button (pressing the knob)
-#
-# The Contour ShuttleXpress (aka SpaceShuttle) has
-# * "Jog Wheel" -- the knob (rotary encoder) on the inside
-# * "Shuttle Ring" -- the spring loaded rubber covered ring
-# * 5 buttons
-#
-# The Contour ShuttlePro has
-# * "Jog Wheel" -- the knob (rotary encoder) on the inside
-# * "Shuttle Ring" -- the spring loaded rubber covered ring
-# * 13 buttons
-#
-# The Contour ShuttlePro V2 has
-# *"Jog Wheel" -- the knob (rotary encoder) on the inside
-# * "Shuttle Ring" -- the spring loaded rubber covered ring
-# * 15 buttons
-
-# We remap all the buttons on the devices so that they start at zero.
-
-# For the ShuttleXpress the buttons are 0 to 4 (left to right)
-
-# For the ShuttlePro, we number the buttons immediately above
-# the ring 0 to 4 (left to right) so that they match our numbering
-# on the ShuttleXpress. The top row is 5, 6, 7, 8. The first row below
-# the ring is 9, 10, and the bottom row is 11, 12.
-
-# For the ShuttlePro V2, buttons 13 & 14 are to the
-# left and right of the wheel respectively.
-
-# We generate 3 kinds of events:
-#
-# button press/release (button_number, press/release)
-# knob rotation (relative_clicks) # typically -1, +1
-# shuttle position (absolute_position) # -7,-6,...,0,...,6,7
-
-# ----------------------------------------------------------------
-# Our ID's for the devices:
-# Not to be confused with anything related to magic hardware numbers.
-
-ID_POWERMATE = 'powermate'
-ID_SHUTTLE_XPRESS = 'shuttle xpress'
-ID_SHUTTLE_PRO = 'shuttle pro'
-ID_SHUTTLE_PRO_V2 = 'shuttle pro v2'
-
-# ------------------------------------------------------------------------
-# format of messages that we read from /dev/input/event*
-# See /usr/include/linux/input.h for more info
-#
-#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)
-
-# ------------------------------------------------------------------------
-# input_event types
-# ------------------------------------------------------------------------
-
-IET_SYN = 0x00 # aka RESET
-IET_KEY = 0x01 # key or button press/release
-IET_REL = 0x02 # relative movement (knob rotation)
-IET_ABS = 0x03 # absolute position (graphics pad, etc)
-IET_MSC = 0x04
-IET_LED = 0x11
-IET_SND = 0x12
-IET_REP = 0x14
-IET_FF = 0x15
-IET_PWR = 0x16
-IET_FF_STATUS = 0x17
-IET_MAX = 0x1f
-
-# ------------------------------------------------------------------------
-# input_event codes (there are a zillion of them, we only define a few)
-# ------------------------------------------------------------------------
-
-# these are valid for IET_KEY
-
-IEC_BTN_0 = 0x100
-IEC_BTN_1 = 0x101
-IEC_BTN_2 = 0x102
-IEC_BTN_3 = 0x103
-IEC_BTN_4 = 0x104
-IEC_BTN_5 = 0x105
-IEC_BTN_6 = 0x106
-IEC_BTN_7 = 0x107
-IEC_BTN_8 = 0x108
-IEC_BTN_9 = 0x109
-IEC_BTN_10 = 0x10a
-IEC_BTN_11 = 0x10b
-IEC_BTN_12 = 0x10c
-IEC_BTN_13 = 0x10d
-IEC_BTN_14 = 0x10e
-IEC_BTN_15 = 0x10f
-
-# these are valid for IET_REL (Relative axes)
-
-IEC_REL_X = 0x00
-IEC_REL_Y = 0x01
-IEC_REL_Z = 0x02
-IEC_REL_HWHEEL = 0x06
-IEC_REL_DIAL = 0x07 # rotating the knob
-IEC_REL_WHEEL = 0x08 # moving the shuttle ring
-IEC_REL_MISC = 0x09
-IEC_REL_MAX = 0x0f
-
-# ------------------------------------------------------------------------
-
-class powermate(threading.Thread):
- """
- Interface to Griffin PowerMate and Contour Shuttles
- """
- def __init__(self, event_receiver=None, filename=None, **kwargs):
- self.event_receiver = event_receiver
- self.handle = -1
- if not imported_ok:
- raise exceptions.RuntimeError, 'powermate not supported on this platform'
-
- if filename:
- if not self._open_device(filename):
- raise exceptions.RuntimeError, 'Unable to find powermate'
- else:
- ok = False
- for d in range(0, 16):
- if self._open_device("/dev/input/event%d" % d):
- ok = True
- break
- if not ok:
- raise exceptions.RuntimeError, 'Unable to find powermate'
-
- threading.Thread.__init__(self, **kwargs)
- self.setDaemon (1)
- self.keep_running = True
- self.start ()
-
- def __del__(self):
- self.keep_running = False
- if self.handle >= 0:
- os.close(self.handle)
- self.handle = -1
-
- def _open_device(self, filename):
- try:
- self.handle = os.open(filename, os.O_RDWR)
- if self.handle < 0:
- return False
-
- # read event device name
- name = fcntl.ioctl(self.handle, gru.hexint(0x80ff4506), chr(0) * 256)
- name = name.replace(chr(0), '')
-
- # do we see anything we recognize?
- if name == 'Griffin PowerMate' or name == 'Griffin SoundKnob':
- self.id = ID_POWERMATE
- self.mapper = _powermate_remapper()
- elif name == 'CAVS SpaceShuttle A/V' or name == 'Contour Design ShuttleXpress':
- self.id = ID_SHUTTLE_XPRESS
- self.mapper = _contour_remapper()
- elif name == 'Contour Design ShuttlePRO':
- self.id = ID_SHUTTLE_PRO
- self.mapper = _contour_remapper()
- elif name == 'Contour Design ShuttlePRO v2':
- self.id = ID_SHUTTLE_PRO_V2
- self.mapper = _contour_remapper()
- else:
- os.close(self.handle)
- self.handle = -1
- return False
-
- # get exclusive control of the device, using ioctl EVIOCGRAB
- # there may be an issue with this on non x86 platforms and if
- # the _IOW,_IOC,... macros in <asm/ioctl.h> are changed
- fcntl.ioctl(self.handle,gru.hexint(0x40044590), 1)
- return True
- except exceptions.OSError:
- return False
-
-
- def set_event_receiver(self, obj):
- self.event_receiver = obj
-
-
- def set_led_state(self, static_brightness, pulse_speed=0,
- pulse_table=0, pulse_on_sleep=0, pulse_on_wake=0):
- """
- What do these magic values mean...
- """
- if self.id != ID_POWERMATE:
- return False
-
- 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)
- return True
-
- def run (self):
- while (self.keep_running):
- s = os.read (self.handle, input_event_size)
- if not s:
- self.keep_running = False
- break
-
- raw_input_event = struct.unpack(input_event_struct,s)
- sec, usec, type, code, val = self.mapper(raw_input_event)
-
- if self.event_receiver is None:
- continue
-
- if type == IET_SYN: # ignore
- pass
- elif type == IET_MSC: # ignore (seems to be PowerMate reporting led brightness)
- pass
- elif type == IET_REL and code == IEC_REL_DIAL:
- #print "Dial: %d" % (val,)
- wx.PostEvent(self.event_receiver, PMRotateEvent(val))
- elif type == IET_REL and code == IEC_REL_WHEEL:
- #print "Shuttle: %d" % (val,)
- wx.PostEvent(self.event_receiver, PMShuttleEvent(val))
- elif type == IET_KEY:
- #print "Key: Btn%d %d" % (code - IEC_BTN_0, val)
- wx.PostEvent(self.event_receiver,
- PMButtonEvent(code - IEC_BTN_0, val))
- else:
- print "powermate: unrecognized event: type = 0x%x code = 0x%x val = %d" % (type, code, val)
-
-
-class _powermate_remapper(object):
- def __init__(self):
- pass
- def __call__(self, event):
- """
- Notice how nice and simple this is...
- """
- return event
-
-class _contour_remapper(object):
- def __init__(self):
- self.prev = None
- def __call__(self, event):
- """
- ...and how screwed up this is
- """
- sec, usec, type, code, val = event
- if type == IET_REL and code == IEC_REL_WHEEL:
- # === Shuttle ring ===
- # First off, this really ought to be IET_ABS, not IET_REL!
- # They never generate a zero value so you can't
- # tell when the shuttle ring is back in the center.
- # We kludge around this by calling both -1 and 1 zero.
- if val == -1 or val == 1:
- return (sec, usec, type, code, 0)
- return event
-
- if type == IET_REL and code == IEC_REL_DIAL:
- # === Jog knob (rotary encoder) ===
- # Dim wits got it wrong again! This one should return a
- # a relative value, e.g., -1, +1. Instead they return
- # a total that runs modulo 256 (almost!). For some
- # reason they count like this 253, 254, 255, 1, 2, 3
-
- if self.prev is None: # first time call
- self.prev = val
- return (sec, usec, IET_SYN, 0, 0) # will be ignored above
-
- diff = val - self.prev
- if diff == 0: # sometimes it just sends stuff...
- return (sec, usec, IET_SYN, 0, 0) # will be ignored above
-
- if abs(diff) > 100: # crossed into the twilight zone
- if self.prev > val: # we've wrapped going forward
- self.prev = val
- return (sec, usec, type, code, +1)
- else: # we've wrapped going backward
- self.prev = val
- return (sec, usec, type, code, -1)
-
- self.prev = val
- return (sec, usec, type, code, diff)
-
- if type == IET_KEY:
- # remap keys so that all 3 gadgets have buttons 0 to 4 in common
- return (sec, usec, type,
- (IEC_BTN_5, IEC_BTN_6, IEC_BTN_7, IEC_BTN_8,
- IEC_BTN_0, IEC_BTN_1, IEC_BTN_2, IEC_BTN_3, IEC_BTN_4,
- IEC_BTN_9, IEC_BTN_10,
- IEC_BTN_11, IEC_BTN_12,
- IEC_BTN_13, IEC_BTN_14)[code - IEC_BTN_0], val)
-
- return event
-
-# ------------------------------------------------------------------------
-# new wxPython event classes
-# ------------------------------------------------------------------------
-
-grEVT_POWERMATE_BUTTON = wx.NewEventType()
-grEVT_POWERMATE_ROTATE = wx.NewEventType()
-grEVT_POWERMATE_SHUTTLE = wx.NewEventType()
-
-EVT_POWERMATE_BUTTON = wx.PyEventBinder(grEVT_POWERMATE_BUTTON, 0)
-EVT_POWERMATE_ROTATE = wx.PyEventBinder(grEVT_POWERMATE_ROTATE, 0)
-EVT_POWERMATE_SHUTTLE = wx.PyEventBinder(grEVT_POWERMATE_SHUTTLE, 0)
-
-class PMButtonEvent(wx.PyEvent):
- def __init__(self, button, value):
- wx.PyEvent.__init__(self)
- self.SetEventType(grEVT_POWERMATE_BUTTON)
- self.button = button
- self.value = value
-
- def Clone (self):
- self.__class__(self.GetId())
-
-
-class PMRotateEvent(wx.PyEvent):
- def __init__(self, delta):
- wx.PyEvent.__init__(self)
- self.SetEventType (grEVT_POWERMATE_ROTATE)
- self.delta = delta
-
- def Clone (self):
- self.__class__(self.GetId())
-
-
-class PMShuttleEvent(wx.PyEvent):
- def __init__(self, position):
- wx.PyEvent.__init__(self)
- self.SetEventType (grEVT_POWERMATE_SHUTTLE)
- self.position = position
-
- def Clone (self):
- self.__class__(self.GetId())
-
-# ------------------------------------------------------------------------
-# Example usage
-# ------------------------------------------------------------------------
-
-if __name__ == '__main__':
- class Frame(wx.Frame):
- def __init__(self,parent=None,id=-1,title='Title',
- pos=wx.DefaultPosition, size=(400,200)):
- wx.Frame.__init__(self,parent,id,title,pos,size)
- EVT_POWERMATE_BUTTON(self, self.on_button)
- EVT_POWERMATE_ROTATE(self, self.on_rotate)
- EVT_POWERMATE_SHUTTLE(self, self.on_shuttle)
- self.brightness = 128
- self.pulse_speed = 0
-
- try:
- self.pm = powermate(self)
- except:
- sys.stderr.write("Unable to find PowerMate or Contour Shuttle\n")
- sys.exit(1)
-
- self.pm.set_led_state(self.brightness, self.pulse_speed)
-
-
- def on_button(self, evt):
- print "Button %d %s" % (evt.button,
- ("Released", "Pressed")[evt.value])
-
- def on_rotate(self, evt):
- print "Rotated %d" % (evt.delta,)
- if 0:
- new = max(0, min(255, self.brightness + evt.delta))
- if new != self.brightness:
- self.brightness = new
- self.pm.set_led_state(self.brightness, self.pulse_speed)
-
- def on_shuttle(self, evt):
- print "Shuttle %d" % (evt.position,)
-
- class App(wx.App):
- def OnInit(self):
- title='PowerMate Demo'
- self.frame = Frame(parent=None,id=-1,title=title)
- self.frame.Show()
- self.SetTopWindow(self.frame)
- return True
-
- app = App()
- app.MainLoop ()