Python driver
From WiiLi
A driver written in python for OSX.
I have long searched for a Wiiremote driver for OSX, accessable by python. All existing drivers and tools either do not support osx or don't have access to the nunchuck. So i decided to write one myself.
This driver was created for my bachelor project called riimod, a video of my installation can be found on: [1]
Contents |
[edit] Requirements
pygame (for the visual demo of the output)
[edit] Todo's
Testing...
Improve the demo
Port to other systems (windows/linux) (partially done, not much tested)
[edit] Sources of information
WMD driver
pywiimote
- (http://code.google.com/p/pywiimote/)
wiiwhiteboard
- (https://sourceforge.net/projects/wiiwhiteboard/)
- (especially the linux implementation)
Thanks to all of the ppl's who have worked on the above sources.
[edit] Hints
I have installed Osculator, which contains a kernel extension, which afaik helps connecting the wiimote (without this extension the connection often fails, you would have to disable/enable bluetooth to make it work again)
[edit] Sourcecode
# changelog
# 13.3.2008:
# - using a dialogue to select the wiimote
# 4.6.2008:
# - added some more info
# - new version upload to wiili.org
# ---
# by Reto Spoerri
# rspoerri (@) nouser.org (http://www.nouser.org)
# A Python Wii-Driver, supporting the Nunchuck for OSX
# ---
# ---
# License:
# Free to use and modify (as long as the credits/license remain) in non-commercial products.
# Contact the autor if planned to use/used in a commercial project.
# ---
# ---
# requirements:
# - lightblue
# ---
# ---
# implemented functions:
# - wiimote:
# - rumble
# - buttons
# - ir
# - multiple ir sensitivity modes
# - gravity
# - 12 of the 14 types of known package formats (not the interleaved ones)
# - gives infos about the unknown packages
# - nunchuck:
# - can be plugged/unplugged during runtime (not that obvious that this works :)
# - gravity
# - buttons
# - joystick
# ---
# ---
# known limitations:
# SCRIPT:
# - this script should be called 100times per second
# - only the last received package data will be stored
# - all other packages will be handled, but unavailable as there is not history in data
# - if it's not called 100times per second it will usually work fine as well
# you will just have missed some packages data
# - not sure if all calibration data from the wiimote are handled correctly
# OPERATING SYSTEMS:
# - WINDOWS:
# - you will need a bluetooth stack from a different manufacturer (bluetooth stick)
# - WIDCOMM should work (lightblue only supports widcom afaik)
# - tested badely
# - OSX:
# - check the hardware limitations if using multiple wiimotes
# - tested quite well
# - Linux:
# - tested a little bit
# - there are some differences between the implementations:
# - only osx gives a dialogue if not mac address is specified for your wiimote
# (also this feature was not checked since a while)
# HARDWARE:
# - If using multiple wiimotes with this library check your bluetooth hardware
# - it may result in lags...
# - i have made bad exeperience with a usb1.0 bluetooth sticks
# - i have made good experience with macbook pro / mac pro internal bluetooth hardware
# ---
# ---
# example programm:
# ---
# requirements:
# - pygame (for the demo)
# ---
# usage:
# - change the wiimote mac address in the code (look for the string at the end of this file)
# - to get your wiimotes mac address you can use lightblue (lightblue.finddevices())
# - run it by calling this script
# edit the ir-sensitivity:
# - '+' and '-' buttons on the wiimote
# ---
import os
import sys
import time
import atexit
import socket
from collections import deque
SIGNAL_RUMBLE = 0x01
SIGNAL_LED1 = 0x10
SIGNAL_LED2 = 0x20
SIGNAL_LED3 = 0x40
SIGNAL_LED4 = 0x80
# Wiimote output commands
OutputReportNone = 0x00
OutputReportLEDs = 0x11
OutputReportType = 0x12
OutputReportIR = 0x13
OutputReportSpeaker = 0x14
OutputReportStatus = 0x15
OutputReportWriteMemory = 0x16
OutputReportReadMemory = 0x17
OutputReportSpeakerData = 0x18
OutputReportSpeakerMute = 0x19
OutputReportIR2 = 0x1a
# Wiimote registers
REGISTER_IR = 0x04b00030
REGISTER_IR_SENSITIVITY_1 = 0x04b00000
REGISTER_IR_SENSITIVITY_2 = 0x04b0001a
REGISTER_IR_MODE = 0x04b00033
REGISTER_EXTENSION_INIT = 0x04a40040
REGISTER_EXTENSION_TYPE = 0x04a400fe
REGISTER_EXTENSION_CALIBRATION = 0x04a40020
# Extension Types
ExtensionTypeNone = 0x00
ExtensionTypeNunchuk = 0xfe
ExtensionTypeClassicController = 0xfd
# IR modes
IrModeOff = 0x00
IrModeBasic = 0x01 # 10 bytes
IrModeExtended = 0x03 # 12 bytes
IrModeFull = 0x05 # 16 bytes * 2 (format unknown)
SIGNAL_IR_SENSITIVITY = {
# [address, data, dataLength] (if possible dont use heading 0x00's (it might not work), 0x12 is ok)
'lvl1' : [ [REGISTER_IR_SENSITIVITY_1, 0x0200007101006400fe, 9], [REGISTER_IR_SENSITIVITY_2, 0xfd05, 2] ] # lvl 1
, 'lvl2' : [ [REGISTER_IR_SENSITIVITY_1, 0x0200007101009600b4, 9], [REGISTER_IR_SENSITIVITY_2, 0xb304, 2] ] # lvl 2
, 'lvl3' : [ [REGISTER_IR_SENSITIVITY_1, 0x020000710100aa0064, 9], [REGISTER_IR_SENSITIVITY_2, 0x6303, 2] ] # lvl 3
, 'lvl4' : [ [REGISTER_IR_SENSITIVITY_1, 0x020000710100c80036, 9], [REGISTER_IR_SENSITIVITY_2, 0x3503, 2] ] # lvl 4
, 'lvl5' : [ [REGISTER_IR_SENSITIVITY_1, 0x020000710100720020, 9], [REGISTER_IR_SENSITIVITY_2, 0x1f03, 2] ] # lvl 5
, 'some1': [ [REGISTER_IR_SENSITIVITY_1, 0x020000710100aa0064, 9], [REGISTER_IR_SENSITIVITY_2, 0x6303, 2] ] # some value...
, 'some2': [ [0x04b00006, 0x90, 1], [0x04b00008, 0x41, 1], [REGISTER_IR_SENSITIVITY_2, 0x4000, 2] ]
, 'max' : [ [0x04b00006, 0x90, 1], [0x04b00008, 0x64, 1], [REGISTER_IR_SENSITIVITY_2, 0x6303, 2] ] # (max sensitivity)
# there are just some tests, will not work
#, 'my1' : [ [REGISTER_IR_SENSITIVITY_1, 0x020000710100720001, 9], [REGISTER_IR_SENSITIVITY_2, 0x0000, 2] ] # lvl 5
#, 'my2' : [ [REGISTER_IR_SENSITIVITY_1, 0x020000710100720005, 9], [REGISTER_IR_SENSITIVITY_2, 0x0400, 2] ] # lvl 5
} # is max sensitivity
SIGNAL_IR_SENSITIVITY_SORTED_LIST = SIGNAL_IR_SENSITIVITY.keys() #['some1', 'lvl1', 'lvl2', 'lvl3', 'lvl4', 'lvl5', 'some2', 'max', 'my1', 'my2']
#SIGNAL_IR_SENSITIVITY_NAME
class WIIMOTESTATE:
def __init__( self ):
self.SEND_ACCEL = False
self.SEND_IR = False
self.SEND_CONTINUOUS = False
self.SEND_EXTENSION = False
self.TRANSMISSION_ENABLED = True
self.BATTERY = 0
self.LED1 = self.LED2 = self.LED3 = self.LED4 = False
self.RUMBLE = False
self.EXTENSIONTYPE = None
self.ExtensionClass = None
self.KEEP_HISTORY = False
self.IR_SENSITIVITY = 'max'
# Accel data
self.AccelCalibrationInfoX0 = self.AccelCalibrationInfoXG = 0.0
self.AccelCalibrationInfoY0 = self.AccelCalibrationInfoYG = 0.0
self.AccelCalibrationInfoZ0 = self.AccelCalibrationInfoZG = 0.0
self.AccelRawX = self.AccelRawY = self.AccelRawZ = 0.0
self.AccelX = self.AccelY = self.AccelZ = 0.0
self.AccelHistoryLen = 50
self.AccelHistoryX = list()
self.AccelHistoryY = list()
self.AccelHistoryZ = list()
# IR data
self.IrRawX1 = self.IrRawX2 = self.IrRawX3 = self.IrRawX4 = 0
self.IrRawY1 = self.IrRawY2 = self.IrRawY3 = self.IrRawY4 = 0
self.IrFound1 = self.IrFound2 = self.IrFound3 = self.IrFound4 = 0
self.IrSize1 = self.IrSize2 = self.IrSize3 = self.IrSize4 = 0
self.IrX1, self.IrX2, self.IrX3, self.IrX4 = 0.0,0.0,0.0,0.0
self.IrY1, self.IrY2, self.IrY3, self.IrY4 = 0.0,0.0,0.0,0.0
self.IrHistoryX1 = list()
self.IrHistoryY1 = list()
self.IrHistoryX2 = list()
self.IrHistoryY2 = list()
self.IrHistoryX3 = list()
self.IrHistoryY3 = list()
self.IrHistoryX4 = list()
self.IrHistoryY4 = list()
# Button data
self.ButtonA = self.ButtonB = False
self.ButtonUp = self.ButtonDown = self.ButtonLeft = self.ButtonRight = False
self.ButtonHome = False
self.ButtonMinus = self.ButtonPlus = False
self.ButtonOne = self.ButtonTwo = False
self.ButtonState = ''
def getAttr( self, valuename ):
return getattr( self, valuename )
def IrUpdated( self ):
pass
def accelUpdated( self ):
self.AccelHistoryX.append( self.AccelX )
self.AccelHistoryX.pop(0)
#del( self.AccelHistoryX[:max(0, len(self.AccelHistoryX)-self.AccelHistoryLen)] )
self.AccelHistoryY.append( self.AccelY )
self.AccelHistoryY.pop(0)
#del( self.AccelHistoryY[:max(0, len(self.AccelHistoryY)-self.AccelHistoryLen)] )
self.AccelHistoryZ.append( self.AccelZ )
self.AccelHistoryZ.pop(0)
#del( self.AccelHistoryZ[:max(0, len(self.AccelHistoryZ)-self.AccelHistoryLen)] )
def getLedSignal( self ):
# (52) 11 XX
signal = 0
if self.LED1: signal += SIGNAL_LED1
if self.LED2: signal += SIGNAL_LED2
if self.LED3: signal += SIGNAL_LED3
if self.LED4: signal += SIGNAL_LED4
if self.RUMBLE: signal += SIGNAL_RUMBLE
return signal
def getSensitivitySignals( self ):
#if self.IR_SENSITIVITY in SIGNAL_IR_SENSITIVITY.keys():
return SIGNAL_IR_SENSITIVITY[self.IR_SENSITIVITY]
#else:
# id = SIGNAL_IR_SENSITIVITY.keys()[self.IR_SENSITIVITY]
# return SIGNAL_IR_SENSITIVITY[id]
def getRumbleSignal( self ):
signal = 0
if self.RUMBLE: signal += SIGNAL_RUMBLE
return signal
def getSendSignal( self ):
# ba 0000001
# bx 0000010
# bai 0000011
# bx 0000100
# bax 0000101
# (52) 12 00 XX
signal = 0x30
if self.SEND_ACCEL:
signal += 0x01
if self.SEND_IR:
signal += 0x02
if self.SEND_EXTENSION:
signal += 0x04
return signal
def getTransmissionSignal( self ):
# (52) 13 XX
signal = 0
if self.SEND_CONTINUOUS:
signal += 0x04
if self.RUMBLE:
signal += 0x01
return signal
def getIrMode( self ):
print "WIIMOTESTATE.getIrMode: IR %s, ACCEL %s, EXTENSION %s" % (['OFF','ON'][self.SEND_IR]
, ['OFF','ON'][self.SEND_ACCEL]
, ['OFF','ON'][self.SEND_EXTENSION]),
if self.SEND_IR:
if self.SEND_ACCEL:
if self.SEND_EXTENSION:
print "basic"
return IrModeBasic # must be this
else:
print "extended"
return IrModeExtended # must be this
else:
print "extended"
return IrModeExtended
else:
print "off"
return IrModeOff
def __repr__debug__( self ):
txt = "B:%2d LED: 1:%s 2:%s 3:%s 4:%s R: %s EXT:%s" % (
self.BATTERY
, [' ','*'][bool(self.LED1)]
, [' ','*'][bool(self.LED2)]
, [' ','*'][bool(self.LED3)]
, [' ','*'][bool(self.LED4)]
, [' ','*'][bool(self.RUMBLE)]
, str(self.EXTENSIONTYPE) )
if self.SEND_ACCEL:
txt += "AccelCalib: X0: %3d Y0: %3d Z0: %3d XG: %3d YG: %3d ZG: %3d" % (
self.AccelCalibrationInfoX0
, self.AccelCalibrationInfoY0
, self.AccelCalibrationInfoZ0
, self.AccelCalibrationInfoXG
, self.AccelCalibrationInfoYG
, self.AccelCalibrationInfoZG )
txt += "AccelRaw: %4d %4d %4d" % ( self.RawX, self.RawY, self.RawZ )
if self.SEND_IR:
txt += "IR: 1: %s %4d %4d %2d 2: %s %4d %4d %2d 3: %s %4d %4d %2d 4: %s %4d %4d %2d" % (
[' ','*'][self.IrFound1], self.IrRawX1, self.IrRawY1, self.IrSize1
, [' ','*'][self.IrFound2], self.IrRawX2, self.IrRawY2, self.IrSize2
, [' ','*'][self.IrFound3], self.IrRawX3, self.IrRawY3, self.IrSize3
, [' ','*'][self.IrFound4], self.IrRawX4, self.IrRawY4, self.IrSize4 )
txt = "Button: %s:%s %s:%s " % ("A", [' ','*'][self.ButtonA], "B", [' ','*'][self.ButtonB])
txt += "%s:%s %s:%s " % ("^", [' ','*'][self.ButtonUp], "v", [' ','*'][self.ButtonDown])
txt += "%s:%s %s:%s " % ("<", [' ','*'][self.ButtonLeft], ">", [' ','*'][self.ButtonRight])
txt += "%s:%s %s:%s " % ("-", [' ','*'][self.ButtonMinus], "+", [' ','*'][self.ButtonPlus])
txt += "%s:%s %s:%s " % ("1", [' ','*'][self.ButtonOne], "2", [' ','*'][self.ButtonTwo])
txt += "%s:%s" % ("Home", [' ','*'][self.ButtonHome])
return txt
def __repr__( self ):
txt = "B:%3d IR: 1:%s 2:%s 3:%s 4:%s R: %s EXT:%s " % ( self.BATTERY
, [' ','*'][bool(self.LED1)]
, [' ','*'][bool(self.LED2)]
, [' ','*'][bool(self.LED3)]
, [' ','*'][bool(self.LED4)]
, [' ','*'][bool(self.RUMBLE)]
, str(self.EXTENSIONTYPE) )
txt = "Button: %s:%s %s:%s " % ("A", [' ','*'][self.ButtonA], "B", [' ','*'][self.ButtonB])
txt += "%s:%s %s:%s " % ("^", [' ','*'][self.ButtonUp] , "v", [' ','*'][self.ButtonDown])
txt += "%s:%s %s:%s " % ("<", [' ','*'][self.ButtonLeft] , ">", [' ','*'][self.ButtonRight])
txt += "%s:%s %s:%s " % ("-", [' ','*'][self.ButtonMinus] , "+", [' ','*'][self.ButtonPlus])
txt += "%s:%s %s:%s " % ("1", [' ','*'][self.ButtonOne] , "2", [' ','*'][self.ButtonTwo])
txt += "%s:%s" % ("Home", [' ','*'][self.ButtonHome])
if self.SEND_ACCEL:
txt += "Accel: %2.2f %2.2f %2.2f " % (self.AccelX, self.AccelY, self.AccelZ)
if self.SEND_IR:
txt += "Ir: 1: %s %4d %4d %2d 2: %s %4d %4d %2d 3: %s %4d %4d %2d 4: %s %4d %4d %2d" % \
( [' ','*'][self.IrFound1], self.IrRawX1, self.IrRawY1, self.IrSize1
, [' ','*'][self.IrFound2], self.IrRawX2, self.IrRawY2, self.IrSize2
, [' ','*'][self.IrFound3], self.IrRawX3, self.IrRawY3, self.IrSize3
, [' ','*'][self.IrFound4], self.IrRawX4, self.IrRawY4, self.IrSize4 )
return txt
def __str__( self ):
return self.__repr__()
class WIIMOTEDUMMYEXTENSIONSTATE:
def __repr__( self ):
return "WIIMOTEDUMMYEXTENSIONSTATE"
def __str__( self ):
return self.__repr__()
class WIIMOTENUNCHUKEXTENSIONSTATE:
AccelX = AccelRawX = AccelCalibrationX0 = AccelCalibrationXG = 0.0
AccelY = AccelRawY = AccelCalibrationY0 = AccelCalibrationYG = 0.0
AccelZ = AccelRawZ = AccelCalibrationZ0 = AccelCalibrationZG = 0.0
MaxX = MidX = MinX = RawX = X = 0.0
MaxY = MidY = MinY = RawY = Y = 0.0
ButtonC = ButtonZ = False
def __repr__debug__( self ):
txt = "NUNCHUK: X: %2.2f %3d %3d %3d Y: %2.2f %3d %3d %3d Z: %2.2f %3d %3d %3d" % (
self.AccelX, self.AccelRawX, self.AccelCalibrationX0, self.AccelCalibrationXG
, self.AccelY, self.AccelRawY, self.AccelCalibrationY0, self.AccelCalibrationZ0
, self.AccelZ, self.AccelRawZ, self.AccelCalibrationYG, self.AccelCalibrationZG
)
txt += "X: %2.2f %3d %3d %3d %3d Y: %2.2f %3d %3d %3d %3d" % (
self.X, self.RawX, self.MinX, self.MidX, self.MaxX
, self.Y, self.RawY, self.MinY, self.MidY, self.MaxY
)
return txt
def __repr__( self ):
txt = "NUNCHUK: X: %3d Y: %3d Z: %3d " % (
self.AccelX, self.AccelY, self.AccelZ
)
txt += "X: %3d Y: %3d C: %s Z: %s" % (
self.X, self.Y, [' ','*'][self.ButtonC], [' ','*'][self.ButtonZ]
)
return txt
def __str__( self ):
return self.__repr__debug__()
# --- some functions ---
def char_to_binary_string(self,char):
ascii = ord(char)
bin = []
while (ascii > 0):
if (ascii & 1) == 1:
bin.append("1")
else:
bin.append("0")
ascii = ascii >> 1
bin.reverse()
binary = "".join(bin)
zerofix = (8 - len(binary)) * '0'
return zerofix + binary
def i2bs(val):
lst = []
while val:
lst.append(val&0xff)
val = val >> 8
lst.reverse()
return lst
def l2hex(l):
# pretty output of a int list (to hex list)
hLst = []
for val in l:
hLst.append( hex(val) )
return hLst
def popMultiple( buffer, num ):
return list(buffer.pop(0) for i in range(num))
def dequeIndex( buffer, query ):
# return the index of a value in a deque
index = 0
for k in buffer:
if k == query:
return index
index += 1
return index
def decryptBuffer( buffer ):
returnBuffer = list()
for i in buffer:
j = (i^0x17) + 0x17
returnBuffer.append( j )
return returnBuffer
# --- the parsers ---
BUTTON_Two = 0x0001
BUTTON_One = 0x0002
BUTTON_B = 0x0004
BUTTON_A = 0x0008
BUTTON_Minus = 0x0010
BUTTON_Home = 0x0080
BUTTON_Left = 0x0100
BUTTON_Right = 0x0200
BUTTON_Down = 0x0400
BUTTON_Up = 0x0800
BUTTON_Plus = 0x1000
def parseIr( buffer, wiiMoteState, size ):
signal = popMultiple( buffer, size )
if size == 12:
wiiMoteState.IrRawX1 = signal[0] + ((signal[2] & 0x30) >> 4 << 8)
wiiMoteState.IrRawY1 = signal[1] + (signal[2] >> 6 << 8)
wiiMoteState.IrSize1 = signal[2] & 0x0f
if wiiMoteState.IrRawY1 == 1023: wiiMoteState.IrFound1 = False
else: wiiMoteState.IrFound1 = True
wiiMoteState.IrRawX2 = signal[3] + ((signal[5] & 0x30) >> 4 << 8)
wiiMoteState.IrRawY2 = signal[4] + (signal[5] >> 6 << 8)
wiiMoteState.IrSize2 = signal[5] & 0x0f
if wiiMoteState.IrRawY2 == 1023: wiiMoteState.IrFound2 = False
else: wiiMoteState.IrFound2 = True
wiiMoteState.IrRawX3 = signal[6] + ((signal[8] & 0x30) >> 4 << 8)
wiiMoteState.IrRawY3 = signal[7] + (signal[8] >> 6 << 8)
wiiMoteState.IrSize3 = signal[8] & 0x0f
if wiiMoteState.IrRawY3 == 1023: wiiMoteState.IrFound3 = False
else: wiiMoteState.IrFound3 = True
wiiMoteState.IrRawX4 = signal[9] + ((signal[11] & 0x30) >> 4 << 8)
wiiMoteState.IrRawY4 = signal[10] + (signal[11] >> 6 << 8)
wiiMoteState.IrSize4 = signal[11] & 0x0f
if wiiMoteState.IrRawY4 == 1023: wiiMoteState.IrFound4 = False
else: wiiMoteState.IrFound4 = True
elif size == 10:
wiiMoteState.IrRawX1 = signal[0] + ((signal[2] & 0x30) >> 4 << 8)
wiiMoteState.IrRawY1 = signal[1] + ((signal[2] & 0xc0) >> 6 << 8)
wiiMoteState.IrSize1 = 5
if wiiMoteState.IrRawY1 == 1023: wiiMoteState.IrFound1 = False
else: wiiMoteState.IrFound1 = True
wiiMoteState.IrRawX2 = signal[3] + ((signal[2] & 0x03) << 8)
wiiMoteState.IrRawY2 = signal[4] + ((signal[2] & 0x0c) >> 2 << 8)
wiiMoteState.IrSize2 = 5
if wiiMoteState.IrRawY2 == 1023: wiiMoteState.IrFound2 = False
else: wiiMoteState.IrFound2 = True
wiiMoteState.IrRawX3 = signal[5] + ((signal[7] & 0x30) >> 4 << 8)
wiiMoteState.IrRawY3 = signal[6] + ((signal[7] & 0xc0) >> 6 << 8)
wiiMoteState.IrSize3 = 5
if wiiMoteState.IrRawY3 == 1023: wiiMoteState.IrFound3 = False
else: wiiMoteState.IrFound3 = True
wiiMoteState.IrRawX4 = signal[8] + ((signal[7] & 0x03) << 8)
wiiMoteState.IrRawY4 = signal[9] + ((signal[7] & 0x0c) >> 2 << 8)
wiiMoteState.IrSize4 = 5
if wiiMoteState.IrRawY4 == 1023: wiiMoteState.IrFound4 = False
else: wiiMoteState.IrFound4 = True
wiiMoteState.IrX1 = wiiMoteState.IrRawX1 / 1024.0
wiiMoteState.IrY1 = wiiMoteState.IrRawY1 / 768.0
wiiMoteState.IrX2 = wiiMoteState.IrRawX2 / 1024.0
wiiMoteState.IrY2 = wiiMoteState.IrRawY2 / 768.0
wiiMoteState.IrX3 = wiiMoteState.IrRawX3 / 1024.0
wiiMoteState.IrY3 = wiiMoteState.IrRawY3 / 768.0
wiiMoteState.IrX4 = wiiMoteState.IrRawX4 / 1024.0
wiiMoteState.IrY4 = wiiMoteState.IrRawY1 / 768.0
wiiMoteState.IrUpdated()
return buffer
def parseAccel( buffer, wiimoteState ):
signal = popMultiple( buffer, 3 )
wiimoteState.AccelRawX = signal[0]
wiimoteState.AccelRawY = signal[1]
wiimoteState.AccelRawZ = signal[2]
wiimoteState.AccelX = (wiimoteState.AccelRawX - wiimoteState.AccelCalibrationInfoX0) \
/ (wiimoteState.AccelCalibrationInfoXG - wiimoteState.AccelCalibrationInfoX0)
wiimoteState.AccelY = (wiimoteState.AccelRawY - wiimoteState.AccelCalibrationInfoY0) \
/ (wiimoteState.AccelCalibrationInfoYG - wiimoteState.AccelCalibrationInfoY0)
wiimoteState.AccelZ = (wiimoteState.AccelRawZ - wiimoteState.AccelCalibrationInfoZ0) \
/ (wiimoteState.AccelCalibrationInfoZG - wiimoteState.AccelCalibrationInfoZ0)
if wiimoteState.KEEP_HISTORY:
wiimoteState.accelUpdated()
return buffer
def parseButtons( buffer, wiiMoteState ):
keybuffer = popMultiple( buffer, 2 )
state = (keybuffer[0]<<8) + keybuffer[1]
wiiMoteState.ButtonA = bool(state&BUTTON_A)
wiiMoteState.ButtonB = bool(state&BUTTON_B)
wiiMoteState.ButtonDown = bool(state&BUTTON_Down)
wiiMoteState.ButtonHome = bool(state&BUTTON_Home)
wiiMoteState.ButtonLeft = bool(state&BUTTON_Left)
wiiMoteState.ButtonMinus = bool(state&BUTTON_Minus)
wiiMoteState.ButtonOne = bool(state&BUTTON_One)
wiiMoteState.ButtonPlus = bool(state&BUTTON_Plus)
wiiMoteState.ButtonRight = bool(state&BUTTON_Right)
wiiMoteState.ButtonTwo = bool(state&BUTTON_Two)
wiiMoteState.ButtonUp = bool(state&BUTTON_Up)
wiiMoteState.ButtonState = state
return buffer
def parseExtension( encryptedBuffer, extensionState ):
if extensionState.__class__ == WIIMOTENUNCHUKEXTENSIONSTATE:
buffer = decryptBuffer(encryptedBuffer)
extensionState.RawX = buffer[0]
extensionState.RawY = buffer[1]
extensionState.AccelRawX = buffer[2]
extensionState.AccelRawY = buffer[3]
extensionState.AccelRawZ = buffer[4]
extensionState.ButtonC = not((buffer[5] & 0x02) >> 1)
extensionState.ButtonZ = not(buffer[5] & 0x01)
extensionState.AccelX = (float(extensionState.AccelRawX) - extensionState.AccelCalibrationX0) \
/ (extensionState.AccelCalibrationXG - extensionState.AccelCalibrationX0)
#print extensionState.AccelX, extensionState.AccelRawX, extensionState.AccelCalibrationX0, extensionState.AccelCalibrationXG
extensionState.AccelY = (float(extensionState.AccelRawY) - extensionState.AccelCalibrationY0) \
/ (extensionState.AccelCalibrationYG - extensionState.AccelCalibrationY0)
extensionState.AccelZ = (float(extensionState.AccelRawZ) - extensionState.AccelCalibrationZ0) \
/ (extensionState.AccelCalibrationZG - extensionState.AccelCalibrationZ0)
extensionState.X = (extensionState.RawX - extensionState.MidX) \
/ float(extensionState.MaxX - extensionState.MinX)
extensionState.Y = (extensionState.RawY - extensionState.MidY) \
/ float(extensionState.MaxY - extensionState.MinY)
return encryptedBuffer
def readReport( memoryReport ):
error = memoryReport[0] & 0x0f
if error == 8:
print "W: readReport: error bit set (address don't exist)"
elif error == 7:
print "W: readReport: error bit set (write-only registers)"
elif error == 0:
pass
# print "I: readReport: error bit not set"
else:
print "E: readReport: error bit is invalid", error
size = ((memoryReport[0] & 0xf0) >> 4)
# print "I: readReport: package size", size
packageOffset = memoryReport[1] << 8 + memoryReport[2]
if size == 1:
header = popMultiple( memoryReport, 2 )
else:
header = popMultiple( memoryReport, 3 )
data = popMultiple( memoryReport, size )
return data
INPUTREPORT_DATA = { "InputReportStatus" : [ 0x20, 8 ]
, "InputReportReadData" : [ 0x21, 23 ]
, "InputReportUnknown1" : [ 0x22, 6 ]
, "InputReportButtons" : [ 0x30, 4 ]
, "InputReportButtonsAccel" : [ 0x31, 7 ]
, "InputReportButtonsExtension8" : [ 0x32, 12 ]
, "InputReportButtonsAccelIR12" : [ 0x33, 19 ]
, "InputReportButtonsExtension19" : [ 0x34, 23 ]
, "InputReportButtonsAccelExtension16" : [ 0x35, 23 ]
, "InputReportButtonsIR10Extension9" : [ 0x36, 23 ]
, "InputReportButtonsAccelIR10Extension6" : [ 0x37, 23 ]
, "InputReportButtonsAccelIR" : [ 0x38, 23 ]
, "InputReportExtension21" : [ 0x3d, 23 ]
, "InputReportInterleaved1" : [ 0x3e, 23 ]
, "InputReportInterleaved2" : [ 0x3f, 23 ] }
INREPORT_V2L = dict(); INREPORT_N2V = dict(); INREPORT_V2N = dict()
for n, [v, l] in INPUTREPORT_DATA.items():
INREPORT_V2L[v] = l
INREPORT_N2V[n] = v
INREPORT_V2N[v] = n
if sys.platform == 'darwin':
import lightblue
class systemWiimoteLibClass:
def __init__( self ):
print "wiimoteLib2.systemWiimoteLibClass: using darwin wiimote subsystem"
self.isThreaded = False
def __init_done__( self ):
# is used on windows for thrading
pass
def run( self ):
pass
def atExit( self ):
print "I: wiimoteLibClass.atExit: closing sockets, deleting sockets"
#self.isocket.shutdown(2) # 0 = done receiving, 1 = done sending, 2 = both
self.isocket.close()
#self.osocket.shutdown(2)
self.osocket.close()
#self.tempSocket.shutdown(2)
#self.tempSocket.close()
del self.isocket
del self.osocket
#del self.tempSocket
#print "wiimotelib2.how to quit lightblue???"
#print dir(lightblue)
def search( self ):
print "I: wiimoteLibClass.search: Searching for a Wiimote"
if not self.connected:
print "I: wiimoteLibClass.search: Press 1 and 2 on your Wiimote to make it discoverable."
devicelist = lightblue.finddevices()
found = list()
for address, name, device_class in devicelist:
if name == u'Nintendo RVL-CNT-01':
found.append( address )
if len(found) > 0:
print "I: wiimoteLibClass.search: Found a wiimote", address
self.found = address
else:
print "I: wiimoteLibClass.search: Couldn't find wiimote. Exiting"
raise SystemExit
return self.found
else:
print "I: wiimoteLibClass.search: already connected to a wiimote"
def connect(self, bd_addr=None):
if bd_addr is None:
# use bluetooth DeviceDiscoverer
self.bd_addr = self.search()
# necessary before opening socket !
time.sleep(1)
else:
self.bd_addr = bd_addr
print "I: wiimoteLibClass.connect: creating sockets for", self.bd_addr
self.isocket = lightblue.socket(lightblue.L2CAP)
#self.tempSocket = lightblue.socket(lightblue.L2CAP)
self.osocket = lightblue.socket(lightblue.L2CAP)
print "I: wiimoteLibClass.connect: connecting to", self.bd_addr
time.sleep(0.1)
connected = False
while not connected:
try:
self.isocket.connect((self.bd_addr,19))
print "I: wiimoteLibClass.connect: socket connect success for",self.bd_addr,19
connected = True
except:
print "I: wiimoteLibClass.connect: socket connect failed for",self.bd_addr,19
time.sleep(5.0)
print "I: - if this never succeeds, remove the nintendo controller from"
print " the bluetooth connections in the osx configuration"
time.sleep(0.1)
connected = False
while not connected:
try:
self.osocket.connect((self.bd_addr,17))
print "I: wiimoteLibClass.connect: socket connect success for",self.bd_addr,17
connected = True
except:
print "I: wiimoteLibClass.connect: socket connect failed for",self.bd_addr,17
time.sleep(5.0)
self.connected = True
print "I: wiimoteLibClass.connect: setting socket timeouts"
try:
self.isocket.settimeout(0.001) #0.0000000001
except NotImplementedError:
print "I: wiimoteLibClass.connect: socket i timeout not implemented with this bluetooth module"
except socket.error:
pass
try:
self.osocket.settimeout(10.0)
except NotImplementedError:
print "I: wiimoteLibClass.connect: socket o timeout not implemented with this bluetooth module"
except socket.error:
pass
print "I: wiimoteLibClass.connect: wiimote successfully connected", self.bd_addr
self.running = True
def readSocketData( self ):
# receive all data from the controller
try:
data = self.isocket.recv(1024)
except lightblue.BluetoothError:
data = list()
except socket.timeout:
data = list()
except socket.error:
data = list()
return data
def _send_data( self, data ):
str_data = ""
for each in data:
str_data += chr(each)
if True:
#try:
self.osocket.send(str_data)
return True
#except socket.error:
# print "E: WiimoteLib._send_data: sending data to wiimote failed %s" % str(data)
# return False
elif sys.platform == 'win32' or sys.platform == 'linux2':
import bluetooth
from bluetooth import *
from threading import Thread
class systemWiimoteLibClass(Thread):
def __init__( self ):
Thread.__init__( self )
self.isThreaded = True
print "wiimoteLib2.systemWiimoteLibClass: using windows driver subsystem"
def __init_done__( self ):
self.start()
def run( self ):
'''# for threaded, but does not work
import objc
# Most useful systems will at least have 'NSObject'.
NSObject = objc.lookUpClass('NSObject')
NSArray = objc.lookUpClass('NSArray')
NSAutoreleasePool = objc.lookUpClass('NSAutoreleasePool')
#rt = pyobjc.runtime # shorthand -- runtime gets used a lot!
pool = NSAutoreleasePool.alloc().init()'''
while True:
self.readData()
def connect( self, bd_addr=None):
if bd_addr is None:
print "wiimoteLib2.systemWiimoteLibClass (win32): none address not implemented"
raise
else:
self.bd_addr = bd_addr
print "I: wiimoteLibClass.connect: creating sockets for", self.bd_addr
try:
self.isocket = bluetooth.BluetoothSocket(bluetooth.L2CAP)
self.osocket = bluetooth.BluetoothSocket(bluetooth.L2CAP)
except:
print "E: The native Windows bluetooth stack doesnt support L2CAP connections."
print "E: - get yourself a bluetooth dongle with a widcomm driver (5.1.0.x)"
print "E: - microsoft was just not able to implement this protocol itself"
raise
print "I: wiimoteLibClass.connect: connecting to", self.bd_addr
#self.isocket.connect((self.bd_addr,19))
time.sleep(0.1)
connected = False
while not connected:
try:
self.isocket.connect((self.bd_addr,19))
print "I: wiimoteLibClass.connect: socket connect success for",self.bd_addr,19
connected = True
except:
print "I: wiimoteLibClass.connect: socket connect failed for",self.bd_addr,19
time.sleep(5.0)
print "I: - if this never succeeds, remove the nintendo controller from"
print " the bluetooth connections in the osx configuration"
time.sleep(0.1)
connected = False
while not connected:
try:
self.osocket.connect((self.bd_addr,17))
print "I: wiimoteLibClass.connect: socket connect success for",self.bd_addr,17
connected = True
except:
print "I: wiimoteLibClass.connect: socket connect failed for",self.bd_addr,17
time.sleep(5.0)
self.connected = True
print "I: wiimoteLibClass.connect: setting socket timeouts"
try:
self.isocket.settimeout(0.0001) #0.0000000001
except NotImplementedError:
print "I: wiimoteLibClass.connect: socket i timeout not implemented with this bluetooth module"
try:
self.osocket.settimeout(1.0)
except NotImplementedError:
print "I: wiimoteLibClass.connect: socket o timeout not implemented with this bluetooth module"
print "I: wiimoteLibClass.connect: wiimote successfully connected", self.bd_addr
self.running = True
def readSocketData( self ):
# receive all data from the controller
try:
data = self.isocket.recv(1024)
except:
data = list()
return data
def _send_data( self, data ):
str_data = ""
for each in data:
str_data += chr(each)
#if True:
try:
self.osocket.send(str_data)
return True
except socket.error:
print "E: WiimoteLib._send_data: sending data to wiimote failed %s" % str(data)
return False
def atExit( self ):
print "I: wiimoteLibClass.atExit: closing sockets, deleting sockets"
self.isocket.shutdown(2) # 0 = done receiving, 1 = done sending, 2 = both
self.isocket.close()
self.osocket.shutdown(2)
self.osocket.close()
del self.isocket
del self.osocket
class wiimoteLibClass( systemWiimoteLibClass ):
def __init__( self, uid=None ):
systemWiimoteLibClass.__init__( self )
# storage containers for received data
self.wiiMoteState = WIIMOTESTATE()
self.extensionState = WIIMOTEDUMMYEXTENSIONSTATE()
self.data = list()
self.connected = False
self.packageCount = 0
if uid is not None:
self.connectToUid( uid )
systemWiimoteLibClass.__init_done__( self )
def keepHistory( self, setting ):
self.wiiMoteState.KEEP_HISTORY = setting
def connectToUid( self, uid ):
if not self.connected:
self.connect( uid )
atexit.register( self.atExit )
# set leds disabled (must be done just after connecting, else they blink forever)
state = self.SetLEDs( 0, 0, 0, 0 )
if state is False:
print "I: wiimoteLibClass.connectToUid: send data test failed, trying again"
import sys
sys.exit()
# accept initializing package (this must be done, if a extension is already plugged in)
for i in xrange(10):
self.step()
self.readCalibration()
# set default settings (ir/accel/continuous disabled)
self.updateIrMode()
for i in xrange(10):
self.step()
else:
state = True
print "W: wiimoteLibClass: already connected"
return state
def readData( self ):
self.data.extend( map(ord, self.readSocketData() ) )
def step( self ):
self.readData()
return self.parseData()
def parseData( self ):
while len(self.data)>=2:
retVal = self.parseDataStep()
if retVal is not None:
return retVal
if retVal == -1:
return None
return None
def parseDataStep( self ):
if len(self.data)>=2:
pkgType = self.data[1]
# check package
try:
if len(self.data) >= INREPORT_V2L[pkgType]:
package = popMultiple( self.data, INREPORT_V2L[pkgType])
else:
print "W: wiimoteLibClass.parseData: invalid or unknown package", hex(pkgType), len(self.data), INREPORT_V2L[pkgType], self.data
return -1
except:
print "E: wiimoteLibClass.parseData: invalid data"
print "E: - ", self.data
print "E: - ", l2hex(self.data)
raise
self.packageCount += 1
tmp = popMultiple( package, 2)
if pkgType == INREPORT_N2V['InputReportStatus']:
package = parseButtons( package, self.wiiMoteState )
print "W: wiimoteLibClass.parseData: InputReportStatus, pkg", l2hex(package)
# get the real LED values in case the values from SetLEDs() somehow becomes out of sync, which really shouldn't be possible
self.wiiMoteState.LED1 = (package[1] & 0x10) != 0
self.wiiMoteState.LED2 = (package[1] & 0x20) != 0
self.wiiMoteState.LED3 = (package[1] & 0x40) != 0
self.wiiMoteState.LED4 = (package[1] & 0x80) != 0
self.wiiMoteState.BATTERY = package[3]
extensionPluggedIn = (package[1] & 0x02) != 0
speakerEnabled = (package[1] & 0x04) != 0
continuousOutputMode = (package[1] & 0x08) != 0
self.initializeExtension()
elif pkgType == INREPORT_N2V['InputReportReadData']:
package = parseButtons( package, self.wiiMoteState )
return package
elif pkgType == INREPORT_N2V['InputReportButtons']:
package = parseButtons( package, self.wiiMoteState )
elif pkgType == INREPORT_N2V['InputReportButtonsAccel']:
package = parseButtons( package, self.wiiMoteState )
package = parseAccel( package, self.wiiMoteState )
elif pkgType == INREPORT_N2V['InputReportButtonsExtension8']:
package = parseButtons( package, self.wiiMoteState )
package = parseExtension( package, self.extensionState )
elif pkgType == INREPORT_N2V['InputReportButtonsAccelIR12']:
package = parseButtons( package, self.wiiMoteState )
package = parseAccel( package, self.wiiMoteState )
package = parseIr( package, self.wiiMoteState, 12 )
elif pkgType == INREPORT_N2V['InputReportButtonsExtension19']:
package = parseButtons( package, self.wiiMoteState )
package = parseExtension( package, self.extensionState )
elif pkgType == INREPORT_N2V['InputReportButtonsAccelExtension16']:
package = parseButtons( package, self.wiiMoteState )
package = parseAccel( package, self.wiiMoteState )
package = parseExtension( package, self.extensionState )
elif pkgType == INREPORT_N2V['InputReportButtonsIR10Extension9']:
package = parseButtons( package, self.wiiMoteState )
package = parseIr( package, self.wiiMoteState, 10 )
package = parseExtension( package, self.extensionState )
elif pkgType == INREPORT_N2V['InputReportButtonsAccelIR10Extension6']:
package = parseButtons( package, self.wiiMoteState )
package = parseAccel( package, self.wiiMoteState )
package = parseIr( package, self.wiiMoteState, 10 )
package = parseExtension( package, self.extensionState )
elif pkgType == INREPORT_N2V['InputReportButtonsAccelIR']:
package = parseButtons( package, self.wiiMoteState )
package = parseAccel( package, self.wiiMoteState )
package = parseIr( package, self.wiiMoteState )
elif pkgType == INREPORT_N2V['InputReportExtension21']:
package = parseExtension( package, self.extensionState )
elif pkgType == INREPORT_N2V['InputReportInterleaved1']:
pass
elif pkgType == INREPORT_N2V['InputReportInterleaved2']:
pass
else:
print "W: wiimoteLib2: unknown package type:", pkgType, l2hex(package)
else:
return -1
def initializeExtension( self ):
# initialize the extension
self._send_data( i2bs(0x521604A400400100000000000000000000000000000000) )
extension = self._read_from_mem(REGISTER_EXTENSION_TYPE, 2)
if extension[0] == ExtensionTypeNunchuk:
print "I: wiimoteLibClass.initializeExtension: found nunchuk extension controller"
self.extensionState = WIIMOTENUNCHUKEXTENSIONSTATE()
self.wiiMoteState.SEND_EXTENSION = True
elif extension[0] == ExtensionTypeClassicController:
print "I: wiimoteLibClass.initializeExtension: found classic extension controller (not handled)"
self.extensionState = WIIMOTEDUMMYEXTENSIONSTATE()
self.wiiMoteState.SEND_EXTENSION = True
elif extension[0] == 0xff:
print "I: wiimoteLibClass.initializeExtension: partially inserted"
self.extensionState = WIIMOTEDUMMYEXTENSIONSTATE()
self.wiiMoteState.SEND_EXTENSION = False
else:
print "I: wiimoteLibClass.initializeExtension: unknown or none inserted %s" % hex(extension[0])
self.extensionState = WIIMOTEDUMMYEXTENSIONSTATE()
self.wiiMoteState.SEND_EXTENSION = False
extensionCalibration = decryptBuffer(self._read_from_mem(REGISTER_EXTENSION_CALIBRATION, 16))
if self.extensionState.__class__ == WIIMOTENUNCHUKEXTENSIONSTATE:
self.extensionState.AccelCalibrationX0 = float(extensionCalibration[0])
self.extensionState.AccelCalibrationY0 = float(extensionCalibration[1])
self.extensionState.AccelCalibrationZ0 = float(extensionCalibration[2])
self.extensionState.AccelCalibrationXG = float(extensionCalibration[4])
self.extensionState.AccelCalibrationYG = float(extensionCalibration[5])
self.extensionState.AccelCalibrationZG = float(extensionCalibration[6])
self.extensionState.MaxX = float(extensionCalibration[8])
self.extensionState.MinX = float(extensionCalibration[9])
self.extensionState.MidX = float(extensionCalibration[10])
self.extensionState.MaxY = float(extensionCalibration[11])
self.extensionState.MinY = float(extensionCalibration[12])
self.extensionState.MidY = float(extensionCalibration[13])
self.updateIrMode()
self._send_data([0x52]+i2bs(0x1200)+[self.wiiMoteState.getSendSignal()])
def SetLEDs(self, led1,led2,led3,led4):
self.wiiMoteState.LED1 = led1
self.wiiMoteState.LED2 = led2
self.wiiMoteState.LED3 = led3
self.wiiMoteState.LED4 = led4
return self.updateRumbleLED()
def SetRumble(self,on):
self.wiiMoteState.RUMBLE = on
self.updateRumbleLED()
def updateRumbleLED( self ):
ledSignal = self.wiiMoteState.getLedSignal()
return self._send_data((0x52,OutputReportLEDs,ledSignal))
def setContinuous( self, continous = True ):
print "I: p3f.src.wiimote.set_continuous"
self.wiiMoteState.SEND_CONTINUOUS = continous
#self._send_data([0x52]+i2bs(0x12)+[self.wiiMoteState.getTransmissionSignal(), self.wiiMoteState.getSendSignal()])
#time.sleep(0.1)
self.updateMode()
def setAccel( self, state ):
print "I: p3f.src.wiimote.setAccel: state %s" % (['off','on'][state])
self.wiiMoteState.SEND_ACCEL = state
self.updateMode()
def activate_accel(self):
print "I: p3f.src.wiimote.activate_accel: is depricated, use setAccel instead"
self.setAccel( True )
def setIr( self, state, sensitivity='max' ):
print "I: p3f.src.wiimote.setIr: state %s sensitivity %s" % (['off','on'][state], str(sensitivity))
if state:
print "I: - activating accel as well, cause ir alone doesnt work"
self.setAccel( True )
self.wiiMoteState.SEND_IR = state
if sensitivity not in SIGNAL_IR_SENSITIVITY:
print "wiimoteLib2.wiimoteLibClass.setIr: INVALID SENSITIVITY", sensitivity, "must be one of", SIGNAL_IR_SENSITIVITY.keys()
raise Exception
self.wiiMoteState.IR_SENSITIVITY = sensitivity # 0 some state, 1 maximum sensitivity
self.updateIrMode()
def activate_IR(self, maxsensitivity = False ):
print "I: p3f.src.wiimote.activate_IR: is depricated, use setIr instead"
if maxsensitivity: # sensitivity must be one of SIGNAL_IR_SENSITIVITY
sensitivity = 'max'
else:
sensitivity = 'lvl3'
self.setIr( True, sensitivity )
def updateIrMode( self ):
self.updateMode()
time.sleep(0.1)
self._send_data([0x52]+i2bs(0x1304))
time.sleep(0.1)
self._send_data([0x52]+i2bs(0x1a04))
time.sleep(0.1)
self._write_to_mem(REGISTER_IR,0x08) # 0x04b00030
time.sleep(0.1)
# sensitivity
for addr, signal, signalLength in self.wiiMoteState.getSensitivitySignals():
self._write_to_mem(addr, signal, signalLength)
time.sleep(0.1)
time.sleep(0.1)
self._write_to_mem(REGISTER_IR_MODE, self.wiiMoteState.getIrMode()) # 0x04b00033
time.sleep(0.1)
self.updateMode()
def updateMode( self ):
time.sleep(0.1)
self._send_data([0x52]+i2bs(0x12)+[self.wiiMoteState.getTransmissionSignal(), self.wiiMoteState.getSendSignal()])
def _get_battery_status(self):
data = self.requestData( (0x52,0x15,0x00), 7 )
print len(data), data
battery_level = (100*data[7])/206
self.wiiMoteState.BATTERY = battery_level
if False: # check if requestdata works correctly
self._send_data((0x52,0x15,0x00))
self.running2 = True
while self.running2:
try:
x= map(ord,self.isocket.recv(32))
except lightblue.BluetoothError:
continue
except socket.timeout:
continue
self.state = ""
for each in x[:17]:
if len(x) >= 7:
self.running2 = False
battery_level = (100*x[7])/206
if self.wiiMoteState.BATTERY != battery_level:
print "E: _get_battery_status: is wrong", self.wiiMoteState.BATTERY, battery_level
raise
else:
print "I: _get_battery_status: is correct", self.wiiMoteState.BATTERY, battery_level
raise
def readCalibration( self ):
# equivalent to wiimote.ReadCalibration
parseData = self._read_from_mem( 0x0016, 7 )
if len(parseData) == 6:
self.wiiMoteState.AccelCalibrationInfoX0 = float(parseData[0])
self.wiiMoteState.AccelCalibrationInfoY0 = float(parseData[1])
self.wiiMoteState.AccelCalibrationInfoZ0 = float(parseData[2])
self.wiiMoteState.AccelCalibrationInfoXG = float(parseData[3])
self.wiiMoteState.AccelCalibrationInfoYG = float(parseData[4])
self.wiiMoteState.AccelCalibrationInfoZG = float(parseData[5])
else:
print "E: wiimoteLibClass.readCalibration: invalid data", parseData
def getWiimoteAttr( self, value ):
#if value==0:
return getattr( self.wiiMoteState, value )
def _write_to_mem(self, address, value, val_len=None):
# print "I: wiimoteLibClass._write_to_mem: ", hex(address), ":", hex(value)
val = i2bs(value)
if val_len is None:
# calculate value length if not defined
val_len=len(val)
val += [0]*(16-val_len)
msg = [0x52,OutputReportWriteMemory] + i2bs(address) + [val_len] + val
self._send_data(msg)
def _read_from_mem( self, address, size ):
''' starts another read loop, and exits if a memory read response happens
'''
# equivalent to wiimote.ReadData
adr = i2bs(address)
adr_len = len(adr)
adr = [0]*(4-adr_len) + adr
siz = i2bs(size)
siz_len = len(siz)
siz = [0]*(2-siz_len) + siz
sendData = [0x52, OutputReportReadMemory] + adr + siz
self._send_data( sendData )
running = True
timer = time.time()
x = 0
while running:
if (time.time()-timer < 1.0):
returnData = self.step()
if returnData is not None:
if len(returnData) >= size:
parseData = readReport( returnData )
return parseData
else:
print "E: wiimoteLibClass._read_from_mem: timeout", address, size
return list()
def testApp( wiimoteId ):
if False:
wiimoteId = lightblue.selectdevice()
wiimote = wiimoteLibClass( wiimoteId[0] )
print "using nintendo wiimote with address", wiimoteId[0]
else:
print "press 1&2 on the wiimote to make it discoverable"
#wiimote = wiimoteLibClass( '00:19:1D:B7:F4:27' )
wiimote = wiimoteLibClass( wiimoteId )
print "wiimote connection succeeded"
debug = pygameDebug( wiimote )
if True:
wiimote.setIr( True, 'max' )
wiimote.setContinuous( True )
if False:
print "set rumble"
wiimote.wiiMoteState.RUMBLE = True
wiimote.SetLEDs( 1,0,0,0 )
time.sleep( 0.1 )
debug.run()
class pygameDebug:
def __init__( self, wiimote ):
self.wiimote = wiimote
if not hasPygame:
print "pygameDebug requires pygame"
raise
pygame.init()
size = width, height = 256, 256
self.screen = pygame.display.set_mode(size)
self.font = pygame.font.Font(None, 17)
# calculate fps
self.t = time.time()
self.c = 0
self.lastPackageCount = 0
# rendering stuff
self.colors = {
'wiiX': (255,0,0)
, 'wiiY': (0,255,0)
, 'wiiZ': (0,0,255)
, 'nunchuckX': (255,255,0)
, 'nunchuckY': (255,0,255)
, 'nunchuckZ': (0,255,255)
}
self.lines = dict()
self.lines['wiiX'] = list()
self.lines['wiiY'] = list()
self.lines['wiiZ'] = list()
self.lines['nunchuckX'] = list()
self.lines['nunchuckY'] = list()
self.lines['nunchuckZ'] = list()
for k,v in self.lines.items():
for i in xrange(256):
v.append(0)
self.activeButtons = list()
def run( self ):
while 1:
self.step()
self.calcFps()
def calcFps( self ):
self.c += 1
if time.time() - self.t > 1.0:
dt = time.time() - self.t
print "fps", self.c/dt
self.t = time.time()
self.c = 0
print "packages received", self.wiimote.packageCount - self.lastPackageCount
self.lastPackageCount = self.wiimote.packageCount
def step( self ):
CONSOLE_OUTPUT = False
self.wiimote.step()
if self.wiimote.wiiMoteState.ButtonA:
print self.wiimote.wiiMoteState
# edit sensitivity
if True:
currentSetting = self.wiimote.wiiMoteState.IR_SENSITIVITY
currentSettingNumber = SIGNAL_IR_SENSITIVITY_SORTED_LIST.index( currentSetting )
maxLen = len(SIGNAL_IR_SENSITIVITY_SORTED_LIST)
print "EDIT SENSITIVITY", currentSetting, currentSettingNumber, maxLen
# increase sensitivity
if self.wiimote.wiiMoteState.ButtonPlus:
if '+' not in self.activeButtons:
# do it here
self.wiimote.setIr( True, SIGNAL_IR_SENSITIVITY_SORTED_LIST[ min(maxLen-1, max(currentSettingNumber+1, 0) ) ] )
self.activeButtons.append( "+" )
else:
if "+" in self.activeButtons:
self.activeButtons.remove( "+" )
# decrease sensitivity
if self.wiimote.wiiMoteState.ButtonMinus:
if '-' not in self.activeButtons:
# do it here
self.wiimote.setIr( True, SIGNAL_IR_SENSITIVITY_SORTED_LIST[ min(maxLen-1, max(currentSettingNumber-1, 0) ) ] )
self.activeButtons.append( "-" )
else:
if "-" in self.activeButtons:
self.activeButtons.remove( "-" )
if True:
l1, l2, l3, l4 = 0,0,0,0
if False:
print self.wiimote.wiiMoteState
wiimote = self.wiimote
points = list()
if wiimote.wiiMoteState.IrFound1:
points.append( [wiimote.wiiMoteState.IrRawX1, wiimote.wiiMoteState.IrRawY1, wiimote.wiiMoteState.IrSize1, (255,0,0)] )
if wiimote.wiiMoteState.IrFound2:
points.append( [wiimote.wiiMoteState.IrRawX2, wiimote.wiiMoteState.IrRawY2, wiimote.wiiMoteState.IrSize2, (255,0,0)] )
if wiimote.wiiMoteState.IrFound3:
points.append( [wiimote.wiiMoteState.IrRawX3, wiimote.wiiMoteState.IrRawY3, wiimote.wiiMoteState.IrSize3, (255,0,0)] )
if wiimote.wiiMoteState.IrFound4:
points.append( [wiimote.wiiMoteState.IrRawX4, wiimote.wiiMoteState.IrRawY4, wiimote.wiiMoteState.IrSize4, (255,0,0)] )
# output wiiMoteState
self.screen.fill((0,0,0))
# show key state
text = self.font.render( wiimote.wiiMoteState.__repr__(), True, (255, 255, 255), (159, 182, 205))
textRect = text.get_rect()
textRect.centerx = self.screen.get_rect().centerx
textRect.centery = self.screen.get_rect().centery
self.screen.blit(text, textRect)
self.lines['wiiX'].append( wiimote.wiiMoteState.AccelX )
self.lines['wiiX'].pop(0)
self.lines['wiiY'].append( wiimote.wiiMoteState.AccelY )
self.lines['wiiY'].pop(0)
self.lines['wiiZ'].append( wiimote.wiiMoteState.AccelZ )
self.lines['wiiZ'].pop(0)
points.append( [ 5, wiimote.wiiMoteState.AccelX*128+128, 1, (0,255,0) ] )
points.append( [ 15, wiimote.wiiMoteState.AccelY*128+128, 1, (0,255,0) ] )
points.append( [ 25, wiimote.wiiMoteState.AccelZ*128+128, 1, (0,255,0) ] )
if CONSOLE_OUTPUT:
print "wiimote.wiiMoteState", wiimote.wiiMoteState
if wiimote.extensionState.__class__ == WIIMOTENUNCHUKEXTENSIONSTATE:
points.append( [ wiimote.extensionState.X*128+128, wiimote.extensionState.Y*128+128, 1, (0,0,255) ] )
points.append( [ 35, wiimote.extensionState.AccelX*128+128, 1, (0,0,255) ] )
points.append( [ 45, wiimote.extensionState.AccelY*128+128, 1, (0,0,255) ] )
points.append( [ 55, wiimote.extensionState.AccelZ*128+128, 1, (0,0,255) ] )
self.lines['nunchuckX'].append( wiimote.extensionState.AccelX )
self.lines['nunchuckX'].pop(0)
self.lines['nunchuckY'].append( wiimote.extensionState.AccelY )
self.lines['nunchuckY'].pop(0)
self.lines['nunchuckZ'].append( wiimote.extensionState.AccelZ )
self.lines['nunchuckZ'].pop(0)
if CONSOLE_OUTPUT:
print "wiimote.extensionState", wiimote.extensionState
# show ir data
for x,y,r,c in points:
pygame.draw.circle(self.screen, c, (int(x/4),int(y/4)), r, 0)
for k,v in self.lines.items():
prev = 128
for i in xrange(256):
p = int(v[i]*32+128)
pygame.draw.line(self.screen, self.colors[k], (i-1,prev),(i,p), 1 )
prev = p
pygame.display.flip()
if True:
if True:
l1 = int(time.time()) & 0x01
l2 = int(time.time()) & 0x02
l3 = int(time.time()) & 0x04
l4 = int(time.time()) & 0x08
else:
l1, l2, l3, l4 = 0,0,0,0
wiimote.SetLEDs( l1, l2, l3, l4 )
if __name__ == "__main__":
hasPygame = False
try:
import pygame
hasPygame = True
except:
print "testing app requires pygame (for visual debug ouput)"
if True:
#p = testApp( '00:19:1D:B7:F4:27' )
p = testApp( '00:1D:BC:2D:35:1E' )
else:
wiimote1 = wiimoteLibClass( '00:1D:BC:2D:35:1E' ) # hand
wiimote1.activate_accel()
wiimote1.activate_IR()
wiimote2 = wiimoteLibClass( '00:19:1D:B7:F4:27' ) # tracking
wiimote2.activate_accel()
wiimote2.activate_IR()
#wiimote1.start()
#wiimote2.start()
#wiimote1.step()
wiimote1.setContinuous( True )
#wiimote2.step()
wiimote2.setContinuous( True )
t = time.time()
c = 0
while True:
time.sleep(0.05)
wiimote1.step()
wiimote2.step()
if time.time() - t > 1.0:
t = time.time()
print "FPS:", c
c = 0
c += 1
wiimote1.SetRumble( wiimote2.wiiMoteState.ButtonB )
wiimote2.SetRumble( wiimote1.wiiMoteState.ButtonB )
[edit] Small Fix
This is most likely fixed in the new version (4.June.08), but i did not actually check it.
In parseButtons() the Button-Values are named A, B .. :
wiiMoteState.A = bool(state&BUTTON_A)
but in WIIMOTESTATE.__repr__() the Button-Values are accessed as ButtonA, ButtonB .. :
txt = "Button: %s:%s %s:%s " % ("A", [' ','*'][self.ButtonA], "B", [' ','*'][self.ButtonB])
Thus the correct values are never displayed, the following changes have to be made in order to show them:
txt = "Button: %s:%s %s:%s " % ("A", [' ','*'][self.A], "B", [' ','*'][self.B])
txt += "%s:%s %s:%s " % ("^", [' ','*'][self.Up], "v", [' ','*'][self.Down])
txt += "%s:%s %s:%s " % ("<", [' ','*'][self.Left], ">", [' ','*'][self.Right])
txt += "%s:%s %s:%s " % ("-", [' ','*'][self.Minus], "+", [' ','*'][self.Plus])
txt += "%s:%s %s:%s " % ("1", [' ','*'][self.One], "2", [' ','*'][self.Two])
txt += "%s:%s\n" % ("Home", [' ','*'][self.Home])
[edit] Some additional notes
EDIT: i uploaded a new version. The old text is deprecated.

