root/branches/dev/wmdemo/wmdemo.c

Revision 116, 10.3 kB (checked in by dsmith, 2 years ago)

deprecated cwiid_{connect,disconnect,command}, added cwiid_{open,close,request_status,set_led,set_rumble,set_rpt_mode}

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