All Classes Namespaces Files Functions Variables Enumerations Enumerator
programs/UrgRecorder/UrgRecorderWidget.cpp
Go to the documentation of this file.
00001 
00010 #include "UrgRecorderWidget.h"
00011 #include "SerialConnectionWidget.h"
00012 #include "EthernetConnectionWidget.h"
00013 #include "RecordConnection.h"
00014 #include "UrgDevice.h"
00015 #include "UrgUsbCom.h"
00016 #include "FindComPorts.h"
00017 #include "DetectOS.h"
00018 #include "TcpipSocket.h"
00019 #include <QTimer>
00020 #include <QDateTime>
00021 #include <QDir>
00022 #include <QTextStream>
00023 #include <QMessageBox>
00024 #include <QShortcut>
00025 #include <QSettings>
00026 
00027 using namespace qrk;
00028 using namespace std;
00029 
00030 #if defined(MSC)
00031 #define snprintf _snprintf
00032 #endif
00033 
00034 
00035 namespace
00036 {
00037     const char* Organization = "Hokuyo LTD.";
00038     const char* Application = "URG Recorder";
00039     const char* UrgDefaultAddress = "192.168.0.10";
00040 
00041     enum {
00042         UrgDefaultPort = 10940,
00043         DefaultCaptureTimes = 10,
00044     };
00045 }
00046 
00047 
00048 struct UrgRecorderWidget::pImpl
00049 {
00050     UrgRecorderWidget* widget_;
00051     SerialConnectionWidget serial_connection_widget_;
00052     EthernetConnectionWidget ethernet_connection_widget_;
00053 
00054     UrgUsbCom urg_usb_;
00055     FindComPorts urg_finder_;
00056     UrgDevice urg_;
00057     Connection* serial_connection_;
00058     TcpipSocket ethernet_connection_;
00059 
00060     QTimer capture_timer_;
00061     QString save_directory_;
00062     size_t capture_max_;
00063     size_t total_times_;
00064     bool is_raw_record_;
00065 
00066     bool intensity_mode_;
00067     bool is_using_serial_;
00068 
00069 
00070     pImpl(UrgRecorderWidget* widget)
00071         : widget_(widget), serial_connection_(NULL),
00072           capture_max_(1), total_times_(0), is_raw_record_(false),
00073           intensity_mode_(false), is_using_serial_(true)
00074     {
00075         urg_finder_.addBaseName("/dev/ttyACM");
00076         urg_finder_.addBaseName("/dev/tty.usbmodem");
00077         urg_finder_.addDriverName("URG Series USB Device Driver");
00078         urg_finder_.addDriverName("URG-X002 USB Device Driver");
00079 
00080         ethernet_connection_widget_.setPort(UrgDefaultPort);
00081     }
00082 
00083 
00084     void initializeForm(void)
00085     {
00086         // 位置と大きさを読み出す
00087         loadSettings();
00088 
00089         // ConnectionWidget の配置
00090         widget_->connection_layout_->addWidget(&serial_connection_widget_);
00091         widget_->connection_layout_->addWidget(&ethernet_connection_widget_);
00092         widget_->connection_dummy_label_->hide();
00093 
00094         // イベントの接続
00095         connect(&serial_connection_widget_, SIGNAL(rescanRequest()),
00096                 widget_, SLOT(rescanPressed()));
00097         connect(&serial_connection_widget_,
00098                 SIGNAL(connectRequest(bool, const std::string&)),
00099                 widget_, SLOT(connectPressed(bool, const std::string&)));
00100 
00101         connect(&ethernet_connection_widget_,
00102                 SIGNAL(connectRequest(bool, const std::string&,
00103                                       unsigned short)),
00104                 widget_, SLOT(connectPressed(bool, const std::string&,
00105                                              unsigned short)));
00106 
00107         connect(widget_->times_spinbox_, SIGNAL(valueChanged(int)),
00108                 widget_, SLOT(timesChanged(int)));
00109 
00110         connect(widget_->record_button_, SIGNAL(clicked()),
00111                 widget_, SLOT(recordPressed()));
00112         connect(widget_->cancel_button_, SIGNAL(clicked()),
00113                 widget_, SLOT(cancelPressed()));
00114 
00115         connect(widget_->raw_button_, SIGNAL(toggled(bool)),
00116                 widget_, SLOT(rawButtonChanged(bool)));
00117 
00118         connect(&capture_timer_, SIGNAL(timeout()),
00119                 widget_, SLOT(recordData()));
00120 
00121         connect(widget_->change_button_, SIGNAL(clicked()),
00122                 widget_, SLOT(changeButtonPressed()));
00123     }
00124 
00125 
00126     void loadSettings(void)
00127     {
00128         QSettings settings(Organization, Application);
00129         widget_->restoreGeometry(settings.value("geometry").toByteArray());
00130         int capture_times =
00131             settings.value("capture_times", DefaultCaptureTimes).toInt();
00132         widget_->times_spinbox_->setValue(capture_times);
00133         widget_->times_progress_->setMaximum(capture_times);
00134 
00135         is_raw_record_ = settings.value("raw_button_checked", false).toBool();
00136         widget_->raw_button_->setChecked(is_raw_record_);
00137         rawButtonChanged(is_raw_record_);
00138 
00139         is_using_serial_ = settings.value("serial_connection", true).toBool();
00140         if (is_using_serial_) {
00141             selectSerial();
00142         } else {
00143             selectEthernet();
00144         }
00145 
00146         string address =
00147             settings.value("address",
00148                            UrgDefaultAddress).toString().toStdString();
00149         ethernet_connection_widget_.setAddress(address);
00150         unsigned short port = settings.value("port", UrgDefaultPort).toInt();
00151         ethernet_connection_widget_.setPort(port);
00152     }
00153 
00154 
00155     void saveSettings(void)
00156     {
00157         QSettings settings(Organization, Application);
00158         settings.setValue("geometry", widget_->saveGeometry());
00159         settings.setValue("capture_times", widget_->times_spinbox_->value());
00160         settings.setValue("raw_button_checked",
00161                           widget_->raw_button_->isChecked());
00162 
00163         settings.setValue("serial_connection", is_using_serial_);
00164         settings.setValue("address",
00165                           ethernet_connection_widget_.address().c_str());
00166         settings.setValue("port", ethernet_connection_widget_.port());
00167     }
00168 
00169 
00170     void setRecording(bool recording)
00171     {
00172         widget_->record_button_->setEnabled(! recording);
00173         widget_->cancel_button_->setEnabled(recording);
00174         widget_->output_group_->setEnabled(! recording);
00175         widget_->times_group_->setEnabled(! recording);
00176     }
00177 
00178 
00179     void recordPressed(void)
00180     {
00181         setRecording(true);
00182 
00183         // 出力先ディレクトリの作成
00184         save_directory_ =
00185             QDateTime::currentDateTime().toString("yyyy-MM-dd_hh_mm_ss");
00186         QDir dir;
00187         dir.mkdir(save_directory_);
00188 
00189         // 取得モードの設定
00190         is_raw_record_ = widget_->raw_button_->isChecked();
00191         if (is_raw_record_) {
00192             is_raw_record_ = true;
00193             serial_connection_ = urg_.connection();
00194             string send_file = save_directory_.toStdString() + "/send.txt";
00195             string receive_file =
00196                 save_directory_.toStdString() + "/receive.txt";
00197             urg_.setConnection(new RecordConnection(serial_connection_,
00198                                                     send_file.c_str(),
00199                                                     receive_file.c_str()));
00200 
00201             // ログに URG の情報を含めるための呼び出し
00202             urg_.loadParameter();
00203         }
00204 
00205         // データ取得の開始
00206         capture_max_ = widget_->times_spinbox_->value();
00207         total_times_ = 0;
00208         if (intensity_mode_) {
00209             urg_.setCaptureMode(IntensityCapture);
00210         } else {
00211             urg_.setCaptureMode(AutoCapture);
00212         }
00213         capture_timer_.setInterval(urg_.scanMsec() / 2);
00214         capture_timer_.start();
00215     }
00216 
00217 
00218     void recordData(void)
00219     {
00220         vector<long> data;
00221         vector<long> intensity_data;
00222 
00223         int n;
00224         if (intensity_mode_) {
00225             n = urg_.captureWithIntensity(data, intensity_data);
00226         } else {
00227             n = urg_.capture(data);
00228         }
00229 
00230         if (n <= 0) {
00231             return;
00232         }
00233         ++total_times_;
00234 
00235         if (! is_raw_record_) {
00236 
00237             // ファイルへのデータ書き出し
00238             char buffer[] = "/data_xxxxxxxxxx.csv";
00239             snprintf(buffer, sizeof(buffer), "/data_%09d.csv", total_times_);
00240             QFile file(save_directory_ + QString(buffer));
00241             if (! file.open(QIODevice::WriteOnly)) {
00242                 // !!! エラー表示
00243                 return;
00244             }
00245 
00246             QTextStream fout(&file);
00247             saveFile(fout, data, intensity_data);
00248         }
00249 
00250         widget_->times_progress_->setValue(total_times_);
00251         if (total_times_ >= capture_max_) {
00252             stopRecording();
00253         }
00254     }
00255 
00256 
00257     void stopRecording(void)
00258     {
00259         setRecording(false);
00260         capture_timer_.stop();
00261         widget_->times_progress_->setValue(0);
00262 
00263         urg_.stop();
00264 
00265         if (is_raw_record_) {
00266             Connection* connection = urg_.connection();
00267             if (connection != serial_connection_) {
00268                 delete connection;
00269                 urg_.setConnection(serial_connection_);
00270             }
00271         }
00272     }
00273 
00274 
00275     void saveFile(QTextStream& fout, const vector<long>& data,
00276                   vector<long>& intensity_data)
00277     {
00278         size_t n = data.size();
00279         for (size_t i = 0; i < n; ++i) {
00280             long length = data[i];
00281             double radian = urg_.index2rad(i);
00282             double x = length * cos(radian);
00283             double y = length * sin(radian);
00284             fout << i << ',' << length << ','
00285                  << radian << ',' << x << ',' << y;
00286 
00287             if (intensity_mode_) {
00288                 fout << ',' << intensity_data[i];
00289             }
00290 
00291             fout << endl;
00292         }
00293     }
00294 
00295 
00296     void rawButtonChanged(bool checked)
00297     {
00298         if (checked) {
00299             widget_->sample_text_->clear();
00300             widget_->sample_text_->
00301                 insertPlainText("# receive data sample\n"
00302                                 "MD0044072501000\n"
00303                                 "99b\n"
00304                                 "...");
00305         } else {
00306             widget_->sample_text_->clear();
00307             widget_->sample_text_->
00308                 insertPlainText("# index, length, radian, x, y\n"
00309                                 "0,669,-2.08621,-329.749,-582.088\n"
00310                                 "1,667,-2.08008,-325.196,-582.354\n"
00311                                 "...");
00312         }
00313     }
00314 
00315 
00316     void selectSerial(void)
00317     {
00318         widget_->change_button_->setText(tr("Change to Ethernet"));
00319         ethernet_connection_widget_.hide();
00320         serial_connection_widget_.show();
00321 
00322         if (serial_connection_) {
00323             urg_.setConnection(serial_connection_);
00324         }
00325 
00326         is_using_serial_ = true;
00327     }
00328 
00329 
00330     void selectEthernet(void)
00331     {
00332         widget_->change_button_->setText(tr("Change to Serial"));
00333         serial_connection_widget_.hide();
00334         ethernet_connection_widget_.show();
00335 
00336         urg_.setConnection(&ethernet_connection_);
00337 
00338         is_using_serial_ = false;
00339     }
00340 
00341 
00342     void set_enables(bool connected)
00343     {
00344         widget_->record_group_->setEnabled(connected);
00345         widget_->cancel_button_->setEnabled(false);
00346 
00347         serial_connection_widget_.setConnected(connected);
00348         ethernet_connection_widget_.setConnected(connected);
00349 
00350         if (connected) {
00351             // フォーカスを Record ボタンに移動させる
00352             widget_->record_button_->setFocus();
00353         }
00354     }
00355 };
00356 
00357 
00358 UrgRecorderWidget::UrgRecorderWidget(QWidget* parent)
00359     : QWidget(parent), pimpl(new pImpl(this))
00360 {
00361     setupUi(this);
00362 
00363     // フォームを初期化し、最初の表示を行う
00364     pimpl->initializeForm();
00365     rescanPressed();
00366 
00367     pimpl->serial_connection_widget_.setFocus();
00368 
00369     // Ctrl-q, Alt-F4 で終了させる
00370     (void) new QShortcut(Qt::CTRL + Qt::Key_Q, this, SLOT(close()));
00371     (void) new QShortcut(Qt::ALT + Qt::Key_F4, this, SLOT(close()));
00372 }
00373 
00374 
00375 UrgRecorderWidget::~UrgRecorderWidget(void)
00376 {
00377 }
00378 
00379 
00380 void UrgRecorderWidget::setIntensityMode(void)
00381 {
00382     if (! pimpl->intensity_mode_) {
00383         pimpl->intensity_mode_ = true;
00384         if (pimpl->intensity_mode_) {
00385             setWindowTitle(windowTitle() + " " + tr("[intensity]"));
00386         }
00387     }
00388 }
00389 
00390 
00391 void UrgRecorderWidget::closeEvent(QCloseEvent* event)
00392 {
00393     static_cast<void>(event);
00394 
00395     pimpl->urg_.stop();
00396     pimpl->saveSettings();
00397 }
00398 
00399 
00400 void UrgRecorderWidget::rescanPressed(void)
00401 {
00402     vector<string> devices;
00403     pimpl->urg_finder_.find(devices);
00404     for (vector<string>::iterator it = devices.begin();
00405          it != devices.end(); ++it) {
00406         if (pimpl->urg_usb_.isUsbCom(it->c_str())) {
00407             *it = *it + " [URG]";
00408         }
00409     }
00410     pimpl->serial_connection_widget_.setDevices(devices);
00411 }
00412 
00413 
00414 void UrgRecorderWidget::connectPressed(bool connection,
00415                                        const string& device)
00416 {
00417     // !!! 接続処理をスレッドで行うように調整する
00418     bool connected = connection;
00419 
00420     if (connection) {
00421         if (! pimpl->urg_.connect(device.c_str())) {
00422             QMessageBox::warning(this, tr("Connection error"),
00423                                  pimpl->urg_.what());
00424             connected = false;
00425         }
00426     } else {
00427         pimpl->stopRecording();
00428     }
00429 
00430     pimpl->set_enables(connected);
00431 }
00432 
00433 
00434 void UrgRecorderWidget::connectPressed(bool connection,
00435                                        const std::string& address,
00436                                        unsigned short port)
00437 {
00438     // !!! 接続処理をスレッドで行うように調整する
00439     bool connected = connection;
00440 
00441     fprintf(stderr, "%p, %p\n", &pimpl->ethernet_connection_, pimpl->urg_.connection());
00442     if (connection) {
00443         if (! pimpl->urg_.connect(address.c_str(), port)) {
00444             QMessageBox::warning(this, tr("Connection error"),
00445                                  pimpl->urg_.what());
00446             connected = false;
00447         }
00448     } else {
00449         pimpl->stopRecording();
00450     }
00451 
00452     pimpl->set_enables(connected);
00453 }
00454 
00455 
00456 void UrgRecorderWidget::recordPressed(void)
00457 {
00458     if (pimpl->capture_timer_.isActive()) {
00459         return;
00460     }
00461     pimpl->recordPressed();
00462 }
00463 
00464 
00465 void UrgRecorderWidget::cancelPressed(void)
00466 {
00467     pimpl->stopRecording();
00468 }
00469 
00470 
00471 void UrgRecorderWidget::timesChanged(int times)
00472 {
00473     times_progress_->setMaximum(times);
00474 
00475     // 再描画が行われるように、2回ほど値をセットしている
00476     times_progress_->setValue(1);
00477     times_progress_->setValue(0);
00478 }
00479 
00480 
00481 void UrgRecorderWidget::recordData(void)
00482 {
00483     pimpl->recordData();
00484 }
00485 
00486 
00487 void UrgRecorderWidget::rawButtonChanged(bool checked)
00488 {
00489     pimpl->rawButtonChanged(checked);
00490 }
00491 
00492 
00493 void UrgRecorderWidget::changeButtonPressed(void)
00494 {
00495     if (pimpl->is_using_serial_) {
00496         pimpl->selectEthernet();
00497     } else {
00498         pimpl->selectSerial();
00499     }
00500 }