root/wminput/main.c @ 15d141cccd9a38fede6b80ab2d6b8f921991cf25

Revision 15d141cccd9a38fede6b80ab2d6b8f921991cf25, 14.4 KB (checked in by dsmith <dsmith@…>, 6 years ago)

Initial import

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

  • Property mode set to 100644
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
18#include <stdio.h>
19#include <stdlib.h>
20
21#include <pthread.h>
22#include <signal.h>
23#include <unistd.h>
24
25#include <wiimote.h>
26
27#include "conf.h"
28#include "util.h"
29#include "wmplugin.h"
30
31struct conf conf;
32
33/* GetOpt */
34#define OPTSTRING       "hc:"
35extern char *optarg;
36extern int optind, opterr, optopt;
37
38/* Prototypes */
39wiimote_mesg_callback_t wiimote_callback;
40int wminput_set_report_mode();
41void process_btn_mesg(struct wiimote_btn_mesg *mesg);
42void process_nunchuk_mesg(struct wiimote_nunchuk_mesg *mesg);
43void process_classic_mesg(struct wiimote_classic_mesg *mesg);
44void process_plugin(struct plugin *, int, union wiimote_mesg * []);
45
46/* Globals */
47wiimote_t *wiimote;
48int init;
49
50#ifndef GLOBAL_CWIID_DIR
51#error Global plugin directory macro undefined
52#endif
53
54#define DEFAULT_CONFIG_FILE     "default"
55
56#define USAGE "usage:%s [-h] [-t tracking_plugin] [BDADDR]\n"
57
58#define GLOBAL_CONFIG_DIR       GLOBAL_CWIID_DIR "/wminput"
59#define GLOBAL_PLUGIN_DIR       GLOBAL_CWIID_DIR "/plugins"
60
61#define HOME_DIR_LEN    128
62int main(int argc, char *argv[])
63{
64        char *config_search_dirs[3], *plugin_search_dirs[3];
65        char *config_filename = DEFAULT_CONFIG_FILE;
66        char home_config_dir[HOME_DIR_LEN];
67        char home_plugin_dir[HOME_DIR_LEN];
68        char *tmp;
69        int c, i;
70        char *str_addr;
71        bdaddr_t bdaddr;
72        sigset_t sigset;
73        int signum, ret=0;
74        struct uinput_listen_data uinput_listen_data;
75        pthread_t uinput_listen_thread;
76
77        init = -1;
78
79        /* Parse Options */
80        while ((c = getopt(argc, argv, OPTSTRING)) != -1) {
81                switch (c) {
82                case 'h':
83                        printf(USAGE, argv[0]);
84                        return 0;
85                        break;
86                case 'c':
87                        config_filename = optarg;
88                        break;
89                case '?':
90                default:
91                        wminput_err("unknown command-line option: -%c", c);
92                        break;
93                }
94        }
95
96        /* Load Config */
97        if ((tmp = getenv("HOME")) == NULL) {
98                wminput_err("unable to find home directory");
99                config_search_dirs[0] = GLOBAL_CONFIG_DIR;
100                plugin_search_dirs[0] = GLOBAL_PLUGIN_DIR;
101                config_search_dirs[1] = plugin_search_dirs[1] = NULL;
102        }
103        else {
104                snprintf(home_config_dir, HOME_DIR_LEN, "%s/.CWiid/wminput", tmp);
105                snprintf(home_plugin_dir, HOME_DIR_LEN, "%s/.CWiid/plugins", tmp);
106                config_search_dirs[0] = home_config_dir;
107                plugin_search_dirs[0] = home_plugin_dir;
108                config_search_dirs[1] = GLOBAL_CONFIG_DIR;
109                plugin_search_dirs[1] = GLOBAL_PLUGIN_DIR;
110                config_search_dirs[2] = plugin_search_dirs[2] = NULL;
111        }
112
113        if (conf_load(&conf, config_filename, config_search_dirs,
114          plugin_search_dirs)) {
115                return -1;
116        }
117
118        /* BDADDR */
119        if (optind < argc) {
120                if (str2ba(argv[optind], &bdaddr)) {
121                        wminput_err("invalid bdaddr");
122                        bdaddr = *BDADDR_ANY;
123                }
124                optind++;
125                if (optind < argc) {
126                        wminput_err("invalid command-line");
127                        printf(USAGE, argv[0]);
128                        conf_unload(&conf);
129                        return -1;
130                }
131        }
132        else if ((str_addr = getenv(WIIMOTE_BDADDR)) != NULL) {
133                if (str2ba(str_addr, &bdaddr)) {
134                        wminput_err("invalid address in %s", WIIMOTE_BDADDR);
135                        bdaddr = *BDADDR_ANY;
136                }
137        }
138        else {
139                bdaddr = *BDADDR_ANY;
140        }
141
142        /* Wiimote connect */
143        printf("Put Wiimote in discoverable mode now (press 1+2)...\n");
144        if ((wiimote = wiimote_connect(bdaddr, wiimote_callback, NULL)) == NULL) {
145                wminput_err("unable to connect");
146                conf_unload(&conf);
147                return -1;
148        }
149
150        /* init plugins */
151        for (i=0; (i < CONF_MAX_PLUGINS) && conf.plugins[i].name; i++) {
152                if ((*conf.plugins[i].init)(i, wiimote)) {
153                        wminput_err("error on %s init", conf.plugins[i].name);
154                        conf_unload(&conf);
155                        wiimote_disconnect(wiimote);
156                        return -1;
157                }
158        }
159
160        if (wminput_set_report_mode()) {
161                conf_unload(&conf);
162                wiimote_disconnect(wiimote);
163                return -1;
164        }
165
166        uinput_listen_data.wiimote = wiimote;
167        uinput_listen_data.conf = &conf;
168        if (pthread_create(&uinput_listen_thread, NULL,
169                           (void *(*)(void *))uinput_listen,
170                           &uinput_listen_data)) {
171                wminput_err("error starting uinput listen thread");
172                conf_unload(&conf);
173                wiimote_disconnect(wiimote);
174                return -1;
175        }
176
177
178        printf("Ready.\n");
179
180        init = 0;
181
182        /* wait */
183        sigemptyset(&sigset);
184        sigaddset(&sigset, SIGTERM);
185        sigaddset(&sigset, SIGINT);
186        sigprocmask(SIG_BLOCK, &sigset, NULL);
187        sigwait(&sigset, &signum);
188
189        printf("Exiting.\n");
190
191        if (pthread_cancel(uinput_listen_thread)) {
192                wminput_err("error canceling uinput listen thread");
193                ret = -1;
194        }
195        else if (pthread_join(uinput_listen_thread, NULL)) {
196                wminput_err("error joing uinput listen thread");
197                ret = -1;
198        }
199
200        /* disconnect */
201        if (wiimote_disconnect(wiimote)) {
202                wminput_err("error on disconnect");
203                ret = -1;
204        }
205
206        if (conf_unload(&conf)) {
207                ret = -1;
208        }
209
210        return ret;
211}
212
213int wmplugin_set_report_mode(int id, unsigned int flags)
214{
215        conf.plugins[id].rpt_mode_flags = flags;
216
217        if (!init) {
218                wminput_set_report_mode();
219        }
220
221        return 0;
222}
223
224int wminput_set_report_mode()
225{
226        unsigned char rpt_mode_flags;
227        int i;
228
229        rpt_mode_flags = conf.rpt_mode_flags;
230
231        for (i=0; (i < CONF_MAX_PLUGINS) && conf.plugins[i].name; i++) {
232                rpt_mode_flags |= conf.plugins[i].rpt_mode_flags;
233        }
234
235        if (wiimote_command(wiimote, WIIMOTE_CMD_RPT_MODE, rpt_mode_flags)) {
236                wminput_err("error setting report mode");
237                return -1;
238        }
239
240        return 0;
241}
242
243void wiimote_callback(int id, int mesg_count, union wiimote_mesg *mesg[])
244{
245        int i;
246
247        for (i=0; i < mesg_count; i++) {
248                switch (mesg[i]->type) {
249                case WIIMOTE_MESG_BTN:
250                        process_btn_mesg((struct wiimote_btn_mesg *) mesg[i]);
251                        break;
252                case WIIMOTE_MESG_NUNCHUK:
253                        process_nunchuk_mesg((struct wiimote_nunchuk_mesg *) mesg[i]);
254                        break;
255                case WIIMOTE_MESG_CLASSIC:
256                        process_classic_mesg((struct wiimote_classic_mesg *) mesg[i]);
257                        break;
258                default:
259                        break;
260                }
261        }
262        for (i=0; (i < CONF_MAX_PLUGINS) && conf.plugins[i].name; i++) {
263                process_plugin(&conf.plugins[i], mesg_count, mesg);
264        }
265        send_event(&conf, EV_SYN, SYN_REPORT, 0);
266}
267
268void process_btn_mesg(struct wiimote_btn_mesg *mesg)
269{
270        static unsigned short prev_buttons = 0;
271        unsigned short pressed, released;
272        int axis_value;
273        int i;
274
275        /* Wiimote Button/Key Events */
276        pressed = mesg->buttons & ~prev_buttons;
277        released = ~mesg->buttons & prev_buttons;
278        for (i=0; i < CONF_WM_BTN_COUNT; i++) {
279                if (pressed & conf.wiimote_bmap[i].mask) {
280                        send_event(&conf, EV_KEY, conf.wiimote_bmap[i].action, 1);
281                }
282                else if (released & conf.wiimote_bmap[i].mask) {
283                        send_event(&conf, EV_KEY, conf.wiimote_bmap[i].action, 0);
284                }
285        }
286        prev_buttons = mesg->buttons;
287
288        /* Wiimote.Dpad.X */
289        if (conf.amap[CONF_WM_AXIS_DPAD_X].action != -1) {
290                axis_value = 0;
291                if (mesg->buttons & WIIMOTE_BTN_LEFT) {
292                        axis_value = -1;
293                }
294                else if (mesg->buttons & WIIMOTE_BTN_RIGHT) {
295                        axis_value = 1;
296                }
297                if (conf.amap[CONF_WM_AXIS_DPAD_X].flags & CONF_INVERT) {
298                        axis_value *= -1;
299                }
300                send_event(&conf, conf.amap[CONF_WM_AXIS_DPAD_X].axis_type,
301                           conf.amap[CONF_WM_AXIS_DPAD_X].action, axis_value);
302        }
303
304        /* Wiimote.Dpad.Y */
305        if (conf.amap[CONF_WM_AXIS_DPAD_Y].action != -1) {
306                axis_value = 0;
307                if (mesg->buttons & WIIMOTE_BTN_DOWN) {
308                        axis_value = -1;
309                }
310                else if (mesg->buttons & WIIMOTE_BTN_UP) {
311                        axis_value = 1;
312                }
313                if (conf.amap[CONF_WM_AXIS_DPAD_Y].flags & CONF_INVERT) {
314                        axis_value *= -1;
315                }
316                send_event(&conf, conf.amap[CONF_WM_AXIS_DPAD_Y].axis_type,
317                           conf.amap[CONF_WM_AXIS_DPAD_Y].action, axis_value);
318        }
319}
320
321void process_nunchuk_mesg(struct wiimote_nunchuk_mesg *mesg)
322{
323        static unsigned char prev_buttons = 0;
324        unsigned char pressed, released;
325        int axis_value;
326        int i;
327
328        /* Nunchuk Button/Key Events */
329        pressed = mesg->buttons & ~prev_buttons;
330        released = ~mesg->buttons & prev_buttons;
331        for (i=0; i < CONF_NC_BTN_COUNT; i++) {
332                if (pressed & conf.nunchuk_bmap[i].mask) {
333                        send_event(&conf, EV_KEY, conf.nunchuk_bmap[i].action, 1);
334                }
335                else if (released & conf.nunchuk_bmap[i].mask) {
336                        send_event(&conf, EV_KEY, conf.nunchuk_bmap[i].action, 0);
337                }
338        }
339        prev_buttons = mesg->buttons;
340
341        /* Nunchuk.Stick.X */
342        if (conf.amap[CONF_NC_AXIS_STICK_X].action != -1) {
343                axis_value = mesg->stick_x;
344                if (conf.amap[CONF_NC_AXIS_STICK_X].flags & CONF_INVERT) {
345                        axis_value = 0xFF - axis_value;
346                }
347                send_event(&conf, conf.amap[CONF_NC_AXIS_STICK_X].axis_type,
348                           conf.amap[CONF_NC_AXIS_STICK_X].action, axis_value);
349        }
350
351        /* Nunchuk.Stick.Y */
352        if (conf.amap[CONF_NC_AXIS_STICK_Y].action != -1) {
353                axis_value = mesg->stick_y;
354                if (conf.amap[CONF_NC_AXIS_STICK_Y].flags & CONF_INVERT) {
355                        axis_value = 0xFF - axis_value;
356                }
357                send_event(&conf, conf.amap[CONF_NC_AXIS_STICK_Y].axis_type,
358                           conf.amap[CONF_NC_AXIS_STICK_Y].action, axis_value);
359        }
360}
361
362void process_classic_mesg(struct wiimote_classic_mesg *mesg)
363{
364        static unsigned short prev_buttons = 0;
365        unsigned short pressed, released;
366        int axis_value;
367        int i;
368
369        /* Classic Button/Key Events */
370        pressed = mesg->buttons & ~prev_buttons;
371        released = ~mesg->buttons & prev_buttons;
372        for (i=0; i < CONF_CC_BTN_COUNT; i++) {
373                if (pressed & conf.classic_bmap[i].mask) {
374                        send_event(&conf, EV_KEY, conf.classic_bmap[i].action, 1);
375                }
376                else if (released & conf.classic_bmap[i].mask) {
377                        send_event(&conf, EV_KEY, conf.classic_bmap[i].action, 0);
378                }
379        }
380        prev_buttons = mesg->buttons;
381
382        /* Classic.Dpad.X */
383        if (conf.amap[CONF_CC_AXIS_DPAD_X].action != -1) {
384                axis_value = 0;
385                if (mesg->buttons & WIIMOTE_CLASSIC_BTN_LEFT) {
386                        axis_value = -1;
387                }
388                else if (mesg->buttons & WIIMOTE_CLASSIC_BTN_RIGHT) {
389                        axis_value = 1;
390                }
391                if (conf.amap[CONF_CC_AXIS_DPAD_X].flags & CONF_INVERT) {
392                        axis_value *= -1;
393                }
394                send_event(&conf, conf.amap[CONF_CC_AXIS_DPAD_X].axis_type,
395                           conf.amap[CONF_CC_AXIS_DPAD_X].action, axis_value);
396        }
397
398        /* Classic.Dpad.Y */
399        if (conf.amap[CONF_CC_AXIS_DPAD_Y].action != -1) {
400                axis_value = 0;
401                if (mesg->buttons & WIIMOTE_CLASSIC_BTN_DOWN) {
402                        axis_value = -1;
403                }
404                else if (mesg->buttons & WIIMOTE_CLASSIC_BTN_UP) {
405                        axis_value = 1;
406                }
407                if (conf.amap[CONF_CC_AXIS_DPAD_Y].flags & CONF_INVERT) {
408                        axis_value *= -1;
409                }
410                send_event(&conf, conf.amap[CONF_CC_AXIS_DPAD_Y].axis_type,
411                           conf.amap[CONF_CC_AXIS_DPAD_Y].action, axis_value);
412        }
413
414        /* Classic.LStick.X */
415        if (conf.amap[CONF_CC_AXIS_L_STICK_X].action != -1) {
416                axis_value = mesg->l_stick_x;
417                if (conf.amap[CONF_CC_AXIS_L_STICK_X].flags & CONF_INVERT) {
418                        axis_value = WIIMOTE_CLASSIC_L_STICK_MAX - axis_value;
419                }
420                send_event(&conf, conf.amap[CONF_CC_AXIS_L_STICK_X].axis_type,
421                           conf.amap[CONF_CC_AXIS_L_STICK_X].action, axis_value);
422        }
423
424        /* Classic.LStick.Y */
425        if (conf.amap[CONF_CC_AXIS_L_STICK_Y].action != -1) {
426                axis_value = mesg->l_stick_y;
427                if (conf.amap[CONF_CC_AXIS_L_STICK_Y].flags & CONF_INVERT) {
428                        axis_value = WIIMOTE_CLASSIC_L_STICK_MAX - axis_value;
429                }
430                send_event(&conf, conf.amap[CONF_CC_AXIS_L_STICK_Y].axis_type,
431                           conf.amap[CONF_CC_AXIS_L_STICK_Y].action, axis_value);
432        }
433
434        /* Classic.RStick.X */
435        if (conf.amap[CONF_CC_AXIS_R_STICK_X].action != -1) {
436                axis_value = mesg->r_stick_x;
437                if (conf.amap[CONF_CC_AXIS_R_STICK_X].flags & CONF_INVERT) {
438                        axis_value = WIIMOTE_CLASSIC_R_STICK_MAX - axis_value;
439                }
440                send_event(&conf, conf.amap[CONF_CC_AXIS_R_STICK_X].axis_type,
441                           conf.amap[CONF_CC_AXIS_R_STICK_X].action, axis_value);
442        }
443
444        /* Classic.RStick.Y */
445        if (conf.amap[CONF_CC_AXIS_R_STICK_Y].action != -1) {
446                axis_value = mesg->r_stick_y;
447                if (conf.amap[CONF_CC_AXIS_R_STICK_Y].flags & CONF_INVERT) {
448                        axis_value = WIIMOTE_CLASSIC_R_STICK_MAX - axis_value;
449                }
450                send_event(&conf, conf.amap[CONF_CC_AXIS_R_STICK_Y].axis_type,
451                           conf.amap[CONF_CC_AXIS_R_STICK_Y].action, axis_value);
452        }
453
454        /* Classic.LAnalog */
455        if (conf.amap[CONF_CC_AXIS_L].action != -1) {
456                axis_value = mesg->l;
457                if (conf.amap[CONF_CC_AXIS_L].flags & CONF_INVERT) {
458                        axis_value = WIIMOTE_CLASSIC_LR_MAX - axis_value;
459                }
460                send_event(&conf, conf.amap[CONF_CC_AXIS_L].axis_type,
461                           conf.amap[CONF_CC_AXIS_L].action, axis_value);
462        }
463
464        /* Classic.RAnalog */
465        if (conf.amap[CONF_CC_AXIS_R].action != -1) {
466                axis_value = mesg->r;
467                if (conf.amap[CONF_CC_AXIS_R].flags & CONF_INVERT) {
468                        axis_value = WIIMOTE_CLASSIC_LR_MAX - axis_value;
469                }
470                send_event(&conf, conf.amap[CONF_CC_AXIS_R].axis_type,
471                           conf.amap[CONF_CC_AXIS_R].action, axis_value);
472        }
473}
474
475void process_plugin(struct plugin *plugin, int mesg_count,
476                    union wiimote_mesg *mesg[])
477{
478        union wiimote_mesg *plugin_mesg[WIIMOTE_MAX_MESG_COUNT];
479        int plugin_mesg_count = 0;
480        int i;
481        unsigned short flag;
482        struct wmplugin_data *data;
483        unsigned int pressed, released;
484        int axis_value;
485
486        for (i=0; i < mesg_count; i++) {
487                switch (mesg[i]->type) {
488                case WIIMOTE_MESG_STATUS:
489                        flag = WIIMOTE_RPT_STATUS;
490                        break;
491                case WIIMOTE_MESG_BTN:
492                        flag = WIIMOTE_RPT_BTN;
493                        break;
494                case WIIMOTE_MESG_ACC:
495                        flag = WIIMOTE_RPT_ACC;
496                        break;
497                case WIIMOTE_MESG_IR:
498                        flag = WIIMOTE_RPT_IR;
499                        break;
500                case WIIMOTE_MESG_NUNCHUK:
501                        flag = WIIMOTE_RPT_NUNCHUK;
502                        break;
503                case WIIMOTE_MESG_CLASSIC:
504                        flag = WIIMOTE_RPT_CLASSIC;
505                        break;
506                default:
507                        break;
508                }
509                if (plugin->rpt_mode_flags & flag) {
510                        plugin_mesg[plugin_mesg_count++] = mesg[i];
511                }
512        }
513
514        if (plugin_mesg_count > 0) {
515                if (!(data = (*plugin->exec)(plugin_mesg_count, plugin_mesg))) {
516                        return;
517                }
518
519                /* Plugin Button/Key Events */
520                pressed = data->buttons & ~plugin->prev_buttons;
521                released = ~data->buttons & plugin->prev_buttons;
522                for (i=0; i < plugin->info->button_count; i++) {
523                        if (pressed & 1<<i) {
524                                send_event(&conf, EV_KEY, plugin->bmap[i].action, 1);
525                        }
526                        else if (released & 1<<i) {
527                                send_event(&conf, EV_KEY, plugin->bmap[i].action, 0);
528                        }
529                }
530                plugin->prev_buttons = data->buttons;
531
532                /* Plugin Axis Events */
533                for (i=0; i < plugin->info->axis_count; i++) {
534                        if ((plugin->amap[i].action != -1) && data->axes &&
535                          data->axes[i].valid) {
536                                axis_value = data->axes[i].value;
537                                if (plugin->amap[i].flags & CONF_INVERT) {
538                                        axis_value = plugin->info->axis_info[i].max +
539                                                     plugin->info->axis_info[i].min - axis_value;
540                                }
541                                send_event(&conf, plugin->amap[i].axis_type,
542                                           plugin->amap[i].action, axis_value);
543                        }
544                }
545        }
546}
547
Note: See TracBrowser for help on using the browser.