summaryrefslogtreecommitdiffhomepage
path: root/tracker-tobii/thread.cpp
diff options
context:
space:
mode:
authorBallista Milsim <ballista.milsim@gmail.com>2020-01-23 15:40:15 +0100
committerBallista Milsim <ballista.milsim@gmail.com>2020-01-23 15:40:15 +0100
commit77885b4d65f49fd220d2426c01cd336402b86c60 (patch)
treeafd0a202db23d7a1db8e6c0cb09f272759162d1a /tracker-tobii/thread.cpp
parentfb994308266093382fffecb8a3fd2645ab811117 (diff)
WIP Tobii Eye tracker support.
Diffstat (limited to 'tracker-tobii/thread.cpp')
-rw-r--r--tracker-tobii/thread.cpp118
1 files changed, 118 insertions, 0 deletions
diff --git a/tracker-tobii/thread.cpp b/tracker-tobii/thread.cpp
new file mode 100644
index 00000000..f9fd2c01
--- /dev/null
+++ b/tracker-tobii/thread.cpp
@@ -0,0 +1,118 @@
+#include "thread.hpp"
+#include "compat/sleep.hpp"
+
+tobii_thread::tobii_thread()
+{
+ head_pose = new tobii_head_pose_t();
+ connect(this, &tobii_thread::tobii_ready_signal, this, &tobii_thread::tobii_ready_signal_impl, Qt::QueuedConnection);
+ connect(this, &tobii_thread::tobii_error_signal, this, &tobii_thread::tobii_error_signal_impl, Qt::QueuedConnection);
+}
+
+tobii_thread::~tobii_thread()
+{
+ if (device) tobii_device_destroy(device);
+ if (api) tobii_api_destroy(api);
+ exit_thread = true;
+ terminate();
+ wait();
+}
+
+void tobii_thread::run()
+{
+ /* See https://developer.tobii.com/consumer-eye-trackers/stream-engine/ */
+ if (tobii_api_create(&api, nullptr, nullptr) != TOBII_ERROR_NO_ERROR)
+ {
+ emit tobii_error_signal("Failed to initialize the Tobii Stream Engine API.");
+ }
+
+ std::vector<std::string> devices;
+ if (tobii_enumerate_local_device_urls(api,
+ [](char const* url, void* user_data)
+ {
+ auto list = (std::vector<std::string>*) user_data;
+ list->push_back(url);
+ }, &devices) != TOBII_ERROR_NO_ERROR)
+ {
+ emit tobii_error_signal("Failed to enumerate devices.");
+ }
+
+ if (devices.size() == 0)
+ {
+ tobii_api_destroy(api);
+ emit tobii_error_signal("No stream engine compatible device(s) found.");
+ }
+ std::string selected_device = devices[0];
+
+ unsigned int retry = 0;
+ tobii_error_t tobii_error = TOBII_ERROR_NO_ERROR;
+ do
+ {
+ tobii_error = tobii_device_create(api, selected_device.c_str(), TOBII_FIELD_OF_USE_INTERACTIVE, &device);
+ if ((tobii_error != TOBII_ERROR_CONNECTION_FAILED) && (tobii_error != TOBII_ERROR_FIRMWARE_UPGRADE_IN_PROGRESS)) break;
+ portable::sleep(interval);
+ ++retry;
+ } while (retry < retries);
+ if (tobii_error != TOBII_ERROR_NO_ERROR) {
+ tobii_api_destroy(api);
+ emit tobii_error_signal("Failed to connect to device.");
+ }
+
+ emit tobii_ready_signal();
+
+ tobii_error = TOBII_ERROR_NO_ERROR;
+ while (!exit_thread)
+ {
+ tobii_error = tobii_wait_for_callbacks(1, &device);
+ if (tobii_error == TOBII_ERROR_TIMED_OUT) continue;
+ else if (tobii_error != TOBII_ERROR_NO_ERROR)
+ {
+ emit tobii_error_signal("tobii_wait_for_callbacks failed.");
+ }
+
+ tobii_error = tobii_device_process_callbacks(device);
+ if (tobii_error == TOBII_ERROR_CONNECTION_FAILED)
+ {
+ unsigned int retry = 0;
+ auto tobii_error = TOBII_ERROR_NO_ERROR;
+ do
+ {
+ tobii_error = tobii_device_reconnect(device);
+ if ((tobii_error != TOBII_ERROR_CONNECTION_FAILED) && (tobii_error != TOBII_ERROR_FIRMWARE_UPGRADE_IN_PROGRESS)) break;
+ portable::sleep(interval);
+ ++retry;
+ } while (retry < retries);
+ if (tobii_error != TOBII_ERROR_NO_ERROR)
+ {
+ emit tobii_error_signal("Connection was lost and reconnection failed.");
+ }
+ continue;
+ }
+ else if (tobii_error != TOBII_ERROR_NO_ERROR)
+ {
+ emit tobii_error_signal("tobii_device_process_callbacks failed.");
+ }
+ }
+}
+
+void tobii_thread::tobii_error_signal_impl(QString error_message)
+{
+ //TODO: log? terminate?
+}
+
+void tobii_thread::tobii_ready_signal_impl()
+{
+ if (tobii_head_pose_subscribe(device, [](tobii_head_pose_t const* head_pose, void* user_data) {
+
+ if ((*head_pose).position_validity != TOBII_VALIDITY_VALID
+ || (*head_pose).rotation_validity_xyz[0] != TOBII_VALIDITY_VALID
+ || (*head_pose).rotation_validity_xyz[1] != TOBII_VALIDITY_VALID
+ || (*head_pose).rotation_validity_xyz[2] != TOBII_VALIDITY_VALID) return;
+
+ tobii_head_pose_t* tobii_head_pose_storage = (tobii_head_pose_t*)user_data;
+ *tobii_head_pose_storage = *head_pose;
+
+ }, head_pose) != TOBII_ERROR_NO_ERROR)
+ {
+ emit tobii_error_signal("Failed to subscribe to head pose stream.");
+ }
+}