34 from __future__
import print_function
35 from bluetooth
import *
44 L2CAP_PSM_HIDP_CTRL = 17
45 L2CAP_PSM_HIDP_INTR = 19
46 inactivity_timout_string =
"--inactivity-timeout"
47 no_disable_bluetoothd_string =
"--no-disable-bluetoothd"
48 redirect_output_string =
"--redirect-output"
49 continuous_motion_output_string =
"--continuous-output"
62 for name
in [
"/dev/input/uinput",
"/dev/misc/uinput",
"/dev/uinput"]:
64 return os.open(name, os.O_WRONLY)
66 except Exception
as e:
70 def __init__(self, buttons, axes, axmin, axmax, axfuzz, axflat):
73 print(
"Trying to modprobe uinput.", file=sys.stderr)
74 os.system(
"modprobe uinput > /dev/null 2>&1")
78 print(
"Can't open uinput device. Is it accessible by this user? "
79 "Did you mean to run as root?", file=sys.stderr)
82 UI_SET_EVBIT = 0x40045564
83 UI_SET_KEYBIT = 0x40045565
84 UI_SET_RELBIT = 0x40045566
85 UI_DEV_CREATE = 0x5501
86 UI_SET_RELBIT = 0x40045566
87 UI_SET_ABSBIT = 0x40045567
88 uinput_user_dev =
"80sHHHHi" + (uinput.ABS_MAX+1)*4*
'i'
90 if len(axes) != len(axmin)
or len(axes) != len(axmax):
91 raise Exception(
"uinputjoy.__init__: axes, axmin and axmax should have same length")
93 absmin = [0] * (uinput.ABS_MAX+1)
94 absmax = [0] * (uinput.ABS_MAX+1)
95 absfuzz = [2] * (uinput.ABS_MAX+1)
96 absflat = [4] * (uinput.ABS_MAX+1)
97 for i
in range(0, len(axes)):
98 absmin[axes[i]] = axmin[i]
99 absmax[axes[i]] = axmax[i]
100 absfuzz[axes[i]] = axfuzz[i]
101 absflat[axes[i]] = axflat[i]
104 struct.pack(uinput_user_dev,
"Sony Playstation SixAxis/DS3",
105 uinput.BUS_USB, 0x054C, 0x0268, 0, 0, *(absmax + absmin + absfuzz + absflat)))
107 fcntl.ioctl(self.
file, UI_SET_EVBIT, uinput.EV_KEY)
110 fcntl.ioctl(self.
file, UI_SET_KEYBIT, b)
113 fcntl.ioctl(self.
file, UI_SET_EVBIT, uinput.EV_ABS)
114 fcntl.ioctl(self.
file, UI_SET_ABSBIT, a)
116 fcntl.ioctl(self.
file, UI_DEV_CREATE)
118 self.
value = [
None] * (len(buttons) + len(axes))
119 self.
type = [uinput.EV_KEY] * len(buttons) + [uinput.EV_ABS] * len(axes)
123 input_event =
"LLHHi"
126 tl = int((t - th) * 1000000)
127 if len(value) != len(self.
value):
128 print(
"Unexpected length for value in update (%i instead of %i). "
129 "This is a bug." % (len(value), len(self.
value)), file=sys.stderr)
130 for i
in range(0, len(value)):
131 if value[i] != self.
value[i]:
132 os.write(self.
file, struct.pack(input_event, th, tl, self.
type[i], self.
code[i], value[i]))
133 self.
value = list(value)
138 Exception.__init__(self,
"Unsupported joystick.")
142 def __init__(self, inactivity_timeout=float(1e3000), continuous_motion_output=
False):
154 buttons = range(0x100, 0x111)
160 for i
in range(-4, 0):
164 if continuous_motion_output:
167 for i
in range(4, len(axmin)-4):
170 self.
axmid = [sum(pair)/2
for pair
in zip(axmin, axmax)]
180 if len(rawdata) == 50:
181 joy_coding =
"!1B2x3B1x4B4x12B15x4H"
182 data = list(struct.unpack(joy_coding, rawdata))
185 print(
"Unexpected prefix (%i). Is this a PS3 Dual Shock or Six Axis?" % prefix, file=sys.stderr)
188 for j
in range(0, 2):
189 curbyte = data.pop(0)
190 for k
in range(0, 8):
191 out.append(int((curbyte & (1 << k)) != 0))
195 abs(out[17:][i] - self.
axmid[i]) > 20
for i
in range(0, len(out)-17-4)
197 if any(out[0:17])
or any(axis_motion):
200 elif len(rawdata) == 13:
201 print(
"Your bluetooth adapter is not supported. "
202 "Does it support Bluetooth 2.0?", file=sys.stderr)
205 print(
"Unexpected packet length (%i). "
206 "Is this a PS3 Dual Shock or Six Axis?" % len(rawdata), file=sys.stderr)
210 self.
joy.update([0] * 17 + self.
axmid)
212 def run(self, intr, ctrl):
216 lastactivitytime = lastvalidtime = time.time()
218 (rd, wr, err) = select.select([intr], [], [], 0.1)
219 curtime = time.time()
220 if len(rd) + len(wr) + len(err) == 0:
221 ctrl.send(
"\x53\xf4\x42\x03\x00\x00")
224 print(
"Connection activated")
227 rawdata = intr.recv(128)
228 except BluetoothError
as s:
229 print(
"Got Bluetooth error %s. Disconnecting." % s)
231 if len(rawdata) == 0:
232 print(
"Joystick shut down the connection, battery may be discharged.")
234 stepout = self.
step(rawdata)
236 lastvalidtime = curtime
238 lastactivitytime = curtime
240 print(
"Joystick inactive for %.0f seconds. "
243 if curtime - lastvalidtime >= 0.1:
246 if curtime - lastvalidtime >= 5:
248 print(
"No valid data for 5 seconds. Disconnecting. "
249 "This should not happen, please report it.")
258 Exception.__init__(self)
264 proc = subprocess.Popen([
'hciconfig'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
265 (out, err) = proc.communicate()
266 if out.find(
'UP') == -1:
267 os.system(
"hciconfig hci0 up > /dev/null 2>&1")
268 if out.find(
'PSCAN') == -1:
269 os.system(
"hciconfig hci0 pscan > /dev/null 2>&1")
278 sock = BluetoothSocket(L2CAP)
282 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
289 sock.bind((
"", port))
290 except Exception
as e:
293 print(
"Error binding to socket, will retry every 5 seconds. "
294 "Do you have another ps3joy.py running? This error occurs on "
295 "some distributions (such as Ubuntu Karmic). "
296 "Please read http://www.ros.org/wiki/ps3joy/Troubleshooting for solutions.",
307 self.
listen(intr_sock, ctrl_sock)
312 self.
listen(intr_sock, ctrl_sock)
317 print(
"Waiting for connection. Disconnect your PS3 joystick from USB and press the pairing button.")
319 intr_sock.settimeout(5)
320 ctrl_sock.settimeout(1)
323 (intr, (idev, iport)) = intr_sock.accept()
325 except Exception
as e:
326 if str(e) ==
'timed out':
333 (ctrl, (cdev, cport)) = ctrl_sock.accept()
334 except Exception
as e:
335 print(
"Got interrupt connection without control connection. Giving up on it.", file=sys.stderr)
340 print(
"Connection terminated.")
342 print(
"Simultaneous connection from two different devices. Ignoring both.", file=sys.stderr)
347 except BadJoystickException:
349 except KeyboardInterrupt:
350 print(
"CTRL+C detected. Exiting.")
352 except Exception
as e:
353 traceback.print_exc()
354 print(
"Caught exception: %s" % str(e), file=sys.stderr)
360 print(
"usage: ps3joy.py [" + inactivity_timout_string +
"=<n>] [" + no_disable_bluetoothd_string +
"] "
361 "[" + redirect_output_string +
"] [" + continuous_motion_output_string +
"]=<f>")
362 print(
"<n>: inactivity timeout in seconds (saves battery life).")
363 print(
"<f>: file name to redirect output to.")
364 print(
"Unless "+no_disable_bluetoothd_string+
" is specified, bluetoothd will be stopped.")
369 if not arg.startswith(prefix):
371 if not arg.startswith(prefix+
"="):
372 print(
"Expected '=' after "+prefix)
378 if __name__ ==
"__main__":
384 args = [
'sudo', sys.executable] + sys.argv + [os.environ]
385 os.execlpe(
'sudo', *args)
387 raise SystemExit(
"Root Privlages Required.")
389 inactivity_timeout = float(1e3000)
390 disable_bluetoothd =
True
391 continuous_output =
False
393 for arg
in sys.argv[1:]:
397 str_value = arg[len(inactivity_timout_string)+1:]
399 inactivity_timeout = float(str_value)
400 if inactivity_timeout < 0:
401 print(
"Inactivity timeout must be positive.")
405 print(
"Error parsing inactivity timeout: " + str_value)
408 elif arg == no_disable_bluetoothd_string:
409 disable_bluetoothd =
False
410 elif arg == continuous_motion_output_string:
411 continuous_output =
True
413 str_value = arg[len(redirect_output_string) + 1:]
415 print(
"Redirecting output to:", str_value)
416 sys.stdout = open(str_value,
"a", 1)
418 print(
"Error opening file to redirect output:", str_value)
420 sys.stderr = sys.stdout
422 print(
"Ignoring parameter: '%s'" % arg)
424 if disable_bluetoothd:
425 os.system(
"/etc/init.d/bluetooth stop > /dev/null 2>&1")
428 while os.system(
"hciconfig hci0 > /dev/null 2>&1") != 0:
429 print(
"No bluetooth dongle found or bluez rosdep not installed. Will retry in 5 seconds.",
432 if inactivity_timeout == float(1e3000):
433 print(
"No inactivity timeout was set. (Run with --help for details.)")
435 print(
"Inactivity timeout set to %.0f seconds." % inactivity_timeout)
437 continuous_motion_output=continuous_output))
438 cm.listen_bluetooth()
440 if disable_bluetoothd:
441 os.system(
"/etc/init.d/bluetooth start > /dev/null 2>&1")
443 errorcode = e.errorcode
444 except KeyboardInterrupt:
445 print(
"CTRL+C detected. Exiting.")