55a1c98dce3735f1112be7db411363277b673178
[minwii.git] / src / pywiiuse / PyWiiUse.py
1 '''Python interface to the wiiuse library for the wii remote
2
3 Just a simple wrapper, no attempt to make the api pythonic. I tried to hide ctypes where
4 necessary.
5
6 This software is free for any use. If you or your lawyer are stupid enough to believe I have any
7 liability for it, then don't use it; otherwise, be my guest.
8
9 Gary Bishop, January 2008
10 hacked for new API and data June 2009
11 '''
12
13 import os
14 import ctypes
15 from ctypes import c_char_p, c_int, c_byte, c_uint, c_uint16, c_float, c_short, c_void_p, c_char
16 from ctypes import CFUNCTYPE, Structure, POINTER, Union, byref, cdll
17 import sys
18
19 # duplicate the wiiuse data structures
20
21 class _Structure(Structure):
22 def __repr__(self):
23 '''Print the fields'''
24 res = []
25 for field in self._fields_:
26 res.append('%s=%s' % (field[0], repr(getattr(self, field[0]))))
27 return self.__class__.__name__ + '(' + ','.join(res) + ')'
28
29 class vec2b(_Structure):
30 _fields_ = [('x', c_byte),
31 ('y', c_byte),
32 ]
33
34 class vec3b(_Structure):
35 _fields_ = [('x', c_byte),
36 ('y', c_byte),
37 ('z', c_byte),
38 ]
39
40 class vec3f(_Structure):
41 _fields_ = [('x', c_float),
42 ('y', c_float),
43 ('z', c_float),
44 ]
45
46 class orient(_Structure):
47 _fields_ = [('roll', c_float),
48 ('pitch', c_float),
49 ('yaw', c_float),
50 ('a_roll', c_float),
51 ('a_pitch', c_float),
52 ]
53
54 def __repr__(self):
55 return 'orient(roll=%f pitch=%f yaw=%f a_roll=%f a_pitch=%f)' % (
56 self.roll, self.pitch, self.yaw, self.a_roll, self.a_pitch)
57
58 class accel(_Structure):
59 _fields_ = [('cal_zero', vec3b),
60 ('cal_g', vec3b),
61 ('st_roll', c_float),
62 ('st_pitch', c_float),
63 ('st_alpha', c_float),
64 ]
65
66 class ir_dot(_Structure):
67 _fields_ = [('visible', c_byte),
68 ('x', c_uint),
69 ('y', c_uint),
70 ('rx', c_short),
71 ('ry', c_short),
72 ('order', c_byte),
73 ('size', c_byte),
74 ]
75
76 class ir(_Structure):
77 _fields_ = [('dot', ir_dot*4),
78 ('num_dots', c_byte),
79 ('aspect', c_int),
80 ('pos', c_int),
81 ('vres', c_uint*2),
82 ('offset', c_int*2),
83 ('state', c_int),
84 ('ax', c_int),
85 ('ay', c_int),
86 ('x', c_int),
87 ('y', c_int),
88 ('distance', c_float),
89 ('z', c_float),
90 ]
91
92 class joystick(_Structure):
93 _fields_ = [('max', vec2b),
94 ('min', vec2b),
95 ('center', vec2b),
96 ('ang', c_float),
97 ('mag', c_float),
98 ]
99
100 class nunchuk(_Structure):
101 _fields_ = [('accel_calib', accel),
102 ('js', joystick),
103 ('flags', POINTER(c_int)),
104 ('btns', c_byte),
105 ('btns_held', c_byte),
106 ('btns_released', c_byte),
107 ('orient_threshold', c_float),
108 ('accel_threshold', c_int),
109 ('accel', vec3b),
110 ('orient', orient),
111 ('gforce', vec3f),
112 ]
113
114 class classic_ctrl(_Structure):
115 _fields_ = [('btns', c_short),
116 ('btns_held', c_short),
117 ('btns_released', c_short),
118 ('r_shoulder', c_float),
119 ('l_shoulder', c_float),
120 ('ljs', joystick),
121 ('rjs', joystick),
122 ]
123
124 class guitar_hero_3(_Structure):
125 _fields_ = [('btns', c_short),
126 ('btns_held', c_short),
127 ('btns_released', c_short),
128 ('whammy_bar', c_float),
129 ('js', joystick),
130 ]
131
132 class expansion_union(Union):
133 _fields_ = [('nunchuk', nunchuk),
134 ('classic', classic_ctrl),
135 ('gh3', guitar_hero_3),
136 ]
137
138 class expansion(_Structure):
139 _fields_ = [('type', c_int),
140 ('u', expansion_union),
141 ]
142
143 class wiimote_state(_Structure):
144 _fields_ = [('exp_ljs_ang', c_float),
145 ('exp_rjs_ang', c_float),
146 ('exp_ljs_mag', c_float),
147 ('exp_rjs_mag', c_float),
148 ('exp_btns', c_uint16),
149 ('exp_orient', orient),
150 ('exp_accel', vec3b),
151 ('exp_r_shoulder', c_float),
152 ('exp_l_shoulder', c_float),
153 ('ir_ax', c_int),
154 ('ir_ay', c_int),
155 ('ir_distance', c_float),
156 ('orient', orient),
157 ('btns', c_uint16),
158 ('accel', vec3b),
159 ]
160
161 if os.name == 'nt':
162 JunkSkip = [('dev_handle', c_void_p),
163 ('hid_overlap', c_void_p*5), # skipping over this data structure
164 ('stack', c_int),
165 ('timeout', c_int),
166 ('normal_timeout', c_byte),
167 ('exp_timeout', c_byte),
168 ]
169 else:
170 JunkSkip = [('bdaddr', c_void_p),
171 ('bdaddr_str', c_char*18),
172 ('out_sock', c_int),
173 ('in_sock', c_int),
174 ]
175
176 EVENT = 1
177 STATUS = 2
178 CONNECT = 3
179 DISCONNECT = 4
180 UNEXPECTED_DISCONNECT = 5
181 READ_DATA = 6
182 NUNCHUK_INSERTED = 7
183 NUNCHUK_REMOVED = 8
184 CLASSIC_CTRL_INSERTED = 9
185 CLASSIC_CTRL_REMOVED = 10
186 GUITAR_HERO_3_CTRL_INSERTED = 11
187 GUITAR_HERO_3_CTRL_REMOVED = 12
188
189 class wiimote(_Structure):
190 _fields_ = [('unid', c_int),
191 ] + JunkSkip + [
192 ('state', c_int),
193 ('leds', c_byte),
194 ('battery_level', c_float),
195 ('flags', c_int),
196 ('handshake_state', c_byte),
197 ('read_req', c_void_p),
198 ('accel_calib', accel),
199 ('exp', expansion),
200 ('accel', vec3b),
201 ('orient', orient),
202 ('gforce', vec3f),
203 ('ir', ir),
204 ('btns', c_uint16),
205 ('btns_held', c_uint16),
206 ('btns_released', c_uint16),
207 ('orient_threshold', c_float),
208 ('accel_threshold', c_int),
209 ('lstate', wiimote_state),
210 ('event', c_int),
211 ('event_buf', c_byte*32),
212 ]
213
214 wiimote_p = POINTER(wiimote)
215 wiimote_pp = POINTER(wiimote_p)
216
217 # make function prototypes a bit easier to declare
218 def cfunc(name, dll, result, *args):
219 '''build and apply a ctypes prototype complete with parameter flags
220 e.g.
221 cvMinMaxLoc = cfunc('cvMinMaxLoc', _cxDLL, None,
222 ('image', POINTER(IplImage), 1),
223 ('min_val', POINTER(double), 2),
224 ('max_val', POINTER(double), 2),
225 ('min_loc', POINTER(CvPoint), 2),
226 ('max_loc', POINTER(CvPoint), 2),
227 ('mask', POINTER(IplImage), 1, None))
228 means locate cvMinMaxLoc in dll _cxDLL, it returns nothing.
229 The first argument is an input image. The next 4 arguments are output, and the last argument is
230 input with an optional value. A typical call might look like:
231
232 min_val,max_val,min_loc,max_loc = cvMinMaxLoc(img)
233 '''
234 atypes = []
235 aflags = []
236 for arg in args:
237 atypes.append(arg[1])
238 aflags.append((arg[2], arg[0]) + arg[3:])
239 return CFUNCTYPE(result, *atypes)((name, dll), tuple(aflags))
240
241 # get the shared library
242 if os.name == 'nt':
243 dll = cdll.LoadLibrary('wiiuse.dll')
244 else:
245 dll = cdll.LoadLibrary('libwiiuse.so')
246
247 # access the functions
248 init = cfunc('wiiuse_init', dll, wiimote_pp,
249 ('wiimotes', c_int, 1))
250 # find = cfunc('wiiuse_find', dll, c_int,
251 # ('wm', wiimote_pp, 1),
252 # ('max_wiimotes', c_int, 1),
253 # ('timeout', c_int, 1))
254 # connect = cfunc('wiiuse_connect', dll, c_int,
255 # ('wm', wiimote_pp, 1),
256 # ('wiimotes', c_int, 1))
257 # poll = cfunc('wiiuse_poll', dll, c_int,
258 # ('wm', wiimote_pp, 1),
259 # ('wiimotes', c_int, 1))
260 find = dll.wiiuse_find
261 connect = dll.wiiuse_connect
262 poll = dll.wiiuse_poll
263 set_leds = dll.wiiuse_set_leds
264 motion_sensing = dll.wiiuse_motion_sensing
265 set_accel_threshold = dll.wiiuse_set_accel_threshold
266 set_orient_threshold = dll.wiiuse_set_orient_threshold
267 set_orient_threshold.argtypes = [wiimote_p, c_float]
268 set_timeout = dll.wiiuse_set_timeout
269
270 def is_pressed(dev, button):
271 return dev.btns & button
272
273 def is_held(dev, button):
274 return dev.btns_held & button
275
276 def is_released(dev, button):
277 return dev.btns_released & button
278
279 def is_just_pressed(dev, button):
280 return is_pressed(dev, button) and not is_held(dev, button)
281
282 def using_acc(wm):
283 return wm.state & 0x10
284
285 def using_exp(wm):
286 return wm.state & 0x20
287
288 def using_ir(wm):
289 return wm.state & 0x40
290
291 LED_NONE = 0
292 LED_1 = 0x10
293 LED_2 = 0x20
294 LED_3 = 0x40
295 LED_4 = 0x80
296
297 LED = [LED_1, LED_2, LED_3, LED_4]
298
299 EXP_NONE = 0
300 EXP_NUNCHUK = 1
301 EXP_CLASSIC = 2
302
303 SMOOTHING = 0x01
304 CONTINUOUS = 0x02
305 ORIENT_THRESH = 0x04
306 INIT_FLAGS = SMOOTHING | ORIENT_THRESH
307
308 IR_ABOVE = 0
309 IR_BELOW = 1
310
311 ASPECT_4_3 = 0
312 ASPECT_16_9 = 1
313
314 button = { '2':0x0001,
315 '1':0x0002,
316 'B':0x0004,
317 'A':0x0008,
318 '-':0x0010,
319 'Home':0x0080,
320 'Left':0x0100,
321 'Right':0x0200,
322 'Down':0x0400,
323 'Up':0x0800,
324 '+':0x1000,
325 }
326
327 nunchuk_button = { 'Z':0x01,
328 'C':0x02,
329 }
330
331
332 if __name__ == '__main__':
333 def handle_event(wm):
334 print 'EVENT', wm.unid, wm.btns
335 print wm.gforce.x, wm.gforce.y, wm.gforce.z
336
337 nmotes = 1
338 wiimotes = init(nmotes)
339 print 'press 1&2'
340 found = find(wiimotes, nmotes, 2)
341 if not found:
342 print 'no wiimotes found'
343 sys.exit(1)
344
345 connected = connect(wiimotes, nmotes)
346 if connected:
347 print 'connected to %d wiimotes (of %d found)' % (connected, found)
348 else:
349 print 'failed to connect to any wiimote.'
350 sys.exit(1)
351
352 set_leds(wiimotes[0], 0x50)
353 motion_sensing(wiimotes[0], 1)
354
355 while True:
356 if poll(wiimotes, nmotes):
357 for i in range(nmotes):
358 m = wiimotes[i][0]
359 if wiimotes[i][0].event == EVENT:
360 handle_event(wiimotes[i][0])
361