From b7c8490bd26daf9b9c3baa79746912c00484c653 Mon Sep 17 00:00:00 2001 From: Marios Fanourakis Date: Wed, 2 Sep 2020 12:43:03 +0200 Subject: [PATCH 1/3] added frequency selection and participant id option --- mainwindow.cpp | 57 +++++++++++++++++++++++++++++++++++++++++----- mainwindow.h | 1 + mainwindow.ui | 62 ++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 105 insertions(+), 15 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index 10a9c94..b7a03ad 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -51,19 +51,22 @@ void push_tobii_gaze(TobiiResearchGazeData *g, void *gaze_stream) { g->right_eye.gaze_point.position_on_display_area.x = NAN; g->right_eye.gaze_point.position_on_display_area.y = NAN; } - const float sample[] = {g->left_eye.gaze_point.position_on_display_area.x, + const float sample[] = {g->device_time_stamp, + g->system_time_stamp, + g->left_eye.gaze_point.position_on_display_area.x, g->left_eye.gaze_point.position_on_display_area.y, g->left_eye.pupil_data.validity ? g->left_eye.pupil_data.diameter : NAN, g->right_eye.gaze_point.position_on_display_area.x, g->right_eye.gaze_point.position_on_display_area.y, g->right_eye.pupil_data.validity ? g->right_eye.pupil_data.diameter : NAN}; - gs->push_sample(sample, g->system_time_stamp / 1000000.); + gs->push_sample(sample); samples_written++; }; MainWindow::MainWindow(QWidget *parent, const char *config_file) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); + connect(ui->address, &QLineEdit::textChanged, this, &MainWindow::refresh_samplingrate); connect(ui->actionLoad_Configuration, &QAction::triggered, [this]() { load_config(QFileDialog::getOpenFileName( this, "Load Configuration File", "", "Configuration Files (*.cfg)")); @@ -90,12 +93,17 @@ MainWindow::MainWindow(QWidget *parent, const char *config_file) void MainWindow::load_config(const QString &filename) { QSettings settings(filename, QSettings::Format::IniFormat); ui->address->setText(settings.value("TobiiPro/address", "127.0.0.1").toString()); + ui->samplingrate->setText(settings.value("TobiiPro/rate", "60").toString()); + ui->participant->setText(settings.value("Participant/ID", "P0").toString()); } void MainWindow::save_config(const QString &filename) { QSettings settings(filename, QSettings::Format::IniFormat); settings.beginGroup("TobiiPro"); settings.setValue("address", ui->address->text()); + settings.setValue("rate", ui->samplingrate->text()); + settings.beginGroup("Participant"); + settings.setValue("ID", ui->participant->text()); } void MainWindow::closeEvent(QCloseEvent *ev) { @@ -120,11 +128,40 @@ void MainWindow::refresh_eyetrackers() { } } +void MainWindow::refresh_samplingrate() { + ui->samplingrateDropdown->clear(); + QString address = ui->address->text(); + try { + + QByteArray addr = address.toLocal8Bit(); + auto res = tobii_research_get_eyetracker(addr.constData(), ¤t_tracker); + if (res != TOBII_RESEARCH_STATUS_OK) + return; + + TobiiResearchGazeOutputFrequencies* frequencies = NULL; + size_t i = 0; + int status = tobii_research_get_all_gaze_output_frequencies(current_tracker, &frequencies); + for (; i < frequencies->frequency_count; i++) { + ui->samplingrateDropdown->addItem(QString::number(frequencies->frequencies[i])); + } + } + catch (std::exception & e) { + QMessageBox::critical( + this, "Error", QStringLiteral("Error: ") + e.what(), QMessageBox::Ok); + } + + +} + void MainWindow::toggleRecording() { if (!gaze_stream) { ui->linkButton->setEnabled(false); // === perform link action === + QString participant = ui->participant->text(); QString address = ui->address->text(); + QString ratestr = ui->samplingrate->text(); + bool ok = false; + double rate = ratestr.toDouble(&ok); try { QByteArray addr = address.toLocal8Bit(); @@ -132,10 +169,9 @@ void MainWindow::toggleRecording() { if (res != TOBII_RESEARCH_STATUS_OK) throw std::runtime_error("Could not connect: " + std::to_string(res)); - const auto samplingrate = 600; // TODO // Start LSL outlet std::string streamname = "Tobii"; - lsl::stream_info info(streamname, "Eyetracker", 6, samplingrate, lsl::cf_float32, + lsl::stream_info info(streamname+"-"+participant.toLocal8Bit().constData(), "Eyetracker", 8,rate, lsl::cf_float32, streamname + "at_" + address.toStdString()); // append some meta-data @@ -147,6 +183,14 @@ void MainWindow::toggleRecording() { .append_child_value("precision", "24"); auto channels = info.desc().append_child("channels"); + channels.append_child("channel") + .append_child_value("label", "device_ts") + .append_child_value("type", "timestamp") + .append_child_value("unit", "milliseconds"); + channels.append_child("channel") + .append_child_value("label", "system_ts") + .append_child_value("type", "timestamp") + .append_child_value("unit", "milliseconds"); channels.append_child("channel") .append_child_value("label", "left_x") .append_child_value("eye", "left") @@ -183,6 +227,7 @@ void MainWindow::toggleRecording() { // reset the counter samples_written = 0; + tobii_research_set_gaze_output_frequency(current_tracker, rate); // subscribe to the stream res = tobii_research_subscribe_to_gaze_data( current_tracker, push_tobii_gaze, gaze_stream.get()); @@ -202,7 +247,7 @@ void MainWindow::toggleRecording() { this, "Error", QStringLiteral("Error: ") + e.what(), QMessageBox::Ok); } ui->linkButton->setEnabled(true); - ui->linkButton->setText("Unlink"); + ui->linkButton->setText("Stop stream"); } else { // === perform unlink action === ui->linkButton->setEnabled(false); @@ -210,7 +255,7 @@ void MainWindow::toggleRecording() { gaze_stream.reset(); statusTimer.stop(); ui->linkButton->setEnabled(true); - ui->linkButton->setText("Link"); + ui->linkButton->setText("Start stream"); } } diff --git a/mainwindow.h b/mainwindow.h index 7e73487..6469d8b 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -25,6 +25,7 @@ private slots: void closeEvent(QCloseEvent *ev) override; void toggleRecording(); void refresh_eyetrackers(); + void refresh_samplingrate(); private: // function for loading / saving the config file diff --git a/mainwindow.ui b/mainwindow.ui index 2086acd..be4f132 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -36,7 +36,7 @@ - Tobii Address + Selected Address @@ -48,14 +48,14 @@ - + - Samplingrate + Rate options - + 0 @@ -67,7 +67,35 @@ - + + + + Selected rate + + + + + + + + + + + + + + Participant + + + + + + + + + + + @@ -76,11 +104,11 @@ - Link + Start stream - + Streams to enable @@ -96,7 +124,7 @@ - + @@ -112,7 +140,7 @@ - + This application is @@ -201,5 +229,21 @@ powered by Tobii + + samplingrateDropdown + activated(QString) + samplingrate + setText(QString) + + + 150 + 57 + + + 150 + 107 + + + From 4cfdd18a0883fd35f404d4da1e3f1a958c574f4b Mon Sep 17 00:00:00 2001 From: Marios Fanourakis Date: Wed, 2 Sep 2020 12:49:40 +0200 Subject: [PATCH 2/3] fixed some config formatting --- mainwindow.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mainwindow.cpp b/mainwindow.cpp index b7a03ad..c329159 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -102,8 +102,10 @@ void MainWindow::save_config(const QString &filename) { settings.beginGroup("TobiiPro"); settings.setValue("address", ui->address->text()); settings.setValue("rate", ui->samplingrate->text()); + settings.endGroup(); settings.beginGroup("Participant"); settings.setValue("ID", ui->participant->text()); + settings.endGroup(); } void MainWindow::closeEvent(QCloseEvent *ev) { From 4bfedd3f36f4be88d23ab5550cc7751b60d439c5 Mon Sep 17 00:00:00 2001 From: Marios Fanourakis Date: Wed, 7 Oct 2020 13:00:08 +0200 Subject: [PATCH 3/3] changed gaze point validity check to be inline (more consistent with the other data) --- mainwindow.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index c329159..5452b28 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -43,6 +43,7 @@ static uint32_t samples_written = 0; void push_tobii_gaze(TobiiResearchGazeData *g, void *gaze_stream) { auto gs = reinterpret_cast(gaze_stream); + /* if (!g->left_eye.gaze_point.validity) { g->left_eye.gaze_point.position_on_display_area.x = NAN; g->left_eye.gaze_point.position_on_display_area.y = NAN; @@ -51,13 +52,14 @@ void push_tobii_gaze(TobiiResearchGazeData *g, void *gaze_stream) { g->right_eye.gaze_point.position_on_display_area.x = NAN; g->right_eye.gaze_point.position_on_display_area.y = NAN; } + */ const float sample[] = {g->device_time_stamp, g->system_time_stamp, - g->left_eye.gaze_point.position_on_display_area.x, - g->left_eye.gaze_point.position_on_display_area.y, + g->left_eye.gaze_point.validity ? g->left_eye.gaze_point.position_on_display_area.x : NAN, + g->left_eye.gaze_point.validity ? g->left_eye.gaze_point.position_on_display_area.y : NAN, g->left_eye.pupil_data.validity ? g->left_eye.pupil_data.diameter : NAN, - g->right_eye.gaze_point.position_on_display_area.x, - g->right_eye.gaze_point.position_on_display_area.y, + g->right_eye.gaze_point.validity ? g->right_eye.gaze_point.position_on_display_area.x : NAN, + g->right_eye.gaze_point.validity ? g->right_eye.gaze_point.position_on_display_area.y : NAN, g->right_eye.pupil_data.validity ? g->right_eye.pupil_data.diameter : NAN}; gs->push_sample(sample); samples_written++;