00001
00015 #include "WiiJoystick.h"
00016 #include "MovingAverage.h"
00017 #include "Angle.h"
00018 #include "MathUtils.h"
00019 #include <cwiid.h>
00020 #include <string>
00021 #include <map>
00022
00023
00024 using namespace qrk;
00025 using namespace std;
00026
00027
00028 namespace
00029 {
00030 bdaddr_t initializeBdaddr(void)
00031 {
00032 bdaddr_t addr;
00033 memset(&addr.b[0], 0, 6);
00034
00035 return addr;
00036 }
00037 }
00038
00039
00040 struct WiiJoystick::pImpl
00041 {
00042 class CallbackHandler
00043 {
00044 public:
00046 class WiiInformation {
00047 enum { Buttons = 7, };
00048
00049 public:
00050 bool quit_;
00051 int battery_percent_;
00052
00053 size_t buttons_timestamp_;
00054 short axis_[2];
00055 bool pressed_[Buttons];
00056 int pressed_times_[Buttons];
00057
00058 struct acc_cal calibration_;
00059 Point3d<double> acceleration_;
00060 Point3d<long> rotation_calibration_;
00061 Point3d<double> rotation_;
00062 size_t acceleration_timestamp_;
00063
00064 MovingAverage<double>* average_x_;
00065 MovingAverage<double>* average_y_;
00066 MovingAverage<double>* average_z_;
00067
00068 size_t acceleration_capture_times_;
00069 size_t rotation_capture_times_;
00070
00071 vector<ir_position> ir_positions_;
00072
00073
00074 WiiInformation(void)
00075 : quit_(false), battery_percent_(0),
00076 buttons_timestamp_(0), acceleration_timestamp_(0),
00077 average_x_(new MovingAverage<double>(1)),
00078 average_y_(new MovingAverage<double>(1)),
00079 average_z_(new MovingAverage<double>(1)),
00080 acceleration_capture_times_(0), rotation_capture_times_(0)
00081 {
00082
00083 axis_[AxisX] = 0;
00084 axis_[AxisY] = 0;
00085
00086 for (int i = 0; i < Buttons; ++i) {
00087 pressed_[i] = false;
00088 pressed_times_[i] = 0;
00089 }
00090
00091
00092
00093
00094
00095 }
00096 };
00097 typedef map<const cwiid_wiimote_t*, WiiInformation*> WiiHash;
00098 static WiiHash wii_hash_;
00099
00100
00101 CallbackHandler(void)
00102 {
00103 }
00104
00105
00106 ~CallbackHandler(void) {
00107 }
00108
00109
00110 static CallbackHandler* getObject(void)
00111 {
00112 static CallbackHandler singleton;
00113 return &singleton;
00114 }
00115
00116
00117 void registerObject(const cwiid_wiimote_t* wii)
00118 {
00119 WiiInformation* wii_information = new WiiInformation;
00120 wii_hash_.insert(WiiHash::value_type(wii, wii_information));
00121 }
00122
00123
00124 void removeObject(const cwiid_wiimote_t* wii)
00125 {
00126 delete wii_hash_[wii];
00127 wii_hash_.erase(wii);
00128 }
00129
00130
00131 void setCalibrationValue(const cwiid_wiimote_t* wii,
00132 struct acc_cal* calibration)
00133 {
00134 wii_hash_[wii]->calibration_ = *calibration;
00135 }
00136
00137
00138 bool haveQuitEvent(const cwiid_wiimote_t* wii)
00139 {
00140 return wii_hash_[wii];
00141 }
00142
00143
00144 static void recordPressed(cwiid_btn_mesg* mesg, WiiInformation* state,
00145 const struct timespec* timestamp)
00146 {
00147 (void)timestamp;
00148
00149 uint16_t buttons = mesg->buttons;
00150
00151
00152 state->axis_[AxisX] =
00153 ((buttons & CWIID_BTN_LEFT) ? -32767 : 0) +
00154 ((buttons & CWIID_BTN_RIGHT) ? +32767 : 0);
00155
00156 state->axis_[AxisY] =
00157 ((buttons & CWIID_BTN_UP) ? +32767 : 0) +
00158 ((buttons & CWIID_BTN_DOWN) ? -32767 : 0);
00159
00160
00161 state->pressed_[BUTTON_A] = (buttons & CWIID_BTN_A) ? true : false;
00162 state->pressed_[BUTTON_B] = (buttons & CWIID_BTN_B) ? true : false;
00163 state->pressed_[BUTTON_MINUS] =
00164 (buttons & CWIID_BTN_MINUS) ? true : false;
00165 state->pressed_[BUTTON_PLUS] = (buttons & CWIID_BTN_PLUS) ? true : false;
00166 state->pressed_[BUTTON_HOME] = (buttons & CWIID_BTN_HOME) ? true : false;
00167 state->pressed_[BUTTON_1] = (buttons & CWIID_BTN_1) ? true : false;
00168 state->pressed_[BUTTON_2] = (buttons & CWIID_BTN_2) ? true : false;
00169
00170
00171
00172 }
00173
00174
00175 static void recordAcceleration(struct cwiid_acc_mesg* mesg,
00176 WiiInformation* state,
00177 const struct timespec* timestamp)
00178 {
00179 (void)timestamp;
00180
00181 ++state->acceleration_capture_times_;
00182 if (state->acceleration_capture_times_ < 4) {
00183
00184 return;
00185 }
00186
00187 uint8_t* acc = mesg->acc;
00188 struct acc_cal& calibration = state->calibration_;
00189
00190 double x = ((double)acc[CWIID_X] - calibration.zero[CWIID_X]) /
00191 (calibration.one[CWIID_X] - calibration.zero[CWIID_X]);
00192 double y = ((double)acc[CWIID_Y] - calibration.zero[CWIID_Y]) /
00193 (calibration.one[CWIID_Y] - calibration.zero[CWIID_Y]);
00194 double z = ((double)acc[CWIID_Z] - calibration.zero[CWIID_Z]) /
00195 (calibration.one[CWIID_Z] - calibration.zero[CWIID_Z]);
00196
00197 state->acceleration_.x = state->average_x_->push_back(x);
00198 state->acceleration_.y = state->average_y_->push_back(y);
00199 state->acceleration_.z = state->average_z_->push_back(z);
00200 }
00201
00202
00203 static void recordRotation(const uint16_t angle_rate[],
00204 WiiInformation* state,
00205 const struct timespec* timestamp)
00206 {
00207 (void)timestamp;
00208
00209
00210 enum {
00211 IgnoreTimes = 8,
00212 AverageTimes = 16
00213 };
00214
00215 ++state->rotation_capture_times_;
00216 if (state->rotation_capture_times_ < IgnoreTimes) {
00217
00218 return;
00219
00220 } else if (state->rotation_capture_times_ < (AverageTimes +
00221 IgnoreTimes)) {
00222 state->rotation_calibration_.x += angle_rate[0];
00223 state->rotation_calibration_.y += angle_rate[1];
00224 state->rotation_calibration_.z += angle_rate[2];
00225 return;
00226
00227 } else if (state->rotation_capture_times_ == (AverageTimes +
00228 IgnoreTimes)) {
00229 state->rotation_calibration_.x /= AverageTimes;
00230 state->rotation_calibration_.y /= AverageTimes;
00231 state->rotation_calibration_.z /= AverageTimes;
00232 }
00233
00234 state->rotation_.x += angle_rate[0] - state->rotation_calibration_.x;
00235 state->rotation_.y += angle_rate[1] - state->rotation_calibration_.y;
00236 state->rotation_.z += angle_rate[2] - state->rotation_calibration_.z;
00237 }
00238
00239
00240 static void recordIrPosition(struct cwiid_ir_mesg* ir_data,
00241 WiiInformation* state,
00242 const struct timespec* timestamp)
00243 {
00244 (void)timestamp;
00245
00246 state->ir_positions_.clear();
00247 for (int i = 0; i < CWIID_IR_SRC_COUNT; ++i) {
00248 ir_position each_position;
00249
00250 if (ir_data->src[i].valid) {
00251 if (ir_data->src[i].size == -1) {
00252 each_position.size = 3;
00253 } else {
00254 each_position.size = ir_data->src[i].size + 1;
00255 }
00256
00257
00258 each_position.position =
00259 Point<double>(1.0 * ir_data->src[i].pos[CWIID_X] / CWIID_IR_X_MAX,
00260 1.0 * ir_data->src[i].pos[CWIID_Y] / CWIID_IR_Y_MAX);
00261 state->ir_positions_.push_back(each_position);
00262 }
00263 }
00264 }
00265
00266
00267 static void callback(cwiid_wiimote_t* wii, int mesg_count,
00268 union cwiid_mesg mesg_array[],
00269 struct timespec *timestamp)
00270 {
00271 WiiInformation* state = wii_hash_[wii];
00272
00273 for (int i = 0; i < mesg_count; ++i) {
00274
00275 switch (mesg_array[i].type) {
00276 case CWIID_MESG_STATUS:
00277 wii_hash_[wii]->battery_percent_ =
00278 static_cast<int>((100.0 * mesg_array[i].status_mesg.battery
00279 / CWIID_BATTERY_MAX));
00280
00281 break;
00282
00283 case CWIID_MESG_BTN:
00284
00285 recordPressed(&mesg_array[i].btn_mesg, state, timestamp);
00286 break;
00287
00288 case CWIID_MESG_ACC:
00289
00290 recordAcceleration(&mesg_array[i].acc_mesg, state, timestamp);
00291 break;
00292
00293 case CWIID_MESG_IR:
00294
00295 recordIrPosition(&mesg_array[i].ir_mesg, state, timestamp);
00296 break;
00297
00298 #if defined(CWIID_RPT_MOTIONPLUS)
00299 case CWIID_MESG_MOTIONPLUS:
00300
00301 recordRotation(mesg_array[i].motionplus_mesg.angle_rate,
00302 state, timestamp);
00303 break;
00304 #endif
00305
00306 case CWIID_MESG_ERROR:
00307 wii_hash_[wii]->quit_ = true;
00308 break;
00309
00310 default:
00311 break;
00312 }
00313 }
00314 }
00315
00316
00317 static int getAxisValue(size_t index, const cwiid_wiimote_t* wii)
00318 {
00319 return wii_hash_[wii]->axis_[index];
00320 }
00321
00322
00323 static bool isButtonPressed(size_t index, const cwiid_wiimote_t* wii)
00324 {
00325 return wii_hash_[wii]->pressed_[index];
00326 }
00327
00328
00329 static int getBatteryPercent(const cwiid_wiimote_t* wii)
00330 {
00331 return wii_hash_[wii]->battery_percent_;
00332 }
00333
00334
00335 static void getAcceleration(Point3d<double>& acceleration,
00336 size_t* timestamp,
00337 const cwiid_wiimote_t* wii)
00338 {
00339
00340 (void)timestamp;
00341
00342 acceleration = wii_hash_[wii]->acceleration_;
00343 }
00344
00345
00346 static void getRotation(Angle& x_axis, Angle& y_axis, Angle& z_axis,
00347 size_t* timestamp, const cwiid_wiimote_t* wii)
00348 {
00349
00350 (void)timestamp;
00351
00352 x_axis = rad(2.0 * M_PI * wii_hash_[wii]->rotation_.x / 8192.0 / 100.0);
00353 y_axis = rad(2.0 * M_PI * wii_hash_[wii]->rotation_.y / 8192.0 / 100.0);
00354 z_axis = rad(2.0 * M_PI * wii_hash_[wii]->rotation_.z / 8192.0 / 100.0);
00355 }
00356
00357
00358 bool setLed(unsigned char led_value, cwiid_wiimote_t* wii)
00359 {
00360 uint8_t led_state =
00361 ((led_value & 0x08) ? CWIID_LED1_ON : 0) |
00362 ((led_value & 0x04) ? CWIID_LED2_ON : 0) |
00363 ((led_value & 0x02) ? CWIID_LED3_ON : 0) |
00364 ((led_value & 0x01) ? CWIID_LED4_ON : 0);
00365
00366 return (cwiid_set_led(wii, led_state)) ? false : true;
00367 }
00368
00369
00370
00371 bool setRumble(bool rumble, cwiid_wiimote_t* wii)
00372 {
00373 return (cwiid_set_rumble(wii, rumble ? 1 : 0)) ? false : true;
00374 }
00375
00376
00377 void setAccelerationAverageSize(size_t num, const cwiid_wiimote_t* wii)
00378 {
00379 if (num <= 0) {
00380
00381 return;
00382 }
00383
00384
00385 delete wii_hash_[wii]->average_x_;
00386 delete wii_hash_[wii]->average_y_;
00387 delete wii_hash_[wii]->average_z_;
00388
00389 wii_hash_[wii]->average_x_ = new MovingAverage<double>(num);
00390 wii_hash_[wii]->average_y_ = new MovingAverage<double>(num);
00391 wii_hash_[wii]->average_z_ = new MovingAverage<double>(num);
00392 }
00393 };
00394
00395
00396 static bdaddr_t bdaddr_any_;
00397
00398 string error_message_;
00399 cwiid_wiimote_t* wii_;
00400 bdaddr_t bdaddr_;
00401 CallbackHandler* callback_;
00402 struct acc_cal calibration_;
00403
00404
00405 pImpl(void)
00406 : error_message_("no error."), wii_(NULL), bdaddr_(bdaddr_any_),
00407 callback_(CallbackHandler::getObject())
00408 {
00409 }
00410
00411
00412 ~pImpl(void)
00413 {
00414 disconnect();
00415 }
00416
00417
00418 bool isError(cwiid_wiimote_t* wii)
00419 {
00420 return (callback_->haveQuitEvent(wii)) ? true : false;
00421 }
00422
00423
00424 bool connect(void)
00425 {
00426 if (isConnected()) {
00427 return true;
00428 }
00429 disconnect();
00430
00431
00432 wii_ = cwiid_open(&bdaddr_, CWIID_FLAG_MESG_IFC);
00433 if (wii_ == NULL) {
00434 error_message_ = "unable to connect.";
00435 return false;
00436 }
00437 setRepeatMode();
00438
00439
00440 callback_->registerObject(wii_);
00441 if (cwiid_set_mesg_callback(wii_, &CallbackHandler::callback)) {
00442 disconnect();
00443 error_message_ = "error setting callback";
00444 return false;
00445 }
00446
00447
00448 if (cwiid_get_acc_cal(wii_, CWIID_EXT_NONE, &calibration_)) {
00449 error_message_ = "unable to retrieve accelerometer calibration";
00450 return false;
00451 }
00452 callback_->setCalibrationValue(wii_, &calibration_);
00453
00454 return true;
00455 }
00456
00457
00458 void disconnect(void)
00459 {
00460 if (! wii_) {
00461
00462 return;
00463 }
00464
00465
00466 callback_->removeObject(wii_);
00467 cwiid_close(wii_);
00468 wii_ = NULL;
00469 }
00470
00471
00472 bool isConnected(void)
00473 {
00474 return (wii_) ? true : false;
00475 }
00476
00477
00478 void setRepeatMode(void)
00479 {
00480 uint8_t rpt_mode =
00481 CWIID_RPT_STATUS | CWIID_RPT_BTN | CWIID_RPT_IR | CWIID_RPT_ACC;
00482 #if defined(CWIID_RPT_MOTIONPLUS)
00483 rpt_mode |= CWIID_RPT_MOTIONPLUS;
00484 #endif
00485 if (cwiid_set_rpt_mode(wii_, rpt_mode)) {
00486 error_message_ = "error setting report mode";
00487 }
00488 #if defined(CWIID_RPT_MOTIONPLUS)
00489 cwiid_enable(wii_, CWIID_FLAG_MOTIONPLUS);
00490 #endif
00491 }
00492 };
00493 bdaddr_t WiiJoystick::pImpl::bdaddr_any_ = initializeBdaddr();
00494 WiiJoystick::pImpl::CallbackHandler::WiiHash
00495 WiiJoystick::pImpl::CallbackHandler::wii_hash_;
00496
00497
00498 WiiJoystick::WiiJoystick(void) : pimpl(new pImpl)
00499 {
00500 }
00501
00502
00503 WiiJoystick::~WiiJoystick(void)
00504 {
00505 }
00506
00507
00508 bool WiiJoystick::findController(int timeout)
00509 {
00510 bool exist = (cwiid_find_wiimote(&pimpl->bdaddr_, timeout)) ? false : true;
00511 return exist;
00512 }
00513
00514
00515 const char* WiiJoystick::what(void) const
00516 {
00517 return pimpl->error_message_.c_str();
00518 }
00519
00520
00521 bool WiiJoystick::connect(int id)
00522 {
00523 (void)id;
00524
00525 return pimpl->connect();
00526 }
00527
00528
00529 void WiiJoystick::disconnect(void)
00530 {
00531 pimpl->disconnect();
00532 }
00533
00534
00535 bool WiiJoystick::isConnected(void) const
00536 {
00537 return pimpl->isConnected();
00538 }
00539
00540
00541 size_t WiiJoystick::axisNum(void) const
00542 {
00543 return 2;
00544 }
00545
00546
00547 int WiiJoystick::axisValue(size_t index)
00548 {
00549
00550
00551 return pimpl->callback_->getAxisValue(index, pimpl->wii_);
00552 }
00553
00554
00555 size_t WiiJoystick::buttonsNum(void) const
00556 {
00557 return 7;
00558 }
00559
00560
00561 bool WiiJoystick::isButtonPressed(size_t index)
00562 {
00563 if (! pimpl->wii_) {
00564 return false;
00565 }
00566
00567
00568
00569 return pimpl->callback_->isButtonPressed(index, pimpl->wii_);
00570 }
00571
00572
00573 int WiiJoystick::buttonPressedTimes(size_t index)
00574 {
00575
00576 static_cast<void>(index);
00577
00578
00579 return 0;
00580 }
00581
00582
00583 void WiiJoystick::acceleration(Point3d<double>& acceleration,
00584 size_t* timestamp)
00585 {
00586 if (! pimpl->wii_) {
00587 return;
00588 }
00589
00590 size_t timestamp_value = 0;
00591 pimpl->callback_->getAcceleration(acceleration,
00592 ×tamp_value, pimpl->wii_);
00593
00594 if (timestamp) {
00595 *timestamp = timestamp_value;
00596 }
00597 }
00598
00599
00600 void WiiJoystick::rotation(Angle& x_axis, Angle& y_axis, Angle& z_axis,
00601 size_t* timestamp)
00602 {
00603 if (! pimpl->wii_) {
00604 return;
00605 }
00606
00607 size_t timestamp_value = 0;
00608 pimpl->callback_->getRotation(x_axis, y_axis, z_axis,
00609 ×tamp_value, pimpl->wii_);
00610
00611 if (timestamp) {
00612 *timestamp = timestamp_value;
00613 }
00614 }
00615
00616
00617 size_t WiiJoystick::batteryPercent(void)
00618 {
00619
00620
00621 return pimpl->callback_->getBatteryPercent(pimpl->wii_);
00622 }
00623
00624
00625 bool WiiJoystick::irPosition(vector<ir_position>& positions)
00626 {
00627
00628
00629 positions = pimpl->callback_->wii_hash_[pimpl->wii_]->ir_positions_;
00630
00631 return true;
00632 }
00633
00634
00635
00636 bool WiiJoystick::setLed(unsigned char led_value)
00637 {
00638 return pimpl->callback_->setLed(led_value, pimpl->wii_);
00639 }
00640
00641
00642
00643 bool WiiJoystick::setRumble(bool rumble)
00644 {
00645 return pimpl->callback_->setRumble(rumble, pimpl->wii_);
00646 }
00647
00648
00649
00650 void WiiJoystick::setAccelerationAverageSize(size_t size)
00651 {
00652 if (! pimpl->wii_) {
00653 return;
00654 }
00655
00656 pimpl->callback_->setAccelerationAverageSize(size, pimpl->wii_);
00657 }