Tilt Five NDK
TiltFiveNative.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2020-2022 Tilt Five, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
21
22#include "TiltFiveNative.h"
23#include "errors.hpp"
24#include "result.hpp"
25
26#include <algorithm>
27#include <atomic>
28#include <chrono>
29#include <functional>
30#include <iomanip>
31#include <iostream>
32#include <map>
33#include <memory>
34#include <mutex>
35#include <set>
36#include <string>
37#include <thread>
38#include <utility>
39#include <vector>
40
44
45namespace tiltfive {
46
50
54
55class Client;
56class Glasses;
57class Wand;
58class WandStreamHelper;
59class GlassesConnectionHelper;
60class ParamChangeHelper;
61class ParamChangeListener;
62
65inline auto obtainWand(T5_WandHandle handle, std::shared_ptr<WandStreamHelper> wandStreamHelper)
67inline auto obtainWandStreamHelper(
72 const std::string& displayName,
73 std::chrono::milliseconds connectionPollInterval)
77 std::chrono::milliseconds pollInterval)
80
82class Client : public std::enable_shared_from_this<Client> {
83private:
84 static constexpr bool kDebug = true;
85
86 Client(std::string applicationId, std::string applicationVersion, const uint8_t sdkType)
87 : mApplicationId(std::move(applicationId))
88 , mApplicationVersion(std::move(applicationVersion)) {
89
90 mClientInfo.applicationId = mApplicationId.c_str();
91 mClientInfo.applicationVersion = mApplicationVersion.c_str();
92 mClientInfo.sdkType = sdkType;
93 }
94
95 const std::string mApplicationId;
96 const std::string mApplicationVersion;
97
98 T5_Context mContext{};
99 T5_ClientInfo mClientInfo{};
100
101 friend Glasses;
102 friend ParamChangeHelper;
103
104 friend std::ostream& operator<<(std::ostream& os, std::shared_ptr<Client> const& instance) {
105 os << *instance;
106 return os;
107 }
108
109 friend std::ostream& operator<<(std::ostream& os, Client const& instance) {
110 os << "<Client:" << instance.mApplicationId << ">";
111 return os;
112 }
113
114 friend auto obtainClient(const std::string& applicationId,
115 const std::string& applicationVersion,
116 void* platformContext,
117 const uint8_t sdkType) -> Result<std::shared_ptr<Client>>;
118
119 static auto create(const std::string& applicationId,
120 const std::string& applicationVersion,
121 void* platformContext,
122 const uint8_t sdkType) -> Result<std::shared_ptr<Client>> {
123
124 // Validate inputs
125 if (applicationId.length() > T5_MAX_STRING_PARAM_LEN) {
127 }
128
129 if (applicationVersion.length() > T5_MAX_STRING_PARAM_LEN) {
131 }
132
133 // Create client
134 auto client =
135 std::shared_ptr<Client>(new Client(applicationId, applicationVersion, sdkType));
136
137 // Start up the service connection
138 auto err = t5CreateContext(&client->mContext, &client->mClientInfo, platformContext);
139 if (err) {
140 return static_cast<Error>(err);
141 }
142
143 return client;
144 };
145
146public:
148 virtual ~Client() {
149 // Release context and library
150 t5DestroyContext(&mContext);
151 mContext = nullptr;
152 }
154
158
165 std::vector<char> buffer;
166 buffer.resize(64);
167
168 size_t bufferSize;
169
170 // If the buffer passed to listGlasses() is too small, it'll return with
171 // an overflow condition, in which case, increase the size of the buffer
172 // and try again.
173 for (;;) {
174 bufferSize = buffer.size();
175 T5_Result err = t5ListGlasses(mContext, buffer.data(), &bufferSize);
176 if (!err) {
177 break;
178 } else if (err == T5_ERROR_OVERFLOW) {
179 if (bufferSize > 1024) {
180 return Error::kOverflow;
181 }
182
183 buffer.resize(bufferSize);
184 } else {
185 return static_cast<Error>(err);
186 }
187 }
188
189 // Peel off string until we encounter a naked null (empty string)
190 std::vector<std::string> glassesList;
191 auto buffPtr = buffer.data();
192 for (;;) {
193 std::string id = buffPtr;
194 if (id.empty()) {
195 break;
196 }
197
198 buffPtr += id.length() + 1;
199 glassesList.push_back(id);
200 }
201 return glassesList;
202 }
203
211 T5_Result err =
213 if (!err) {
214 return std::string(value.get(), size);
215 } else {
216 return static_cast<Error>(err);
217 }
218 }
219
228 uint16_t changedParamsCount = 32;
229 std::vector<T5_ParamSys> changedParamsBuffer(changedParamsCount);
230
231 changedParamsBuffer.resize(changedParamsCount);
232 T5_Result err =
233 t5GetChangedSystemParams(mContext, changedParamsBuffer.data(), &changedParamsCount);
234
235 for (;;) {
236 if (!err) {
237 changedParamsBuffer.resize(changedParamsCount);
238 return changedParamsBuffer;
239
240 } else if (err == T5_ERROR_OVERFLOW) {
241 changedParamsCount = changedParamsBuffer.size() * 2;
242 continue;
243
244 } else {
245 return static_cast<Error>(err);
246 }
247 }
248 }
249
262 int64_t value = 0;
263
264 T5_Result err =
266 if (!err) {
267 return value != 0;
268 } else if (err == T5_ERROR_SETTING_UNKNOWN) {
269 return false;
270 } else {
271 return static_cast<Error>(err);
272 }
273 }
274
281
282 T5_Result err = t5GetGameboardSize(mContext, type, &size);
283 if (!err) {
284 return size;
285 } else {
286 return static_cast<Error>(err);
287 }
288 }
289
297 [[nodiscard]] auto createParamChangedHelper(
301
302 return obtainParamChangeHelper(shared_from_this(), std::move(listener), pollInterval);
303 }
304};
305
307enum class ConnectionState : int {
311
313 kReserved,
314
317
320};
321
323class Glasses : public std::enable_shared_from_this<Glasses> {
324 friend Client;
325 friend ParamChangeHelper;
326
327 const std::string mIdentifier;
328 const std::shared_ptr<Client> mClient;
329 std::weak_ptr<WandStreamHelper> mWandStreamHelper{};
330 T5_Glasses mGlasses{};
331
332 friend std::ostream& operator<<(std::ostream& os, std::shared_ptr<Glasses> const& instance) {
333 os << *instance;
334 return os;
335 }
336
337 friend std::ostream& operator<<(std::ostream& os, Glasses const& instance) {
338 os << "<Glasses:" << instance.mIdentifier << ">";
339 return os;
340 }
341
342 friend auto obtainGlasses(const std::string& identifier, const std::shared_ptr<Client>& client)
344
345 explicit Glasses(std::string identifier, std::shared_ptr<Client> client)
346 : mIdentifier(std::move(identifier)), mClient(std::move(client)) {}
347
348 static auto create(std::string identifier, std::shared_ptr<Client> client)
350
351 if (!client) {
353 }
354
355 T5_Glasses handle;
356 T5_Result err = t5CreateGlasses(client->mContext, identifier.c_str(), &handle);
357
358 if (err) {
359 return static_cast<Error>(err);
360 }
361
362 std::shared_ptr<Glasses> glasses{new Glasses(identifier, client)};
363
364 glasses->mGlasses = handle;
365
366 return glasses;
367 }
368
369public:
379 [[nodiscard]] auto getIdentifier() const -> std::string {
380 return mIdentifier;
381 }
382
387 T5_ConnectionState connectionState;
388 T5_Result err = t5GetGlassesConnectionState(mGlasses, &connectionState);
389 if (err != T5_SUCCESS) {
390 return static_cast<Error>(err);
391 }
392
393 switch (connectionState) {
396
399
402
405
406 default:
408 }
409 }
410
419 uint16_t changedParamsCount = 32;
420 std::vector<T5_ParamGlasses> changedParamsBuffer(changedParamsCount);
421
422 changedParamsBuffer.resize(changedParamsCount);
423 T5_Result err =
424 t5GetChangedGlassesParams(mGlasses, changedParamsBuffer.data(), &changedParamsCount);
425
426 for (;;) {
427 if (!err) {
428 changedParamsBuffer.resize(changedParamsCount);
429 return changedParamsBuffer;
430
431 } else if (err == T5_ERROR_OVERFLOW) {
432 changedParamsCount = changedParamsBuffer.size() * 2;
433 continue;
434
435 } else {
436 return static_cast<Error>(err);
437 }
438 }
439 }
440
449 double value = 0;
451 if (!err) {
452 return value;
453 } else {
454 return static_cast<Error>(err);
455 }
456 }
457
470 mGlasses, 0, kT5_ParamGlasses_UTF8_FriendlyName, value.get(), &size);
471 if (!err) {
472 return std::string(value.get());
473 } else {
474 return static_cast<Error>(err);
475 }
476 }
477
498 auto reserve(const std::string& displayName) -> Result<void> {
499 T5_Result err = t5ReserveGlasses(mGlasses, displayName.c_str());
500 if (!err) {
501 return kSuccess;
502 } else {
503 return static_cast<Error>(err);
504 }
505 }
506
522 T5_Result err = t5EnsureGlassesReady(mGlasses);
523 if (!err) {
524 return kSuccess;
525 } else {
526 return static_cast<Error>(err);
527 }
528 }
529
538 T5_Result err = t5ReleaseGlasses(mGlasses);
539 if (!err) {
540 return kSuccess;
541 } else {
542 return static_cast<Error>(err);
543 }
544 }
545
552 T5_GlassesPose pose;
553 T5_Result err = t5GetGlassesPose(mGlasses, usage, &pose);
554
555 if (!err) {
556 return pose;
557 } else {
558 return static_cast<Error>(err);
559 }
560 }
561
566 auto initGraphicsContext(T5_GraphicsApi graphicsApi, void* graphicsContext) -> Result<void> {
567 T5_Result err = t5InitGlassesGraphicsContext(mGlasses, graphicsApi, graphicsContext);
568 if (!err) {
569 return kSuccess;
570 }
571 return static_cast<Error>(err);
572 }
573
578 T5_Result err = t5ConfigureCameraStreamForGlasses(mGlasses, config);
579 if (!err) {
580 return kSuccess;
581 } else {
582 return static_cast<Error>(err);
583 }
584 }
585
587 //
590 T5_CamImage img;
591 T5_Result err = t5GetFilledCamImageBuffer(mGlasses, &img);
592 if (!err) {
593 return std::move(img);
594 } else {
595 return static_cast<Error>(err);
596 }
597 }
598
600 //
603 T5_Result err = t5SubmitEmptyCamImageBuffer(mGlasses, imgBuffer);
604 if (!err) {
605 return kSuccess;
606 } else {
607 return static_cast<Error>(err);
608 }
609 }
610
612 //
615 auto cancelCamImageBuffer(uint8_t* buffer) -> Result<void> {
616 T5_Result err = t5CancelCamImageBuffer(mGlasses, buffer);
617 if (!err) {
618 return kSuccess;
619 } else {
620 return static_cast<Error>(err);
621 }
622 }
623
627 auto sendFrame(const T5_FrameInfo* const frameInfo) -> Result<void> {
628 T5_Result err = t5SendFrameToGlasses(mGlasses, frameInfo);
629 if (!err) {
630 return kSuccess;
631 } else {
632 return static_cast<Error>(err);
633 }
634 }
635
640 uint8_t wandCount = 4;
641 std::vector<T5_WandHandle> wandBuffer(wandCount);
642
643 for (;;) {
644 wandBuffer.resize(wandCount);
645 T5_Result err = t5ListWandsForGlasses(mGlasses, wandBuffer.data(), &wandCount);
646
647 if (!err) {
649 wands.reserve(wandCount);
650
651 for (auto i = 0; i < wandCount; i++) {
652 wands.push_back(wandBuffer[i]);
653 }
654
655 return wands;
656
657 } else if (err == T5_ERROR_OVERFLOW) {
658 wandCount = wandBuffer.size() * 2;
659 continue;
660
661 } else {
662 return static_cast<Error>(err);
663 }
664 }
665 }
666
671 T5_Result err = t5ConfigureWandStreamForGlasses(mGlasses, config);
672 if (!err) {
673 return kSuccess;
674 } else {
675 return static_cast<Error>(err);
676 }
677 }
678
695 T5_WandStreamEvent event;
696
697 T5_Result err = t5ReadWandStreamForGlasses(mGlasses, &event, timeout.count());
698 if (!err) {
699 return event;
700 } else {
701 return static_cast<Error>(err);
702 }
703 }
704
710 auto wandStreamHelper = mWandStreamHelper.lock();
711 if (!wandStreamHelper) {
712 // needs initialization
713 wandStreamHelper = obtainWandStreamHelper(shared_from_this());
714 mWandStreamHelper = wandStreamHelper;
715 }
716 return wandStreamHelper;
717 }
718
727 const std::string& displayName,
728 std::chrono::milliseconds connectionPollInterval = std::chrono::milliseconds(100))
730
732 shared_from_this(), displayName, connectionPollInterval);
733 }
734
736 virtual ~Glasses() {
737 // Disconnect the glasses if they're connected
738 auto connectionState = getConnectionState();
739 if (!connectionState) {
740 return;
741 }
742
743 if (mGlasses) {
744 t5DestroyGlasses(&mGlasses);
745 mGlasses = nullptr;
746 }
747 }
749};
750
755private:
756 const std::shared_ptr<Glasses> mGlasses;
757 const std::string mDisplayName;
758 const std::chrono::milliseconds mConnectionPollInterval;
759 const std::chrono::milliseconds mConnectedPollInterval = mConnectionPollInterval * 10;
760
761 std::atomic<bool> mRunning{true};
762 std::thread mThread;
763
764 std::mutex mLastAsyncErrorMtx;
765 std::atomic<std::error_code> mLastAsyncError{};
766
767 void setLastAsyncError(std::error_code err) {
768 std::lock_guard<std::mutex> lock(mLastAsyncErrorMtx);
769 mLastAsyncError = err;
770 }
771
772 void threadMain() {
773 while (mRunning) {
774 auto connectionState = mGlasses->getConnectionState();
775 if (!connectionState) {
776 setLastAsyncError(connectionState.error());
777 std::this_thread::sleep_for(mConnectionPollInterval);
778 continue;
779 }
780
781 switch (*connectionState) {
783 // Attempt to connect
784 auto result = mGlasses->reserve(mDisplayName);
785 if (!result) {
786 setLastAsyncError(result.error());
787 }
788 // No action on success - the next call to getConnectionState() will
789 // detect the change
790
791 break;
792 }
793
796 auto result = mGlasses->ensureReady();
797 if (!result) {
798 setLastAsyncError(result.error());
799 }
800 // No action on success - the next call to getConnectionState() will
801 // detect the change
802
803 break;
804 }
805
807 // If we're connected, increase polling interval to reduce excessive
808 // connections state queries (at the expense of slowing detection of
809 // disconnected devices).
810 std::this_thread::sleep_for(mConnectedPollInterval);
811 break;
812 }
813
814 std::this_thread::sleep_for(mConnectionPollInterval);
815 }
816 }
817
819 const std::string& displayName,
820 std::chrono::milliseconds connectionPollInterval)
822
824 std::string displayName,
825 std::chrono::milliseconds connectionPollInterval)
826 : mGlasses(std::move(glasses))
827 , mDisplayName{std::move(displayName)}
828 , mConnectionPollInterval(connectionPollInterval) {
829
830 mThread = std::thread(&GlassesConnectionHelper::threadMain, this);
831 }
832
833public:
835 [[nodiscard]] auto glasses() -> Glasses& {
836 return *mGlasses;
837 }
838
841 auto connectionState = mGlasses->getConnectionState();
842 if (!connectionState) {
843 return connectionState.error();
844 }
845
846 while (*connectionState != ConnectionState::kConnected) {
847 std::this_thread::sleep_for(mConnectionPollInterval);
848
849 connectionState = mGlasses->getConnectionState();
850 if (!connectionState) {
851 return connectionState.error();
852 }
853 }
854
855 return kSuccess;
856 }
857
862 auto start = std::chrono::steady_clock::now();
863
864 auto connectionState = mGlasses->getConnectionState();
865 if (!connectionState) {
866 return connectionState.error();
867 }
868
869 while (*connectionState != ConnectionState::kConnected) {
870 if ((std::chrono::steady_clock::now() - start) > timeout) {
871 return Error::kTimeout;
872 }
873
874 std::this_thread::sleep_for(mConnectionPollInterval);
875
876 connectionState = mGlasses->getConnectionState();
877 if (!connectionState) {
878 return connectionState.error();
879 }
880 }
881
882 return kSuccess;
883 }
884
892 std::lock_guard<std::mutex> lock(mLastAsyncErrorMtx);
893 return mLastAsyncError.exchange({});
894 }
895
897 virtual ~GlassesConnectionHelper() {
898 mRunning = false;
899 if (mThread.joinable()) {
900 mThread.join();
901 }
902 }
904};
905
913class WandStreamHelper : public std::enable_shared_from_this<WandStreamHelper> {
914private:
915 friend Wand;
916
917 const std::shared_ptr<Glasses> mGlasses;
918 const std::chrono::milliseconds mPollTimeout;
919
920 std::atomic<bool> mWandListDirty{true};
921 std::mutex mWandListMtx; // guards access to mWandList
923
924 std::atomic<bool> mRunning{true};
925 std::thread mThread;
926
927 std::mutex mLastWandReportsMtx; // guards access to mLastWandReports
929
930 std::mutex mLastAsyncErrorMtx;
931 std::atomic<std::error_code> mLastAsyncError{};
932
933 void setLastAsyncError(std::error_code err) {
934 std::lock_guard<std::mutex> lock(mLastAsyncErrorMtx);
935 mLastAsyncError = err;
936 }
937
938 auto drainStream(const std::shared_ptr<Glasses>& glasses) -> Result<void> {
939 while (mRunning) {
940 auto result = glasses->readWandStream(mPollTimeout);
941 if (!result) {
942 return result.error();
943 }
944
945 std::lock_guard<std::mutex> lock{mLastWandReportsMtx};
946
947 // Process the event
948 switch (result->type) {
950 mLastWandReports[result->wandId] = {};
951 mWandListDirty = true;
952 break;
953
955 mLastWandReports.erase(result->wandId);
956 mWandListDirty = true;
957 break;
958
960 mWandListDirty = true;
961 break;
962
964 mLastWandReports[result->wandId] = result->report;
965 break;
966 }
967 }
968
969 return Error::kUnavailable;
970 }
971
972 // Update the reports map based on the latest wand list.
973 // Ensure empty reports are populated for newly-connected wands.
974 // Remove reports for wands that are no longer connected.
975 //
976 // PRECONDITIONS: Wand list mutex must be held.
977 auto refreshReports() -> void {
978 std::lock_guard<std::mutex> lock{mLastWandReportsMtx};
979
980 // Obtain a set of the wand handles held in mLastWandReports
981 std::set<T5_WandHandle> lastWandReportKeys;
982 std::transform(mLastWandReports.cbegin(),
983 mLastWandReports.cend(),
984 std::inserter(lastWandReportKeys, lastWandReportKeys.end()),
985 [](std::pair<T5_WandHandle, T5_WandReport> pair) { return pair.first; });
986
987 // Remove from the list all connected wands and add empty reports for new wands.
988 for (const auto& connectedWand : mWandList) {
989 lastWandReportKeys.erase(connectedWand);
990 mLastWandReports.insert({connectedWand, T5_WandReport{}});
991 }
992
993 // The remainder of the list is wand reports for disconnected wands - remove them
994 for (auto defunctKey : lastWandReportKeys) {
995 mLastWandReports.erase(defunctKey);
996 }
997 }
998
999 void threadMain() {
1000 T5_WandStreamConfig streamConfig{true};
1001 bool configured = false;
1002
1003 while (mRunning) {
1004 // Configure the stream if we haven't already
1005 if (!configured) {
1006 auto configureRequest = mGlasses->configureWandStream(&streamConfig);
1007 if (!configureRequest) {
1008 setLastAsyncError(configureRequest.error());
1010 continue;
1011 }
1012 configured = true;
1013 }
1014
1015 // Drain the stream
1016 auto result = drainStream(mGlasses);
1017 if ((result.error() != tiltfive::Error::kTimeout) &&
1018 (result.error() != tiltfive::Error::kUnavailable)) {
1019
1020 // For errors other than timeout, record it, small delay and loop
1021 setLastAsyncError(result.error());
1023 }
1024 }
1025
1026 // Disable the stream
1027 streamConfig.enabled = false;
1028 auto configureRequest = mGlasses->configureWandStream(&streamConfig);
1029 if (!configureRequest) {
1030 setLastAsyncError(configureRequest.error());
1031 }
1032
1033 // Flag as no longer running if we've exited due to error
1034 mRunning = false;
1035 }
1036
1037 friend inline auto obtainWandStreamHelper(std::shared_ptr<Glasses> glasses,
1038 std::chrono::milliseconds pollTimeout)
1040
1041 explicit WandStreamHelper(
1044 : mGlasses(std::move(glasses)), mPollTimeout(pollTimeout) {
1045
1046 mThread = std::thread(&WandStreamHelper::threadMain, this);
1047 }
1048
1049 auto getLatestReport(const T5_WandHandle& handle) -> Result<T5_WandReport> {
1050 std::lock_guard<std::mutex> lock{mLastWandReportsMtx};
1051
1052 auto report = mLastWandReports.find(handle);
1053 if (report == mLastWandReports.end()) {
1055 }
1056
1057 return report->second;
1058 };
1059
1060public:
1069 std::lock_guard<std::mutex> lock(mLastAsyncErrorMtx);
1070 return mLastAsyncError.exchange({});
1071 }
1072
1080 std::lock_guard<std::mutex> lock{mWandListMtx};
1081
1082 // Update the wand list if it's been invalidated
1083 if (mWandListDirty.exchange(false)) {
1084 auto result = mGlasses->listWands();
1085 if (!result) {
1086 mWandListDirty = true;
1087 return result.error();
1088 }
1089
1090 std::vector<T5_WandHandle> wandHandles;
1091 for (auto wandHandle : *result) {
1092 wandHandles.push_back(wandHandle);
1093 }
1094 mWandList = wandHandles;
1095
1096 refreshReports();
1097 }
1098
1099 // Realize wand list
1101 for (auto wandHandle : mWandList) {
1102 wands.push_back(obtainWand(wandHandle, shared_from_this()));
1103 }
1104
1105 return wands;
1106 };
1107
1109 virtual ~WandStreamHelper() {
1110 mRunning = false;
1111 if (mThread.joinable()) {
1112 mThread.join();
1113 }
1114 }
1116};
1117
1120public:
1123 virtual auto onSysParamChanged(const std::vector<T5_ParamSys>& changed) -> void = 0;
1124
1128 const std::vector<T5_ParamGlasses>& changed) -> void = 0;
1129
1131 virtual ~ParamChangeListener() = default;
1133};
1134
1138private:
1139 const std::shared_ptr<Client> mClient;
1140 const std::weak_ptr<ParamChangeListener> mChangeListener;
1141
1142 static constexpr size_t kDefaultSettingBufferSize = 16;
1143
1144 std::mutex mRegisteredGlassesMtx;
1145 std::set<std::shared_ptr<Glasses>> mRegisteredGlasses;
1146
1147 std::vector<T5_ParamSys> mChangedSysParams;
1148 std::vector<T5_ParamGlasses> mChangedGlassesParams;
1149
1150 std::chrono::milliseconds mPollInterval;
1151
1152 std::thread mThread;
1153 std::atomic<bool> mRunning{true};
1154
1155 std::mutex mLastAsyncErrorMtx;
1156 std::atomic<std::error_code> mLastAsyncError{};
1157
1158 void setLastAsyncError(std::error_code err) {
1159 std::lock_guard<std::mutex> lock(mLastAsyncErrorMtx);
1160 mLastAsyncError = err;
1161 }
1162
1165 std::chrono::milliseconds pollInterval)
1167
1170 std::chrono::milliseconds pollInterval)
1171 : mClient(std::move(client))
1172 , mChangeListener(std::move(listener))
1173 , mPollInterval(pollInterval) {
1174
1175 mThread = std::thread(&ParamChangeHelper::threadMain, this);
1176 }
1177
1178 auto checkGlassesParams(const std::shared_ptr<ParamChangeListener>& listener) -> void {
1179 std::lock_guard<std::mutex> lock(mRegisteredGlassesMtx);
1180 for (const auto& glasses : mRegisteredGlasses) {
1181 checkGlassesParams(glasses, listener);
1182 }
1183 }
1184
1185 auto checkGlassesParams(const std::shared_ptr<Glasses>& glasses,
1186 const std::shared_ptr<ParamChangeListener>& listener) -> void {
1187 uint16_t changeCount;
1188
1189 mChangedGlassesParams.resize(kDefaultSettingBufferSize);
1190 for (;;) {
1191 changeCount = mChangedGlassesParams.size();
1193 glasses->mGlasses, mChangedGlassesParams.data(), &changeCount);
1194
1195 if (!err) {
1196 if (changeCount > 0) {
1197 mChangedGlassesParams.resize(changeCount);
1198 listener->onGlassesParamChanged(glasses, mChangedGlassesParams);
1199 }
1200 break;
1201 }
1202
1203 // Error - increase buffer if we overflowed, or record the error and exit
1204 if (err == T5_ERROR_OVERFLOW) {
1205 mChangedSysParams.resize(mChangedSysParams.size() * 2);
1206 continue;
1207 }
1208
1209 setLastAsyncError(static_cast<Error>(err));
1210 break;
1211 }
1212 }
1213
1214 auto checkSysParams(const std::shared_ptr<ParamChangeListener>& listener) -> void {
1215 uint16_t changeCount;
1216
1217 mChangedSysParams.resize(kDefaultSettingBufferSize);
1218 for (;;) {
1219 changeCount = mChangedSysParams.size();
1220 T5_Result err =
1221 t5GetChangedSystemParams(mClient->mContext, mChangedSysParams.data(), &changeCount);
1222
1223 if (!err) {
1224 if (changeCount > 0) {
1225 mChangedSysParams.resize(changeCount);
1226 listener->onSysParamChanged(mChangedSysParams);
1227 }
1228 break;
1229 }
1230
1231 // Error - increase buffer if we overflowed, or record the error and exit
1232 if (err == T5_ERROR_OVERFLOW) {
1233 mChangedSysParams.resize(mChangedSysParams.size() * 2);
1234 continue;
1235 }
1236
1237 setLastAsyncError(static_cast<Error>(err));
1238 break;
1239 }
1240 }
1241
1242 auto threadMain() -> void {
1243 while (mRunning) {
1244 // Listener weak_ptr -> shared_ptr or exit
1245 {
1246 auto listener = mChangeListener.lock();
1247 if (!listener) {
1248 break;
1249 }
1250
1251 checkGlassesParams(listener);
1252
1253 checkSysParams(listener);
1254 }
1255
1256 std::this_thread::sleep_for(mPollInterval);
1257 }
1258 }
1259
1260public:
1262 virtual ~ParamChangeHelper() {
1263 mRunning = false;
1264 if (mThread.joinable()) {
1265 mThread.join();
1266 }
1267 }
1269
1278 std::lock_guard<std::mutex> lock(mLastAsyncErrorMtx);
1279 return mLastAsyncError.exchange({});
1280 }
1281
1283 auto registerGlasses(const std::shared_ptr<Glasses>& glasses) -> void {
1284 std::lock_guard<std::mutex> lock(mRegisteredGlassesMtx);
1285 mRegisteredGlasses.insert(glasses);
1286 }
1287
1289 auto deregisterGlasses(const std::shared_ptr<Glasses>& glasses) -> void {
1290 std::lock_guard<std::mutex> lock(mRegisteredGlassesMtx);
1291 mRegisteredGlasses.erase(glasses);
1292 }
1293};
1294
1297class Wand {
1298private:
1299 T5_WandHandle mHandle;
1300 std::shared_ptr<WandStreamHelper> mWandStreamHelper;
1301
1302 friend WandStreamHelper;
1303
1304 friend std::ostream& operator<<(std::ostream& os, std::shared_ptr<Wand> const& instance) {
1305 os << *instance;
1306 return os;
1307 }
1308
1309 friend std::ostream& operator<<(std::ostream& os, Wand const& instance) {
1310 os << "<Wand:" << +instance.mHandle << ">";
1311 return os;
1312 }
1313
1316
1318 : mHandle(handle), mWandStreamHelper(std::move(wandStreamHelper)) {}
1319
1320public:
1323 return mWandStreamHelper->getLatestReport(mHandle);
1324 }
1325
1327 [[nodiscard]] T5_WandHandle handle() const {
1328 return mHandle;
1329 }
1330};
1331
1341inline auto obtainClient(const std::string& applicationId,
1342 const std::string& applicationVersion,
1343 void* platformContext,
1344 const uint8_t sdkType = 0) -> Result<std::shared_ptr<Client>> {
1345
1346 return Client::create(applicationId, applicationVersion, platformContext, sdkType);
1347}
1348
1355inline auto obtainGlasses(const std::string& identifier, const std::shared_ptr<Client>& client)
1357 return Glasses::create(identifier, client);
1358}
1359
1362 std::chrono::milliseconds pollTimeout)
1364 return std::shared_ptr<WandStreamHelper>(new WandStreamHelper(std::move(glasses), pollTimeout));
1365}
1366
1370 return std::shared_ptr<Wand>(new Wand(handle, std::move(wandStreamHelper)));
1371}
1372
1375 const std::string& displayName,
1376 std::chrono::milliseconds connectionPollInterval)
1378
1380 new GlassesConnectionHelper(std::move(glasses), displayName, connectionPollInterval));
1381}
1382
1386 std::chrono::milliseconds pollInterval)
1388
1390 new ParamChangeHelper(std::move(client), std::move(listener), pollInterval));
1391}
1393
1395
1396} // namespace tiltfive
1397
1399
1402inline std::ostream& operator<<(std::ostream& os, const T5_WandReport& instance) {
1403 // Print the validity flags
1404 os << "[" << (instance.analogValid ? "A" : "_") << (instance.buttonsValid ? "B" : "_")
1405 << (instance.poseValid ? "P" : "_") << "]";
1406
1407 if (instance.analogValid) {
1408 os << "[A: " << std::right << std::fixed << std::setw(10) << instance.stick.x << "x"
1409 << std::right << std::fixed << std::setw(10) << instance.stick.y << " | " << std::right
1410 << std::fixed << std::setw(10) << instance.trigger << "]";
1411 } else {
1412 os << "[A: Invalid]";
1413 }
1414
1415 if (instance.buttonsValid) {
1416 os << "[B: " << (instance.buttons.t5 ? "T" : "_") << (instance.buttons.one ? "1" : "_")
1417 << (instance.buttons.two ? "2" : "_") << (instance.buttons.three ? "3" : "_")
1418 << (instance.buttons.a ? "A" : "_") << (instance.buttons.b ? "B" : "_")
1419 << (instance.buttons.x ? "X" : "_") << (instance.buttons.y ? "Y" : "_") << "]";
1420 } else {
1421 os << "[B: Invalid]";
1422 }
1423
1424 if (instance.poseValid) {
1425 os << "[P: (" << std::right << std::fixed << std::setw(10) << instance.posGrip_GBD.x << ","
1426 << std::right << std::fixed << std::setw(10) << instance.posGrip_GBD.y << ","
1427 << std::right << std::fixed << std::setw(10) << instance.posGrip_GBD.z << ") ("
1428 << std::right << std::fixed << std::setw(10) << instance.rotToWND_GBD.w << ","
1429 << std::right << std::fixed << std::setw(10) << instance.rotToWND_GBD.x << ","
1430 << std::right << std::fixed << std::setw(10) << instance.rotToWND_GBD.y << ","
1431 << std::right << std::fixed << std::setw(10) << instance.rotToWND_GBD.z << ")"
1432 << "]";
1433 }
1434
1435 return os;
1436}
1437
1441 std::string gameboardType;
1442 switch (instance.gameboardType) {
1444 gameboardType = "None";
1445 break;
1447 gameboardType = "LE";
1448 break;
1450 gameboardType = "XE";
1451 break;
1453 gameboardType = "XE (Raised)";
1454 break;
1455 default:
1456 // Shouldn't happen unless there's some bad casting going on elsewhere.
1457 gameboardType = std::string("[Invalid T5_GameboardType : ") +
1458 std::to_string(static_cast<int>(instance.gameboardType)) +
1459 std::string("]");
1460 break;
1461 }
1462
1463 os << "[" << instance.timestampNanos << "| " << gameboardType << " (" << std::right
1464 << std::fixed << std::setw(10) << instance.posGLS_GBD.x << "," << std::right << std::fixed
1465 << std::setw(10) << instance.posGLS_GBD.y << "," << std::right << std::fixed << std::setw(10)
1466 << instance.posGLS_GBD.z << ") (" << std::right << std::fixed << std::setw(10)
1467 << instance.rotToGLS_GBD.w << "," << std::right << std::fixed << std::setw(10)
1468 << instance.rotToGLS_GBD.x << "," << std::right << std::fixed << std::setw(10)
1469 << instance.rotToGLS_GBD.y << "," << std::right << std::fixed << std::setw(10)
1470 << instance.rotToGLS_GBD.z << ")"
1471 << "]";
1472
1473 return os;
1474}
1475
1478inline std::ostream& operator<<(std::ostream& os, const T5_ParamSys& instance) {
1479 switch (instance) {
1481 os << "Service Version";
1482 break;
1483
1485 os << "UI Attention Required";
1486 break;
1487
1488 default:
1489 // Shouldn't happen unless there's some bad casting going on elsewhere.
1490 os << "[Invalid T5_ParamSys : " << static_cast<int>(instance) << "]";
1491 break;
1492 }
1493
1494 return os;
1495}
1496
1500 switch (instance) {
1502 os << "IPD";
1503 break;
1504
1506 os << "Friendly Name";
1507 break;
1508
1509 default:
1510 // Shouldn't happen unless there's some bad casting going on elsewhere.
1511 os << "[Invalid T5_ParamGlasses : " << static_cast<int>(instance) << "]";
1512 break;
1513 }
1514
1515 return os;
1516}
1517
uint32_t T5_Result
Represents an error code that may be returned by the Tilt Five™ API.
Definition: errors.h:47
C++ errors for the Tilt Five™ API.
C++ Templated common return type for the Tilt Five™ API.
C interface definition for the Tilt Five™ API.
#define T5_ERROR_SETTING_UNKNOWN
The requested param is unknown.
Definition: errors.h:93
#define T5_SUCCESS
Success.
Definition: errors.h:54
#define T5_ERROR_OVERFLOW
Buffer overflow.
Definition: errors.h:102
Error
Error codes returned by most functions of return type Result.
Definition: errors.hpp:37
@ kStringOverflow
String overflow.
@ kTimeout
Timeout.
@ kInvalidArgument
Argument(s) are invalid.
@ kUnavailable
Target is unavailable.
@ kSuccess
Success.
@ kOverflow
Buffer overflow.
@ kTargetNotFound
Target (wand) not found.
@ kInternalError
An internal error occurred.
T5_EXPORT T5_Result t5CreateContext(T5_Context *context, const T5_ClientInfo *clientInfo, void *platformContext)
Create a context object.
T5_EXPORT void t5DestroyContext(T5_Context *context)
Destroy a context object.
T5_EXPORT T5_Result t5CreateGlasses(T5_Context context, const char *id, T5_Glasses *glasses)
Create a glasses access object.
T5_EXPORT T5_Result t5GetGameboardSize(T5_Context context, T5_GameboardType gameboardType, T5_GameboardSize *gameboardSize)
Get the gameboard dimensions.
T5_EXPORT void t5DestroyGlasses(T5_Glasses *glasses)
Destroy a glasses object.
T5_EXPORT T5_Result t5ListGlasses(T5_Context context, char *buffer, size_t *bufferSize)
Enumerate all glasses.
T5_EXPORT T5_Result t5GetSystemUtf8Param(T5_Context context, T5_ParamSys param, char *buffer, size_t *bufferSize)
Get a system-wide UTF-8 encoded string parameter.
T5_EXPORT T5_Result t5GetSystemIntegerParam(T5_Context context, T5_ParamSys param, int64_t *value)
Get a system-wide integer parameter.
T5_EXPORT T5_Result t5GetChangedSystemParams(T5_Context context, T5_ParamSys *buffer, uint16_t *count)
Get a system-wide list of changed parameters.
T5_EXPORT T5_Result t5CancelCamImageBuffer(T5_Glasses glasses, uint8_t *buffer)
Clear out the remaining buffers and return all buffers as a vector of camera images.
T5_EXPORT T5_Result t5GetFilledCamImageBuffer(T5_Glasses glasses, T5_CamImage *image)
T5_EXPORT T5_Result t5ReleaseGlasses(T5_Glasses glasses)
T5_EXPORT T5_Result t5ConfigureCameraStreamForGlasses(T5_Glasses glasses, T5_CameraStreamConfig config)
Configure the camera stream.
T5_EXPORT T5_Result t5SubmitEmptyCamImageBuffer(T5_Glasses glasses, T5_CamImage *image)
Submit an empty image buffer to be filled by the camera frame stream.
T5_EXPORT T5_Result t5GetGlassesConnectionState(T5_Glasses glasses, T5_ConnectionState *connectionState)
Get the exclusivity/connection status of the glasses.
T5_EXPORT T5_Result t5ReserveGlasses(T5_Glasses glasses, const char *displayName)
Reserve glasses for exclusive operations by the client.
T5_EXPORT T5_Result t5EnsureGlassesReady(T5_Glasses glasses)
Ensure that reserved glasses are ready for exclusive operations.
T5_EXPORT T5_Result t5SendFrameToGlasses(T5_Glasses glasses, const T5_FrameInfo *info)
Send a frame to display on the glasses.
T5_EXPORT T5_Result t5InitGlassesGraphicsContext(T5_Glasses glasses, T5_GraphicsApi graphicsApi, void *graphicsContext)
Initialize the graphics context to enable sending rendered frames to the glasses.
T5_EXPORT T5_Result t5GetGlassesPose(T5_Glasses glasses, T5_GlassesPoseUsage usage, T5_GlassesPose *pose)
Get the latest pose of the glasses.
T5_EXPORT T5_Result t5GetGlassesFloatParam(T5_Glasses glasses, T5_WandHandle wand, T5_ParamGlasses param, double *value)
Get a glasses floating point parameter.
T5_EXPORT T5_Result t5GetGlassesUtf8Param(T5_Glasses glasses, T5_WandHandle wand, T5_ParamGlasses param, char *buffer, size_t *bufferSize)
Get a glasses UTF-8 encoded string parameter.
T5_EXPORT T5_Result t5GetChangedGlassesParams(T5_Glasses glasses, T5_ParamGlasses *buffer, uint16_t *count)
Get a glasses-specific list of changed parameters.
T5_EXPORT T5_Result t5ReadWandStreamForGlasses(T5_Glasses glasses, T5_WandStreamEvent *event, uint32_t timeoutMs)
Read from the wands event stream.
T5_EXPORT T5_Result t5ListWandsForGlasses(T5_Glasses glasses, T5_WandHandle *buffer, uint8_t *count)
List available wands connected to this glasses.
T5_EXPORT T5_Result t5ConfigureWandStreamForGlasses(T5_Glasses glasses, const T5_WandStreamConfig *config)
Configure the wand event stream.
auto obtainParamChangeHelper(std::shared_ptr< Client > client, std::weak_ptr< ParamChangeListener > listener, std::chrono::milliseconds pollInterval) -> std::unique_ptr< ParamChangeHelper >
Internal utility function - Do not call directly.
auto obtainGlassesConnectionHelper(std::shared_ptr< Glasses > glasses, const std::string &displayName, std::chrono::milliseconds connectionPollInterval) -> std::unique_ptr< GlassesConnectionHelper >
Internal utility function - Do not call directly.
auto obtainClient(const std::string &applicationId, const std::string &applicationVersion, void *platformContext, const uint8_t sdkType=0) -> Result< std::shared_ptr< Client > >
Obtain an instance of the Tilt Five™ API client.
auto obtainWandStreamHelper(std::shared_ptr< Glasses > glasses, std::chrono::milliseconds pollTimeout) -> std::shared_ptr< WandStreamHelper >
Internal utility function - Do not call directly.
auto obtainGlasses(const std::string &identifier, const std::shared_ptr< Client > &client) -> Result< std::shared_ptr< Glasses > >
Obtain an instance of the Tilt Five™ Glasses.
auto obtainWand(T5_WandHandle handle, std::shared_ptr< WandStreamHelper > wandStreamHelper) -> std::shared_ptr< Wand >
Internal utility function - Do not call directly.
ConnectionState
Represents the exclusivity connection state of glasses.
@ kReserved
Glasses are reserved for exclusive use by this client.
@ kConnected
Glasses are connected for exclusive use by this client.
@ kDisconnected
Glasses were previously connected for exclusive use, but have now disconnected.
@ kNotExclusivelyConnected
Glasses have not been connected for exclusive use. They may still be connected to the host.
std::ostream & operator<<(std::ostream &os, const T5_WandReport &instance)
Support for writing T5_WandReport to an std::ostream.
#define T5_MAX_STRING_PARAM_LEN
The maximum number of characters allowed for string values.
Definition: types.h:38
T5_ConnectionState
Glasses connection state.
Definition: types.h:153
T5_ParamGlasses
Possible parameters that can be retrieved for glasses.
Definition: types.h:419
uint8_t T5_WandHandle
Opaque handle used with wands.
Definition: types.h:83
struct T5_ContextImpl * T5_Context
Opaque handle used with system-wide functions.
Definition: types.h:71
T5_GraphicsApi
Graphics API types.
Definition: types.h:86
T5_ParamSys
Possible parameters that can be retrieved with System-wide parameters.
Definition: types.h:429
T5_GameboardType
Possible gameboard types.
Definition: types.h:98
struct T5_GlassesImpl * T5_Glasses
Opaque handle used with glasses.
Definition: types.h:77
T5_GlassesPoseUsage
Glasses pose usage indicator.
Definition: types.h:168
@ kT5_ConnectionState_Disconnected
Glasses were previously exclusively connected, but the device has disconnected.
Definition: types.h:164
@ kT5_ConnectionState_ExclusiveConnection
Glasses are connected for exclusive use.
Definition: types.h:155
@ kT5_ConnectionState_NotExclusivelyConnected
Glasses have not been exclusively connected or reserved.
Definition: types.h:161
@ kT5_ConnectionState_ExclusiveReservation
Glasses are reserved for exclusive use.
Definition: types.h:158
@ kT5_ParamGlasses_Float_IPD
Interpupillary distance - Float, millimeters
Definition: types.h:422
@ kT5_ParamGlasses_UTF8_FriendlyName
User-facing name of the glasses - UTF8.
Definition: types.h:425
@ kT5_ParamSys_Integer_CPL_AttRequired
Non-zero if the control panel requires user interaction (E.g. Important firmware update) - Integer,...
Definition: types.h:435
@ kT5_ParamSys_UTF8_Service_Version
Version of the service software - UTF8.
Definition: types.h:431
@ kT5_GameboardType_LE
An LE gameboard.
Definition: types.h:103
@ kT5_GameboardType_XE
An XE gameboard, flap laid flat.
Definition: types.h:106
@ kT5_GameboardType_None
No gameboard.
Definition: types.h:100
@ kT5_GameboardType_XE_Raised
An XE gameboard, flap raised at an angle on the kickstand.
Definition: types.h:109
@ kT5_WandStreamEventType_Connect
Wand connected.
Definition: types.h:321
@ kT5_WandStreamEventType_Disconnect
Wand disconnected.
Definition: types.h:324
@ kT5_WandStreamEventType_Report
Wand report (Pose, Buttons, Trigger, Stick, Battery)
Definition: types.h:330
@ kT5_WandStreamEventType_Desync
Stream has desynchronized.
Definition: types.h:327
constexpr pair(piecewise_construct_t, tuple< _Args1... >, tuple< _Args2... >)
size_t start() const
valarray< size_t > size() const
constexpr _OutputIterator transform(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _UnaryOperation __unary_op)
constexpr _OI move(_II __first, _II __last, _OI __result)
void lock(_L1 &__l1, _L2 &__l2, _L3 &... __l3)
insert_iterator< _Container > inserter(_Container &__x, typename _Container::iterator __i)
basic_string< char > string
constexpr auto empty(const _Container &__cont) noexcept(noexcept(__cont.empty())) -> decltype(__cont.empty())
void sleep_for(const chrono::duration< _Rep, _Period > &__rtime)
Templated return type with support for error conditions.
Definition: result.hpp:37
Specialization of tiltfive::Result for functions with 'no return'.
Definition: result.hpp:199
Client for communicating with the Tilt Five™ API.
auto getServiceVersion() -> Result< std::string >
Get the version of the Tilt Five™ service.
auto getGameboardSize(T5_GameboardType type) -> Result< T5_GameboardSize >
Obtain the dimensions of the gameboard.
auto getChangedParams() -> Result< std::vector< T5_ParamSys > >
Get a system-wide list of changed parameters.
friend auto obtainClient(const std::string &applicationId, const std::string &applicationVersion, void *platformContext, const uint8_t sdkType) -> Result< std::shared_ptr< Client > >
Obtain an instance of the Tilt Five™ API client.
auto isTiltFiveUiRequestingAttention() -> Result< bool >
Check if the Tilt Five™ UI wants the users attention.
auto listGlasses() -> Result< std::vector< std::string > >
Enumerate glasses.
auto createParamChangedHelper(std::weak_ptr< ParamChangeListener > listener, std::chrono::milliseconds pollInterval=std::chrono::milliseconds(100)) -> std::unique_ptr< ParamChangeHelper >
Create a ParamChangeHelper.
Represents an instance of Tilt Five™ glasses.
auto initGraphicsContext(T5_GraphicsApi graphicsApi, void *graphicsContext) -> Result< void >
Initialize the glasses for graphics operations.
auto getIpd() -> Result< double >
Get the current IPD setting for this glasses.
auto getFilledCamImageBuffer() -> Result< T5_CamImage >
Get the latest camera image for this glasses.
auto getChangedParams() -> Result< std::vector< T5_ParamGlasses > >
Get a system-wide list of changed parameters.
auto release() -> Result< void >
Release previously-reserved glasses.
auto submitEmptyCamImageBuffer(T5_CamImage *imgBuffer) -> Result< void >
Submit a buffer to the camera image stream to hold Camera Frame data.
auto sendFrame(const T5_FrameInfo *const frameInfo) -> Result< void >
Send a frame to display on the glasses.
auto configureWandStream(const T5_WandStreamConfig *const config) -> Result< void >
Configure the wand event stream.
auto getLatestGlassesPose(T5_GlassesPoseUsage usage) -> Result< T5_GlassesPose >
Get the latest pose for this glasses.
friend auto obtainGlasses(const std::string &identifier, const std::shared_ptr< Client > &client) -> Result< std::shared_ptr< Glasses > >
Obtain an instance of the Tilt Five™ Glasses.
auto cancelCamImageBuffer(uint8_t *buffer) -> Result< void >
Cancel an image buffer in use by the service for freeing.
auto readWandStream(std::chrono::milliseconds timeout=std::chrono::milliseconds(100)) -> Result< T5_WandStreamEvent >
Read from the wands event stream.
auto reserve(const std::string &displayName) -> Result< void >
Reserve glasses for exclusive operations by the client.
auto configureCameraStream(T5_CameraStreamConfig config) -> Result< void >
Configure the wand event stream.
auto getConnectionState() -> Result< ConnectionState >
Get the current connection state of the glasses.
auto listWands() -> Result< std::vector< T5_WandHandle > >
Obtain a list of connected wands.
auto createConnectionHelper(const std::string &displayName, std::chrono::milliseconds connectionPollInterval=std::chrono::milliseconds(100)) -> std::unique_ptr< GlassesConnectionHelper >
Create a GlassesConnectionHelper.
auto getWandStreamHelper() -> std::shared_ptr< WandStreamHelper >
Get a WandStreamHelper.
auto getIdentifier() const -> std::string
Obtain a hardware (not user facing) identifier for the glasses.
auto ensureReady() -> Result< void >
Ensure that reserved glasses are ready for exclusive operations.
auto getFriendlyName() -> Result< std::string >
Get the user-facing name of the glasses.
Utility class to automate the Glasses exclusive connection process.
auto awaitConnection(const std::chrono::milliseconds timeout) -> Result< void >
Block until a connection is established or timed out.
auto awaitConnection() -> Result< void >
Block until a connection is established.
auto glasses() -> Glasses &
Obtain a reference to the wrapped tiltfive::Glasses object.
friend auto obtainGlassesConnectionHelper(std::shared_ptr< Glasses > glasses, const std::string &displayName, std::chrono::milliseconds connectionPollInterval) -> std::unique_ptr< GlassesConnectionHelper >
Internal utility function - Do not call directly.
auto consumeLastAsyncError() -> std::error_code
Obtain and consume the last asynchronous error.
Utility class to manage the wand stream.
auto listWands() -> Result< std::vector< std::shared_ptr< Wand > > >
Obtain a list of tiltfive::Wand.
friend auto obtainWandStreamHelper(std::shared_ptr< Glasses > glasses, std::chrono::milliseconds pollTimeout) -> std::shared_ptr< WandStreamHelper >
Internal utility function - Do not call directly.
auto consumeLastAsyncError() -> std::error_code
Obtain and consume the last asynchronous error.
Virtual base class for use with tiltfive::ParamChangeHelper.
virtual auto onSysParamChanged(const std::vector< T5_ParamSys > &changed) -> void=0
Called by a tiltfive::ParamChangeHelper when system-wide (T5_ParamSys) params have changed.
virtual auto onGlassesParamChanged(const std::shared_ptr< Glasses > &glasses, const std::vector< T5_ParamGlasses > &changed) -> void=0
Called by a tiltfive::ParamChangeHelper when glasses specific (T5_ParamGlasses) params have changed.
Utility class to track changes to parameters Using ParamChangeHelper.
auto registerGlasses(const std::shared_ptr< Glasses > &glasses) -> void
Register glasses for parameter change tracking.
friend auto obtainParamChangeHelper(std::shared_ptr< Client > client, std::weak_ptr< ParamChangeListener > listener, std::chrono::milliseconds pollInterval) -> std::unique_ptr< ParamChangeHelper >
Internal utility function - Do not call directly.
auto deregisterGlasses(const std::shared_ptr< Glasses > &glasses) -> void
De-register glasses for parameter change tracking.
auto consumeLastAsyncError() -> std::error_code
Obtain and consume the last asynchronous error.
Represents an abstract instance of a Tilt Five™ wand Used with tiltfive::WandStreamHelper.
T5_WandHandle handle() const
Get the wand handle.
friend auto obtainWand(T5_WandHandle handle, std::shared_ptr< WandStreamHelper > wandStreamHelper) -> std::shared_ptr< Wand >
Internal utility function - Do not call directly.
auto getLatestReport() const -> Result< T5_WandReport >
Get the latest wand report for this wand.
Physical dimensions of a gameboard.
Definition: types.h:113
Client provided information for use with t5CreateGlasses()
Definition: types.h:136
uint8_t sdkType
The SDK type.
Definition: types.h:146
const char * applicationId
The application ID.
Definition: types.h:138
const char * applicationVersion
The application version.
Definition: types.h:141
Glasses pose information to be retrieved with t5GetGlassesPose()
Definition: types.h:199
uint64_t timestampNanos
The timestamp of the pose.
Definition: types.h:201
T5_Vec3 posGLS_GBD
The position of the origin of the GLS (glasses) frame relative to the GBD (gameboard) frame.
Definition: types.h:205
T5_Quat rotToGLS_GBD
The rotation that transforms points in the GBD (gameboard) frame orientation to the GLS (glasses) fra...
Definition: types.h:209
T5_GameboardType gameboardType
The type of gameboard visible for this pose.
Definition: types.h:212
Camera stream configuration.
Definition: types.h:216
Render information to be used with t5SendFrameToGlasses()
Definition: types.h:225
Camera Frame information to be retrieved with t5GetFilledCamImageBuffer()
Definition: types.h:276
Wand stream configuration.
Definition: types.h:312
Contains wand related information (Pose, Buttons, Trigger, Stick, Battery)
Definition: types.h:346
bool poseValid
Validity of pose parameters. True = valid.
Definition: types.h:360
T5_Quat rotToWND_GBD
WND/GBD rotation unit quaternion.
Definition: types.h:388
struct T5_WandReport::@5 buttons
Buttons state. True = Pressed.
T5_Vec3 posGrip_GBD
Position (Grip) - Vector3f.
Definition: types.h:397
float trigger
Trigger - Analog, Range [0.0 - 1.0], 1.0 = Fully depressed.
Definition: types.h:363
bool analogValid
Validity of analog parameters. True = valid.
Definition: types.h:351
bool buttonsValid
Validity of button parameters. True = valid.
Definition: types.h:357
T5_Vec2 stick
Stick (X/Y) - Analog, Range [-1.0 - 1.0], 0 = Centered, 1.0 = Top/Right.
Definition: types.h:366
Represents an event from the wand stream.
Definition: types.h:404
const char * c_str() const noexcept
size_type length() const noexcept
void insert(_InputIterator __first, _InputIterator __last)
const_iterator end() const noexcept
const_iterator cend() const noexcept
size_type erase(const key_type &__x)
iterator find(const key_type &__x)
const_iterator cbegin() const noexcept
iterator end() const noexcept
void insert(_InputIterator __first, _InputIterator __last)
size_type erase(const key_type &__x)
void resize(size_type __new_size)
void push_back(const value_type &__x)
void reserve(size_type __n)
_Tp * data() noexcept
size_type size() const noexcept
pointer get() const noexcept