diff options
author | elupus <elupus@xbmc.org> | 2011-10-24 22:19:57 +0200 |
---|---|---|
committer | elupus <elupus@xbmc.org> | 2011-10-24 22:33:13 +0200 |
commit | 5d01bfccc256cd657eb8cd95dc956bc4db852789 (patch) | |
tree | d21454424685e6beb2ffd836759a2607deff1746 /tools | |
parent | e59804fccbc7de01afce08f87b4dae31ff0f2e44 (diff) |
Move all of the sixaxis code into the sixaxis "lib"
Diffstat (limited to 'tools')
-rwxr-xr-x | tools/EventClients/Clients/PS3 Sixaxis Controller/ps3d.py | 99 | ||||
-rw-r--r-- | tools/EventClients/lib/python/ps3/keymaps.py | 54 | ||||
-rw-r--r-- | tools/EventClients/lib/python/ps3/sixaxis.py | 232 |
3 files changed, 192 insertions, 193 deletions
diff --git a/tools/EventClients/Clients/PS3 Sixaxis Controller/ps3d.py b/tools/EventClients/Clients/PS3 Sixaxis Controller/ps3d.py index 0000163aa9..dfc2c11fd5 100755 --- a/tools/EventClients/Clients/PS3 Sixaxis Controller/ps3d.py +++ b/tools/EventClients/Clients/PS3 Sixaxis Controller/ps3d.py @@ -22,30 +22,27 @@ import traceback import time import struct import threading +import os -sys.path.append("../PS3 BD Remote") - -try: - # try loading modules from source directory +if os.path.exists("../../lib/python"): + sys.path.append("../PS3 BD Remote") sys.path.append("../../lib/python") from bt.hid import HID from bt.bt import bt_lookup_name from xbmcclient import XBMCClient from ps3 import sixaxis - from ps3.keymaps import keymap_sixaxis from ps3_remote import process_keys as process_remote try: import zeroconf except: zeroconf = None ICON_PATH = "../../icons/" -except: +else: # fallback to system wide modules from xbmc.bt.hid import HID from xbmc.bt.bt import bt_lookup_name from xbmc.xbmcclient import XBMCClient from xbmc.ps3 import sixaxis - from xbmc.ps3.keymaps import keymap_sixaxis from xbmc.ps3_remote import process_keys as process_remote from xbmc.defs import * try: @@ -110,21 +107,6 @@ class StoppableThread ( threading.Thread ): else: return False -# to make sure all combination keys are checked first -# we sort the keymap's button codes in reverse order -# this guranties that any bit combined button code -# will be processed first -keymap_sixaxis_keys = keymap_sixaxis.keys() -keymap_sixaxis_keys.sort() -keymap_sixaxis_keys.reverse() - -def getkeys(bflags): - keys = []; - for k in keymap_sixaxis_keys: - if (k & bflags) == k: - keys.append(k) - bflags = bflags & ~k - return keys; class PS3SixaxisThread ( StoppableThread ): def __init__(self, csock, isock, ipaddr="127.0.0.1"): @@ -135,86 +117,26 @@ class PS3SixaxisThread ( StoppableThread ): self.set_timeout(600) def run(self): - sixaxis.initialize(self.csock, self.isock) + six = sixaxis.sixaxis(self.xbmc, self.csock, self.isock) self.xbmc.connect() - bflags = 0 - released = set() - pressed = set() - pending = set() - held = set() - psflags = 0 - psdown = 0 - toggle_mouse = 0 self.reset_timeout() try: while not self.stop(): - if self.timed_out(): - - for key in (held | pressed): - (mapname, action, amount, axis) = keymap_sixaxis[key] - self.xbmc.send_button_state(map=mapname, button=action, amount=0, down=0, axis=axis) + if self.timed_out(): raise Exception("PS3 Sixaxis powering off, timed out") if self.idle_time() > 50: self.xbmc.connect() try: - data = sixaxis.read_input(self.isock) + if six.process_socket(self.isock): + self.reset_timeout() except Exception, e: - print str(e) + print e break - if not data: - continue - - (bflags, psflags, pressure, analog) = sixaxis.process_input(data, self.xbmc, toggle_mouse) - - if analog: - self.reset_timeout() - - if psflags: - self.reset_timeout() - if psdown: - if (time.time() - psdown) > 5: - - for key in (held | pressed): - (mapname, action, amount, axis) = keymap_sixaxis[key] - self.xbmc.send_button_state(map=mapname, button=action, amount=0, down=0, axis=axis) - - raise Exception("PS3 Sixaxis powering off, user request") - else: - psdown = time.time() - else: - if psdown: - toggle_mouse = 1 - toggle_mouse - psdown = 0 - - keys = set(getkeys(bflags)) - released = (pressed | held) - keys - held = (pressed | held) - released - pressed = (keys - held) & pending - pending = (keys - held) - - for key in released: - (mapname, action, amount, axis) = keymap_sixaxis[key] - self.xbmc.send_button_state(map=mapname, button=action, amount=0, down=0, axis=axis) - - for key in held: - (mapname, action, amount, axis) = keymap_sixaxis[key] - if amount > 0: - amount = pressure[amount-1] * 256 - self.xbmc.send_button_state(map=mapname, button=action, amount=amount, down=1, axis=axis) - - for key in pressed: - (mapname, action, amount, axis) = keymap_sixaxis[key] - if amount > 0: - amount = pressure[amount-1] * 256 - self.xbmc.send_button_state(map=mapname, button=action, amount=amount, down=1, axis=axis) - - if keys: - self.reset_timeout() - except Exception, e: printerr() + six.close() self.close_sockets() @@ -229,7 +151,6 @@ class PS3RemoteThread ( StoppableThread ): self.current_xbmc = 0 def run(self): - sixaxis.initialize(self.csock, self.isock) self.xbmc.connect() try: # start the zeroconf thread if possible diff --git a/tools/EventClients/lib/python/ps3/keymaps.py b/tools/EventClients/lib/python/ps3/keymaps.py index fe2e8f9121..de7ee121c0 100644 --- a/tools/EventClients/lib/python/ps3/keymaps.py +++ b/tools/EventClients/lib/python/ps3/keymaps.py @@ -79,57 +79,3 @@ keymap_remote = { "39": 'pause' ,#PAUSE } - -SX_SQUARE = 32768 -SX_X = 16384 -SX_CIRCLE = 8192 -SX_TRIANGLE = 4096 -SX_R1 = 2048 -SX_R2 = 512 -SX_R3 = 4 -SX_L1 = 1024 -SX_L2 = 256 -SX_L3 = 2 -SX_DUP = 16 -SX_DDOWN = 64 -SX_DLEFT = 128 -SX_DRIGHT = 32 -SX_SELECT = 1 -SX_START = 8 - -SX_LSTICK_X = 0 -SX_LSTICK_Y = 1 -SX_RSTICK_X = 2 -SX_RSTICK_Y = 3 - -# (map, key, amount index, axis) -keymap_sixaxis = { - SX_X : ('XG', 'A', 0, 0), - SX_CIRCLE : ('XG', 'B', 0, 0), - SX_SQUARE : ('XG', 'X', 0, 0), - SX_TRIANGLE : ('XG', 'Y', 0, 0), - - SX_DUP : ('XG', 'dpadup', 0, 0), - SX_DDOWN : ('XG', 'dpaddown', 0, 0), - SX_DLEFT : ('XG', 'dpadleft', 0, 0), - SX_DRIGHT : ('XG', 'dpadright', 0, 0), - - SX_START : ('XG', 'start', 0, 0), - SX_SELECT : ('XG', 'back', 0, 0), - - SX_R1 : ('XG', 'white', 0, 0), - SX_R2 : ('XG', 'rightanalogtrigger', 6, 1), - SX_L2 : ('XG', 'leftanalogtrigger', 5, 1), - SX_L1 : ('XG', 'black', 0, 0), - - SX_L3 : ('XG', 'leftthumbbutton', 0, 0), - SX_R3 : ('XG', 'rightthumbbutton', 0, 0), -} - -# (data index, left map, left action, right map, right action) -axismap_sixaxis = { - SX_LSTICK_X : ('XG', 'leftthumbstickleft' , 'leftthumbstickright'), - SX_LSTICK_Y : ('XG', 'leftthumbstickup' , 'leftthumbstickdown'), - SX_RSTICK_X : ('XG', 'rightthumbstickleft', 'rightthumbstickright'), - SX_RSTICK_Y : ('XG', 'rightthumbstickup' , 'rightthumbstickdown'), -} diff --git a/tools/EventClients/lib/python/ps3/sixaxis.py b/tools/EventClients/lib/python/ps3/sixaxis.py index c3cacb6c09..c8f2d4f48d 100644 --- a/tools/EventClients/lib/python/ps3/sixaxis.py +++ b/tools/EventClients/lib/python/ps3/sixaxis.py @@ -23,16 +23,78 @@ import struct import math import binascii from bluetooth import set_l2cap_mtu -from keymaps import keymap_sixaxis -from keymaps import axismap_sixaxis -xval = 0 -yval = 0 -num_samples = 16 -sumx = [0] * num_samples -sumy = [0] * num_samples -sumr = [0] * num_samples -axis_amount = [0, 0, 0, 0] +SX_SELECT = 1 << 0 +SX_L3 = 1 << 1 +SX_R3 = 1 << 2 +SX_START = 1 << 3 +SX_DUP = 1 << 4 +SX_DRIGHT = 1 << 5 +SX_DDOWN = 1 << 6 +SX_DLEFT = 1 << 7 +SX_L2 = 1 << 8 +SX_R2 = 1 << 9 +SX_L1 = 1 << 10 +SX_R1 = 1 << 11 +SX_TRIANGLE = 1 << 12 +SX_CIRCLE = 1 << 13 +SX_X = 1 << 14 +SX_SQUARE = 1 << 15 +SX_POWER = 1 << 16 + +SX_LSTICK_X = 0 +SX_LSTICK_Y = 1 +SX_RSTICK_X = 2 +SX_RSTICK_Y = 3 + +# (map, key, amount index, axis) +keymap_sixaxis = { + SX_X : ('XG', 'A', 0, 0), + SX_CIRCLE : ('XG', 'B', 0, 0), + SX_SQUARE : ('XG', 'X', 0, 0), + SX_TRIANGLE : ('XG', 'Y', 0, 0), + + SX_DUP : ('XG', 'dpadup', 0, 0), + SX_DDOWN : ('XG', 'dpaddown', 0, 0), + SX_DLEFT : ('XG', 'dpadleft', 0, 0), + SX_DRIGHT : ('XG', 'dpadright', 0, 0), + + SX_START : ('XG', 'start', 0, 0), + SX_SELECT : ('XG', 'back', 0, 0), + + SX_R1 : ('XG', 'white', 0, 0), + SX_R2 : ('XG', 'rightanalogtrigger', 6, 1), + SX_L2 : ('XG', 'leftanalogtrigger', 5, 1), + SX_L1 : ('XG', 'black', 0, 0), + + SX_L3 : ('XG', 'leftthumbbutton', 0, 0), + SX_R3 : ('XG', 'rightthumbbutton', 0, 0), +} + +# (data index, left map, left action, right map, right action) +axismap_sixaxis = { + SX_LSTICK_X : ('XG', 'leftthumbstickleft' , 'leftthumbstickright'), + SX_LSTICK_Y : ('XG', 'leftthumbstickup' , 'leftthumbstickdown'), + SX_RSTICK_X : ('XG', 'rightthumbstickleft', 'rightthumbstickright'), + SX_RSTICK_Y : ('XG', 'rightthumbstickup' , 'rightthumbstickdown'), +} + +# to make sure all combination keys are checked first +# we sort the keymap's button codes in reverse order +# this guranties that any bit combined button code +# will be processed first +keymap_sixaxis_keys = keymap_sixaxis.keys() +keymap_sixaxis_keys.sort() +keymap_sixaxis_keys.reverse() + +def getkeys(bflags): + keys = []; + for k in keymap_sixaxis_keys: + if (k & bflags) == k: + keys.append(k) + bflags = bflags & ~k + return keys; + def normalize(val): upperlimit = 65281 @@ -80,16 +142,44 @@ def normalize_angle(val, valrange): val = -1.0 return (val + 0.5) * 65535.0 -def initialize(control_sock, interrupt_sock): +def average(array): + val = 0 + for i in array: + val += i + return val / len(array) + +def smooth(arr, val): + cnt = len(arr) + arr.insert(0, val) + arr.pop(cnt) + return average(arr) + +class sixaxis(): + def __init__(self, xbmc, control_sock, interrupt_sock): + + self.xbmc = xbmc + self.num_samples = 16 + self.sumx = [0] * self.num_samples + self.sumy = [0] * self.num_samples + self.sumr = [0] * self.num_samples + self.axis_amount = [0, 0, 0, 0] + + self.released = set() + self.pressed = set() + self.pending = set() + self.held = set() + self.psflags = 0 + self.psdown = 0 + self.mouse_enabled = 0 + + set_l2cap_mtu(control_sock, 64) + set_l2cap_mtu(interrupt_sock, 64) + time.sleep(0.25) # If we ask to quickly here, it sometimes doesn't start + # sixaxis needs this to enable it # 0x53 => HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE control_sock.send("\x53\xf4\x42\x03\x00\x00") - time.sleep(0.25) data = control_sock.recv(1) - - set_l2cap_mtu(control_sock, 64) - set_l2cap_mtu(interrupt_sock, 64) - # This command will turn on the gyro and set the leds # I wonder if turning on the gyro makes it draw more current?? # it's probably a flag somewhere in the following command @@ -116,24 +206,34 @@ def initialize(control_sock, interrupt_sock): bytes.extend([0x00, 0x00, 0x00, 0x00, 0x00]) control_sock.send(struct.pack("42B", *bytes)) - time.sleep(0.25) data = control_sock.recv(1) + def __del__(self): + self.close() - return data + def close(self): + for key in (self.held | self.pressed): + (mapname, action, amount, axis) = keymap_sixaxis[key] + self.xbmc.send_button_state(map=mapname, button=action, amount=0, down=0, axis=axis) + self.held = set() + self.pressed = set() -def read_input(isock): - return isock.recv(50) + def process_socket(self, isock): + data = isock.recv(50) + if data == None: + return False + return self.process_data(data) -def process_input(data, xbmc=None, mouse_enabled=0): + + def process_data(self, data): if len(data) < 3: - return (0, 0, 0, False) + return False # make sure this is the correct report if struct.unpack("BBB", data[0:3]) != (0xa1, 0x01, 0x00): - return (0, 0, 0, False) + return False if len(data) >= 48: v1 = struct.unpack("h", data[42:44]) @@ -155,8 +255,7 @@ def process_input(data, xbmc=None, mouse_enabled=0): rz = float(v4[0]) at = math.sqrt(ax*ax + ay*ay + az*az) - bflags = struct.unpack("H", data[3:5])[0] - psflags = struct.unpack("B", data[5:6])[0] + bflags = struct.unpack("<I", data[3:7])[0] if len(data) > 27: pressure = struct.unpack("BBBBBBBBBBBB", data[15:27]) else: @@ -169,39 +268,72 @@ def process_input(data, xbmc=None, mouse_enabled=0): xpos = normalize_angle(roll, math.radians(30)) ypos = normalize_angle(pitch, math.radians(30)) + - # update our sliding window array - sumx.insert(0, xpos) - sumy.insert(0, ypos) - sumx.pop(num_samples) - sumy.pop(num_samples) + axis = struct.unpack("BBBB", data[7:11]) + return self.process_input(bflags, pressure, axis, xpos, ypos) - # reset average - xval = 0 - yval = 0 + def process_input(self, bflags, pressure, axis, xpos, ypos): - # do a sliding window average to remove high frequency - # noise in accelerometer sampling - for i in range(0, num_samples): - xval += sumx[i] - yval += sumy[i] + xval = smooth(self.sumx, xpos) + yval = smooth(self.sumy, ypos) analog = False - axis = struct.unpack("BBBB", data[7:11]) - if xbmc: - for i in range(4): + for i in range(4): config = axismap_sixaxis[i] - axis_amount[i] = send_singleaxis(xbmc, axis[i], axis_amount[i], config[0], config[1], config[2]) - if axis_amount[i] != 0: - analog = True + self.axis_amount[i] = self.send_singleaxis(axis[i], self.axis_amount[i], config[0], config[1], config[2]) + if self.axis_amount[i] != 0: + analog = True + + # send the mouse position to xbmc + if self.mouse_enabled == 1: + self.xbmc.send_mouse_position(xval, yval) - # send the mouse position to xbmc - if mouse_enabled == 1: - xbmc.send_mouse_position(xval/num_samples, yval/num_samples) + if (bflags & SX_POWER) == SX_POWER: + if self.psdown: + if (time.time() - self.psdown) > 5: + + for key in (self.held | self.pressed): + (mapname, action, amount, axis) = keymap_sixaxis[key] + self.xbmc.send_button_state(map=mapname, button=action, amount=0, down=0, axis=axis) + + raise Exception("PS3 Sixaxis powering off, user request") + else: + self.psdown = time.time() + else: + if self.psdown: + self.mouse_enabled = 1 - self.mouse_enabled + self.psdown = 0 + + keys = set(getkeys(bflags)) + self.released = (self.pressed | self.held) - keys + self.held = (self.pressed | self.held) - self.released + self.pressed = (keys - self.held) & self.pending + self.pending = (keys - self.held) + + for key in self.released: + (mapname, action, amount, axis) = keymap_sixaxis[key] + self.xbmc.send_button_state(map=mapname, button=action, amount=0, down=0, axis=axis) + + for key in self.held: + (mapname, action, amount, axis) = keymap_sixaxis[key] + if amount > 0: + amount = pressure[amount-1] * 256 + self.xbmc.send_button_state(map=mapname, button=action, amount=amount, down=1, axis=axis) + + for key in self.pressed: + (mapname, action, amount, axis) = keymap_sixaxis[key] + if amount > 0: + amount = pressure[amount-1] * 256 + self.xbmc.send_button_state(map=mapname, button=action, amount=amount, down=1, axis=axis) + + if analog or keys or self.mouse_enabled: + return True + else: + return False - return (bflags, psflags, pressure, analog) -def send_singleaxis(xbmc, axis, last_amount, mapname, action_min, action_pos): + def send_singleaxis(self, axis, last_amount, mapname, action_min, action_pos): amount = normalize_axis(axis, 0.30) if last_amount < 0: last_action = action_min @@ -218,9 +350,9 @@ def send_singleaxis(xbmc, axis, last_amount, mapname, action_min, action_pos): new_action = None if last_action and new_action != last_action: - xbmc.send_button_state(map=mapname, button=last_action, amount=0, axis=1) + self.xbmc.send_button_state(map=mapname, button=last_action, amount=0, axis=1) if new_action and amount != last_amount: - xbmc.send_button_state(map=mapname, button=new_action, amount=abs(amount), axis=1) + self.xbmc.send_button_state(map=mapname, button=new_action, amount=abs(amount), axis=1) return amount |