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