root/wminput/py_plugin.c

Revision 2100f14c612471084434b364501e3818c7f4144e, 13.9 kB (checked in by L. Donnie Smith <donnie.smith@…>, 3 years ago)

Various administrative updates

change email addresses
remove individual file changelogs (that's what version control is for)

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