PythonWrapper: cwiidmodule.c

File cwiidmodule.c, 15.2 kB (added by jmtulloss, 2 years ago)

had a reference count error that is now fixed

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  * 2007-05-07 Justin M. Tulloss <jmtulloss@gmail.com>
23  * * Refactored according to dsmith's wishes, removed unnecessary locks
24  *
25  * 2007-04-26 Justin M. Tulloss <jmtulloss@gmail.com>
26  * * Updated for new libcwiid API
27  *
28  * 2007-04-24 Justin M. Tulloss <jmtulloss@gmail.com>
29  * * Initial Changelog
30  */
31
32 //Apparently this has to be first for every python interpreter extension
33 #include "Python.h"
34
35 //Standard Includes
36 #include <stdio.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <limits.h>
40 #include <stdlib.h>
41 #include <dlfcn.h>
42 #include <pthread.h>
43
44 //Interesting includes
45 #include "cwiid.h"
46 #include "structmember.h"
47
48 //Python Function declarations
49 void initcwiidmodule(void);
50
51 static int Wiimote_constructor(PyObject* self, PyObject* args);
52 PyObject* Wiimote_read(PyObject* self, PyObject* args);
53 PyObject* Wiimote_write(PyObject* self, PyObject* args);
54 PyObject* Wiimote_command(PyObject* self, PyObject* args);
55 PyObject* Wiimote_disconnect(PyObject* self, PyObject* args);
56 PyObject* Wiimote_enable(PyObject* self, PyObject* args);
57 PyObject* Wiimote_disable(PyObject* self, PyObject* args);
58 PyObject* Wiimote_get_mesg(PyObject* self, PyObject* args);
59 PyObject* Wiimote_set_callback(PyObject* self, PyObject* args);
60 PyObject* Wiimote_get_state(PyObject* self, PyObject* args);
61
62
63 //Types
64
65 typedef struct {
66     PyObject_HEAD
67     cwiid_wiimote_t* wiimote;
68     PyObject* callback;
69 }cwiidmodule;
70
71 //Type private functions
72 static void cwiidmodule_dealloc(cwiidmodule* self);
73 static PyObject*
74     cwiidmodule_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
75
76 //Helper functions
77 void callbackBridge(cwiid_wiimote_t* wiimote,
78     int mesg_count, union cwiid_mesg mesg[]);
79 static PyObject* processMesgs(int mesg_count, union cwiid_mesg mesg[]);
80 static int cwiid_start(cwiidmodule* self, int flags);
81 static PyObject* notImplemented();
82
83 static bdaddr_t btAddr;
84
85
86 //Associates cwiid functions with python ones
87 static PyMethodDef modMethods[] =
88 {
89     {NULL, NULL}
90 };
91
92 //Our type methods
93 static PyMethodDef cwiidMethods[] =
94 {
95
96     //{"__init__", constructorwii, METH_VARARGS, "cwiid(function)"},
97     {"read", Wiimote_read, METH_VARARGS, "read from wiimote"},
98     {"write", Wiimote_write, METH_VARARGS, "write to wiimote"},
99     {"command", Wiimote_command, METH_VARARGS, "send wiimote command"},
100     {"enable", Wiimote_enable, METH_VARARGS, "enable flags on wiimote"},
101     {"disable", Wiimote_disable, METH_VARARGS, "disable flags on wiimote"},
102     {"get_mesg", Wiimote_get_mesg, METH_VARARGS, "blocking call to get messages"},
103     {"set_callback", Wiimote_set_callback, METH_VARARGS, "setup a mesg processing callback"},
104     {"get_state", Wiimote_get_state, METH_VARARGS, "polling interface"},
105     {"disconnect", Wiimote_disconnect, METH_VARARGS, "disconnect wiimote"},
106     {NULL, NULL}
107 };
108
109 static PyMemberDef cwiidMembers[] = {
110     {"_wiimote", T_OBJECT_EX, offsetof(cwiidmodule, wiimote), 0, "wiimote"},
111     {"_callback", T_OBJECT_EX,offsetof(cwiidmodule, callback),0,"callback"},
112     {NULL}
113 };
114
115
116 //Defines a new type in python
117 static PyTypeObject WiimoteType= {
118     PyObject_HEAD_INIT(NULL)
119     0,                         /*ob_size*/
120     "cwiidmodule.Wiimote", /*tp_name*/
121     sizeof(cwiidmodule),       /*tp_basicsize*/
122     0,                         /*tp_itemsize*/
123     (destructor)cwiidmodule_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 c-python interface",/* 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     cwiidMethods,              /* tp_methods */
147     cwiidMembers,              /* tp_members */
148     0,                         /* 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_constructor,  /* tp_init */
155     0,                         /* tp_alloc */
156     cwiidmodule_new,                 /* tp_new */
157 };
158
159 //Allocate and deallocate functions
160 static void
161 cwiidmodule_dealloc(cwiidmodule* self)
162 {
163     cwiid_disconnect(self->wiimote);
164     Py_XDECREF(self->callback);
165     self->ob_type->tp_free((PyObject*)self);
166 }
167
168 static PyObject*
169 cwiidmodule_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
170 {
171     cwiidmodule* self;
172
173     self = (cwiidmodule*) type->tp_alloc(type, 0);
174
175     return (PyObject*) self;
176 }
177
178 PyMODINIT_FUNC
179 initcwiidmodule(void)
180 {
181     PyObject* m;
182
183     if (PyType_Ready(&WiimoteType) <0 )
184         return;
185
186     //Open the cwiid library
187     dlopen("libcwiid.so", RTLD_LAZY);
188     if (!(m = Py_InitModule3("cwiidmodule", modMethods,
189       "Module for accessing the wiimote through cwiid")))
190         return;
191
192     Py_INCREF(&WiimoteType);
193     PyModule_AddObject(m, "Wiimote", (PyObject*)&WiimoteType);
194
195 }
196
197 int
198 cwiid_start(cwiidmodule* self, int flags)
199 {
200     cwiid_wiimote_t* theMote;
201     btAddr = *BDADDR_ANY;
202
203     //Set up wiimote
204     if(!(theMote = cwiid_connect(&btAddr, flags)))
205     {
206         return -1;
207     }
208     cwiid_set_data(theMote,(void*)self); //keep pyobject with wiimote
209     self->wiimote = theMote; //keep wiimote with pyobject
210     self->callback = Py_None;
211     return 0;
212 }
213
214 static int
215 Wiimote_constructor(PyObject* self, PyObject* args)
216 {
217     PyObject* pyFlags;
218
219     //Get out parameters
220     if (PyArg_UnpackTuple(args, "constructor", 1, 1, &pyFlags))
221     {
222         if (!PyInt_Check(pyFlags))
223         {
224             PyErr_SetString(PyExc_TypeError, "Parameter must be int");
225             return 0;
226         }
227     }
228
229     if(cwiid_start((cwiidmodule*)self, PyInt_AsLong(pyFlags))<0)
230     {
231         PyErr_SetString(PyExc_IOError, "Could not connect to wiimote");
232     }
233     PyEval_InitThreads();
234    
235     return 0;
236 }
237
238
239 PyObject*
240 Wiimote_read(PyObject* self, PyObject* args)
241 {
242         //Python types
243         PyObject* pyflags;
244         PyObject* pyoffset;
245         PyObject* pylength;
246
247         PyObject* pyRetBuf;
248
249         //C types
250         uint8_t flags;
251         uint32_t offset;
252         uint32_t length;
253         void * buf;
254
255     PyArg_UnpackTuple(args, "read", 3, 3, &pyflags,&pyoffset,&pylength);
256     if(!(PyInt_Check(pyflags)
257                 && PyInt_Check(pyoffset)
258                 && PyInt_Check(pylength)))
259     {
260         PyErr_SetString(PyExc_TypeError, "arguments must be ints");
261     }
262        
263     //marshal everything over
264     flags  = (uint8_t)  PyInt_AsLong(pyflags);
265     offset = (uint32_t) PyInt_AsLong(pyoffset);
266         length = (uint32_t) PyInt_AsLong(pylength);
267
268         //TODO: More error checking
269         buf = malloc(length);
270         cwiid_read(((cwiidmodule*)self)->wiimote,flags,offset,length,buf);
271         pyRetBuf = PyBuffer_FromMemory((char*)buf, length);
272
273         Py_XINCREF(pyRetBuf);
274         return pyRetBuf;
275        
276 }
277
278 PyObject*
279 Wiimote_write(PyObject* self, PyObject* args)
280 {
281     return notImplemented();
282 }
283
284 PyObject*
285 Wiimote_command(PyObject* self, PyObject* args)
286 {
287     //Python types
288     PyObject* pycommand;
289     PyObject* pyflags;
290
291     //C types
292     enum cwiid_command command;
293     uint8_t flags;
294
295     PyArg_UnpackTuple(args, "command", 2, 2, &pycommand, &pyflags);
296     if(!(PyInt_Check(pycommand) && PyInt_Check(pyflags)))
297     {
298         PyErr_SetString(PyExc_TypeError, "command and flags must be ints");
299     }
300
301     //marshal everything over
302     command = (enum cwiid_command) PyInt_AsLong(pycommand);
303     flags = (uint8_t) PyInt_AsLong(pyflags);
304
305
306     //finally, send the command to the wiimote
307     cwiid_command(((cwiidmodule*)self)->wiimote, command, flags);
308
309     Py_RETURN_NONE;
310 }
311
312 PyObject*
313 Wiimote_disconnect(PyObject* self, PyObject* args)
314 {
315     return notImplemented();
316 }
317
318 PyObject*
319 Wiimote_enable(PyObject* self, PyObject* args)
320 {
321     return notImplemented();
322 }
323
324 PyObject*
325 Wiimote_disable(PyObject* self, PyObject* args)
326 {
327     return notImplemented();
328 }
329
330 PyObject*
331 Wiimote_get_mesg(PyObject* self, PyObject* args)
332 {
333     union cwiid_mesg** mesgs;
334     int mesg_count;
335
336     //get the messages from Mr. Wiimote
337
338     return processMesgs(mesg_count, *mesgs);
339 }
340
341 PyObject*
342 Wiimote_set_callback(PyObject* self, PyObject* args)
343 {
344     PyObject* pyCallback;
345
346     PyArg_UnpackTuple(args, "set_callback", 1, 1, &pyCallback);
347     if (!PyCallable_Check(pyCallback))
348     {
349         PyErr_SetString(PyExc_TypeError, "callback must be callable!");
350     }
351         Py_XINCREF(pyCallback);
352
353     //Set this callback as an attribute in the class
354     if (((cwiidmodule*)self)->callback== Py_None)//wasn't a callback before
355     {
356         cwiid_set_mesg_callback(((cwiidmodule*)self)->wiimote,
357             (cwiid_mesg_callback_t*) callbackBridge);
358     }
359     ((cwiidmodule*)self)->callback = pyCallback;
360
361     Py_RETURN_NONE;
362 }
363
364 PyObject*
365 Wiimote_get_state(PyObject* self, PyObject* args)
366 {
367     return notImplemented();
368 }
369
370 static PyObject*
371 notImplemented()
372 {
373     PyErr_SetString(PyExc_NotImplementedError, "This has not yet been implemented");
374    
375     Py_RETURN_NONE;
376 }
377
378 void
379 callbackBridge(cwiid_wiimote_t* wiimote,
380     int mesg_count, union cwiid_mesg mesg[])
381 {
382     PyObject* argTuple;
383     PyObject* pyself;
384     //PyObject* pyCallback;
385     PyGILState_STATE gstate;
386    
387     gstate = PyGILState_Ensure();
388
389     argTuple = processMesgs(mesg_count, mesg);
390
391     //Put id and the list of messages as the arguments to the callback
392     pyself = (PyObject*) cwiid_get_data(wiimote);
393     if (PyMethod_Check(((cwiidmodule*)pyself)->callback))
394     {
395         //Sorry for the ugliness here.
396         //After determining that the callback is a method in a class,
397         //this line calls that function object with self and the argtuple
398         //as arguments.
399         PyObject_CallFunction(
400             PyMethod_Function(((cwiidmodule*)pyself)->callback),"(OO)",
401             PyMethod_Class(((cwiidmodule*)pyself)->callback), argTuple
402             );
403     }
404     else
405         PyObject_CallFunction(((cwiidmodule*)pyself)->callback,
406             "(O)",argTuple);
407
408     Py_XDECREF(argTuple); //actually need to decref the entire structure
409     PyGILState_Release(gstate);
410 }
411
412 /* This is the function responsible for marshaling the cwiid messages from
413  * C to python. It's rather complicated since it uses a complex C union
414  * to store the data and multiple enumerations to figure out what data is
415  * actually being sent. Neither of these common C types really translate
416  * well into Python. I've done my best to translate it to python as follows:
417  *
418  * Python callback takes arg (mesgs). The mesgs is a list of
419  * mesg tuples which contain the mesg type and a dict of the arguments.
420  *
421  * Ex:
422  * mesgs =>[(CWIID_BTN_MESG,{"buttons":btnMask}),
423  *          (CWIID_ACC_MESG,{"x":xVal, "y":yVal, "z":zVal})]
424  */
425 static PyObject*
426 processMesgs(int mesg_count, union cwiid_mesg mesg[])
427 {
428     PyObject* mesglist; //List of message tuples
429     PyObject* amesg; //A single message (type, [arguments])
430     PyObject* mesgVal; //Dictionary of arguments for a message
431
432     int i;
433
434     mesglist = PyList_New(0);
435     Py_XINCREF(mesglist);
436     for (i = 0; i < mesg_count; i++)
437     {
438
439         mesgVal = PyDict_New();
440         Py_XINCREF(mesgVal);
441         switch (mesg[i].type) {
442             case CWIID_MESG_STATUS:
443                 PyDict_SetItemString(mesgVal, "battery",
444                     Py_BuildValue("B", mesg[i].status_mesg.battery));
445                 switch (mesg[i].status_mesg.ext_type)
446                 {
447                     case CWIID_EXT_NONE:
448                         PyDict_SetItemString(mesgVal, "extension",
449                             Py_BuildValue("s","none"));
450                         break;
451                     case CWIID_EXT_NUNCHUK:
452                         PyDict_SetItemString(mesgVal, "extension",
453                             Py_BuildValue("s","nunchuck"));
454                         break;
455                     case CWIID_EXT_CLASSIC:
456                         PyDict_SetItemString(mesgVal, "extension",
457                             Py_BuildValue("s","classic"));
458                         break;
459                     default:
460                         break;
461                 }
462                 break;
463             case CWIID_MESG_BTN:
464                 PyDict_SetItemString(mesgVal, "buttons",
465                     Py_BuildValue("H", mesg[i].btn_mesg.buttons));
466                 break;
467             case CWIID_MESG_ACC:
468                 PyDict_SetItemString(mesgVal, "x",
469                     Py_BuildValue("B", mesg[i].acc_mesg.acc[0]));
470                 PyDict_SetItemString(mesgVal, "y",
471                     Py_BuildValue("B", mesg[i].acc_mesg.acc[1]));
472                 PyDict_SetItemString(mesgVal, "z",
473                     Py_BuildValue("B", mesg[i].acc_mesg.acc[2]));
474                 break;
475             case CWIID_MESG_IR:
476                 break;
477             case CWIID_MESG_NUNCHUK:
478                 break;
479             case CWIID_MESG_CLASSIC:
480                 break;
481             case CWIID_MESG_ERROR:
482                 switch(mesg[i].error_mesg.error)
483                 {
484                     case CWIID_ERROR_DISCONNECT:
485                         PyDict_SetItemString(mesgVal, "error",
486                             Py_BuildValue("s",
487                                 "Wiimote was disconnected"));
488                         break;
489                     case CWIID_ERROR_COMM:
490                         PyDict_SetItemString(mesgVal, "error",
491                             Py_BuildValue("s",
492                                 "Communication error occurred"));
493                         break;
494                     default:
495                         PyDict_SetItemString(mesgVal, "error",
496                             Py_BuildValue("s","An Unknown error occurred"));
497                         break;
498                 }
499                 break;
500             default:
501                 PyDict_SetItemString(mesgVal, "error",
502                     Py_BuildValue("s","Unknown message arrived"));
503                 break;
504         }
505
506         //Finally Put the type next to the message in a tuple and
507         //append them to the list of messages
508         amesg = Py_BuildValue("(iO)", mesg[i].type, mesgVal);
509         Py_XINCREF(amesg);
510         PyList_Append(mesglist, amesg);
511     }
512
513     return mesglist;
514 }