Expérimentations (concluantes) de hand tracking.
[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, c_ubyte, c_ushort
16 from ctypes import CFUNCTYPE, Structure, POINTER, Union, byref, cdll
17 from ctypes.util import find_library
18 import sys
19
20 # duplicate the wiiuse data structures
21
22 class _Structure(Structure):
23 def __repr__(self):
24 '''Print the fields'''
25 res = []
26 for field in self._fields_:
27 res.append('%s=%s' % (field[0], repr(getattr(self, field[0]))))
28 return self.__class__.__name__ + '(' + ','.join(res) + ')'
29
30 class vec2b(_Structure):
31 _fields_ = [('x', c_byte),
32 ('y', c_byte),
33 ]
34
35 class vec3b(_Structure):
36 _fields_ = [('x', c_byte),
37 ('y', c_byte),
38 ('z', c_byte),
39 ]
40
41 class vec3w(_Structure):
42 _fields_ = [('x', c_ushort),
43 ('y', c_ushort),
44 ('z', c_ushort),
45 ]
46
47 class vec3f(_Structure):
48 _fields_ = [('x', c_float),
49 ('y', c_float),
50 ('z', c_float),
51 ]
52
53 class orient(_Structure):
54 _fields_ = [('roll', c_float),
55 ('pitch', c_float),
56 ('yaw', c_float),
57 ('a_roll', c_float),
58 ('a_pitch', c_float),
59 ]
60
61 def __repr__(self):
62 return 'orient(roll=%f pitch=%f yaw=%f a_roll=%f a_pitch=%f)' % (
63 self.roll, self.pitch, self.yaw, self.a_roll, self.a_pitch)
64
65 class accel(_Structure):
66 _fields_ = [('cal_zero', vec3w),
67 ('cal_g', vec3w),
68 ('st_roll', c_float),
69 ('st_pitch', c_float),
70 ('st_alpha', c_float),
71 ]
72
73 class ir_dot(_Structure):
74 _fields_ = [('visible', c_byte),
75 ('x', c_uint),
76 ('y', c_uint),
77 ('rx', c_short),
78 ('ry', c_short),
79 ('order', c_byte),
80 ('size', c_byte),
81 ]
82
83 class ir(_Structure):
84 _fields_ = [('dot', ir_dot*4),
85 ('num_dots', c_byte),
86 ('aspect', c_int),
87 ('pos', c_int),
88 ('vres', c_uint*2),
89 ('offset', c_int*2),
90 ('state', c_int),
91 ('ax', c_int),
92 ('ay', c_int),
93 ('x', c_int),
94 ('y', c_int),
95 ('distance', c_float),
96 ('z', c_float),
97 ]
98
99 def __str__(self) :
100 l = []
101 pr = l.append
102 for name, typ in self._fields_ :
103 try :
104 pr('(%s, %s)' % (name, getattr(self, name)))
105 except :
106 pass
107 return '\n'.join(l)
108
109 class joystick(_Structure):
110 _fields_ = [('max', vec2b),
111 ('min', vec2b),
112 ('center', vec2b),
113 ('ang', c_float),
114 ('mag', c_float),
115 ]
116
117 class nunchuk(_Structure):
118 _fields_ = [('accel_calib', accel),
119 ('js', joystick),
120 ('flags', POINTER(c_int)),
121 ('btns', c_byte),
122 ('btns_last', c_byte),
123 ('btns_held', c_byte),
124 ('btns_released', c_byte),
125 ('orient_threshold', c_float),
126 ('accel_threshold', c_float),
127 ('accel', vec3w),
128 ('orient', orient),
129 ('gforce', vec3f),
130 ]
131
132 class classic_ctrl(_Structure):
133 _fields_ = [('btns', c_short),
134 ('btns_last', c_short),
135 ('btns_held', c_short),
136 ('btns_released', c_short),
137 ('r_shoulder', c_float),
138 ('l_shoulder', c_float),
139 ('ljs', joystick),
140 ('rjs', joystick),
141 ]
142
143 class guitar_hero_3(_Structure):
144 _fields_ = [('btns', c_short),
145 ('btns_last', c_short),
146 ('btns_held', c_short),
147 ('btns_released', c_short),
148 ('whammy_bar', c_float),
149 ('js', joystick),
150 ]
151
152 class motion_plus(_Structure):
153 _fields_ = [('rx', c_short),
154 ('ry', c_short),
155 ('rz', c_short),
156 ('status', c_ubyte),
157 ('ext', c_ubyte)
158 ]
159
160 class expansion_union(Union):
161 _fields_ = [('nunchuk', nunchuk),
162 ('classic', classic_ctrl),
163 ('gh3', guitar_hero_3),
164 ('mp', motion_plus)
165 ]
166
167 class expansion(_Structure):
168 _fields_ = [('type', c_int),
169 ('u', expansion_union),
170 ]
171
172 class wiimote_state(_Structure):
173 _fields_ = [('exp_ljs_ang', c_float),
174 ('exp_rjs_ang', c_float),
175 ('exp_ljs_mag', c_float),
176 ('exp_rjs_mag', c_float),
177 ('exp_btns', c_ushort),
178 ('exp_orient', orient),
179 ('exp_accel', vec3w),
180 ('exp_r_shoulder', c_float),
181 ('exp_l_shoulder', c_float),
182 ('drx', c_short),
183 ('dry', c_short),
184 ('drz', c_short),
185 ('ir_ax', c_int),
186 ('ir_ay', c_int),
187 ('ir_distance', c_float),
188 ('orient', orient),
189 ('btns', c_ushort),
190 ('accel', vec3b),
191 ('exp', expansion)
192 ]
193
194 if os.name == 'nt':
195 JunkSkip = [('dev_handle', c_void_p),
196 ('hid_overlap', c_void_p*5), # skipping over this data structure
197 ('stack', c_int),
198 ('timeout', c_int),
199 ('normal_timeout', c_byte),
200 ('exp_timeout', c_byte),
201 ]
202
203 elif sys.platform == 'darwin' :
204 JunkSkip = [('device', c_void_p),
205 ('bdaddr_str', c_char*18)
206 ]
207
208 else:
209 JunkSkip = [('bdaddr', c_void_p),
210 ('bdaddr_str', c_char*18),
211 ('out_sock', c_int),
212 ('in_sock', c_int),
213 ]
214
215 EVENT = 1
216 STATUS = 2
217 CONNECT = 3
218 DISCONNECT = 4
219 UNEXPECTED_DISCONNECT = 5
220 READ_DATA = 6
221 NUNCHUK_INSERTED = 7
222 NUNCHUK_REMOVED = 8
223 CLASSIC_CTRL_INSERTED = 9
224 CLASSIC_CTRL_REMOVED = 10
225 GUITAR_HERO_3_CTRL_INSERTED = 11
226 GUITAR_HERO_3_CTRL_REMOVED = 12
227
228 class wiimote(_Structure):
229 _fields_ = [('unid', c_int),
230 ] + JunkSkip + [
231 ('state', c_int),
232 ('leds', c_byte),
233 ('battery_level', c_float),
234
235 ('flags', c_int),
236
237 ('handshake_state', c_byte),
238 ('expansion_state', c_ubyte),
239 ('read_req', c_void_p),
240 ('data_req', c_void_p),
241
242 ('cmd_head', c_void_p),
243 ('cmd_tail', c_void_p),
244 ('accel_calib', accel),
245 ('exp', expansion),
246
247 ('accel', vec3w),
248 ('orient', orient),
249 ('gforce', vec3f),
250
251 ('ir', ir),
252
253 ('btns', c_ushort),
254 ('btns_last', c_ushort),
255 ('btns_held', c_ushort),
256 ('btns_released', c_ushort),
257 ('orient_threshold', c_float),
258 ('accel_threshold', c_int),
259
260 ('lstate', wiimote_state),
261
262 ('event', c_int),
263 ('event_buf', c_byte*32),
264 ('motion_plus_id', c_ubyte*6)
265 ]
266
267 wiimote_p = POINTER(wiimote)
268 wiimote_pp = POINTER(wiimote_p)
269
270 # make function prototypes a bit easier to declare
271 def cfunc(name, dll, result, *args):
272 '''build and apply a ctypes prototype complete with parameter flags
273 e.g.
274 cvMinMaxLoc = cfunc('cvMinMaxLoc', _cxDLL, None,
275 ('image', POINTER(IplImage), 1),
276 ('min_val', POINTER(double), 2),
277 ('max_val', POINTER(double), 2),
278 ('min_loc', POINTER(CvPoint), 2),
279 ('max_loc', POINTER(CvPoint), 2),
280 ('mask', POINTER(IplImage), 1, None))
281 means locate cvMinMaxLoc in dll _cxDLL, it returns nothing.
282 The first argument is an input image. The next 4 arguments are output, and the last argument is
283 input with an optional value. A typical call might look like:
284
285 min_val,max_val,min_loc,max_loc = cvMinMaxLoc(img)
286 '''
287 atypes = []
288 aflags = []
289 for arg in args:
290 atypes.append(arg[1])
291 aflags.append((arg[2], arg[0]) + arg[3:])
292 return CFUNCTYPE(result, *atypes)((name, dll), tuple(aflags))
293
294 # get the shared library
295 lib = find_library('wiiuse') or find_library('libwiiuse')
296 dll = cdll.LoadLibrary(lib)
297
298 #if os.name == 'nt':
299 # dll = cdll.LoadLibrary('wiiuse.dll')
300 #else:
301 # dll = cdll.LoadLibrary('libwiiuse.so')
302
303 # access the functions
304 init = cfunc('wiiuse_init', dll, wiimote_pp,
305 ('wiimotes', c_int, 1))
306 # find = cfunc('wiiuse_find', dll, c_int,
307 # ('wm', wiimote_pp, 1),
308 # ('max_wiimotes', c_int, 1),
309 # ('timeout', c_int, 1))
310 # connect = cfunc('wiiuse_connect', dll, c_int,
311 # ('wm', wiimote_pp, 1),
312 # ('wiimotes', c_int, 1))
313 # poll = cfunc('wiiuse_poll', dll, c_int,
314 # ('wm', wiimote_pp, 1),
315 # ('wiimotes', c_int, 1))
316 find = dll.wiiuse_find
317 connect = dll.wiiuse_connect
318 poll = dll.wiiuse_poll
319 set_leds = dll.wiiuse_set_leds
320 motion_sensing = dll.wiiuse_motion_sensing
321 set_accel_threshold = dll.wiiuse_set_accel_threshold
322 set_orient_threshold = dll.wiiuse_set_orient_threshold
323 set_orient_threshold.argtypes = [wiimote_p, c_float]
324 set_timeout = dll.wiiuse_set_timeout
325 set_ir = dll.wiiuse_set_ir
326 set_ir_position = dll.wiiuse_set_ir_position
327 set_ir_vres = dll.wiiuse_set_ir_vres
328
329 def is_pressed(dev, button):
330 return dev.btns & button
331
332 def is_held(dev, button):
333 return dev.btns_held & button
334
335 def is_released(dev, button):
336 return dev.btns_released & button
337
338 def is_just_pressed(dev, button):
339 return is_pressed(dev, button) and not is_held(dev, button)
340
341 def using_acc(wm):
342 return wm.state & 0x10
343
344 def using_exp(wm):
345 return wm.state & 0x20
346
347 def using_ir(wm):
348 return wm.state & 0x40
349
350 LED_NONE = 0
351 LED_1 = 0x10
352 LED_2 = 0x20
353 LED_3 = 0x40
354 LED_4 = 0x80
355
356 LED = [LED_1, LED_2, LED_3, LED_4]
357
358 EXP_NONE = 0
359 EXP_NUNCHUK = 1
360 EXP_CLASSIC = 2
361
362 SMOOTHING = 0x01
363 CONTINUOUS = 0x02
364 ORIENT_THRESH = 0x04
365 INIT_FLAGS = SMOOTHING | ORIENT_THRESH
366
367 IR_ABOVE = 0
368 IR_BELOW = 1
369
370 ASPECT_4_3 = 0
371 ASPECT_16_9 = 1
372
373 button = { '2':0x0001,
374 '1':0x0002,
375 'B':0x0004,
376 'A':0x0008,
377 '-':0x0010,
378 'Home':0x0080,
379 'Left':0x0100,
380 'Right':0x0200,
381 'Down':0x0400,
382 'Up':0x0800,
383 '+':0x1000,
384 }
385
386 nunchuk_button = { 'Z':0x01,
387 'C':0x02,
388 }
389
390
391 if __name__ == '__main__':
392 def handle_event(wm):
393 print 'EVENT', wm.unid, wm.btns
394 #print wm.gforce.x, wm.gforce.y, wm.gforce.z
395 print wm.ir
396
397 nmotes = 1
398 wiimotes = init(nmotes)
399 print 'press 1&2'
400 found = find(wiimotes, nmotes, 2)
401 if not found:
402 print 'no wiimotes found'
403 sys.exit(1)
404
405 connected = connect(wiimotes, nmotes)
406 if connected:
407 print 'connected to %d wiimotes (of %d found)' % (connected, found)
408 else:
409 print 'failed to connect to any wiimote.'
410 sys.exit(1)
411
412 set_leds(wiimotes[0], 0x20)
413 motion_sensing(wiimotes[0], 1)
414 set_ir(wiimotes[0], 1)
415
416 while True:
417 try :
418 if poll(wiimotes, nmotes):
419 print '.'
420 for i in range(nmotes):
421 m = wiimotes[i][0]
422 if wiimotes[i][0].event == EVENT:
423 handle_event(wiimotes[i][0])
424 except KeyboardInterrupt :
425 break
426