root/trunk/python/Wiimote.c

Revision 179, 23.4 kB (checked in by dsmith, 7 months ago)

Allow multithreading during Wiimote constructor (python) (#62)

Line 
1 /*
2  * Copyright (C) 2007 Justin M. Tulloss <jmtulloss@gmail.com>
3  *
4  * Interface from Python to libcwiid
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA  02110-1301  USA
20  *
21  * ChangeLog:
22  * 2008-01-19 L. Donnie Smith <cwiid@abstrakraft.org>
23  * * print callback error tracebacks
24  *
25  * 2007-06-18 L. Donnie Smith <cwiid@abstrakraft.org>
26  * * revised error messages and doc strings
27  *
28  * 2007-06-05 L. Donnie Smith <cwiid@abstrakraft.org>
29  * * removed Wiimote_FromC function
30  * * added bdaddr argument to Wiimote.init
31  * * overloaded Wiimote.init to accept CObject (existing wiimote),
32  *   and logic to avoid closing it on dealloc
33  *
34  * 2007-06-01 L. Donnie Smith <cwiid@abstrakraft.org>
35  * * added Wiimote_FromC
36  * * added get_acc_cal
37  *
38  * 2007-05-27 Arthur Peters <amp@singingwizard.org>
39  * * removed set_mesg_callback from methods table
40  *
41  * 2007-05-22 L. Donnie Smith <cwiid@abstrakraft.org>
42  * * changed disconnect to close
43  * * replaced command with attributes for rpt_mode, rumble, led,
44  *   added request_status method
45  * * fixed memory leak in get_mesg
46  * * added function names to argument parsing errors
47  * * changed to processMesg to ConvertMesgArray with global visibility
48  *
49  * 2007-05-15 L. Donnie Smith <cwiid@abstrakraft.org>
50  * * revised message types
51  * * revised argument/keylist parsing
52  *
53  * 2007-05-14 L. Donnie Smith <cwiid@abstrakraft.org>
54  * * moved Wiimote class to separate file
55  */
56
57 #include "Python.h"
58 #include "structmember.h"
59 #include <errno.h>
60 #include <bluetooth/bluetooth.h>
61 #include "cwiid.h"
62
63 typedef struct {
64         PyObject_HEAD
65         cwiid_wiimote_t *wiimote;
66         PyObject *callback;
67         char close_on_dealloc;
68 } Wiimote;
69
70 /* method prototypes */
71 static PyObject *
72         Wiimote_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
73 static void Wiimote_dealloc(Wiimote *self);
74 static int Wiimote_init(Wiimote *self, PyObject *args, PyObject *kwds);
75 static PyObject *Wiimote_close(Wiimote *self);
76
77 static PyObject *Wiimote_enable(Wiimote *self, PyObject *args, PyObject *kwds);
78 static PyObject *
79         Wiimote_disable(Wiimote *self, PyObject *args, PyObject *kwds);
80
81 static int
82         Wiimote_set_mesg_callback(Wiimote *self, PyObject *args, void *closure);
83 static PyObject *Wiimote_get_mesg(Wiimote *self);
84 static PyObject *Wiimote_get_state(Wiimote *self, void *closure);
85 static PyObject *Wiimote_get_acc_cal(Wiimote *self, PyObject *args,
86                                      PyObject *kwds);
87
88 static PyObject *Wiimote_request_status(Wiimote *self);
89 static int Wiimote_set_led(Wiimote *self, PyObject *PyLed, void *closure);
90 static int
91         Wiimote_set_rumble(Wiimote *self, PyObject *PyRumble, void *closure);
92 static int
93         Wiimote_set_rpt_mode(Wiimote *self, PyObject *PyRptMode, void *closure);
94
95 static PyObject *Wiimote_read(Wiimote *self, PyObject *args, PyObject *kwds);
96 static PyObject *Wiimote_write(Wiimote *self, PyObject *args, PyObject *kwds);
97
98 /* helper prototypes */
99 static cwiid_mesg_callback_t CallbackBridge;
100 PyObject *ConvertMesgArray(int mesg_count, union cwiid_mesg mesg[]);
101
102 static PyMethodDef Wiimote_Methods[] =
103 {
104         {"close", (PyCFunction)Wiimote_close, METH_NOARGS,
105          "close()\n\nClose the Wiimote connection"},
106         {"enable", (PyCFunction)Wiimote_enable, METH_VARARGS | METH_KEYWORDS,
107          "enable(flags)\n\nenable Wiimote connection flags"},
108         {"disable", (PyCFunction)Wiimote_disable, METH_VARARGS | METH_KEYWORDS,
109          "disable(flags)\n\ndisable Wiimote connection flags"},
110         {"get_mesg", (PyCFunction)Wiimote_get_mesg, METH_NOARGS,
111          "get_mesg() -> message list\n\nretrieve message list from queue"},
112         {"get_acc_cal", (PyCFunction)Wiimote_get_acc_cal,
113          METH_VARARGS | METH_KEYWORDS,
114          "get_acc_cal(extension) -> calibration tuple\n\n"
115          "retrieve calibration information"},
116         {"request_status", (PyCFunction)Wiimote_request_status, METH_NOARGS,
117          "request_status()\n\nrequest status message"},
118         {"read", (PyCFunction)Wiimote_read, METH_VARARGS | METH_KEYWORDS,
119          "read(flags,offset,len) -> buffer\n\nread data from Wiimote"},
120         {"write", (PyCFunction)Wiimote_write, METH_VARARGS | METH_KEYWORDS,
121          "write(flags,offset,buffer)\n\nwrite data to Wiimote"},
122         {NULL, NULL, 0, NULL}
123 };
124
125 static PyGetSetDef Wiimote_GetSet[] = {
126         {"state", (getter)Wiimote_get_state, NULL, "Wiimote state", NULL},
127         {"mesg_callback", NULL, (setter)Wiimote_set_mesg_callback,
128          "Wiimote message callback", NULL},
129         {"led", NULL, (setter)Wiimote_set_led, "Wiimote led state", NULL},
130         {"rumble", NULL, (setter)Wiimote_set_rumble, "Wiimote rumble state", NULL},
131         {"rpt_mode", NULL, (setter)Wiimote_set_rpt_mode, "Wiimote report mode",
132          NULL},
133         {NULL, NULL, NULL, NULL, NULL}
134 };
135
136 PyTypeObject Wiimote_Type = {
137         PyObject_HEAD_INIT(NULL)
138         0,                                              /* ob_size */
139         "cwiid.Wiimote",                /* tp_name */
140         sizeof(Wiimote),                /* tp_basicsize */
141         0,                                              /* tp_itemsize */
142         (destructor)Wiimote_dealloc,    /* tp_dealloc */
143         0,                                              /* tp_print */
144         0,                                              /* tp_getattr */
145         0,                                              /* tp_setattr */
146         0,                                              /* tp_compare */
147         0,                                              /* tp_repr */
148         0,                                              /* tp_as_number */
149         0,                                              /* tp_as_sequence */
150         0,                                              /* tp_as_mapping */
151         0,                                              /* tp_hash */
152         0,                                              /* tp_call */
153         0,                                              /* tp_str */
154         0,                                              /* tp_getattro */
155         0,                                              /* tp_setattro */
156         0,                                              /* tp_as_buffer */
157         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,       /* tp_flags */
158         "CWiid Wiimote connection object",      /* tp_doc */
159         0,                                              /* tp_traverse */
160         0,                                              /* tp_clear */
161         0,                                              /* tp_richcompare */
162         0,                                              /* tp_weaklistoffset */
163         0,                                              /* tp_iter */
164         0,                                              /* tp_iternext */
165         Wiimote_Methods,                /* tp_methods */
166         0,                                              /* tp_members */
167         Wiimote_GetSet,                 /* tp_getset */
168         0,                                              /* tp_base */
169         0,                                              /* tp_dict */
170         0,                                              /* tp_descr_get */
171         0,                                              /* tp_descr_set */
172         0,                                              /* tp_dictoffset */
173         (initproc)Wiimote_init, /* tp_init */
174         0,                                              /* tp_alloc */
175         Wiimote_new,                    /* tp_new */
176 };
177
178 /* Allocate and deallocate functions */
179 static PyObject *
180         Wiimote_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
181 {
182         Wiimote* self;
183
184         if (!(self = (Wiimote *) type->tp_alloc(type, 0))) {
185                 return NULL;
186         }
187
188         self->wiimote = NULL;
189         Py_INCREF(self->callback = Py_None);
190         self->close_on_dealloc = 0;
191
192         return (PyObject*) self;
193 }
194
195 static void Wiimote_dealloc(Wiimote *self)
196 {
197         if (self->close_on_dealloc && self->wiimote) {
198                 cwiid_close(self->wiimote);
199         }
200         Py_XDECREF(self->callback);
201         self->ob_type->tp_free((PyObject *)self);
202 }
203
204 static int Wiimote_init(Wiimote* self, PyObject* args, PyObject *kwds)
205 {
206         static char *kwlist[] = {"bdaddr", "flags", NULL};
207         PyObject *PyObj;
208         cwiid_wiimote_t *wiimote = NULL;
209         char *str_bdaddr = NULL;
210         bdaddr_t bdaddr;
211         int flags = 0;
212
213         /* Overloaded function - if a single CObject is passed in, it's
214          * an existing CObject.  Otherwise, create a new one */
215         if (PyTuple_Size(args) == 1) {
216                 PyObj = PyTuple_GET_ITEM(args, 0);
217                 if (PyCObject_Check(PyObj)) {
218                         wiimote = PyCObject_AsVoidPtr(PyObj);
219                         self->close_on_dealloc = 0;
220                 }
221         }
222
223         if (!wiimote) {
224                 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|si:cwiid.Wiimote.init",
225                                                  kwlist, &str_bdaddr, &flags)) {
226                         return -1;
227                 }
228
229                 if (str_bdaddr) {
230                         if (str2ba(str_bdaddr, &bdaddr)) {
231                                 PyErr_SetString(PyExc_ValueError, "bad bdaddr");
232                                 return -1;
233                         }
234                 }
235                 else {
236                         bdaddr = *BDADDR_ANY;
237                 }
238
239                 Py_BEGIN_ALLOW_THREADS
240                 wiimote = cwiid_open(&bdaddr, flags);
241                 Py_END_ALLOW_THREADS
242                 if (!wiimote) {
243                         PyErr_SetString(PyExc_RuntimeError,
244                                         "Error opening wiimote connection");
245                         return -1;
246                 }
247                 else {
248                         self->close_on_dealloc = 1;
249                 }
250         }
251
252         cwiid_set_data(wiimote, self);
253         self->wiimote = wiimote;
254         return 0;
255 }
256
257 static PyObject *Wiimote_close(Wiimote *self)
258 {
259         if (cwiid_close(self->wiimote)) {
260                 PyErr_SetString(PyExc_RuntimeError,
261                                 "Error closing wiimote connection");
262                 self->wiimote = NULL;
263                 return NULL;
264         }
265         self->wiimote = NULL;
266
267         Py_RETURN_NONE;
268 }
269
270 static PyObject *Wiimote_enable(Wiimote *self, PyObject *args, PyObject *kwds)
271 {
272         static char *kwlist[] = {"flags", NULL};
273         int flags;
274
275         if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:cwiid.Wiimote.enable",
276                                          kwlist, &flags)) {
277                 return NULL;
278         }
279
280         if (cwiid_enable(self->wiimote, flags)) {
281                 PyErr_SetString(PyExc_RuntimeError, "Error enabling wiimote flags");
282                 return NULL;
283         }
284
285         Py_RETURN_NONE;
286 }
287
288 static PyObject *Wiimote_disable(Wiimote *self, PyObject *args, PyObject *kwds)
289 {
290         static char *kwlist[] = {"flags", NULL};
291         int flags;
292
293         if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:cwiid.Wiimote.disable",
294                                          kwlist, &flags)) {
295                 return NULL;
296         }
297
298         if (cwiid_disable(self->wiimote, flags)) {
299                 PyErr_SetString(PyExc_RuntimeError, "Error disabling wiimote flags");
300                 return NULL;
301         }
302
303         Py_RETURN_NONE;
304 }
305
306 static int
307         Wiimote_set_mesg_callback(Wiimote *self, PyObject *NewCallback,
308                                   void *closure)
309 {
310         PyObject *OldCallback;
311
312         if (!PyCallable_Check(NewCallback)) {
313                 PyErr_SetString(PyExc_TypeError, "callback must be callable!");
314         }
315         OldCallback = self->callback;
316
317         if ((OldCallback == Py_None) && (NewCallback != Py_None)) {
318                 if (cwiid_set_mesg_callback(self->wiimote, CallbackBridge)) {
319                         PyErr_SetString(PyExc_AttributeError,
320                                         "Error setting wiimote callback");
321                         return -1;
322                 }
323         }
324         else if ((OldCallback != Py_None) && (NewCallback == Py_None)) {
325                 if (cwiid_set_mesg_callback(self->wiimote, NULL)) {
326                         PyErr_SetString(PyExc_AttributeError,
327                                         "Error clearing wiimote callback");
328                         return -1;
329                 }
330         }
331
332         Py_INCREF(NewCallback);
333         Py_DECREF(OldCallback);
334         self->callback = NewCallback;
335
336         return 0;
337 }
338
339 static PyObject *Wiimote_get_mesg(Wiimote *self)
340 {
341         union cwiid_mesg *mesg;
342         int mesg_count;
343         struct timespec t;
344         PyObject *PyMesg;
345
346         if (cwiid_get_mesg(self->wiimote, &mesg_count, &mesg, &t)) {
347                 if (errno == EAGAIN) {
348                         Py_RETURN_NONE;
349                 }
350                 else {
351                         PyErr_SetString(PyExc_RuntimeError,
352                                         "Error getting wiimote message list");
353                         return NULL;
354                 }
355         }
356
357         PyMesg = ConvertMesgArray(mesg_count, mesg);
358
359         free(mesg);
360
361         return PyMesg;
362 }
363
364 static PyObject *Wiimote_get_state(Wiimote* self, void *closure)
365 {
366         struct cwiid_state state;
367         PyObject *PyState;
368
369         if (cwiid_get_state(self->wiimote, &state)) {
370                 PyErr_SetString(PyExc_IOError, "get state error");
371                 return NULL;
372         }
373
374         PyState = Py_BuildValue("{s:B,s:B,s:B,s:B,s:i,s:i}",
375                                 "rpt_mode", state.rpt_mode,
376                                 "led", state.led,
377                                 "rumble", state.rumble,
378                                 "battery", state.battery,
379                                 "ext_type", state.ext_type,
380                                 "error", state.error);
381
382         if (state.rpt_mode & CWIID_RPT_BTN) {
383                 PyObject *PyBtn = Py_BuildValue("I", state.buttons);
384                 if (!PyBtn) {
385                         Py_DECREF(PyState);
386                         return NULL;
387                 }
388                 if (PyDict_SetItemString(PyState, "buttons", PyBtn)) {
389                         Py_DECREF(PyState);
390                         Py_DECREF(PyBtn);
391                         return NULL;
392                 }
393                 Py_DECREF(PyBtn);
394         }
395
396         if (state.rpt_mode & CWIID_RPT_ACC) {
397                 PyObject *PyAcc = Py_BuildValue("(B,B,B)",
398                                                                     state.acc[CWIID_X],
399                                             state.acc[CWIID_Y],
400                                             state.acc[CWIID_Z]);
401                 if (!PyAcc) {
402                         Py_DECREF(PyState);
403                         return NULL;
404                 }
405                 if (PyDict_SetItemString(PyState, "acc", PyAcc)) {
406                         Py_DECREF(PyState);
407                         Py_DECREF(PyAcc);
408                         return NULL;
409                 }
410                 Py_DECREF(PyAcc);
411         }
412
413         if (state.rpt_mode & CWIID_RPT_IR) {
414                 int i;
415                 PyObject *PyIr = PyList_New(CWIID_IR_SRC_COUNT);
416
417                 if (!PyIr) {
418                         Py_DECREF(PyState);
419                         return NULL;
420                 }
421
422                 if (PyDict_SetItemString(PyState, "ir_src", PyIr)) {
423                         Py_DECREF(PyState);
424                         Py_DECREF(PyIr);
425                         return NULL;
426                 }
427
428                 Py_DECREF(PyIr);
429
430                 for (i=0; i < CWIID_IR_SRC_COUNT; i++) {
431                         PyObject *PyIrSrc;
432                         PyObject *PySize;
433
434                         if (state.ir_src[i].valid) {
435                                 PyIrSrc = Py_BuildValue("{s:(I,I)}",
436                                                         "pos",
437                                                           state.ir_src[i].pos[CWIID_X],
438                                                           state.ir_src[i].pos[CWIID_Y]);
439                                 if (!PyIrSrc) {
440                                         Py_DECREF(PyState);
441                                         return NULL;
442                                 }
443
444                                 if (state.ir_src[i].size != -1) {
445                                         if (!(PySize = PyInt_FromLong(
446                                           (long)state.ir_src[i].size))) {
447                                                 Py_DECREF(PyState);
448                                                 Py_DECREF(PyIrSrc);
449                                                 return NULL;
450                                         }
451                                         if (PyDict_SetItemString(PyIrSrc, "size", PySize)) {
452                                                 Py_DECREF(PyState);
453                                                 Py_DECREF(PyIrSrc);
454                                                 Py_DECREF(PySize);
455                                                 return NULL;
456                                         }
457
458                                         Py_DECREF(PySize);
459                                 }
460                         }
461                         else {
462                                 Py_INCREF(PyIrSrc = Py_None);
463                         }
464
465                         PyList_SET_ITEM(PyIr, i, PyIrSrc);
466                 }
467         }
468
469         switch (state.ext_type) {
470                 PyObject *PyExt;
471         case CWIID_EXT_NUNCHUK:
472                 if (state.rpt_mode & CWIID_RPT_NUNCHUK) {
473                         PyExt = Py_BuildValue("{s:(B,B),s:(B,B,B),s:I}",
474                                               "stick",
475                                                 state.ext.nunchuk.stick[CWIID_X],
476                                                 state.ext.nunchuk.stick[CWIID_Y],
477                                               "acc",
478                                                 state.ext.nunchuk.acc[CWIID_X],
479                                                 state.ext.nunchuk.acc[CWIID_Y],
480                                                 state.ext.nunchuk.acc[CWIID_Z],
481                                               "buttons", state.ext.nunchuk.buttons);
482
483                         if (!PyExt) {
484                                 Py_DECREF(PyState);
485                                 return NULL;
486                         }
487
488                         if (PyDict_SetItemString(PyState, "nunchuk", PyExt)) {
489                                 Py_DECREF(PyState);
490                                 Py_DECREF(PyExt);
491                                 return NULL;
492                         }
493
494                         Py_DECREF(PyExt);
495                 }
496                 break;
497         case CWIID_EXT_CLASSIC:
498                 if (state.rpt_mode & CWIID_RPT_CLASSIC) {
499                         PyExt = Py_BuildValue("{s:(B,B),s:(B,B),s:B,s:B,s:I}",
500                                               "l_stick",
501                                                 state.ext.classic.l_stick[CWIID_X],
502                                                 state.ext.classic.l_stick[CWIID_Y],
503                                               "r_stick",
504                                                 state.ext.classic.r_stick[CWIID_X],
505                                                 state.ext.classic.r_stick[CWIID_Y],
506                                               "l", state.ext.classic.l,
507                                               "r", state.ext.classic.r,
508                                               "buttons", state.ext.classic.buttons);
509
510                         if (!PyExt) {
511                                 Py_DECREF(PyState);
512                                 return NULL;
513                         }
514
515                         if (PyDict_SetItemString(PyState, "classic", PyExt)) {
516                                 Py_DECREF(PyState);
517                                 Py_DECREF(PyExt);
518                                 return NULL;
519                         }
520
521                         Py_DECREF(PyExt);
522                 }
523                 break;
524         default:
525                 break;
526         }
527
528         return PyState;
529 }
530
531 static PyObject *Wiimote_get_acc_cal(Wiimote *self, PyObject *args,
532                                      PyObject *kwds)
533 {
534         static char *kwlist[] = { "ext_type", NULL };
535         int ext_type;
536         struct acc_cal acc_cal;
537         PyObject *PyAccCal;
538
539         if (!PyArg_ParseTupleAndKeywords(args, kwds,
540                                          "i:cwiid.Wiimote.get_acc_cal", kwlist,
541                                          &ext_type)) {
542                 return NULL;
543         }
544
545         if (cwiid_get_acc_cal(self->wiimote, ext_type, &acc_cal)) {
546                 PyErr_SetString(PyExc_RuntimeError,
547                                 "Error getting wiimote acc calibration");
548                 return NULL;
549         }
550
551         if (!(PyAccCal = Py_BuildValue("([i,i,i],[i,i,i])", acc_cal.zero[0],
552                                        acc_cal.zero[1], acc_cal.zero[2],
553                                        acc_cal.one[0], acc_cal.one[1],
554                                        acc_cal.one[2]))) {
555                 return NULL;
556         }
557
558         return PyAccCal;
559 }
560
561 static PyObject *Wiimote_request_status(Wiimote *self)
562 {
563         if (cwiid_request_status(self->wiimote)) {
564                 PyErr_SetString(PyExc_RuntimeError, "Error requesting wiimote status");
565                 return NULL;
566         }
567
568         Py_RETURN_NONE;
569 }
570
571 static int Wiimote_set_led(Wiimote *self, PyObject *PyLed, void *closure)
572 {
573         long led;
574
575         if (((led = PyInt_AsLong(PyLed)) == -1) && PyErr_Occurred()) {
576                 return -1;
577         }
578
579         if (cwiid_set_led(self->wiimote, (uint8_t)led)) {
580                 PyErr_SetString(PyExc_AttributeError,
581                                 "Error setting wiimote led state");
582                 return -1;
583         }
584
585         return 0;
586 }
587
588 static int
589         Wiimote_set_rumble(Wiimote *self, PyObject *PyRumble, void *closure)
590 {
591         long rumble;
592
593         if (((rumble = PyInt_AsLong(PyRumble)) == -1) && PyErr_Occurred()) {
594                 return -1;
595         }
596
597         if (cwiid_set_rumble(self->wiimote, (uint8_t)rumble)) {
598                 PyErr_SetString(PyExc_AttributeError,
599                                 "Error setting wiimote rumble state");
600                 return -1;
601         }
602
603         return 0;
604 }
605
606 static int
607         Wiimote_set_rpt_mode(Wiimote *self, PyObject *PyRptMode, void *closure)
608 {
609         long rpt_mode;
610
611         if (((rpt_mode = PyInt_AsLong(PyRptMode)) == -1) && PyErr_Occurred()) {
612                 return -1;
613         }
614
615         if (cwiid_set_rpt_mode(self->wiimote, (uint8_t)rpt_mode)) {
616                 PyErr_SetString(PyExc_AttributeError,
617                                 "Error setting wiimote report mode");
618                 return -1;
619         }
620
621         return 0;
622 }
623
624 /* static PyObject *Wiimote_command(Wiimote *self, PyObject *args, PyObject *kwds)
625 {
626         static char *kwlist[] = { "command", "flags", NULL };
627         int command, flags;
628
629         if (!PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwlist, &command,
630                                          &flags)) {
631                 return NULL;
632         }
633
634         cwiid_command(self->wiimote, (enum cwiid_command)command, (uint8_t)flags);
635
636         Py_RETURN_NONE;
637 }
638 */
639
640 static PyObject *Wiimote_read(Wiimote *self, PyObject *args, PyObject *kwds)
641 {
642         static char *kwlist[] = { "flags", "offset", "len", NULL };
643         unsigned char flags;
644         unsigned int offset;
645         unsigned int len;
646         void *buf;
647         PyObject *pyRetBuf;
648
649         if (!PyArg_ParseTupleAndKeywords(args, kwds, "BII:cwiid.Wiimote.read",
650                                          kwlist, &flags, &offset, &len)) {
651                 return NULL;
652         }
653
654         if (!(pyRetBuf = PyBuffer_New(len))) {
655                 return NULL;
656         }
657         if (PyObject_AsWriteBuffer(pyRetBuf, &buf, (int *)&len)) {
658                 Py_DECREF(pyRetBuf);
659                 return NULL;
660         }
661         if (cwiid_read(self->wiimote,flags,offset,len,buf)) {
662                 PyErr_SetString(PyExc_RuntimeError, "Error reading wiimote data");
663                 Py_DECREF(pyRetBuf);
664                 return NULL;
665         }
666
667         return pyRetBuf;
668 }
669
670 static PyObject *Wiimote_write(Wiimote *self, PyObject *args, PyObject *kwds)
671 {
672         static char *kwlist[] = { "flags", "offset", "buffer", NULL };
673         unsigned char flags;
674         unsigned int offset;
675         void *buf;
676         int len;
677
678         if (!PyArg_ParseTupleAndKeywords(args, kwds, "BIt#:cwiid.Wiimote.write",
679                                          kwlist, &flags, &offset, &buf, &len)) {
680                 return NULL;
681         }
682
683         if (cwiid_write(self->wiimote, flags, offset, len, buf)) {
684                 PyErr_SetString(PyExc_RuntimeError, "Error writing wiimote data");
685                 return NULL;
686         }
687
688         Py_RETURN_NONE;
689 }
690
691 static void CallbackBridge(cwiid_wiimote_t *wiimote, int mesg_count,
692                                union cwiid_mesg mesg[], struct timespec *t)
693 {
694         PyObject *ArgTuple;
695         PyObject *PySelf;
696         PyGILState_STATE gstate;
697
698         gstate = PyGILState_Ensure();
699
700         ArgTuple = ConvertMesgArray(mesg_count, mesg);
701
702         /* Put id and the list of messages as the arguments to the callback */
703         PySelf = (PyObject *) cwiid_get_data(wiimote);
704         if (!PyObject_CallFunction(((Wiimote *)PySelf)->callback, "(O)",
705                                    ArgTuple)) {
706                 PyErr_Print();
707         }
708
709         Py_XDECREF(ArgTuple);
710         PyGILState_Release(gstate);
711 }
712
713 /* This is the function responsible for marshaling the cwiid messages from
714  * C to python. It's rather complicated since it uses a complex C union
715  * to store the data and multiple enumerations to figure out what data is
716  * actually being sent. Neither of these common C types really translate
717  * well into Python. I've done my best to translate it to python as follows:
718  *
719  * Python callback takes arg (mesgs). The mesgs is a list of
720  * mesg tuples which contain the mesg type and a dict of the arguments.
721  *
722  * Ex:
723  * mesgs =>[(cwiid.STATUS_MESG,{"battery":battery,"ext_type":ext_type}),
724  *          (cwiid.BTN_MESG,buttons),
725  *          (cwiid.ACC_MESG,(x,y,z)),
726  *          (cwiid.IR_MESG,[{"pos":(x,y),"size":size}, ...]),
727  *          (cwiid.NUNCHUK_MESG,{"stick":(x,y),"acc":(x,y,z),
728  *                               "buttons":buttons},
729  *          (cwiid.CLASSIC_MESG,{"l_stick":(x,y),"r_stick":(x,y),"l":l,"r":r,
730  *                               "buttons":buttons},
731  *          (cwiid.ERROR_MESG,error)]
732  */
733 PyObject *ConvertMesgArray(int mesg_count, union cwiid_mesg mesg[])
734 {
735         PyObject *mesglist; /* List of message tuples */
736         PyObject *amesg; /* A single message (type, [arguments]) */
737         PyObject *mesgVal; /* Dictionary of arguments for a message */
738         PyObject *PyIrList;
739         int i, j;
740
741         if (!(mesglist = PyList_New(mesg_count))) {
742                 return NULL;
743         }
744
745         for (i = 0; i < mesg_count; i++) {
746                 switch (mesg[i].type) {
747                 case CWIID_MESG_STATUS:
748                         mesgVal = Py_BuildValue("{s:B,s:i}",
749                                                 "battery", mesg[i].status_mesg.battery,
750                                                 "ext_type", mesg[i].status_mesg.ext_type);
751                         break;
752                 case CWIID_MESG_BTN:
753                         mesgVal = Py_BuildValue("I", mesg[i].btn_mesg.buttons);
754                         break;
755                 case CWIID_MESG_ACC:
756                         mesgVal = Py_BuildValue("(B,B,B)", mesg[i].acc_mesg.acc[CWIID_X],
757                                                            mesg[i].acc_mesg.acc[CWIID_Y],
758                                                            mesg[i].acc_mesg.acc[CWIID_Z]);
759                         break;
760                 case CWIID_MESG_IR:
761                         mesgVal = NULL;
762
763                         if (!(PyIrList = PyList_New(CWIID_IR_SRC_COUNT))) {
764                                 break;
765                         }
766
767                         for (j=0; j < CWIID_IR_SRC_COUNT; j++) {
768                                 PyObject *PyIrSrc;
769                                 PyObject *PySize;
770
771                                 if (mesg[i].ir_mesg.src[j].valid) {
772                                         PyIrSrc = Py_BuildValue("{s:(I,I)}",
773                                                      "pos",
774                                                        mesg[i].ir_mesg.src[j].pos[CWIID_X],
775                                                        mesg[i].ir_mesg.src[j].pos[CWIID_Y]);
776
777                                         if (!PyIrSrc) {
778                                                 Py_DECREF(PyIrList);
779                                                 PyIrList = NULL;
780                                                 break;
781                                         }
782
783                                         if (mesg[i].ir_mesg.src[j].size != -1) {
784                                                 if (!(PySize = PyInt_FromLong(
785                                                   (long)mesg[i].ir_mesg.src[j].size))) {
786                                                         Py_DECREF(PyIrList);
787                                                         Py_DECREF(PyIrSrc);
788                                                         PyIrList = NULL;
789                                                         break;
790                                                 }
791                                                 if (PyDict_SetItemString(PyIrSrc, "size", PySize)) {
792                                                         Py_DECREF(PyIrList);
793                                                         Py_DECREF(PyIrSrc);
794                                                         Py_DECREF(PySize);
795                                                         PyIrList = NULL;
796                                                         break;
797                                                 }
798
799                                                 Py_DECREF(PySize);
800                                         }
801                                 }
802                                 else {
803                                         Py_INCREF(PyIrSrc = Py_None);
804                                 }
805                                 PyList_SET_ITEM(PyIrList, j, PyIrSrc);
806                         }
807
808                         if (!PyIrList) {
809                                 break;
810                         }
811
812                         mesgVal = PyIrList;
813                         break;
814                 case CWIID_MESG_NUNCHUK:
815                         mesgVal = Py_BuildValue("{s:(B,B),s:(B,B,B),s:I}",
816                                                 "stick",
817                                                   mesg[i].nunchuk_mesg.stick[CWIID_X],
818                                                   mesg[i].nunchuk_mesg.stick[CWIID_Y],
819                                                 "acc",
820                                                   mesg[i].nunchuk_mesg.acc[CWIID_X],
821                                                   mesg[i].nunchuk_mesg.acc[CWIID_Y],
822                                                   mesg[i].nunchuk_mesg.acc[CWIID_Z],
823                                                 "buttons", mesg[i].nunchuk_mesg.buttons);
824                         break;
825                 case CWIID_MESG_CLASSIC:
826                         mesgVal = Py_BuildValue("{s:(B,B),s:(B,B),s:B,s:B,s:I}",
827                                      "l_stick",
828                                        mesg[i].classic_mesg.l_stick[CWIID_X],
829                                        mesg[i].classic_mesg.l_stick[CWIID_Y],
830                                      "r_stick",
831                                        mesg[i].classic_mesg.r_stick[CWIID_X],
832                                        mesg[i].classic_mesg.r_stick[CWIID_Y],
833                                      "l", mesg[i].classic_mesg.l,
834                                      "r", mesg[i].classic_mesg.r,
835                                      "buttons", mesg[i].classic_mesg.buttons);
836                         break;
837                 case CWIID_MESG_ERROR:
838                         mesgVal = Py_BuildValue("i", mesg[i].error_mesg.error);
839                         break;
840                 default:
841                         Py_INCREF(mesgVal = Py_None);
842                         break;
843                 }
844
845                 if (!mesgVal) {
846                         return NULL;
847                 }
848
849                 /* Finally Put the type next to the message in a tuple and
850                  * append them to the list of messages */
851                 if (!(amesg = Py_BuildValue("(iO)", mesg[i].type, mesgVal))) {
852                         Py_DECREF(mesgVal);
853                         return NULL;
854                 }
855                 Py_DECREF(mesgVal);
856                 PyList_SET_ITEM(mesglist, i, amesg);
857         }
858
859         return mesglist;
860 }
Note: See TracBrowser for help on using the browser.