1
// $Id: wiimote.cpp 3192 2007-09-20 03:06:10Z grumbel $
3
// Pingus - A free Lemmings clone
4
// Copyright (C) 2007 Ingo Ruhnke <grumbel@gmx.de>
6
// This program is free software; you can redistribute it and/or
7
// modify it under the terms of the GNU General Public License
8
// as published by the Free Software Foundation; either version 2
9
// of the License, or (at your option) any later version.
11
// This program is distributed in the hope that it will be useful,
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
// GNU General Public License for more details.
16
// You should have received a copy of the GNU General Public License
17
// along with this program; if not, write to the Free Software
18
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
#include "wiimote.hpp"
29
Wiimote::id2str(int id)
31
if (id == WIIMOTE_A) return "a";
32
else if (id == WIIMOTE_B) return "b";
33
else if (id == WIIMOTE_LEFT) return "left";
34
else if (id == WIIMOTE_RIGHT) return "right";
35
else if (id == WIIMOTE_UP) return "up";
36
else if (id == WIIMOTE_DOWN) return "down";
37
else if (id == WIIMOTE_PLUS) return "plus";
38
else if (id == WIIMOTE_MINUS) return "minus";
39
else if (id == WIIMOTE_HOME) return "home";
40
else if (id == WIIMOTE_1) return "1";
41
else if (id == WIIMOTE_2) return "2";
43
else if (id == NUNCHUK_C) return "nunchuk:c";
44
else if (id == NUNCHUK_Z) return "nunchuk:z";
46
else if (id == CLASSIC_LEFT) return "classic:left";
47
else if (id == CLASSIC_RIGHT) return "classic:right";
48
else if (id == CLASSIC_UP) return "classic:up";
49
else if (id == CLASSIC_DOWN) return "classic:down";
50
else if (id == CLASSIC_PLUS) return "classic:plus";
51
else if (id == CLASSIC_MINUS) return "classic:minus";
52
else if (id == CLASSIC_HOME) return "classic:home";
53
else if (id == CLASSIC_A) return "classic:a";
54
else if (id == CLASSIC_B) return "classic:b";
55
else if (id == CLASSIC_X) return "classic:x";
56
else if (id == CLASSIC_Y) return "classic:y";
57
else if (id == CLASSIC_L) return "classic:l";
58
else if (id == CLASSIC_R) return "classic:r";
59
else if (id == CLASSIC_ZL) return "classic:zl";
60
else if (id == CLASSIC_ZR) return "classic:zr";
66
Wiimote::str2id(const std::string& str)
68
if (str == "a") return WIIMOTE_A;
69
else if (str == "b") return WIIMOTE_B;
70
else if (str == "left") return WIIMOTE_LEFT;
71
else if (str == "right") return WIIMOTE_RIGHT;
72
else if (str == "up") return WIIMOTE_UP;
73
else if (str == "down") return WIIMOTE_DOWN;
74
else if (str == "plus" || str == "+") return WIIMOTE_PLUS;
75
else if (str == "minus" || str == "-") return WIIMOTE_MINUS;
76
else if (str == "home") return WIIMOTE_HOME;
77
else if (str == "1") return WIIMOTE_1;
78
else if (str == "2") return WIIMOTE_2;
80
else if (str == "nunchuk:c") return NUNCHUK_C;
81
else if (str == "nunchuk:z") return NUNCHUK_Z;
83
else if (str == "classic:left") return CLASSIC_LEFT;
84
else if (str == "classic:right") return CLASSIC_RIGHT;
85
else if (str == "classic:up") return CLASSIC_UP;
86
else if (str == "classic:down") return CLASSIC_DOWN;
87
else if (str == "classic:plus" || str == "classic:+") return CLASSIC_PLUS;
88
else if (str == "classic:minus" || str == "classic:-") return CLASSIC_MINUS;
89
else if (str == "classic:home") return CLASSIC_HOME;
90
else if (str == "classic:a") return CLASSIC_A;
91
else if (str == "classic:b") return CLASSIC_B;
92
else if (str == "classic:x") return CLASSIC_X;
93
else if (str == "classic:y") return CLASSIC_Y;
94
else if (str == "classic:l") return CLASSIC_L;
95
else if (str == "classic:r") return CLASSIC_R;
96
else if (str == "classic:zl") return CLASSIC_ZL;
97
else if (str == "classic:zr") return CLASSIC_ZR;
106
wiimote = new Wiimote();
121
m_nunchuk_stick_x(0),
122
m_nunchuk_stick_y(0),
125
pthread_mutex_init(&mutex, NULL);
127
assert(wiimote == 0);
130
cwiid_set_err(&Wiimote::err_callback);
136
pthread_mutex_destroy(&mutex);
142
assert(m_wiimote == 0);
144
/* Connect to any wiimote */
145
bdaddr_t bdaddr = *BDADDR_ANY;
147
/* Connect to address in string WIIMOTE_BDADDR */
148
/* str2ba(WIIMOTE_BDADDR, &bdaddr); */
150
/* Connect to the wiimote */
151
printf("Put Wiimote in discoverable mode now (press 1+2)...\n");
153
if (!(m_wiimote = cwiid_connect(&bdaddr, CWIID_FLAG_MESG_IFC)))
155
fprintf(stderr, "Unable to connect to wiimote\n");
159
std::cout << "Wiimote connected: " << m_wiimote << std::endl;
160
if (cwiid_set_mesg_callback(m_wiimote, &Wiimote::mesg_callback))
162
std::cerr << "Unable to set message callback" << std::endl;
165
// FIXME: Could init this depending on what events are actually bound
166
if (cwiid_command(m_wiimote, CWIID_CMD_RPT_MODE,
173
std::cerr << "Wiimote: Error setting report mode" << std::endl;
176
{ // read calibration data
179
if (cwiid_read(m_wiimote, CWIID_RW_EEPROM, 0x16, 7, buf))
181
std::cout << "Wiimote: Unable to retrieve accelerometer calibration" << std::endl;
185
wiimote_zero.x = buf[0];
186
wiimote_zero.y = buf[1];
187
wiimote_zero.z = buf[2];
189
wiimote_one.x = buf[4];
190
wiimote_one.y = buf[5];
191
wiimote_one.z = buf[6];
194
if (cwiid_read(m_wiimote, CWIID_RW_REG | CWIID_RW_DECODE, 0xA40020, 7, buf))
196
std::cout << "Wiimote: Unable to retrieve wiimote accelerometer calibration" << std::endl;
200
nunchuk_zero.x = buf[0];
201
nunchuk_zero.y = buf[1];
202
nunchuk_zero.z = buf[2];
204
nunchuk_one.x = buf[4];
205
nunchuk_one.y = buf[5];
206
nunchuk_one.z = buf[6];
209
std::cout << "Wiimote Calibration: "
210
<< (int)wiimote_zero.x << ", "
211
<< (int)wiimote_zero.x << ", "
212
<< (int)wiimote_zero.x << " - "
213
<< (int)wiimote_one.x << ", "
214
<< (int)wiimote_one.x << ", "
215
<< (int)wiimote_one.x << std::endl;
217
std::cout << "Nunchuk Calibration: "
218
<< (int)nunchuk_zero.x << ", "
219
<< (int)nunchuk_zero.x << ", "
220
<< (int)nunchuk_zero.x << " - "
221
<< (int)nunchuk_one.x << ", "
222
<< (int)nunchuk_one.x << ", "
223
<< (int)nunchuk_one.x << std::endl;
230
Wiimote::disconnect()
234
cwiid_disconnect(m_wiimote);
240
Wiimote::set_led(unsigned char led_state)
242
if (m_led_state != led_state)
244
//std::cout << "Wiimote: " << (int)m_led_state << std::endl;
245
m_led_state = led_state;
247
if (cwiid_command(m_wiimote, CWIID_CMD_LED, m_led_state)) {
248
fprintf(stderr, "Error setting LEDs \n");
254
Wiimote::set_led(int num, bool state)
256
assert(num >= 1 && num <= 4);
258
int new_led_state = m_led_state;
260
new_led_state |= (1 << (num-1));
262
new_led_state &= ~(1 << (num-1));
264
set_led(new_led_state);
268
Wiimote::set_rumble(bool r)
274
if (cwiid_command(m_wiimote, CWIID_CMD_RUMBLE, m_rumble)) {
275
std::cerr << "Error setting rumble" << std::endl;
281
Wiimote::add_button_event(int device, int button, bool down)
283
// std::cout << "Wiimote::add_button_event: " << device << " " << button << " " << down << std::endl;
286
event.type = WiimoteEvent::WIIMOTE_BUTTON_EVENT;
287
event.button.device = 0;
288
event.button.button = button;
289
event.button.down = down;
291
events.push_back(event);
295
Wiimote::add_axis_event(int device, int axis, float pos)
297
//std::cout << "Wiimote::add_axis_event: " << device << " " << axis << " " << pos << std::endl;
301
event.type = WiimoteEvent::WIIMOTE_AXIS_EVENT;
302
event.axis.device = 0;
303
event.axis.axis = axis;
304
event.axis.pos = pos;
306
events.push_back(event);
310
Wiimote::add_acc_event(int device, int accelerometer, float x, float y, float z)
314
event.type = WiimoteEvent::WIIMOTE_ACC_EVENT;
315
event.acc.device = 0;
316
event.acc.accelerometer = accelerometer;
321
events.push_back(event);
326
Wiimote::on_status(const cwiid_status_mesg& msg)
328
printf("Status Report: battery=%d extension=", msg.battery);
329
switch (msg.ext_type)
335
case CWIID_EXT_NUNCHUK:
339
case CWIID_EXT_CLASSIC:
340
printf("Classic Controller");
344
printf("Unknown Extension");
351
Wiimote::on_error(const cwiid_error_mesg& msg)
353
std::cout << "On Error" << std::endl;
357
if (cwiid_disconnect(m_wiimote))
359
fprintf(stderr, "Error on wiimote disconnect\n");
366
Wiimote::on_button(const cwiid_btn_mesg& msg)
368
#define CHECK_BTN(btn, num) if (changes & btn) add_button_event(0, num, m_buttons & btn)
370
uint16_t changes = m_buttons ^ msg.buttons;
371
m_buttons = msg.buttons;
373
CHECK_BTN(CWIID_BTN_A, WIIMOTE_A);
374
CHECK_BTN(CWIID_BTN_B, WIIMOTE_B);
376
CHECK_BTN(CWIID_BTN_LEFT, WIIMOTE_LEFT);
377
CHECK_BTN(CWIID_BTN_RIGHT, WIIMOTE_RIGHT);
378
CHECK_BTN(CWIID_BTN_UP, WIIMOTE_UP);
379
CHECK_BTN(CWIID_BTN_DOWN, WIIMOTE_DOWN);
381
CHECK_BTN(CWIID_BTN_PLUS, WIIMOTE_PLUS);
382
CHECK_BTN(CWIID_BTN_HOME, WIIMOTE_HOME);
383
CHECK_BTN(CWIID_BTN_MINUS, WIIMOTE_MINUS);
385
CHECK_BTN(CWIID_BTN_1, WIIMOTE_1);
386
CHECK_BTN(CWIID_BTN_2, WIIMOTE_2);
390
Wiimote::on_acc(const cwiid_acc_mesg& msg)
392
//printf("Acc Report: x=%d, y=%d, z=%d\n", msg.acc[0], msg.acc[1], msg.acc[2]);
395
(msg.acc[0] - wiimote_zero.x) / float(wiimote_one.x - wiimote_zero.x),
396
(msg.acc[1] - wiimote_zero.y) / float(wiimote_one.y - wiimote_zero.y),
397
(msg.acc[2] - wiimote_zero.z) / float(wiimote_one.z - wiimote_zero.z));
401
Wiimote::on_ir(const cwiid_ir_mesg& msg)
403
bool is_valid = false;
404
for (int i = 0; i < CWIID_IR_SRC_COUNT; ++i)
405
is_valid = is_valid || msg.src[i].valid;
409
std::cout << "IR Report: ";
410
for (int i = 0; i < CWIID_IR_SRC_COUNT; ++i)
412
if (msg.src[i].valid) {
413
std::cout << "(" << msg.src[i].pos[0] << ", " << msg.src[i].pos[1] << ") ";
416
std::cout << std::endl;
420
/** Convert value to float while taking calibration data, left/center/right into account */
421
inline float to_float(uint8_t min,
428
return Math::clamp(-1.0f, -(center - value) / float(center - min), 1.0f);
430
else if (value > center)
432
return Math::clamp(-1.0f, (value - center) / float(max - center), 1.0f);
441
Wiimote::on_nunchuk(const cwiid_nunchuk_mesg& msg)
443
uint8_t changes = m_nunchuk_btns ^ msg.buttons;
444
m_nunchuk_btns = msg.buttons;
446
#define CHECK_NCK_BTN(btn, num) if (changes & btn) add_button_event(0, num, m_nunchuk_btns & btn)
448
CHECK_NCK_BTN(CWIID_NUNCHUK_BTN_Z, NUNCHUK_Z);
449
CHECK_NCK_BTN(CWIID_NUNCHUK_BTN_C, NUNCHUK_C);
451
// FIXME: Read real calibration data, instead of hardcoded one
452
float nunchuk_stick_x = to_float(37, 129, 231, msg.stick[0]);
453
float nunchuk_stick_y = -to_float(22, 119, 213, msg.stick[1]);
455
if (m_nunchuk_stick_x != nunchuk_stick_x)
457
m_nunchuk_stick_x = nunchuk_stick_x;
458
add_axis_event(0, 0, m_nunchuk_stick_x);
461
if (m_nunchuk_stick_y != nunchuk_stick_y)
463
m_nunchuk_stick_y = nunchuk_stick_y;
464
add_axis_event(0, 1, m_nunchuk_stick_y);
468
(msg.acc[0] - nunchuk_zero.x) / float(nunchuk_one.x - nunchuk_zero.x),
469
(msg.acc[1] - nunchuk_zero.y) / float(nunchuk_one.y - nunchuk_zero.y),
470
(msg.acc[2] - nunchuk_zero.z) / float(nunchuk_one.z - nunchuk_zero.z));
472
printf("Nunchuk Report: btns=%.2X stick=(%3d,%3d) (%5.2f, %5.2f) acc.x=%d acc.y=%d acc.z=%d\n",
474
msg.stick[0], msg.stick[1],
477
msg.acc[0], msg.acc[1], msg.acc[2]);
481
Wiimote::on_classic(const cwiid_classic_mesg& msg)
483
printf("Classic Report: btns=%.4X l_stick=(%d,%d) r_stick=(%d,%d) "
484
"l=%d r=%d\n", msg.buttons,
485
msg.l_stick[0], msg.l_stick[1],
486
msg.r_stick[0], msg.r_stick[1],
490
std::vector<WiimoteEvent>
491
Wiimote::pop_events()
493
pthread_mutex_lock(&mutex);
494
std::vector<WiimoteEvent> ret = events;
496
pthread_mutex_unlock(&mutex);
500
// Callback function that get called by the Wiimote thread
502
Wiimote::err(cwiid_wiimote_t* w, const char *s, va_list ap)
504
pthread_mutex_lock(&mutex);
507
printf("%d:", cwiid_get_id(w));
514
pthread_mutex_unlock(&mutex);
518
Wiimote::mesg(cwiid_wiimote_t* w, int mesg_count, union cwiid_mesg mesg[])
520
pthread_mutex_lock(&mutex);
522
//std::cout << "StatusCallback: " << w << " " << mesg_count << std::endl;
523
for (int i=0; i < mesg_count; i++)
525
switch (mesg[i].type)
527
case CWIID_MESG_STATUS:
528
wiimote->on_status(mesg[i].status_mesg);
532
wiimote->on_button(mesg[i].btn_mesg);
536
wiimote->on_acc(mesg[i].acc_mesg);
540
wiimote->on_ir(mesg[i].ir_mesg);
543
case CWIID_MESG_NUNCHUK:
544
wiimote->on_nunchuk(mesg[i].nunchuk_mesg);
547
case CWIID_MESG_CLASSIC:
548
wiimote->on_classic(mesg[i].classic_mesg);
551
case CWIID_MESG_ERROR:
552
wiimote->on_error(mesg[i].error_mesg);
556
printf("Wiimote: Unknown Report");
561
pthread_mutex_unlock(&mutex);
564
// static callback functions
567
Wiimote::err_callback(cwiid_wiimote_t* w, const char *s, va_list ap)
569
wiimote->err(w, s, ap);
573
Wiimote::mesg_callback(cwiid_wiimote_t* w, int mesg_count, union cwiid_mesg mesg[], timespec*)
575
wiimote->mesg(w, mesg_count, mesg);