Ticket #38: main.c

File main.c, 19.2 kB (added by xkill, 5 years ago)

wminput main.c

Line 
1/* Copyright (C) 2007 L. Donnie Smith <wiimote@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 *
19 *  2007-07-24 Pablo Catalina <xkill@ciberhell.ath.cx>
20 *  * Signaling support to trap SIGINT, SIGTERM and SIGUSR1 that exit the program.
21 *  * Syslog support
22 *  * Daemon support
23 *
24 *  2007-07-19 Pablo Catalina <xkill@ciberhell.ath.cx>
25 *  * always listen in wiimote standby mode, with wait time support
26 *
27 *  2007-06-18 L. Donnie Smith <cwiid@abstrakraft.org>
28 *  * revised error messages
29 *
30 *  2007-06-05 L. Donnie Smith <cwiid@abstrakraft.org>
31 *  * refactored to isolate plugin logic
32 *
33 *  2007-06-01 Nick <nickishappy@gmail.com>
34 *  * reworked command-line options (added standard options, long options)
35 *
36 *  2007-06-01 L. Donnie Smith <cwiid@abstrakraft.org>
37 *  * added python plugin support
38 *  * pass mesg instead of &mesg to wmplugin_exec
39 *
40 *  2007-05-16 L. Donnie Smith <cwiid@abstrakraft.org>
41 *  * changed cwiid_{connect,disconnect,command} to
42 *    cwiid_{open,close,request_status|set_led|set_rumble|set_rpt_mode}
43 *
44 *  2007-05-14 L. Donnie Smith <cwiid@abstrakraft.org>
45 *  * added timestamp to message callback
46 *
47 *  2007-04-24 L. Donnie Smith <cwiid@abstrakraft.org>
48 *  * update for API overhaul
49 *
50 *  2007-04-09 L. Donnie Smith <cwiid@abstrakraft.org>
51 *  * updated for libcwiid rename
52 *
53 *  2007-04-04 L. Donnie Smith <cwiid@abstrakraft.org>
54 *  * exit on cwiid_error
55 *
56 *  2007-03-03 L. Donnie Smith <cwiid@abstrakraft.org>
57 *  * Initial ChangeLog
58 *  * type audit (stdint, const, char booleans)
59 */
60
61#include <stdint.h>
62#include <stdio.h>
63#include <stdlib.h>
64#include <getopt.h>
65
66#include <pthread.h>
67#include <signal.h>
68#include <sys/types.h>
69#include <unistd.h>
70
71#include <cwiid.h>
72
73#include "conf.h"
74#include "util.h"
75#include "wmplugin.h"
76#include "c_plugin.h"
77#include "py_plugin.h"
78#include "syslog.h"
79
80
81struct conf conf;
82
83/* Prototypes */
84cwiid_mesg_callback_t cwiid_callback;
85int wminput_set_report_mode();
86void process_btn_mesg(struct cwiid_btn_mesg *mesg);
87void process_nunchuk_mesg(struct cwiid_nunchuk_mesg *mesg);
88void process_classic_mesg(struct cwiid_classic_mesg *mesg);
89void process_plugin(struct plugin *, int, union cwiid_mesg []);
90
91/* Globals */
92cwiid_wiimote_t *wiimote;
93char init;
94int always=0, wait_time=0, daemon_mode=0, wiimote_connected=0;
95
96#define DEFAULT_CONFIG_FILE     "default"
97
98#define HOME_DIR_LEN    128
99
100void print_usage(void)
101{
102        printf("wminput is a program that allows you to use a wiimote as a standard input device\n");
103        printf("Usage: %s [OPTIONS]...\n\n", "wminput");
104        printf("Options:\n");
105        printf("\t-h, --help\t\tPrints this output.\n");
106        printf("\t-v, --version\t\toutput version information and exit.\n");
107        printf("\t-c, --config [file]\tChoose config file to use.\n");
108        printf("\t-w, --wait\t\tWait indefinitely for wiimote to connect.\n");
109        printf("\t-a, --always <s>\tWait always but wait N seconds before discover.\n\t\t\t\tDon't kill when wiimote disconnect.\n");
110        printf("\t-d, --daemon \tPut wminput into daemon mode\n");
111}
112
113void handle_exit(int sig){
114        signal (sig,handle_exit);
115        syslog(LOG_INFO,"wminput user exit. CTRL+C or KILL");
116        if (daemon_mode==0) {
117                printf ("User exit. CTRL+C or KILL \n");
118        }
119        closelog();
120        always=0;
121}
122
123
124int main(int argc, char *argv[])
125{
126        char wait_forever = 0;
127        char *config_search_dirs[3], *plugin_search_dirs[3];
128        char *config_filename = DEFAULT_CONFIG_FILE;
129        char home_config_dir[HOME_DIR_LEN];
130        char home_plugin_dir[HOME_DIR_LEN];
131        char *tmp;
132        int c, i;
133        char *str_addr;
134        bdaddr_t bdaddr;
135        struct uinput_listen_data uinput_listen_data;
136        pthread_t uinput_listen_thread;
137        int ret=0;
138
139//      openlog("cwiid-wminput",LOG_PID,LOG_DAEMON);
140
141        init = 1;
142
143        /* Parse Options */
144        while (1) {
145                int option_index = 0;
146
147                static struct option long_options[] = {
148                        {"help", 0, 0, 'h'},
149                        {"wait", 0, 0, 'w'},
150                        {"config", 1, 0, 'c'},
151                        {"version", 0, 0, 'v'},
152                        {"always", 1, 0, 'a'},
153                        {"daemon", 0, 0, 'd'},
154                        {0, 0, 0, 0}
155                };
156
157                c = getopt_long (argc, argv, "hwa:c:vd", long_options, &option_index);
158
159                if (c == -1) {
160                        break;
161                }
162
163                switch (c) {
164                case 'h':
165                        print_usage();
166                        return 0;
167                        break;
168                case 'a':
169                        always=1;
170                        if (optarg) {
171                                wait_time = atoi(optarg);
172                        }
173                        break;
174                case 'w':
175                        wait_forever = 1;
176                        break;
177                case 'c':
178                        config_filename = optarg;
179                        break;
180                case 'v':
181                        printf("CWiid Version %s\n", CWIID_VERSION);
182                        return 0;
183                        break;
184                case '?':
185                        printf("Try `wminput --help` for more information\n");
186                        return 1;
187                        break;
188                case 'd':
189                        printf("Entering daemon mode\n");
190                        daemon ( 1, 0);
191                        daemon_mode=1;
192                        break;
193                default:
194                        return -1;
195                        break;
196                }
197        }
198
199        if (c_init()) {
200                return -1;
201        }
202        if (py_init()) {
203                return -1;
204        }
205
206        /* Load Config */
207        /* Setup search directory arrays */
208        if ((tmp = getenv("HOME")) == NULL) {
209                wminput_err("Unable to find home directory");
210                config_search_dirs[0] = WMINPUT_CONFIG_DIR;
211                plugin_search_dirs[0] = CWIID_PLUGINS_DIR;
212                config_search_dirs[1] = plugin_search_dirs[1] = NULL;
213        }
214        else {
215                snprintf(home_config_dir, HOME_DIR_LEN, "%s/.cwiid/wminput", tmp);
216                snprintf(home_plugin_dir, HOME_DIR_LEN, "%s/.cwiid/plugins", tmp);
217                config_search_dirs[0] = home_config_dir;
218                plugin_search_dirs[0] = home_plugin_dir;
219                config_search_dirs[1] = WMINPUT_CONFIG_DIR;
220                plugin_search_dirs[1] = CWIID_PLUGINS_DIR;
221                config_search_dirs[2] = plugin_search_dirs[2] = NULL;
222        }
223
224        if (conf_load(&conf, config_filename, config_search_dirs,
225          plugin_search_dirs)) {
226                return -1;
227        }
228        /* Determine BDADDR */
229        /* priority: command-line option, environment variable, BDADDR_ANY */
230        if (optind < argc) {
231                if (str2ba(argv[optind], &bdaddr)) {
232                        wminput_err("invalid bdaddr");
233                        bdaddr = *BDADDR_ANY;
234                }
235                optind++;
236                if (optind < argc) {
237                        wminput_err("invalid command-line");
238                        print_usage();
239                        conf_unload(&conf);
240                        return -1;
241                }
242        }
243        else if ((str_addr = getenv(WIIMOTE_BDADDR)) != NULL) {
244                if (str2ba(str_addr, &bdaddr)) {
245                        wminput_err("invalid address in %s", WIIMOTE_BDADDR);
246                        bdaddr = *BDADDR_ANY;
247                }
248        }
249        else {
250                bdaddr = *BDADDR_ANY;
251        }
252
253        signal (SIGINT,handle_exit);
254        signal (SIGTERM,handle_exit);
255        signal (SIGUSR1,handle_exit);
256        syslog(LOG_INFO,"CWiid Version %s. wminput started", CWIID_VERSION);
257
258        do {
259        /* TODO: fix wait_forever logic - currently assumes bdaddr is unspecified */
260        /* Wiimote Connect */
261
262                syslog (LOG_INFO,"Catching wiimote");
263                if (daemon_mode==0) {
264                        printf("Put Wiimote in discoverable mode now (press 1+2)...\n");
265                }
266                if (wait_forever) {
267                        if (cwiid_find_wiimote(&bdaddr, -1)) {
268                                wminput_err("error finding wiimote");
269                                conf_unload(&conf);
270                                return -1;
271                        }
272                }
273                if ((wiimote = cwiid_open(&bdaddr, CWIID_FLAG_MESG_IFC)) == NULL) {
274                        wminput_err("unable to connect");
275                        conf_unload(&conf);
276                        return -1;
277                } else {
278                        wiimote_connected = 1;
279                }
280                if (cwiid_set_mesg_callback(wiimote, &cwiid_callback)) {
281                        wminput_err("error setting callback");
282                        conf_unload(&conf);
283                        return -1;
284                }
285       
286                if (c_wiimote(wiimote)) {
287                        conf_unload(&conf);
288                        return -1;
289                }
290                if (py_wiimote(wiimote)) {
291                        conf_unload(&conf);
292                        return -1;
293                }
294       
295                /* init plugins */
296                for (i=0; (i < CONF_MAX_PLUGINS) && conf.plugins[i].name; i++) {
297                        switch (conf.plugins[i].type) {
298                        case PLUGIN_C:
299                                if (c_plugin_init(&conf.plugins[i], i)) {
300                                        wminput_err("error on %s init", conf.plugins[i].name);
301                                        conf_unload(&conf);
302                                        cwiid_close(wiimote);
303                                        return -1;
304                                }
305                                break;
306                        case PLUGIN_PYTHON:
307                                if (py_plugin_init(&conf.plugins[i], i)) {
308                                        wminput_err("error %s init", conf.plugins[i].name);
309                                        conf_unload(&conf);
310                                        cwiid_close(wiimote);
311                                        return -1;
312                                }
313                                break;
314                        }
315                }
316       
317                if (wminput_set_report_mode()) {
318                        conf_unload(&conf);
319                        cwiid_close(wiimote);
320                        return -1;
321                }
322       
323                uinput_listen_data.wiimote = wiimote;
324                uinput_listen_data.conf = &conf;
325                if (pthread_create(&uinput_listen_thread, NULL,
326                                   (void *(*)(void *))uinput_listen,
327                                   &uinput_listen_data)) {
328                        wminput_err("error starting uinput listen thread");
329                        conf_unload(&conf);
330                        cwiid_close(wiimote);
331                        return -1;
332                }
333
334               
335       
336                syslog(LOG_INFO,"Wiimote Cached");
337
338                if (daemon_mode==0) {
339                        printf("Ready.\n");
340                }
341               
342                init = 0;
343       
344
345                do {
346                        sleep (2);
347                }
348                while (wiimote_connected == 1) ;
349
350                if ( wait_time > 0 ) {
351                        if (daemon_mode==0) {
352                                printf ("Waiting %ds\n",wait_time);     
353                        }
354                        syslog (LOG_INFO,"Waiting %ds for retry.",wait_time);
355                        sleep ( wait_time );
356                }
357
358                       
359        } while (always==1);
360
361        syslog(LOG_INFO,"WMInput exit");       
362        if (daemon_mode==0) {
363                printf("Exiting.\n");
364        }
365
366        if (pthread_cancel(uinput_listen_thread)) {
367                wminput_err("Error canceling uinput listen thread");
368                ret = -1;
369        }
370        else if (pthread_join(uinput_listen_thread, NULL)) {
371                wminput_err("Error joining uinput listen thread");
372                ret = -1;
373        }
374
375        /* disconnect */
376        if (cwiid_close(wiimote)) {
377                wminput_err("Error on wiimote disconnect");
378                ret = -1;
379        }
380
381        if (conf_unload(&conf)) {
382                ret = -1;
383        }
384
385        py_deinit();
386
387        return ret;
388}
389
390int wminput_set_report_mode()
391{
392        unsigned char rpt_mode_flags;
393        int i;
394
395        rpt_mode_flags = conf.rpt_mode_flags;
396
397        for (i=0; (i < CONF_MAX_PLUGINS) && conf.plugins[i].name; i++) {
398                rpt_mode_flags |= conf.plugins[i].rpt_mode_flags;
399        }
400
401        if (cwiid_set_rpt_mode(wiimote, rpt_mode_flags)) {
402                wminput_err("Error setting report mode");
403                return -1;
404        }
405
406        return 0;
407}
408
409int wmplugin_set_rpt_mode(int id, uint8_t flags)
410{
411        conf.plugins[id].rpt_mode_flags = flags;
412
413        if (!init) {
414                wminput_set_report_mode();
415        }
416
417        return 0;
418}
419
420void cwiid_callback(cwiid_wiimote_t *wiimote, int mesg_count,
421                    union cwiid_mesg mesg[], struct timespec *timestamp)
422{
423        int i;
424
425        for (i=0; i < mesg_count; i++) {
426                switch (mesg[i].type) {
427                case CWIID_MESG_BTN:
428                        process_btn_mesg((struct cwiid_btn_mesg *) &mesg[i]);
429                        break;
430                case CWIID_MESG_NUNCHUK:
431                        process_nunchuk_mesg((struct cwiid_nunchuk_mesg *) &mesg[i]);
432                        break;
433                case CWIID_MESG_CLASSIC:
434                        process_classic_mesg((struct cwiid_classic_mesg *) &mesg[i]);
435                        break;
436                case CWIID_MESG_ERROR:
437                        syslog (LOG_INFO,"Wiimote disappears");
438                        wminput_err("Wiimote disappears");
439                        wiimote_connected = 0;
440                        break;
441                default:
442                        break;
443                }
444        }
445        for (i=0; (i < CONF_MAX_PLUGINS) && conf.plugins[i].name; i++) {
446                process_plugin(&conf.plugins[i], mesg_count, mesg);
447        }
448        send_event(&conf, EV_SYN, SYN_REPORT, 0);
449}
450
451void process_btn_mesg(struct cwiid_btn_mesg *mesg)
452{
453        static uint16_t prev_buttons = 0;
454        uint16_t pressed, released;
455        __s32 axis_value;
456        int i;
457
458        /* Wiimote Button/Key Events */
459        pressed = mesg->buttons & ~prev_buttons;
460        released = ~mesg->buttons & prev_buttons;
461        for (i=0; i < CONF_WM_BTN_COUNT; i++) {
462                if (conf.wiimote_bmap[i].active) {
463                        if (pressed & conf.wiimote_bmap[i].mask) {
464                                send_event(&conf, EV_KEY, conf.wiimote_bmap[i].action, 1);
465                        }
466                        else if (released & conf.wiimote_bmap[i].mask) {
467                                send_event(&conf, EV_KEY, conf.wiimote_bmap[i].action, 0);
468                        }
469                }
470        }
471        prev_buttons = mesg->buttons;
472
473        /* Wiimote.Dpad.X */
474        if (conf.amap[CONF_WM_AXIS_DPAD_X].active) {
475                axis_value = 0;
476                if (mesg->buttons & CWIID_BTN_LEFT) {
477                        axis_value = -1;
478                }
479                else if (mesg->buttons & CWIID_BTN_RIGHT) {
480                        axis_value = 1;
481                }
482                if (conf.amap[CONF_WM_AXIS_DPAD_X].flags & CONF_INVERT) {
483                        axis_value *= -1;
484                }
485                send_event(&conf, conf.amap[CONF_WM_AXIS_DPAD_X].axis_type,
486                           conf.amap[CONF_WM_AXIS_DPAD_X].action, axis_value);
487        }
488
489        /* Wiimote.Dpad.Y */
490        if (conf.amap[CONF_WM_AXIS_DPAD_Y].active) {
491                axis_value = 0;
492                if (mesg->buttons & CWIID_BTN_DOWN) {
493                        axis_value = -1;
494                }
495                else if (mesg->buttons & CWIID_BTN_UP) {
496                        axis_value = 1;
497                }
498                if (conf.amap[CONF_WM_AXIS_DPAD_Y].flags & CONF_INVERT) {
499                        axis_value *= -1;
500                }
501                send_event(&conf, conf.amap[CONF_WM_AXIS_DPAD_Y].axis_type,
502                           conf.amap[CONF_WM_AXIS_DPAD_Y].action, axis_value);
503        }
504}
505
506void process_nunchuk_mesg(struct cwiid_nunchuk_mesg *mesg)
507{
508        static uint8_t prev_buttons = 0;
509        uint8_t pressed, released;
510        __s32 axis_value;
511        int i;
512
513        /* Nunchuk Button/Key Events */
514        pressed = mesg->buttons & ~prev_buttons;
515        released = ~mesg->buttons & prev_buttons;
516        for (i=0; i < CONF_NC_BTN_COUNT; i++) {
517                if (conf.nunchuk_bmap[i].active) {
518                        if (pressed & conf.nunchuk_bmap[i].mask) {
519                                send_event(&conf, EV_KEY, conf.nunchuk_bmap[i].action, 1);
520                        }
521                        else if (released & conf.nunchuk_bmap[i].mask) {
522                                send_event(&conf, EV_KEY, conf.nunchuk_bmap[i].action, 0);
523                        }
524                }
525        }
526        prev_buttons = mesg->buttons;
527
528        /* Nunchuk.Stick.X */
529        if (conf.amap[CONF_NC_AXIS_STICK_X].active) {
530                axis_value = mesg->stick[CWIID_X];
531                if (conf.amap[CONF_NC_AXIS_STICK_X].flags & CONF_INVERT) {
532                        axis_value = 0xFF - axis_value;
533                }
534                send_event(&conf, conf.amap[CONF_NC_AXIS_STICK_X].axis_type,
535                           conf.amap[CONF_NC_AXIS_STICK_X].action, axis_value);
536        }
537
538        /* Nunchuk.Stick.Y */
539        if (conf.amap[CONF_NC_AXIS_STICK_Y].active) {
540                axis_value = mesg->stick[CWIID_Y];
541                if (conf.amap[CONF_NC_AXIS_STICK_Y].flags & CONF_INVERT) {
542                        axis_value = 0xFF - axis_value;
543                }
544                send_event(&conf, conf.amap[CONF_NC_AXIS_STICK_Y].axis_type,
545                           conf.amap[CONF_NC_AXIS_STICK_Y].action, axis_value);
546        }
547}
548
549void process_classic_mesg(struct cwiid_classic_mesg *mesg)
550{
551        static uint16_t prev_buttons = 0;
552        uint16_t pressed, released;
553        __s32 axis_value;
554        int i;
555
556        /* Classic Button/Key Events */
557        pressed = mesg->buttons & ~prev_buttons;
558        released = ~mesg->buttons & prev_buttons;
559        for (i=0; i < CONF_CC_BTN_COUNT; i++) {
560                if (conf.classic_bmap[i].active) {
561                        if (pressed & conf.classic_bmap[i].mask) {
562                                send_event(&conf, EV_KEY, conf.classic_bmap[i].action, 1);
563                        }
564                        else if (released & conf.classic_bmap[i].mask) {
565                                send_event(&conf, EV_KEY, conf.classic_bmap[i].action, 0);
566                        }
567                }
568        }
569        prev_buttons = mesg->buttons;
570
571        /* Classic.Dpad.X */
572        if (conf.amap[CONF_CC_AXIS_DPAD_X].active) {
573                axis_value = 0;
574                if (mesg->buttons & CWIID_CLASSIC_BTN_LEFT) {
575                        axis_value = -1;
576                }
577                else if (mesg->buttons & CWIID_CLASSIC_BTN_RIGHT) {
578                        axis_value = 1;
579                }
580                if (conf.amap[CONF_CC_AXIS_DPAD_X].flags & CONF_INVERT) {
581                        axis_value *= -1;
582                }
583                send_event(&conf, conf.amap[CONF_CC_AXIS_DPAD_X].axis_type,
584                           conf.amap[CONF_CC_AXIS_DPAD_X].action, axis_value);
585        }
586
587        /* Classic.Dpad.Y */
588        if (conf.amap[CONF_CC_AXIS_DPAD_Y].active) {
589                axis_value = 0;
590                if (mesg->buttons & CWIID_CLASSIC_BTN_DOWN) {
591                        axis_value = -1;
592                }
593                else if (mesg->buttons & CWIID_CLASSIC_BTN_UP) {
594                        axis_value = 1;
595                }
596                if (conf.amap[CONF_CC_AXIS_DPAD_Y].flags & CONF_INVERT) {
597                        axis_value *= -1;
598                }
599                send_event(&conf, conf.amap[CONF_CC_AXIS_DPAD_Y].axis_type,
600                           conf.amap[CONF_CC_AXIS_DPAD_Y].action, axis_value);
601        }
602
603        /* Classic.LStick.X */
604        if (conf.amap[CONF_CC_AXIS_L_STICK_X].active) {
605                axis_value = mesg->l_stick[CWIID_X];
606                if (conf.amap[CONF_CC_AXIS_L_STICK_X].flags & CONF_INVERT) {
607                        axis_value = CWIID_CLASSIC_L_STICK_MAX - axis_value;
608                }
609                send_event(&conf, conf.amap[CONF_CC_AXIS_L_STICK_X].axis_type,
610                           conf.amap[CONF_CC_AXIS_L_STICK_X].action, axis_value);
611        }
612
613        /* Classic.LStick.Y */
614        if (conf.amap[CONF_CC_AXIS_L_STICK_Y].active) {
615                axis_value = mesg->l_stick[CWIID_Y];
616                if (conf.amap[CONF_CC_AXIS_L_STICK_Y].flags & CONF_INVERT) {
617                        axis_value = CWIID_CLASSIC_L_STICK_MAX - axis_value;
618                }
619                send_event(&conf, conf.amap[CONF_CC_AXIS_L_STICK_Y].axis_type,
620                           conf.amap[CONF_CC_AXIS_L_STICK_Y].action, axis_value);
621        }
622
623        /* Classic.RStick.X */
624        if (conf.amap[CONF_CC_AXIS_R_STICK_X].active) {
625                axis_value = mesg->r_stick[CWIID_X];
626                if (conf.amap[CONF_CC_AXIS_R_STICK_X].flags & CONF_INVERT) {
627                        axis_value = CWIID_CLASSIC_R_STICK_MAX - axis_value;
628                }
629                send_event(&conf, conf.amap[CONF_CC_AXIS_R_STICK_X].axis_type,
630                           conf.amap[CONF_CC_AXIS_R_STICK_X].action, axis_value);
631        }
632
633        /* Classic.RStick.Y */
634        if (conf.amap[CONF_CC_AXIS_R_STICK_Y].active) {
635                axis_value = mesg->r_stick[CWIID_Y];
636                if (conf.amap[CONF_CC_AXIS_R_STICK_Y].flags & CONF_INVERT) {
637                        axis_value = CWIID_CLASSIC_R_STICK_MAX - axis_value;
638                }
639                send_event(&conf, conf.amap[CONF_CC_AXIS_R_STICK_Y].axis_type,
640                           conf.amap[CONF_CC_AXIS_R_STICK_Y].action, axis_value);
641        }
642
643        /* Classic.LAnalog */
644        if (conf.amap[CONF_CC_AXIS_L].active) {
645                axis_value = mesg->l;
646                if (conf.amap[CONF_CC_AXIS_L].flags & CONF_INVERT) {
647                        axis_value = CWIID_CLASSIC_LR_MAX - axis_value;
648                }
649                send_event(&conf, conf.amap[CONF_CC_AXIS_L].axis_type,
650                           conf.amap[CONF_CC_AXIS_L].action, axis_value);
651        }
652
653        /* Classic.RAnalog */
654        if (conf.amap[CONF_CC_AXIS_R].active) {
655                axis_value = mesg->r;
656                if (conf.amap[CONF_CC_AXIS_R].flags & CONF_INVERT) {
657                        axis_value = CWIID_CLASSIC_LR_MAX - axis_value;
658                }
659                send_event(&conf, conf.amap[CONF_CC_AXIS_R].axis_type,
660                           conf.amap[CONF_CC_AXIS_R].action, axis_value);
661        }
662}
663
664void process_plugin(struct plugin *plugin, int mesg_count,
665                    union cwiid_mesg mesg[])
666{
667        static union cwiid_mesg plugin_mesg[CWIID_MAX_MESG_COUNT];
668        int plugin_mesg_count = 0;
669        int i;
670        uint8_t flag;
671        uint16_t pressed, released;
672        __s32 axis_value;
673
674        for (i=0; i < mesg_count; i++) {
675                switch (mesg[i].type) {
676                case CWIID_MESG_STATUS:
677                        flag = CWIID_RPT_STATUS;
678                        break;
679                case CWIID_MESG_BTN:
680                        flag = CWIID_RPT_BTN;
681                        break;
682                case CWIID_MESG_ACC:
683                        flag = CWIID_RPT_ACC;
684                        break;
685                case CWIID_MESG_IR:
686                        flag = CWIID_RPT_IR;
687                        break;
688                case CWIID_MESG_NUNCHUK:
689                        flag = CWIID_RPT_NUNCHUK;
690                        break;
691                case CWIID_MESG_CLASSIC:
692                        flag = CWIID_RPT_CLASSIC;
693                        break;
694                default:
695                        break;
696                }
697                if (plugin->rpt_mode_flags & flag) {
698                        /* TODO: copy correct (smaller) message size */
699                        memcpy(&plugin_mesg[plugin_mesg_count++], &mesg[i], sizeof mesg[i]);
700                }
701        }
702
703        if (plugin_mesg_count > 0) {
704                switch (plugin->type) {
705                case PLUGIN_C:
706                        if (c_plugin_exec(plugin, plugin_mesg_count, plugin_mesg)) {
707                                return;
708                        }
709                        break;
710                case PLUGIN_PYTHON:
711                        if (py_plugin_exec(plugin, plugin_mesg_count, plugin_mesg)) {
712                                return;
713                        }
714                        break;
715                }
716
717                /* Plugin Button/Key Events */
718                pressed = plugin->data->buttons & ~plugin->prev_buttons;
719                released = ~plugin->data->buttons & plugin->prev_buttons;
720                for (i=0; i < plugin->info->button_count; i++) {
721                        if (plugin->bmap[i].active) {
722                                if (pressed & 1<<i) {
723                                        send_event(&conf, EV_KEY, plugin->bmap[i].action, 1);
724                                }
725                                else if (released & 1<<i) {
726                                        send_event(&conf, EV_KEY, plugin->bmap[i].action, 0);
727                                }
728                        }
729                }
730                plugin->prev_buttons = plugin->data->buttons;
731
732                /* Plugin Axis Events */
733                for (i=0; i < plugin->info->axis_count; i++) {
734                        if (plugin->amap[i].active && plugin->data->axes &&
735                          plugin->data->axes[i].valid) {
736                                axis_value = plugin->data->axes[i].value;
737                                if (plugin->amap[i].flags & CONF_INVERT) {
738                                        axis_value = plugin->info->axis_info[i].max +
739                                                     plugin->info->axis_info[i].min - axis_value;
740                                }
741                                send_event(&conf, plugin->amap[i].axis_type,
742                                           plugin->amap[i].action, axis_value);
743                        }
744                }
745        }
746}