root/wminput/py_plugin.c @ 7e5f213decff36c62421b1b3d02d02b3037c79a2

Revision 7e5f213decff36c62421b1b3d02d02b3037c79a2, 14.5 KB (checked in by dsmith <dsmith@…>, 6 years ago)

wminput daemon mode

git-svn-id: http://abstrakraft.org/cwiid/svn/trunk@142 918edb2d-ff29-0410-9de2-eb38e7f22bc7

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