aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorelupus <elupus@xbmc.org>2011-10-24 22:19:57 +0200
committerelupus <elupus@xbmc.org>2011-10-24 22:33:13 +0200
commit5d01bfccc256cd657eb8cd95dc956bc4db852789 (patch)
treed21454424685e6beb2ffd836759a2607deff1746 /tools
parente59804fccbc7de01afce08f87b4dae31ff0f2e44 (diff)
Move all of the sixaxis code into the sixaxis "lib"
Diffstat (limited to 'tools')
-rwxr-xr-xtools/EventClients/Clients/PS3 Sixaxis Controller/ps3d.py99
-rw-r--r--tools/EventClients/lib/python/ps3/keymaps.py54
-rw-r--r--tools/EventClients/lib/python/ps3/sixaxis.py232
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