| 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 |
} |
|---|