root/wmdemo/wmserverdemo.c

Revision 1a6f4671cbdc7bd54db8046818012c5e3a20264b, 12.1 kB (checked in by L. Donnie Smith <donnie.smith@…>, 2 years ago)

Basic support for cwiid_listen

  • Property mode set to 100644
Line 
1#include <stdarg.h>
2#include <stdio.h>
3#include <stdlib.h>
4
5#include <bluetooth/bluetooth.h>
6#include <cwiid.h>
7
8/* This is a sample program written to demonstrate basic CWiid libwiimote
9 * usage, until _actual_ documentation can be written.  It's quick and dirty
10 * has a horrible interface, but it's sparce enough to pick out the important
11 * parts easily.  For examples of read and write code, see wmgui.  Speaker
12 * support is "experimental" (read: bad) enough to be disabled.  The beginnings
13 * of a speaker output function are in libwiimote source. */
14/* Note: accelerometer (including nunchuk) and IR outputs produce a
15 * lot of data - the purpose of this program is demonstration, not good
16 * interface, and it shows. */
17
18cwiid_mesg_callback_t cwiid_callback;
19
20#define toggle_bit(bf,b)        \
21        (bf) = ((bf) & b)               \
22               ? ((bf) & ~(b))  \
23               : ((bf) | (b))
24
25#define MENU \
26        "1: toggle LED 1\n" \
27        "2: toggle LED 2\n" \
28        "3: toggle LED 3\n" \
29        "4: toggle LED 4\n" \
30        "5: toggle rumble\n" \
31        "a: toggle accelerometer reporting\n" \
32        "b: toggle button reporting\n" \
33        "c: enable motionplus, if connected\n" \
34        "e: toggle extension reporting\n" \
35        "i: toggle ir reporting\n" \
36        "m: toggle messages\n" \
37        "p: print this menu\n" \
38        "r: request status message ((t) enables callback output)\n" \
39        "s: print current state\n" \
40        "t: toggle status reporting\n" \
41        "x: exit\n"
42
43void set_led_state(cwiid_wiimote_t *wiimote, unsigned char led_state);
44void set_rpt_mode(cwiid_wiimote_t *wiimote, unsigned char rpt_mode);
45void print_state(struct cwiid_state *state);
46
47cwiid_err_t err;
48void err(cwiid_wiimote_t *wiimote, const char *s, va_list ap)
49{
50        if (wiimote) printf("%d:", cwiid_get_id(wiimote));
51        else printf("-1:");
52        vprintf(s, ap);
53        printf("\n");
54}
55
56int main(int argc, char *argv[])
57{
58        cwiid_wiimote_t *wiimote;       /* wiimote handle */
59        struct cwiid_state state;       /* wiimote state */
60        bdaddr_t bdaddr;        /* bluetooth device address */
61        unsigned char mesg = 0;
62        unsigned char led_state = 0;
63        unsigned char rpt_mode = 0;
64        unsigned char rumble = 0;
65        int exit = 0;
66
67        cwiid_set_err(err);
68
69        /* Connect to address given on command-line, if present */
70        if (argc > 1) {
71                str2ba(argv[1], &bdaddr);
72        }
73        else {
74                bdaddr = *BDADDR_ANY;
75        }
76
77        /* Connect to the wiimote */
78        printf("Press any button on a synced wiimote to connect\n");
79        if (!(wiimote = cwiid_listen(0))) {
80                fprintf(stderr, "Unable to connect to wiimote\n");
81                return -1;
82        }
83        if (cwiid_set_mesg_callback(wiimote, cwiid_callback)) {
84                fprintf(stderr, "Unable to set message callback\n");
85        }
86
87        printf("Note: To demonstrate the new API interfaces, wmdemo no longer "
88               "enables messages by default.\n"
89               "Output can be gathered through the new state-based interface (s), "
90               "or by enabling the messages interface (m).\n");
91
92        /* Menu */
93        printf("%s", MENU);
94
95        while (!exit) {
96                switch (getchar()) {
97                case '1':
98                        toggle_bit(led_state, CWIID_LED1_ON);
99                        set_led_state(wiimote, led_state);
100                        break;
101                case '2':
102                        toggle_bit(led_state, CWIID_LED2_ON);
103                        set_led_state(wiimote, led_state);
104                        break;
105                case '3':
106                        toggle_bit(led_state, CWIID_LED3_ON);
107                        set_led_state(wiimote, led_state);
108                        break;
109                case '4':
110                        toggle_bit(led_state, CWIID_LED4_ON);
111                        set_led_state(wiimote, led_state);
112                        break;
113                case '5':
114                        toggle_bit(rumble, 1);
115                        if (cwiid_set_rumble(wiimote, rumble)) {
116                                fprintf(stderr, "Error setting rumble\n");
117                        }
118                        break;
119                case 'a':
120                        toggle_bit(rpt_mode, CWIID_RPT_ACC);
121                        set_rpt_mode(wiimote, rpt_mode);
122                        break;
123                case 'b':
124                        toggle_bit(rpt_mode, CWIID_RPT_BTN);
125                        set_rpt_mode(wiimote, rpt_mode);
126                        break;
127                case 'c':
128                        cwiid_enable(wiimote, CWIID_FLAG_MOTIONPLUS);
129                        break;
130                case 'e':
131                        /* CWIID_RPT_EXT is actually
132                         * CWIID_RPT_NUNCHUK | CWIID_RPT_CLASSIC | CWIID_RPT_BALANCE */
133                        toggle_bit(rpt_mode, CWIID_RPT_EXT);
134                        set_rpt_mode(wiimote, rpt_mode);
135                        break;
136                case 'i':
137                        /* libwiimote picks the highest quality IR mode available with the
138                         * other options selected (not including as-yet-undeciphered
139                         * interleaved mode */
140                        toggle_bit(rpt_mode, CWIID_RPT_IR);
141                        set_rpt_mode(wiimote, rpt_mode);
142                        break;
143                case 'm':
144                        if (!mesg) {
145                                if (cwiid_enable(wiimote, CWIID_FLAG_MESG_IFC)) {
146                                        fprintf(stderr, "Error enabling messages\n");
147                                }
148                                else {
149                                        mesg = 1;
150                                }
151                        }
152                        else {
153                                if (cwiid_disable(wiimote, CWIID_FLAG_MESG_IFC)) {
154                                        fprintf(stderr, "Error disabling message\n");
155                                }
156                                else {
157                                        mesg = 0;
158                                }
159                        }
160                        break;
161                case 'p':
162                        printf("%s", MENU);
163                        break;
164                case 'r':
165                        if (cwiid_request_status(wiimote)) {
166                                fprintf(stderr, "Error requesting status message\n");
167                        }
168                        break;
169                case 's':
170                        if (cwiid_get_state(wiimote, &state)) {
171                                fprintf(stderr, "Error getting state\n");
172                        }
173                        print_state(&state);
174                        break;
175                case 't':
176                        toggle_bit(rpt_mode, CWIID_RPT_STATUS);
177                        set_rpt_mode(wiimote, rpt_mode);
178                        break;
179                case 'x':
180                        exit = -1;
181                        break;
182                case '\n':
183                        break;
184                default:
185                        fprintf(stderr, "invalid option\n");
186                }
187        }
188
189        if (cwiid_close(wiimote)) {
190                fprintf(stderr, "Error on wiimote disconnect\n");
191                return -1;
192        }
193
194        return 0;
195}
196
197void set_led_state(cwiid_wiimote_t *wiimote, unsigned char led_state)
198{
199        if (cwiid_set_led(wiimote, led_state)) {
200                fprintf(stderr, "Error setting LEDs \n");
201        }
202}
203       
204void set_rpt_mode(cwiid_wiimote_t *wiimote, unsigned char rpt_mode)
205{
206        if (cwiid_set_rpt_mode(wiimote, rpt_mode)) {
207                fprintf(stderr, "Error setting report mode\n");
208        }
209}
210
211void print_state(struct cwiid_state *state)
212{
213        int i;
214        int valid_source = 0;
215
216        printf("Report Mode:");
217        if (state->rpt_mode & CWIID_RPT_STATUS) printf(" STATUS");
218        if (state->rpt_mode & CWIID_RPT_BTN) printf(" BTN");
219        if (state->rpt_mode & CWIID_RPT_ACC) printf(" ACC");
220        if (state->rpt_mode & CWIID_RPT_IR) printf(" IR");
221        if (state->rpt_mode & CWIID_RPT_NUNCHUK) printf(" NUNCHUK");
222        if (state->rpt_mode & CWIID_RPT_CLASSIC) printf(" CLASSIC");
223        if (state->rpt_mode & CWIID_RPT_BALANCE) printf(" BALANCE");
224        if (state->rpt_mode & CWIID_RPT_MOTIONPLUS) printf(" MOTIONPLUS");
225        printf("\n");
226       
227        printf("Active LEDs:");
228        if (state->led & CWIID_LED1_ON) printf(" 1");
229        if (state->led & CWIID_LED2_ON) printf(" 2");
230        if (state->led & CWIID_LED3_ON) printf(" 3");
231        if (state->led & CWIID_LED4_ON) printf(" 4");
232        printf("\n");
233
234        printf("Rumble: %s\n", state->rumble ? "On" : "Off");
235
236        printf("Battery: %d%%\n",
237               (int)(100.0 * state->battery / CWIID_BATTERY_MAX));
238
239        printf("Buttons: %X\n", state->buttons);
240
241        printf("Acc: x=%d y=%d z=%d\n", state->acc[CWIID_X], state->acc[CWIID_Y],
242               state->acc[CWIID_Z]);
243
244        printf("IR: ");
245        for (i = 0; i < CWIID_IR_SRC_COUNT; i++) {
246                if (state->ir_src[i].valid) {
247                        valid_source = 1;
248                        printf("(%d,%d) ", state->ir_src[i].pos[CWIID_X],
249                                           state->ir_src[i].pos[CWIID_Y]);
250                }
251        }
252        if (!valid_source) {
253                printf("no sources detected");
254        }
255        printf("\n");
256
257        switch (state->ext_type) {
258        case CWIID_EXT_NONE:
259                printf("No extension\n");
260                break;
261        case CWIID_EXT_UNKNOWN:
262                printf("Unknown extension attached\n");
263                break;
264        case CWIID_EXT_NUNCHUK:
265                printf("Nunchuk: btns=%.2X stick=(%d,%d) acc.x=%d acc.y=%d "
266                       "acc.z=%d\n", state->ext.nunchuk.buttons,
267                       state->ext.nunchuk.stick[CWIID_X],
268                       state->ext.nunchuk.stick[CWIID_Y],
269                       state->ext.nunchuk.acc[CWIID_X],
270                       state->ext.nunchuk.acc[CWIID_Y],
271                       state->ext.nunchuk.acc[CWIID_Z]);
272                break;
273        case CWIID_EXT_CLASSIC:
274                printf("Classic: btns=%.4X l_stick=(%d,%d) r_stick=(%d,%d) "
275                       "l=%d r=%d\n", state->ext.classic.buttons,
276                       state->ext.classic.l_stick[CWIID_X],
277                       state->ext.classic.l_stick[CWIID_Y],
278                       state->ext.classic.r_stick[CWIID_X],
279                       state->ext.classic.r_stick[CWIID_Y],
280                       state->ext.classic.l, state->ext.classic.r);
281                break;
282        case CWIID_EXT_BALANCE:
283                printf("Balance: right_top=%d right_bottom=%d "
284                       "left_top=%d left_bottom=%d\n",
285                       state->ext.balance.right_top,
286                       state->ext.balance.right_bottom,
287                       state->ext.balance.left_top,
288                       state->ext.balance.left_bottom);
289                break;
290        case CWIID_EXT_MOTIONPLUS:
291                printf("MotionPlus: angle_rate=(%d,%d,%d) low_speed=(%d,%d,%d)\n",
292                       state->ext.motionplus.angle_rate[0],
293                       state->ext.motionplus.angle_rate[1],
294                       state->ext.motionplus.angle_rate[2],
295                       state->ext.motionplus.low_speed[0],
296                       state->ext.motionplus.low_speed[1],
297                       state->ext.motionplus.low_speed[2]);
298                break;
299        }
300}
301
302/* Prototype cwiid_callback with cwiid_callback_t, define it with the actual
303 * type - this will cause a compile error (rather than some undefined bizarre
304 * behavior) if cwiid_callback_t changes */
305/* cwiid_mesg_callback_t has undergone a few changes lately, hopefully this
306 * will be the last.  Some programs need to know which messages were received
307 * simultaneously (e.g. for correlating accelerometer and IR data), and the
308 * sequence number mechanism used previously proved cumbersome, so we just
309 * pass an array of messages, all of which were received at the same time.
310 * The id is to distinguish between multiple wiimotes using the same callback.
311 * */
312void cwiid_callback(cwiid_wiimote_t *wiimote, int mesg_count,
313                    union cwiid_mesg mesg[], struct timespec *timestamp)
314{
315        int i, j;
316        int valid_source;
317
318        for (i=0; i < mesg_count; i++)
319        {
320                switch (mesg[i].type) {
321                case CWIID_MESG_STATUS:
322                        printf("Status Report: battery=%d extension=",
323                               mesg[i].status_mesg.battery);
324                        switch (mesg[i].status_mesg.ext_type) {
325                        case CWIID_EXT_NONE:
326                                printf("none");
327                                break;
328                        case CWIID_EXT_NUNCHUK:
329                                printf("Nunchuk");
330                                break;
331                        case CWIID_EXT_CLASSIC:
332                                printf("Classic Controller");
333                                break;
334                        case CWIID_EXT_BALANCE:
335                                printf("Balance Board");
336                                break;
337                        case CWIID_EXT_MOTIONPLUS:
338                                printf("MotionPlus");
339                                break;
340                        default:
341                                printf("Unknown Extension");
342                                break;
343                        }
344                        printf("\n");
345                        break;
346                case CWIID_MESG_BTN:
347                        printf("Button Report: %.4X\n", mesg[i].btn_mesg.buttons);
348                        break;
349                case CWIID_MESG_ACC:
350                        printf("Acc Report: x=%d, y=%d, z=%d\n",
351                   mesg[i].acc_mesg.acc[CWIID_X],
352                               mesg[i].acc_mesg.acc[CWIID_Y],
353                               mesg[i].acc_mesg.acc[CWIID_Z]);
354                        break;
355                case CWIID_MESG_IR:
356                        printf("IR Report: ");
357                        valid_source = 0;
358                        for (j = 0; j < CWIID_IR_SRC_COUNT; j++) {
359                                if (mesg[i].ir_mesg.src[j].valid) {
360                                        valid_source = 1;
361                                        printf("(%d,%d) ", mesg[i].ir_mesg.src[j].pos[CWIID_X],
362                                                           mesg[i].ir_mesg.src[j].pos[CWIID_Y]);
363                                }
364                        }
365                        if (!valid_source) {
366                                printf("no sources detected");
367                        }
368                        printf("\n");
369                        break;
370                case CWIID_MESG_NUNCHUK:
371                        printf("Nunchuk Report: btns=%.2X stick=(%d,%d) acc.x=%d acc.y=%d "
372                               "acc.z=%d\n", mesg[i].nunchuk_mesg.buttons,
373                               mesg[i].nunchuk_mesg.stick[CWIID_X],
374                               mesg[i].nunchuk_mesg.stick[CWIID_Y],
375                               mesg[i].nunchuk_mesg.acc[CWIID_X],
376                               mesg[i].nunchuk_mesg.acc[CWIID_Y],
377                               mesg[i].nunchuk_mesg.acc[CWIID_Z]);
378                        break;
379                case CWIID_MESG_CLASSIC:
380                        printf("Classic Report: btns=%.4X l_stick=(%d,%d) r_stick=(%d,%d) "
381                               "l=%d r=%d\n", mesg[i].classic_mesg.buttons,
382                               mesg[i].classic_mesg.l_stick[CWIID_X],
383                               mesg[i].classic_mesg.l_stick[CWIID_Y],
384                               mesg[i].classic_mesg.r_stick[CWIID_X],
385                               mesg[i].classic_mesg.r_stick[CWIID_Y],
386                               mesg[i].classic_mesg.l, mesg[i].classic_mesg.r);
387                        break;
388                case CWIID_MESG_BALANCE:
389                        printf("Balance Report: right_top=%d right_bottom=%d "
390                               "left_top=%d left_bottom=%d\n",
391                               mesg[i].balance_mesg.right_top,
392                               mesg[i].balance_mesg.right_bottom,
393                               mesg[i].balance_mesg.left_top,
394                               mesg[i].balance_mesg.left_bottom);
395                        break;
396                case CWIID_MESG_MOTIONPLUS:
397                        printf("MotionPlus Report: angle_rate=(%d,%d,%d) low_speed=(%d,%d,%d)\n",
398                               mesg[i].motionplus_mesg.angle_rate[0],
399                               mesg[i].motionplus_mesg.angle_rate[1],
400                               mesg[i].motionplus_mesg.angle_rate[2],
401                               mesg[i].motionplus_mesg.low_speed[0],
402                               mesg[i].motionplus_mesg.low_speed[1],
403                               mesg[i].motionplus_mesg.low_speed[2]);
404                        break;
405                case CWIID_MESG_ERROR:
406                        if (cwiid_close(wiimote)) {
407                                fprintf(stderr, "Error on wiimote disconnect\n");
408                                exit(-1);
409                        }
410                        exit(0);
411                        break;
412                default:
413                        printf("Unknown Report");
414                        break;
415                }
416        }
417}
Note: See TracBrowser for help on using the browser.