root/branches/dev/wminput/py_plugin.c

Revision 124, 13.7 kB (checked in by dsmith, 2 years ago)

wminput plugin refactoring

Line 
1 /* Copyright (C) 2007 L. Donnie Smith <cwiid@abstrakraft.org>
2  *
3  *  This program is free software; you can redistribute it and/or modify
4  *  it under the terms of the GNU General Public License as published by
5  *  the Free Software Foundation; either version 2 of the License, or
6  *  (at your option) any later version.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the Free Software
15  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
16  *
17  *  ChangeLog:
18  *  2007-06-05 L. Donnie Smith <cwiid@abstrakraft.org>
19  *  * relocated all python plugin logic here
20  *  * now imports plugins without changing directories
21  *
22  *  2007-06-03 L. Donnie Smith <cwiid@abstrakraft.org>
23  *  * added WMPLUGIN_ABS and WMPLUGIN_REL constants
24  *
25  *  2007-06-01 L. Donnie Smith <cwiid@abstrakraft.org>
26  *  * Initial ChangeLog
27  */
28
29 #include "Python.h"
30
31 #include <stdint.h>
32 #include <stdlib.h>
33
34 #include <unistd.h>
35
36 #include "structmember.h"
37 #include "cwiid.h"
38
39 #include "wmplugin.h"
40 #include "conf.h"
41 #include "util.h"
42
43 /* TODO: print error messages */
44 /* TODO: improve error checking */
45
46 struct py_plugin {
47         PyObject *PyInfo;
48         PyObject *handle;
49         PyObject *init;
50         PyObject *exec;
51 };
52
53 static PyObject *PyCWiidModule = NULL;
54 static PyObject *PySysModule = NULL;
55 static PyObject *PyPath = NULL;
56 static PyObject *PyWiimote = NULL;
57 static PyObject *(*ConvertMesgArray)(int, union cwiid_mesg[]);
58
59 static int py_plugin_info(struct plugin *, PyObject *);
60 static PyObject *set_rpt_mode(PyObject *, PyObject *, PyObject *);
61
62 #define WMPLUGIN_CONST_MACRO(a) {#a, WMPLUGIN_##a}
63 static struct {
64         char *name;
65         int value;
66 } wmplugin_constants[] = {
67         WMPLUGIN_CONST_MACRO(ABS),
68         WMPLUGIN_CONST_MACRO(REL),
69         WMPLUGIN_CONST_MACRO(PARAM_INT),
70         WMPLUGIN_CONST_MACRO(PARAM_FLOAT),
71         {NULL, 0}
72 };
73
74 static PyMethodDef Module_Methods[] =
75 {
76         {"set_rpt_mode", (PyCFunction)set_rpt_mode, METH_VARARGS | METH_KEYWORDS,
77          "set plugin report mode"},
78         {NULL, NULL, 0, NULL}
79 };
80
81 int py_init(void)
82 {
83         PyObject *PyObj, *PyWmPluginModule;
84         int i;
85
86         Py_Initialize();
87
88         if (!(PyCWiidModule = PyImport_ImportModule("cwiid"))) {
89                 PyErr_Print();
90                 goto ERR_HND;
91         }
92
93         if (!(PySysModule = PyImport_ImportModule("sys"))) {
94                 PyErr_Print();
95                 goto ERR_HND;
96         }
97
98         if (!(PyPath = PyObject_GetAttrString(PySysModule, "path"))) {
99                 PyErr_Print();
100                 goto ERR_HND;
101         }
102
103         if (!(PyObj = PyObject_GetAttrString(PyCWiidModule,
104                                               "ConvertMesgArray"))) {
105                 PyErr_Print();
106                 goto ERR_HND;
107         }
108         ConvertMesgArray = PyCObject_AsVoidPtr(PyObj);
109         Py_DECREF(PyObj);
110
111         /* note: PyWmPluginModule is a borrowed reference - do not decref */
112         if (!(PyWmPluginModule = Py_InitModule3("wmplugin", Module_Methods,
113                                                "plugin interface for wminput"))) {
114                 PyErr_Print();
115                 goto ERR_HND;
116         }
117
118         for (i = 0; wmplugin_constants[i].name; i++) {
119                 if (PyModule_AddIntConstant(PyWmPluginModule,
120                                             wmplugin_constants[i].name,
121                                             wmplugin_constants[i].value)) {
122                         PyErr_Print();
123                         goto ERR_HND;
124                 }
125         }
126
127         PyRun_SimpleString("import sys; sys.path.append('.')");
128
129         return 0;
130
131 ERR_HND:
132         if (PyCWiidModule) {
133                 Py_DECREF(PyCWiidModule);
134                 PyCWiidModule = NULL;
135         }
136
137         if (PyPath) {
138                 Py_DECREF(PyPath);
139                 PyPath = NULL;
140         }
141
142         if (PySysModule) {
143                 Py_DECREF(PySysModule);
144                 PySysModule = NULL;
145         }
146
147         Py_Finalize();
148
149         return -1;
150 }
151
152 int py_wiimote(cwiid_wiimote_t *wiimote)
153 {
154         PyObject *PyWiimoteType, *PyCObject, *PyArgs;
155
156         if (!(PyWiimoteType = PyObject_GetAttrString(PyCWiidModule, "Wiimote"))) {
157                 PyErr_Print();
158                 return -1;
159         }
160
161         if (!(PyCObject = PyCObject_FromVoidPtr(wiimote, NULL))) {
162                 PyErr_Print();
163                 Py_DECREF(PyWiimoteType);
164                 return -1;
165         }
166
167         if (!(PyArgs = Py_BuildValue("(O)", PyCObject))) {
168                 PyErr_Print();
169                 Py_DECREF(PyCObject);
170                 Py_DECREF(PyWiimoteType);
171                 return -1;
172         }
173
174         Py_DECREF(PyCObject);
175
176         if (!(PyWiimote = PyObject_CallObject(PyWiimoteType, PyArgs))) {
177                 PyErr_Print();
178                 Py_DECREF(PyArgs);
179                 Py_DECREF(PyWiimoteType);
180                 return -1;
181         }
182
183         Py_DECREF(PyArgs);
184         Py_DECREF(PyWiimoteType);
185
186         return 0;
187 }
188
189 void py_deinit(void)
190 {
191         Py_DECREF(PyWiimote);
192         Py_DECREF(PyCWiidModule);
193         Py_DECREF(PyPath);
194         Py_DECREF(PySysModule);
195         Py_Finalize();
196 }
197
198 int py_plugin_open(struct plugin *plugin, char *dir)
199 {
200         PyObject *handle, *info;
201         PyObject *PyStr;
202
203         if (!(PyStr = PyString_FromString(dir))) {
204                 PyErr_Print();
205                 return -1;
206         }
207
208         if (PyList_Insert(PyPath, 0, PyStr)) {
209                 Py_DECREF(PyStr);
210                 return -1;
211         }
212
213         if (!(handle = PyImport_ImportModule(plugin->name))) {
214                 /* TODO: print only syntax errors, not "module not found errors" */
215                 PyErr_Print();
216                 if (PySequence_DelItem(PyPath, 0)) {
217                         PyErr_Print();
218                 }
219                 Py_DECREF(PyStr);
220                 return -1;
221         }
222
223         if (PySequence_DelItem(PyPath, 0)) {
224                 PyErr_Print();
225         }
226         Py_DECREF(PyStr);
227
228         if (!(plugin->p = malloc(sizeof(struct py_plugin)))) {
229                 wminput_err("malloc error");
230                 return -1;
231         }
232
233         plugin->type = PLUGIN_PYTHON;
234         plugin->info = NULL;
235         plugin->data = NULL;
236         ((struct py_plugin *) plugin->p)->init = NULL;
237         ((struct py_plugin *) plugin->p)->exec = NULL;
238
239         if (!(plugin->info = malloc(sizeof *plugin->info))) {
240                 wminput_err("malloc error");
241                 goto ERR_HND;
242         }
243         if (!(plugin->data = malloc(sizeof *plugin->data))) {
244                 wminput_err("malloc error");
245                 goto ERR_HND;
246         }
247         if (!(((struct py_plugin *)plugin->p)->init =
248           PyObject_GetAttrString(handle, "wmplugin_init"))) {
249                 PyErr_Print();
250                 goto ERR_HND;
251         }
252         if (!PyCallable_Check(((struct py_plugin *)plugin->p)->init)) {
253                 wminput_err("Unable to load plugin init function: not callable");
254                 goto ERR_HND;
255         }
256         if (!(((struct py_plugin *)plugin->p)->exec =
257           PyObject_GetAttrString(handle, "wmplugin_exec"))) {
258                 PyErr_Print();
259                 goto ERR_HND;
260         }
261         if (!PyCallable_Check(((struct py_plugin *)plugin->p)->exec)) {
262                 wminput_err("Unable to load plugin exec function: not callable");
263                 goto ERR_HND;
264         }
265         if (!(info = PyObject_GetAttrString(handle, "wmplugin_info"))) {
266                 PyErr_Print();
267                 goto ERR_HND;
268         }
269         if (!PyCallable_Check(info)) {
270                 wminput_err("Unable to load plugin info function: not callable");
271                 Py_DECREF((PyObject *)info);
272                 goto ERR_HND;
273         }
274         if (py_plugin_info(plugin, info)) {
275                 wminput_err("python_info error");
276                 Py_DECREF((PyObject *)info);
277                 goto ERR_HND;
278         }
279         Py_DECREF((PyObject *)info);
280
281         ((struct py_plugin *) plugin->p)->handle = handle;
282
283         return 0;
284
285 ERR_HND:
286         if (plugin->info) {
287                 free(plugin->info);
288         }
289         if (plugin->data) {
290                 free(plugin->data);
291         }
292         if (plugin->p) {
293                 if (((struct py_plugin *)plugin->p)->init) {
294                         Py_DECREF(((struct py_plugin *)plugin->p)->init);
295                 }
296                 if (((struct py_plugin *)plugin->p)->exec) {
297                         Py_DECREF(((struct py_plugin *)plugin->p)->exec);
298                 }
299                 free(plugin->p);
300         }
301         Py_DECREF(handle);
302         return -1;
303 }
304
305 void py_plugin_close(struct plugin *plugin)
306 {
307         free(plugin->info);
308         free(plugin->data);
309         Py_DECREF(((struct py_plugin *)plugin->p)->PyInfo);
310         Py_DECREF(((struct py_plugin *)plugin->p)->init);
311         Py_DECREF(((struct py_plugin *)plugin->p)->exec);
312         Py_DECREF(((struct py_plugin *)plugin->p)->handle);
313         free(plugin->p);
314 }
315
316 static int py_plugin_info(struct plugin *plugin, PyObject *info)
317 {
318         PyObject *PyButtonInfo, *PyAxisInfo, *PyParamInfo;
319         PyObject *PyObj;
320         int i;
321
322         if (!(((struct py_plugin *)plugin->p)->PyInfo =
323           PyObject_CallObject(info, NULL))) {
324                 PyErr_Print();
325                 goto ERR_HND;
326         }
327
328         if (!PyArg_ParseTuple(((struct py_plugin *)plugin->p)->PyInfo, "OOO",
329                               &PyButtonInfo, &PyAxisInfo, &PyParamInfo)) {
330                 PyErr_Print();
331                 goto ERR_HND;
332         }
333
334         if (!(PySequence_Check(PyButtonInfo) && PySequence_Check(PyAxisInfo) &&
335               PySequence_Check(PyParamInfo))) {
336                 wminput_err("info not sequences");
337                 goto ERR_HND;
338         }
339
340         plugin->info->button_count = PySequence_Size(PyButtonInfo);
341         for (i=0; i < plugin->info->button_count; i++) {
342                 if (!(PyObj = PySequence_GetItem(PyButtonInfo, i))) {
343                         PyErr_Print();
344                         goto ERR_HND;
345                 }
346
347                 if (!(plugin->info->button_info[i].name = PyString_AsString(PyObj))) {
348                         PyErr_Print();
349                         Py_DECREF(PyObj);
350                         goto ERR_HND;
351                 }
352
353                 Py_DECREF(PyObj);
354         }
355
356         plugin->info->axis_count = PySequence_Size(PyAxisInfo);
357         for (i=0; i < plugin->info->axis_count; i++) {
358                 unsigned int type;
359
360                 if (!(PyObj = PySequence_GetItem(PyAxisInfo, i))) {
361                         PyErr_Print();
362                         goto ERR_HND;
363                 }
364
365                 if (!PyArg_ParseTuple(PyObj, "sIiiii",
366                                       &plugin->info->axis_info[i].name,
367                                       &type,
368                                       &plugin->info->axis_info[i].max,
369                                       &plugin->info->axis_info[i].min,
370                                       &plugin->info->axis_info[i].fuzz,
371                                       &plugin->info->axis_info[i].flat)) {
372                         PyErr_Print();
373                         Py_DECREF(PyObj);
374                         goto ERR_HND;
375                 }
376
377                 plugin->info->axis_info[i].type = type;
378
379                 Py_DECREF(PyObj);
380         }
381
382         plugin->info->param_count = PySequence_Size(PyParamInfo);
383         for (i=0; i < plugin->info->param_count; i++) {
384                 if (!(PyObj = PySequence_GetItem(PyParamInfo, i))) {
385                         PyErr_Print();
386                         goto ERR_HND;
387                 }
388
389                 if (!PyArg_ParseTuple(PyObj, "siO", &plugin->info->param_info[i].name,
390                                       &plugin->info->param_info[i].type,
391                                       &plugin->info->param_info[i].ptr)) {
392                         PyErr_Print();
393                         Py_DECREF(PyObj);
394                         goto ERR_HND;
395                 }
396
397                 Py_DECREF(PyObj);
398         }
399
400         return 0;
401
402 ERR_HND:
403         if (((struct py_plugin *)plugin->p)->PyInfo) {
404                 Py_DECREF(((struct py_plugin *)plugin->p)->PyInfo);
405         }
406
407         return -1;
408 }
409
410 int py_plugin_init(struct plugin *plugin, int id)
411 {
412         PyObject *PyArgs;
413
414         if (!(PyArgs = Py_BuildValue("(i,O)", id, PyWiimote))) {
415                 PyErr_Print();
416                 return -1;
417         }
418
419         if (!PyObject_CallObject(((struct py_plugin *)plugin->p)->init, PyArgs)) {
420                 PyErr_Print();
421                 Py_DECREF(PyArgs);
422                 return -1;
423         }
424
425         Py_DECREF(PyArgs);
426
427         return 0;
428 }
429
430 int py_plugin_exec(struct plugin *plugin, int mesg_count,
431                    union cwiid_mesg mesg[])
432 {
433         PyObject *PyArgs, *PyMesg, *PyData, *PyButtonData, *PyAxisData, *PyObj;
434         int i;
435
436         if (!(PyMesg = ConvertMesgArray(mesg_count, mesg))) {
437                 PyErr_Print();
438                 return -1;
439         }
440
441         if (!(PyArgs = Py_BuildValue("(O)", PyMesg))) {
442                 PyErr_Print();
443                 Py_DECREF(PyMesg);
444                 return -1;
445         }
446
447         Py_DECREF(PyMesg);
448
449         if (!(PyData = PyObject_CallObject(((struct py_plugin *)plugin->p)->exec,
450                                            PyArgs))) {
451                 PyErr_Print();
452                 Py_DECREF(PyArgs);
453                 return -1;
454         }
455
456         Py_DECREF(PyArgs);
457
458         if (!PyArg_ParseTuple(PyData, "OO", &PyButtonData, &PyAxisData)) {
459                 PyErr_Print();
460                 Py_DECREF(PyData);
461                 return -1;
462         }
463
464         if (!(PySequence_Check(PyButtonData) && PySequence_Check(PyAxisData))) {
465                 wminput_err("exec not sequences");
466                 Py_DECREF(PyData);
467                 return -1;
468         }
469
470         if (PySequence_Size(PyButtonData) != plugin->info->button_count) {
471                 wminput_err("exec bad button sequence");
472                 Py_DECREF(PyData);
473                 return -1;
474         }
475         plugin->data->buttons = 0;
476         for (i=0; i < plugin->info->button_count; i++) {
477                 if (!(PyObj = PySequence_GetItem(PyButtonData, i))) {
478                         PyErr_Print();
479                         Py_DECREF(PyData);
480                         return -1;
481                 }
482
483                 if (PyObj == Py_True) {
484                         plugin->data->buttons |= 1<<i;
485                 }
486                 else if (PyObj != Py_False) {
487                         wminput_err("exec bad button value");
488                         Py_DECREF(PyObj);
489                         Py_DECREF(PyData);
490                         return -1;
491                 }
492
493                 Py_DECREF(PyObj);
494         }
495
496         if (PySequence_Size(PyAxisData) != plugin->info->axis_count) {
497                 wminput_err("exec bad axis sequence");
498                 Py_DECREF(PyData);
499                 return -1;
500         }
501         for (i=0; i < plugin->info->axis_count; i++) {
502                 if (!(PyObj = PySequence_GetItem(PyAxisData, i))) {
503                         PyErr_Print();
504                         Py_DECREF(PyData);
505                         return -1;
506                 }
507
508                 if (PyObj == Py_None) {
509                         plugin->data->axes[i].valid = 0;
510                 }
511                 else if (!PyInt_Check(PyObj)) {
512                         wminput_err("exec bad axis value");
513                         Py_DECREF(PyObj);
514                         Py_DECREF(PyData);
515                         return -1;
516                 }
517                 else {
518                         plugin->data->axes[i].valid = 1;
519                         plugin->data->axes[i].value = PyInt_AsLong(PyObj);
520                 }
521
522                 Py_DECREF(PyObj);
523         }
524
525         Py_DECREF(PyData);
526
527         return 0;
528 }
529
530 int py_plugin_param_int(struct plugin *plugin, int i, int value)
531 {
532         PyObject *PyObj;
533
534         switch (plugin->info->param_info[i].type) {
535         case WMPLUGIN_PARAM_INT:
536                 PyObj = PyInt_FromLong(value);
537                 if (PyObject_SetAttrString(((struct py_plugin *)plugin->p)->handle,
538                                            plugin->info->param_info[i].name,
539                                            PyObj)) {
540                         PyErr_Print();
541                         return -1;
542                 }
543                 break;
544         case WMPLUGIN_PARAM_FLOAT:
545                 PyObj = PyFloat_FromDouble((double)value);
546                 if (PyObject_SetAttrString(((struct py_plugin *)plugin->p)->handle,
547                                            plugin->info->param_info[i].name,
548                                            PyObj)) {
549                         PyErr_Print();
550                         return -1;
551                 }
552                 break;
553         }
554
555         return 0;
556 }
557
558 int py_plugin_param_float(struct plugin *plugin, int i, float value)
559 {
560         PyObject *PyObj;
561
562         switch (plugin->info->param_info[i].type) {
563         case WMPLUGIN_PARAM_INT:
564                 wminput_err("possible loss of precision: %s.%s (cast float to int)",
565                             plugin->name, plugin->info->param_info[i].name);
566                 PyObj = PyInt_FromLong((int)value);
567                 if (PyObject_SetAttrString(((struct py_plugin *)plugin->p)->handle,
568                                            plugin->info->param_info[i].name,
569                                            PyObj)) {
570                         PyErr_Print();
571                         return -1;
572                 }
573                 break;
574         case WMPLUGIN_PARAM_FLOAT:
575                 PyObj = PyFloat_FromDouble((double)value);
576                 if (PyObject_SetAttrString(((struct py_plugin *)plugin->p)->handle,
577                                            plugin->info->param_info[i].name,
578                                            PyObj)) {
579                         PyErr_Print();
580                         return -1;
581                 }
582                 break;
583         }
584
585         return 0;
586 }
587
588 static PyObject *set_rpt_mode(PyObject *self, PyObject *args, PyObject *kwds)
589 {
590         static char *kwlist[] = {"id", "rpt_mode", NULL};
591         int id, rpt_mode;
592
593         if (!PyArg_ParseTupleAndKeywords(args, kwds, "ii:wmplugin:set_rpt_mode",
594                                          kwlist, &id, &rpt_mode)) {
595                 return NULL;
596         }
597
598         if (wmplugin_set_rpt_mode(id, rpt_mode)) {
599                 return NULL;
600         }
601
602         Py_RETURN_NONE;
603 }
Note: See TracBrowser for help on using the browser.