root/python/Wiimote.c

Revision 78159c03792fdbcd912e7a640fd22d20d268fa0e, 28.5 kB (checked in by L. Donnie Smith <donnie.smith@…>, 2 years ago)

MotionPlus' low-speed bits for Python-interface.

  • Property mode set to 100644
Line 
1/*
2 * Copyright (C) 2007 Justin M. Tulloss <jmtulloss@gmail.com>, L. Donnie Smith <donnie.smith@gatech.edu>
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 */
22
23#include "Python.h"
24#include "structmember.h"
25#include <errno.h>
26#include <bluetooth/bluetooth.h>
27#include <cwiid.h>
28
29#if (PY_VERSION_HEX < 0x02050000)
30  #ifndef PY_SSIZE_T_MIN
31    typedef int Py_ssize_t;
32    #define PY_SSIZE_T_MAX INT_MAX
33    #define PY_SSIZE_T_MIN INT_MIN
34  #endif
35#endif
36
37typedef struct {
38        PyObject_HEAD
39        cwiid_wiimote_t *wiimote;
40        PyObject *callback;
41        char close_on_dealloc;
42} Wiimote;
43
44/* method prototypes */
45static PyObject *
46        Wiimote_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
47static void Wiimote_dealloc(Wiimote *self);
48static int Wiimote_init(Wiimote *self, PyObject *args, PyObject *kwds);
49static PyObject *Wiimote_close(Wiimote *self);
50
51static PyObject *Wiimote_enable(Wiimote *self, PyObject *args, PyObject *kwds);
52static PyObject *
53        Wiimote_disable(Wiimote *self, PyObject *args, PyObject *kwds);
54
55static int
56        Wiimote_set_mesg_callback(Wiimote *self, PyObject *args, void *closure);
57static PyObject *Wiimote_get_mesg(Wiimote *self);
58static PyObject *Wiimote_get_state(Wiimote *self, void *closure);
59static PyObject *Wiimote_get_acc_cal(Wiimote *self, PyObject *args,
60                                     PyObject *kwds);
61static PyObject *Wiimote_get_balance_cal(Wiimote *self);
62
63static PyObject *Wiimote_request_status(Wiimote *self);
64static int Wiimote_set_led(Wiimote *self, PyObject *PyLed, void *closure);
65static int
66        Wiimote_set_rumble(Wiimote *self, PyObject *PyRumble, void *closure);
67static int
68        Wiimote_set_rpt_mode(Wiimote *self, PyObject *PyRptMode, void *closure);
69
70static PyObject *Wiimote_send_rpt(Wiimote *self, PyObject *args, PyObject *kwds);
71static PyObject *Wiimote_read(Wiimote *self, PyObject *args, PyObject *kwds);
72static PyObject *Wiimote_write(Wiimote *self, PyObject *args, PyObject *kwds);
73
74/* helper prototypes */
75static cwiid_mesg_callback_t CallbackBridge;
76PyObject *ConvertMesgArray(int mesg_count, union cwiid_mesg mesg[]);
77
78static PyMethodDef Wiimote_Methods[] =
79{
80        {"close", (PyCFunction)Wiimote_close, METH_NOARGS,
81         "close()\n\nClose the Wiimote connection"},
82        {"enable", (PyCFunction)Wiimote_enable, METH_VARARGS | METH_KEYWORDS,
83         "enable(flags)\n\nenable Wiimote connection flags"},
84        {"disable", (PyCFunction)Wiimote_disable, METH_VARARGS | METH_KEYWORDS,
85         "disable(flags)\n\ndisable Wiimote connection flags"},
86        {"get_mesg", (PyCFunction)Wiimote_get_mesg, METH_NOARGS,
87         "get_mesg() -> message list\n\nretrieve message list from queue"},
88        {"get_acc_cal", (PyCFunction)Wiimote_get_acc_cal,
89         METH_VARARGS | METH_KEYWORDS,
90         "get_acc_cal(extension) -> calibration tuple\n\n"
91         "retrieve accelerometer calibration information"},
92        {"get_balance_cal", (PyCFunction)Wiimote_get_balance_cal, METH_NOARGS,
93         "get_balance_cal() -> calibration tuple\n\n"
94         "retrieve Balance Board calibration information"},
95        {"request_status", (PyCFunction)Wiimote_request_status, METH_NOARGS,
96         "request_status()\n\nrequest status message"},
97        {"read", (PyCFunction)Wiimote_read, METH_VARARGS | METH_KEYWORDS,
98         "read(flags,offset,len) -> buffer\n\nread data from Wiimote"},
99        {"send_rpt", (PyCFunction)Wiimote_send_rpt, METH_VARARGS | METH_KEYWORDS,
100         "send_rpt(flags,report,buffer)\n\nsend a report to Wiimote"},
101        {"write", (PyCFunction)Wiimote_write, METH_VARARGS | METH_KEYWORDS,
102         "write(flags,offset,buffer)\n\nwrite data to Wiimote"},
103        {NULL, NULL, 0, NULL}
104};
105
106static PyGetSetDef Wiimote_GetSet[] = {
107        {"state", (getter)Wiimote_get_state, NULL, "Wiimote state", NULL},
108        {"mesg_callback", NULL, (setter)Wiimote_set_mesg_callback,
109         "Wiimote message callback", NULL},
110        {"led", NULL, (setter)Wiimote_set_led, "Wiimote led state", NULL},
111        {"rumble", NULL, (setter)Wiimote_set_rumble, "Wiimote rumble state", NULL},
112        {"rpt_mode", NULL, (setter)Wiimote_set_rpt_mode, "Wiimote report mode",
113         NULL},
114        {NULL, NULL, NULL, NULL, NULL}
115};
116
117PyTypeObject Wiimote_Type = {
118        PyObject_HEAD_INIT(NULL)
119        0,                                              /* ob_size */
120        "cwiid.Wiimote",                /* tp_name */
121        sizeof(Wiimote),                /* tp_basicsize */
122        0,                                              /* tp_itemsize */
123        (destructor)Wiimote_dealloc,    /* tp_dealloc */
124        0,                                              /* tp_print */
125        0,                                              /* tp_getattr */
126        0,                                              /* tp_setattr */
127        0,                                              /* tp_compare */
128        0,                                              /* tp_repr */
129        0,                                              /* tp_as_number */
130        0,                                              /* tp_as_sequence */
131        0,                                              /* tp_as_mapping */
132        0,                                              /* tp_hash */
133        0,                                              /* tp_call */
134        0,                                              /* tp_str */
135        0,                                              /* tp_getattro */
136        0,                                              /* tp_setattro */
137        0,                                              /* tp_as_buffer */
138        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,       /* tp_flags */
139        "CWiid Wiimote connection object",      /* tp_doc */
140        0,                                              /* tp_traverse */
141        0,                                              /* tp_clear */
142        0,                                              /* tp_richcompare */
143        0,                                              /* tp_weaklistoffset */
144        0,                                              /* tp_iter */
145        0,                                              /* tp_iternext */
146        Wiimote_Methods,                /* tp_methods */
147        0,                                              /* tp_members */
148        Wiimote_GetSet,                 /* tp_getset */
149        0,                                              /* tp_base */
150        0,                                              /* tp_dict */
151        0,                                              /* tp_descr_get */
152        0,                                              /* tp_descr_set */
153        0,                                              /* tp_dictoffset */
154        (initproc)Wiimote_init, /* tp_init */
155        0,                                              /* tp_alloc */
156        Wiimote_new,                    /* tp_new */
157};
158
159/* Allocate and deallocate functions */
160static PyObject *
161        Wiimote_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
162{
163        Wiimote* self;
164
165        if (!(self = (Wiimote *) type->tp_alloc(type, 0))) {
166                return NULL;
167        }
168
169        self->wiimote = NULL;
170        Py_INCREF(self->callback = Py_None);
171        self->close_on_dealloc = 0;
172
173        return (PyObject*) self;
174}
175
176static void Wiimote_dealloc(Wiimote *self)
177{
178        if (self->close_on_dealloc && self->wiimote) {
179                cwiid_close(self->wiimote);
180        }
181        Py_XDECREF(self->callback);
182        self->ob_type->tp_free((PyObject *)self);
183}
184
185static int Wiimote_init(Wiimote* self, PyObject* args, PyObject *kwds)
186{
187        static char *kwlist[] = {"bdaddr", "flags", NULL};
188        PyObject *PyObj;
189        cwiid_wiimote_t *wiimote = NULL;
190        char *str_bdaddr = NULL;
191        bdaddr_t bdaddr;
192        int flags = 0;
193
194        /* Overloaded function - if a single CObject is passed in, it's
195         * an existing CObject.  Otherwise, create a new one */
196        if (PyTuple_Size(args) == 1) {
197                PyObj = PyTuple_GET_ITEM(args, 0);
198                if (PyCObject_Check(PyObj)) {
199                        wiimote = PyCObject_AsVoidPtr(PyObj);
200                        self->close_on_dealloc = 0;
201                }
202        }
203
204        if (!wiimote) {
205                if (!PyArg_ParseTupleAndKeywords(args, kwds, "|si:cwiid.Wiimote.init",
206                                                 kwlist, &str_bdaddr, &flags)) {
207                        return -1;
208                }
209
210                if (str_bdaddr) {
211                        if (str2ba(str_bdaddr, &bdaddr)) {
212                                PyErr_SetString(PyExc_ValueError, "bad bdaddr");
213                                return -1;
214                        }
215                }
216                else {
217                        bdaddr = *BDADDR_ANY;
218                }
219
220                Py_BEGIN_ALLOW_THREADS
221                wiimote = cwiid_open(&bdaddr, flags);
222                Py_END_ALLOW_THREADS
223                if (!wiimote) {
224                        PyErr_SetString(PyExc_RuntimeError,
225                                        "Error opening wiimote connection");
226                        return -1;
227                }
228                else {
229                        self->close_on_dealloc = 1;
230                }
231        }
232
233        cwiid_set_data(wiimote, self);
234        self->wiimote = wiimote;
235        return 0;
236}
237
238#define SET_CLOSED_ERROR        PyErr_SetString(PyExc_ValueError, "Wiimote is closed")
239
240static PyObject *Wiimote_close(Wiimote *self)
241{
242        if (!self->wiimote) {
243                SET_CLOSED_ERROR;
244                return NULL;
245        }
246
247        if (cwiid_close(self->wiimote)) {
248                PyErr_SetString(PyExc_RuntimeError,
249                                "Error closing wiimote connection");
250                self->wiimote = NULL;
251                return NULL;
252        }
253        self->wiimote = NULL;
254
255        Py_RETURN_NONE;
256}
257
258static PyObject *Wiimote_enable(Wiimote *self, PyObject *args, PyObject *kwds)
259{
260        static char *kwlist[] = {"flags", NULL};
261        int flags;
262
263        if (!self->wiimote) {
264                SET_CLOSED_ERROR;
265                return NULL;
266        }
267
268        if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:cwiid.Wiimote.enable",
269                                         kwlist, &flags)) {
270                return NULL;
271        }
272
273        if (cwiid_enable(self->wiimote, flags)) {
274                PyErr_SetString(PyExc_RuntimeError, "Error enabling wiimote flags");
275                return NULL;
276        }
277
278        Py_RETURN_NONE;
279}
280
281static PyObject *Wiimote_disable(Wiimote *self, PyObject *args, PyObject *kwds)
282{
283        static char *kwlist[] = {"flags", NULL};
284        int flags;
285
286        if (!self->wiimote) {
287                SET_CLOSED_ERROR;
288                return NULL;
289        }
290
291        if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:cwiid.Wiimote.disable",
292                                         kwlist, &flags)) {
293                return NULL;
294        }
295
296        if (cwiid_disable(self->wiimote, flags)) {
297                PyErr_SetString(PyExc_RuntimeError, "Error disabling wiimote flags");
298                return NULL;
299        }
300
301        Py_RETURN_NONE;
302}
303
304static int
305        Wiimote_set_mesg_callback(Wiimote *self, PyObject *NewCallback,
306                                  void *closure)
307{
308        PyObject *OldCallback;
309
310        if (!self->wiimote) {
311                SET_CLOSED_ERROR;
312                return -1;
313        }
314
315        if (!PyCallable_Check(NewCallback)) {
316                PyErr_SetString(PyExc_TypeError, "callback must be callable!");
317        }
318        OldCallback = self->callback;
319
320        if ((OldCallback == Py_None) && (NewCallback != Py_None)) {
321                if (cwiid_set_mesg_callback(self->wiimote, CallbackBridge)) {
322                        PyErr_SetString(PyExc_AttributeError,
323                                        "Error setting wiimote callback");
324                        return -1;
325                }
326        }
327        else if ((OldCallback != Py_None) && (NewCallback == Py_None)) {
328                if (cwiid_set_mesg_callback(self->wiimote, NULL)) {
329                        PyErr_SetString(PyExc_AttributeError,
330                                        "Error clearing wiimote callback");
331                        return -1;
332                }
333        }
334
335        Py_INCREF(NewCallback);
336        Py_DECREF(OldCallback);
337        self->callback = NewCallback;
338
339        return 0;
340}
341
342static PyObject *Wiimote_get_mesg(Wiimote *self)
343{
344        union cwiid_mesg *mesg;
345        int mesg_count;
346        struct timespec t;
347        PyObject *PyMesg;
348
349        if (!self->wiimote) {
350                SET_CLOSED_ERROR;
351                return NULL;
352        }
353
354        if (cwiid_get_mesg(self->wiimote, &mesg_count, &mesg, &t)) {
355                if (errno == EAGAIN) {
356                        Py_RETURN_NONE;
357                }
358                else {
359                        PyErr_SetString(PyExc_RuntimeError,
360                                        "Error getting wiimote message list");
361                        return NULL;
362                }
363        }
364
365        PyMesg = ConvertMesgArray(mesg_count, mesg);
366
367        free(mesg);
368
369        return PyMesg;
370}
371
372static PyObject *Wiimote_get_state(Wiimote* self, void *closure)
373{
374        struct cwiid_state state;
375        PyObject *PyState;
376
377        if (!self->wiimote) {
378                SET_CLOSED_ERROR;
379                return NULL;
380        }
381
382        if (cwiid_get_state(self->wiimote, &state)) {
383                PyErr_SetString(PyExc_IOError, "get state error");
384                return NULL;
385        }
386
387        PyState = Py_BuildValue("{s:B,s:B,s:B,s:B,s:i,s:i}",
388                                "rpt_mode", state.rpt_mode,
389                                "led", state.led,
390                                "rumble", state.rumble,
391                                "battery", state.battery,
392                                "ext_type", state.ext_type,
393                                "error", state.error);
394
395        if (state.rpt_mode & CWIID_RPT_BTN) {
396                PyObject *PyBtn = Py_BuildValue("I", state.buttons);
397                if (!PyBtn) {
398                        Py_DECREF(PyState);
399                        return NULL;
400                }
401                if (PyDict_SetItemString(PyState, "buttons", PyBtn)) {
402                        Py_DECREF(PyState);
403                        Py_DECREF(PyBtn);
404                        return NULL;
405                }
406                Py_DECREF(PyBtn);
407        }
408
409        if (state.rpt_mode & CWIID_RPT_ACC) {
410                PyObject *PyAcc = Py_BuildValue("(B,B,B)",
411                                                                    state.acc[CWIID_X],
412                                            state.acc[CWIID_Y],
413                                            state.acc[CWIID_Z]);
414                if (!PyAcc) {
415                        Py_DECREF(PyState);
416                        return NULL;
417                }
418                if (PyDict_SetItemString(PyState, "acc", PyAcc)) {
419                        Py_DECREF(PyState);
420                        Py_DECREF(PyAcc);
421                        return NULL;
422                }
423                Py_DECREF(PyAcc);
424        }
425
426        if (state.rpt_mode & CWIID_RPT_IR) {
427                int i;
428                PyObject *PyIr = PyList_New(CWIID_IR_SRC_COUNT);
429
430                if (!PyIr) {
431                        Py_DECREF(PyState);
432                        return NULL;
433                }
434
435                if (PyDict_SetItemString(PyState, "ir_src", PyIr)) {
436                        Py_DECREF(PyState);
437                        Py_DECREF(PyIr);
438                        return NULL;
439                }
440
441                Py_DECREF(PyIr);
442
443                for (i=0; i < CWIID_IR_SRC_COUNT; i++) {
444                        PyObject *PyIrSrc;
445                        PyObject *PySize;
446
447                        if (state.ir_src[i].valid) {
448                                PyIrSrc = Py_BuildValue("{s:(I,I)}",
449                                                        "pos",
450                                                          state.ir_src[i].pos[CWIID_X],
451                                                          state.ir_src[i].pos[CWIID_Y]);
452                                if (!PyIrSrc) {
453                                        Py_DECREF(PyState);
454                                        return NULL;
455                                }
456
457                                if (state.ir_src[i].size != -1) {
458                                        if (!(PySize = PyInt_FromLong(
459                                          (long)state.ir_src[i].size))) {
460                                                Py_DECREF(PyState);
461                                                Py_DECREF(PyIrSrc);
462                                                return NULL;
463                                        }
464                                        if (PyDict_SetItemString(PyIrSrc, "size", PySize)) {
465                                                Py_DECREF(PyState);
466                                                Py_DECREF(PyIrSrc);
467                                                Py_DECREF(PySize);
468                                                return NULL;
469                                        }
470
471                                        Py_DECREF(PySize);
472                                }
473                        }
474                        else {
475                                Py_INCREF(PyIrSrc = Py_None);
476                        }
477
478                        PyList_SET_ITEM(PyIr, i, PyIrSrc);
479                }
480        }
481
482        switch (state.ext_type) {
483                PyObject *PyExt;
484        case CWIID_EXT_NUNCHUK:
485                if (state.rpt_mode & CWIID_RPT_NUNCHUK) {
486                        PyExt = Py_BuildValue("{s:(B,B),s:(B,B,B),s:I}",
487                                              "stick",
488                                                state.ext.nunchuk.stick[CWIID_X],
489                                                state.ext.nunchuk.stick[CWIID_Y],
490                                              "acc",
491                                                state.ext.nunchuk.acc[CWIID_X],
492                                                state.ext.nunchuk.acc[CWIID_Y],
493                                                state.ext.nunchuk.acc[CWIID_Z],
494                                              "buttons", state.ext.nunchuk.buttons);
495
496                        if (!PyExt) {
497                                Py_DECREF(PyState);
498                                return NULL;
499                        }
500
501                        if (PyDict_SetItemString(PyState, "nunchuk", PyExt)) {
502                                Py_DECREF(PyState);
503                                Py_DECREF(PyExt);
504                                return NULL;
505                        }
506
507                        Py_DECREF(PyExt);
508                }
509                break;
510        case CWIID_EXT_CLASSIC:
511                if (state.rpt_mode & CWIID_RPT_CLASSIC) {
512                        PyExt = Py_BuildValue("{s:(B,B),s:(B,B),s:B,s:B,s:I}",
513                                              "l_stick",
514                                                state.ext.classic.l_stick[CWIID_X],
515                                                state.ext.classic.l_stick[CWIID_Y],
516                                              "r_stick",
517                                                state.ext.classic.r_stick[CWIID_X],
518                                                state.ext.classic.r_stick[CWIID_Y],
519                                              "l", state.ext.classic.l,
520                                              "r", state.ext.classic.r,
521                                              "buttons", state.ext.classic.buttons);
522
523                        if (!PyExt) {
524                                Py_DECREF(PyState);
525                                return NULL;
526                        }
527
528                        if (PyDict_SetItemString(PyState, "classic", PyExt)) {
529                                Py_DECREF(PyState);
530                                Py_DECREF(PyExt);
531                                return NULL;
532                        }
533
534                        Py_DECREF(PyExt);
535                }
536                break;
537        case CWIID_EXT_BALANCE:
538                if (state.rpt_mode & CWIID_RPT_BALANCE) {
539                        PyExt = Py_BuildValue("{s:I,s:I,s:I,s:I}",
540                                              "right_top",
541                                                state.ext.balance.right_top,
542                                              "right_bottom",
543                                                state.ext.balance.right_bottom,
544                                              "left_top",
545                                                state.ext.balance.left_top,
546                                              "left_bottom",
547                                                state.ext.balance.left_bottom);
548
549                        if (!PyExt) {
550                                Py_DECREF(PyState);
551                                return NULL;
552                        }
553
554                        if (PyDict_SetItemString(PyState, "balance", PyExt)) {
555                                Py_DECREF(PyState);
556                                Py_DECREF(PyExt);
557                                return NULL;
558                        }
559
560                        Py_DECREF(PyExt);
561                }
562                break;
563        case CWIID_EXT_MOTIONPLUS:
564                if (state.rpt_mode & CWIID_RPT_MOTIONPLUS) {
565                        PyExt = Py_BuildValue("{s:(I,I,I),s:(I,I,I)}",
566                                          "angle_rate",
567                                  state.ext.motionplus.angle_rate[CWIID_PHI],
568                                  state.ext.motionplus.angle_rate[CWIID_THETA],
569                                  state.ext.motionplus.angle_rate[CWIID_PSI],
570                                  "low_speed",
571                                  state.ext.motionplus.low_speed[CWIID_PHI],
572                                  state.ext.motionplus.low_speed[CWIID_THETA],
573                                  state.ext.motionplus.low_speed[CWIID_PSI]);
574
575                        if (!PyExt) {
576                                Py_DECREF(PyState);
577                                return NULL;
578                        }
579
580                        if (PyDict_SetItemString(PyState, "motionplus", PyExt)) {
581                                Py_DECREF(PyState);
582                                Py_DECREF(PyExt);
583                                return NULL;
584                        }
585
586                        Py_DECREF(PyExt);
587                }
588                break;
589        default:
590                break;
591        }
592
593        return PyState;
594}
595
596static PyObject *Wiimote_get_acc_cal(Wiimote *self, PyObject *args,
597                                     PyObject *kwds)
598{
599        static char *kwlist[] = { "ext_type", NULL };
600        int ext_type;
601        struct acc_cal acc_cal;
602        PyObject *PyAccCal;
603
604        if (!self->wiimote) {
605                SET_CLOSED_ERROR;
606                return NULL;
607        }
608
609        if (!PyArg_ParseTupleAndKeywords(args, kwds,
610                                         "i:cwiid.Wiimote.get_acc_cal", kwlist,
611                                         &ext_type)) {
612                return NULL;
613        }
614
615        if (cwiid_get_acc_cal(self->wiimote, ext_type, &acc_cal)) {
616                PyErr_SetString(PyExc_RuntimeError,
617                                "Error getting wiimote acc calibration");
618                return NULL;
619        }
620
621        if (!(PyAccCal = Py_BuildValue("([i,i,i],[i,i,i])", acc_cal.zero[0],
622                                       acc_cal.zero[1], acc_cal.zero[2],
623                                       acc_cal.one[0], acc_cal.one[1],
624                                       acc_cal.one[2]))) {
625                return NULL;
626        }
627
628        return PyAccCal;
629}
630
631static PyObject *Wiimote_get_balance_cal(Wiimote *self)
632{
633        struct balance_cal balance_cal;
634        PyObject *PyBalCal;
635
636        if (cwiid_get_balance_cal(self->wiimote, &balance_cal)) {
637                PyErr_SetString(PyExc_RuntimeError,
638                                "Error getting balance board calibration");
639                return NULL;
640        }
641
642        if (!(PyBalCal = Py_BuildValue("([i,i,i],[i,i,i],[i,i,i],[i,i,i])",
643                                       balance_cal.right_top[0],
644                                       balance_cal.right_top[1],
645                                       balance_cal.right_top[2],
646                                       balance_cal.right_bottom[0],
647                                       balance_cal.right_bottom[1],
648                                       balance_cal.right_bottom[2],
649                                       balance_cal.left_top[0],
650                                       balance_cal.left_top[1],
651                                       balance_cal.left_top[2],
652                                       balance_cal.left_bottom[0],
653                                       balance_cal.left_bottom[1],
654                                       balance_cal.left_bottom[2]))) {
655                return NULL;
656        }
657
658        return PyBalCal;
659}
660
661static PyObject *Wiimote_request_status(Wiimote *self)
662{
663        if (!self->wiimote) {
664                SET_CLOSED_ERROR;
665                return NULL;
666        }
667
668        if (cwiid_request_status(self->wiimote)) {
669                PyErr_SetString(PyExc_RuntimeError, "Error requesting wiimote status");
670                return NULL;
671        }
672
673        Py_RETURN_NONE;
674}
675
676static int Wiimote_set_led(Wiimote *self, PyObject *PyLed, void *closure)
677{
678        long led;
679
680        if (!self->wiimote) {
681                SET_CLOSED_ERROR;
682                return -1;
683        }
684
685        if (((led = PyInt_AsLong(PyLed)) == -1) && PyErr_Occurred()) {
686                return -1;
687        }
688
689        if (cwiid_set_led(self->wiimote, (uint8_t)led)) {
690                PyErr_SetString(PyExc_AttributeError,
691                                "Error setting wiimote led state");
692                return -1;
693        }
694
695        return 0;
696}
697
698static int
699        Wiimote_set_rumble(Wiimote *self, PyObject *PyRumble, void *closure)
700{
701        long rumble;
702
703        if (!self->wiimote) {
704                SET_CLOSED_ERROR;
705                return -1;
706        }
707
708        if (((rumble = PyInt_AsLong(PyRumble)) == -1) && PyErr_Occurred()) {
709                return -1;
710        }
711
712        if (cwiid_set_rumble(self->wiimote, (uint8_t)rumble)) {
713                PyErr_SetString(PyExc_AttributeError,
714                                "Error setting wiimote rumble state");
715                return -1;
716        }
717
718        return 0;
719}
720
721static int
722        Wiimote_set_rpt_mode(Wiimote *self, PyObject *PyRptMode, void *closure)
723{
724        long rpt_mode;
725
726        if (!self->wiimote) {
727                SET_CLOSED_ERROR;
728                return -1;
729        }
730
731        if (((rpt_mode = PyInt_AsLong(PyRptMode)) == -1) && PyErr_Occurred()) {
732                return -1;
733        }
734
735        if (cwiid_set_rpt_mode(self->wiimote, (uint8_t)rpt_mode)) {
736                PyErr_SetString(PyExc_AttributeError,
737                                "Error setting wiimote report mode");
738                return -1;
739        }
740
741        return 0;
742}
743
744/* static PyObject *Wiimote_command(Wiimote *self, PyObject *args, PyObject *kwds)
745{
746        static char *kwlist[] = { "command", "flags", NULL };
747        int command, flags;
748
749        if (!PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwlist, &command,
750                                         &flags)) {
751                return NULL;
752        }
753
754        cwiid_command(self->wiimote, (enum cwiid_command)command, (uint8_t)flags);
755
756        Py_RETURN_NONE;
757}
758*/
759
760static PyObject *Wiimote_send_rpt(Wiimote *self, PyObject *args, PyObject *kwds)
761{
762        static char *kwlist[] = { "flags", "report", "buffer", NULL };
763        unsigned char flags, report;
764        void *buf;
765        int len;
766
767        if (!self->wiimote) {
768                SET_CLOSED_ERROR;
769                return NULL;
770        }
771
772        if (!PyArg_ParseTupleAndKeywords(args, kwds, "BBt#:cwiid.Wiimote.send_rpt",
773                                         kwlist, &flags, &report, &buf, &len)) {
774                return NULL;
775        }
776
777        if (cwiid_send_rpt(self->wiimote, flags, report, len, buf)) {
778                PyErr_SetString(PyExc_RuntimeError, "Error sending report");
779                return NULL;
780        }
781
782        Py_RETURN_NONE;
783}
784
785static PyObject *Wiimote_read(Wiimote *self, PyObject *args, PyObject *kwds)
786{
787        static char *kwlist[] = { "flags", "offset", "len", NULL };
788        unsigned char flags;
789        unsigned int offset;
790        Py_ssize_t len;
791        void *buf;
792        PyObject *pyRetBuf;
793
794        if (!self->wiimote) {
795                SET_CLOSED_ERROR;
796                return NULL;
797        }
798
799        if (!PyArg_ParseTupleAndKeywords(args, kwds, "BII:cwiid.Wiimote.read",
800                                         kwlist, &flags, &offset, &len)) {
801                return NULL;
802        }
803
804        if (!(pyRetBuf = PyBuffer_New(len))) {
805                return NULL;
806        }
807        if (PyObject_AsWriteBuffer(pyRetBuf, &buf, &len)) {
808                Py_DECREF(pyRetBuf);
809                return NULL;
810        }
811        if (cwiid_read(self->wiimote,flags,offset,len,buf)) {
812                PyErr_SetString(PyExc_RuntimeError, "Error reading wiimote data");
813                Py_DECREF(pyRetBuf);
814                return NULL;
815        }
816
817        return pyRetBuf;
818}
819
820static PyObject *Wiimote_write(Wiimote *self, PyObject *args, PyObject *kwds)
821{
822        static char *kwlist[] = { "flags", "offset", "buffer", NULL };
823        unsigned char flags;
824        unsigned int offset;
825        void *buf;
826        int len;
827
828        if (!self->wiimote) {
829                SET_CLOSED_ERROR;
830                return NULL;
831        }
832
833        if (!PyArg_ParseTupleAndKeywords(args, kwds, "BIt#:cwiid.Wiimote.write",
834                                         kwlist, &flags, &offset, &buf, &len)) {
835                return NULL;
836        }
837
838        if (cwiid_write(self->wiimote, flags, offset, len, buf)) {
839                PyErr_SetString(PyExc_RuntimeError, "Error writing wiimote data");
840                return NULL;
841        }
842
843        Py_RETURN_NONE;
844}
845
846static void CallbackBridge(cwiid_wiimote_t *wiimote, int mesg_count,
847                               union cwiid_mesg mesg[], struct timespec *t)
848{
849        PyObject *ArgTuple;
850        PyObject *PySelf;
851        PyGILState_STATE gstate;
852
853        gstate = PyGILState_Ensure();
854
855        ArgTuple = ConvertMesgArray(mesg_count, mesg);
856
857        /* Put id and the list of messages as the arguments to the callback */
858        PySelf = (PyObject *) cwiid_get_data(wiimote);
859        if (!PyObject_CallFunction(((Wiimote *)PySelf)->callback, "(O, d)",
860                                   ArgTuple,
861                                   t->tv_sec + ((double) t->tv_nsec) * 1e-9)) {
862                PyErr_Print();
863        }
864
865        Py_XDECREF(ArgTuple);
866        PyGILState_Release(gstate);
867}
868
869/* This is the function responsible for marshaling the cwiid messages from
870 * C to python. It's rather complicated since it uses a complex C union
871 * to store the data and multiple enumerations to figure out what data is
872 * actually being sent. Neither of these common C types really translate
873 * well into Python. I've done my best to translate it to python as follows:
874 *
875 * Python callback takes arg (mesgs). The mesgs is a list of
876 * mesg tuples which contain the mesg type and a dict of the arguments.
877 *
878 * Ex:
879 * mesgs =>[(cwiid.STATUS_MESG,{"battery":battery,"ext_type":ext_type}),
880 *          (cwiid.BTN_MESG,buttons),
881 *          (cwiid.ACC_MESG,(x,y,z)),
882 *          (cwiid.IR_MESG,[{"pos":(x,y),"size":size}, ...]),
883 *          (cwiid.NUNCHUK_MESG,{"stick":(x,y),"acc":(x,y,z),
884 *                               "buttons":buttons},
885 *          (cwiid.CLASSIC_MESG,{"l_stick":(x,y),"r_stick":(x,y),"l":l,"r":r,
886 *                               "buttons":buttons},
887 *          (cwiid.BALANCE_MESG,{"right_top":right_top,
888 *                               "right_bottom":right_bottom,
889 *                               "left_top":left_top,
890 *                               "left_bottom":left_bottom},
891 *          (cwiid.MOTIONPLUS_MESG,{"angle_rate":(psi,theta,phi),
892 *                                  "low_speed":(psi,theta,phi)},
893 *          (cwiid.ERROR_MESG,error)]
894 */
895PyObject *ConvertMesgArray(int mesg_count, union cwiid_mesg mesg[])
896{
897        PyObject *mesglist; /* List of message tuples */
898        PyObject *amesg; /* A single message (type, [arguments]) */
899        PyObject *mesgVal; /* Dictionary of arguments for a message */
900        PyObject *PyIrList;
901        int i, j;
902
903        if (!(mesglist = PyList_New(mesg_count))) {
904                return NULL;
905        }
906
907        for (i = 0; i < mesg_count; i++) {
908                switch (mesg[i].type) {
909                case CWIID_MESG_STATUS:
910                        mesgVal = Py_BuildValue("{s:B,s:i}",
911                                                "battery", mesg[i].status_mesg.battery,
912                                                "ext_type", mesg[i].status_mesg.ext_type);
913                        break;
914                case CWIID_MESG_BTN:
915                        mesgVal = Py_BuildValue("I", mesg[i].btn_mesg.buttons);
916                        break;
917                case CWIID_MESG_ACC:
918                        mesgVal = Py_BuildValue("(B,B,B)", mesg[i].acc_mesg.acc[CWIID_X],
919                                                           mesg[i].acc_mesg.acc[CWIID_Y],
920                                                           mesg[i].acc_mesg.acc[CWIID_Z]);
921                        break;
922                case CWIID_MESG_IR:
923                        mesgVal = NULL;
924
925                        if (!(PyIrList = PyList_New(CWIID_IR_SRC_COUNT))) {
926                                break;
927                        }
928
929                        for (j=0; j < CWIID_IR_SRC_COUNT; j++) {
930                                PyObject *PyIrSrc;
931                                PyObject *PySize;
932
933                                if (mesg[i].ir_mesg.src[j].valid) {
934                                        PyIrSrc = Py_BuildValue("{s:(I,I)}",
935                                                     "pos",
936                                                       mesg[i].ir_mesg.src[j].pos[CWIID_X],
937                                                       mesg[i].ir_mesg.src[j].pos[CWIID_Y]);
938
939                                        if (!PyIrSrc) {
940                                                Py_DECREF(PyIrList);
941                                                PyIrList = NULL;
942                                                break;
943                                        }
944
945                                        if (mesg[i].ir_mesg.src[j].size != -1) {
946                                                if (!(PySize = PyInt_FromLong(
947                                                  (long)mesg[i].ir_mesg.src[j].size))) {
948                                                        Py_DECREF(PyIrList);
949                                                        Py_DECREF(PyIrSrc);
950                                                        PyIrList = NULL;
951                                                        break;
952                                                }
953                                                if (PyDict_SetItemString(PyIrSrc, "size", PySize)) {
954                                                        Py_DECREF(PyIrList);
955                                                        Py_DECREF(PyIrSrc);
956                                                        Py_DECREF(PySize);
957                                                        PyIrList = NULL;
958                                                        break;
959                                                }
960
961                                                Py_DECREF(PySize);
962                                        }
963                                }
964                                else {
965                                        Py_INCREF(PyIrSrc = Py_None);
966                                }
967                                PyList_SET_ITEM(PyIrList, j, PyIrSrc);
968                        }
969
970                        if (!PyIrList) {
971                                break;
972                        }
973
974                        mesgVal = PyIrList;
975                        break;
976                case CWIID_MESG_NUNCHUK:
977                        mesgVal = Py_BuildValue("{s:(B,B),s:(B,B,B),s:I}",
978                                                "stick",
979                                                  mesg[i].nunchuk_mesg.stick[CWIID_X],
980                                                  mesg[i].nunchuk_mesg.stick[CWIID_Y],
981                                                "acc",
982                                                  mesg[i].nunchuk_mesg.acc[CWIID_X],
983                                                  mesg[i].nunchuk_mesg.acc[CWIID_Y],
984                                                  mesg[i].nunchuk_mesg.acc[CWIID_Z],
985                                                "buttons", mesg[i].nunchuk_mesg.buttons);
986                        break;
987                case CWIID_MESG_CLASSIC:
988                        mesgVal = Py_BuildValue("{s:(B,B),s:(B,B),s:B,s:B,s:I}",
989                                     "l_stick",
990                                       mesg[i].classic_mesg.l_stick[CWIID_X],
991                                       mesg[i].classic_mesg.l_stick[CWIID_Y],
992                                     "r_stick",
993                                       mesg[i].classic_mesg.r_stick[CWIID_X],
994                                       mesg[i].classic_mesg.r_stick[CWIID_Y],
995                                     "l", mesg[i].classic_mesg.l,
996                                     "r", mesg[i].classic_mesg.r,
997                                     "buttons", mesg[i].classic_mesg.buttons);
998                        break;
999                case CWIID_MESG_BALANCE:
1000                        mesgVal = Py_BuildValue("{s:I,s:I,s:I,s:I}",
1001                                     "right_top",
1002                                       mesg[i].balance_mesg.right_top,
1003                                     "right_bottom",
1004                                       mesg[i].balance_mesg.right_bottom,
1005                                     "left_top",
1006                                       mesg[i].balance_mesg.left_top,
1007                                     "left_bottom",
1008                                       mesg[i].balance_mesg.left_bottom);
1009                        break;
1010                case CWIID_MESG_MOTIONPLUS:
1011                        mesgVal = Py_BuildValue("{s:(I,I,I),s:(I,I,I)}",
1012                                                "angle_rate",
1013                                    mesg[i].motionplus_mesg.angle_rate[CWIID_PHI],
1014                                    mesg[i].motionplus_mesg.angle_rate[CWIID_THETA],
1015                                    mesg[i].motionplus_mesg.angle_rate[CWIID_PSI],
1016                                    "low_speed",
1017                                    mesg[i].motionplus_mesg.low_speed[CWIID_PHI],
1018                                    mesg[i].motionplus_mesg.low_speed[CWIID_THETA],
1019                                    mesg[i].motionplus_mesg.low_speed[CWIID_PSI]);
1020                                   
1021                        break;
1022                case CWIID_MESG_ERROR:
1023                        mesgVal = Py_BuildValue("i", mesg[i].error_mesg.error);
1024                        break;
1025                default:
1026                        Py_INCREF(mesgVal = Py_None);
1027                        break;
1028                }
1029
1030                if (!mesgVal) {
1031                        return NULL;
1032                }
1033
1034                /* Finally Put the type next to the message in a tuple and
1035                 * append them to the list of messages */
1036                if (!(amesg = Py_BuildValue("(iO)", mesg[i].type, mesgVal))) {
1037                        Py_DECREF(mesgVal);
1038                        return NULL;
1039                }
1040                Py_DECREF(mesgVal);
1041                PyList_SET_ITEM(mesglist, i, amesg);
1042        }
1043
1044        return mesglist;
1045}
Note: See TracBrowser for help on using the browser.