All Classes Namespaces Files Functions Variables Enumerations Enumerator
libs/controller/WiiJoystick_lin.cpp
Go to the documentation of this file.
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         // !!! 1回が約 10 msec で 1000 分なので、100 回以上の resize()
00092         //accelerations_.resize(200);
00093 
00094         // !!! calibration_ は未初期化
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           // 元のソースでは、ここで NUNCHUK とかの処理もしていたが、省略
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           // IR 情報の取得
00295           recordIrPosition(&mesg_array[i].ir_mesg, state, timestamp);
00296           break;
00297 
00298 #if defined(CWIID_RPT_MOTIONPLUS)
00299         case CWIID_MESG_MOTIONPLUS:
00300           // Motion Plus 情報の取得
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       // !!! timestamp を反映させる
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       // !!! timstamp を反映させる
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                                     &timestamp_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                                 &timestamp_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 // LED 設定
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 }