| Tilt Five NDK |

sample.cpp
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
19
21
22#include "include/TiltFiveNative.hpp"
23
24#include <chrono>
25#include <iostream>
26
28 using Client = std::shared_ptr<tiltfive::Client>;
30 using Glasses = std::shared_ptr<tiltfive::Glasses>;
32 using Wand = std::shared_ptr<tiltfive::Wand>;
33
34// Shim C++14 chrono_literals ms
35 constexpr std::chrono::milliseconds operator""_ms(unsigned long long ms) {
36 return std::chrono::milliseconds(ms);
37}
38
40//
44 auto waitForGlasses(Client& client) -> tiltfive::Result<Glasses> {
45 std::cout << "Looking for glasses..." << std::flush;
46
47 // Loop until we find glasses
48 auto glassesList = client->listGlasses();
49 if (!glassesList) {
50 return glassesList.error();
51 }
52 while (glassesList->empty()) {
53 std::cout << "." << std::flush;
54 std::this_thread::sleep_for(100_ms);
55
56 // Request a list of the available glasses
57 glassesList = client->listGlasses();
58 if (!glassesList) {
59 return glassesList.error();
60 }
61 }
62
63 // Print out the found glasses
64 for (auto& glassesInstance : *glassesList) {
65 std::cout << "Found : " << glassesInstance << std::endl;
66 }
67
68 // Return the first found glasses
69 return tiltfive::obtainGlasses(glassesList->front(), client);
70}
72
73 auto doThingsWithWands(const Wand& wand) -> tiltfive::Result<void> {
74 std::cout << "Doing something with wand : " << wand << std::endl;
75
76 auto start = std::chrono::steady_clock::now();
77 do {
78 auto report = wand->getLatestReport();
79 std::cout << "\r" << report;
80 } while ((std::chrono::steady_clock::now() - start) < 10000_ms);
81
82 std::cout << std::endl << "Done with wand" << std::endl;
83
84 return tiltfive::kSuccess;
85}
86
87 auto waitForWand(Glasses& glasses) -> tiltfive::Result<Wand> {
88 std::cout << "Looking for wand..." << std::flush;
89
90 auto wandHelper = glasses->getWandStreamHelper();
91
92 for (;;) {
93 auto wands = wandHelper->listWands();
94 if (wands) {
95 if (!wands->empty()) {
96 std::cout << "Found : " << wands->front() << std::endl;
97 return wands->front();
98 }
99 } else {
100 std::cerr << "Error listing wands : " << wands << std::endl;
101 return wands.error();
102 }
103
104 std::cout << "." << std::flush;
105 std::this_thread::sleep_for(100_ms);
106 }
107}
108
110 auto readPoses(Glasses& glasses) -> tiltfive::Result<void> {
111 auto start = std::chrono::steady_clock::now();
112 do {
113 auto pose = glasses->getLatestGlassesPose(kT5_GlassesPoseUsage_GlassesPresentation);
114 if (!pose) {
115 if (pose.error() == tiltfive::Error::kTryAgain) {
116 std::cout << "\rPose unavailable - Is gameboard visible? ";
117 } else {
118 return pose.error();
119 }
120 } else {
121 std::cout << "\r" << pose;
122 }
123 } while ((std::chrono::steady_clock::now() - start) < 10000_ms);
124
125 return tiltfive::kSuccess;
126}
128
129 auto doThingsWithGlasses(Glasses& glasses) -> tiltfive::Result<void> {
130 std::cout << "Doing something with : " << glasses << std::endl;
131
133 // Get the friendly name for the glasses
134 // This is the name that's user set in the Tilt Five™ control panel.
135 auto friendlyName = glasses->getFriendlyName();
136 if (friendlyName) {
137 std::cout << "Obtained friendly name : " << friendlyName << std::endl;
138 } else if (friendlyName.error() == tiltfive::Error::kSettingUnknown) {
139 std::cerr << "Couldn't get friendly name : Service reports it's not set" << std::endl;
140 } else {
141 std::cerr << "Error obtaining friendly name : " << friendlyName << std::endl;
142 }
143
144 // Get the IPD for the glasses
145 // This is user set IPD in the Tilt Five™ control panel.
146 auto ipd = glasses->getIpd();
147 if (ipd) {
148 std::cout << "Obtained IPD : " << ipd << "m" << std::endl;
149 } else if (ipd.error() == tiltfive::Error::kSettingUnknown) {
150 std::cerr << "Couldn't get IPD : Service reports it's not set" << std::endl;
151 } else {
152 std::cerr << "Error obtaining IPD : " << ipd << std::endl;
153 return ipd.error();
154 }
156
157 // Wait for a wand to connect
158 auto wand = waitForWand(glasses);
159 if (wand) {
160 auto result = doThingsWithWands(*wand);
161 if (!result) {
162 std::cerr << "Error doing things with wands : " << result << std::endl;
163 return result.error();
164 }
165 } else {
166 std::cerr << "Error waiting for wand : " << wand << std::endl;
167 return wand.error();
168 }
169
170 {
172 // Wait for exclusive glasses connection
173 auto connectionHelper = glasses->createConnectionHelper("Awesome game - Player 1");
174 auto connectionResult = connectionHelper->awaitConnection(10000_ms);
175 if (connectionResult) {
176 std::cout << "Glasses connected for exclusive use" << std::endl;
177 } else {
178 std::cerr << "Error connecting glasses for exclusive use : " << connectionResult
179 << std::endl;
180 return connectionResult.error();
181 }
183
184 // Reading poses
185 auto result = readPoses(glasses);
186 if (!result) {
187 std::cerr << "Error reading poses : " << result << std::endl;
188 return result.error();
189 }
190 }
191
192 // The connectionHelper is destroyed at the end of the previous scope, but the glasses are still
193 // reserved. Let's release them, then confirm that exclusive ops such as reading poses fails.
194 auto releaseResult = glasses->release();
195 if (!releaseResult) {
196 std::cerr << "Failed to release glasses : " << releaseResult << std::endl;
197 return releaseResult.error();
198 }
199 auto readPosesResult = readPoses(glasses);
200 if (readPosesResult) {
201 std::cerr << "Reading poses unexpectedly succeeded after glasses release\n";
202 } else if (readPosesResult.error() != tiltfive::Error::kNotConnected) {
203 std::cerr << "Unexpected pose read error: " << readPosesResult << "\n";
204 }
205
206 std::cout << std::endl << "Done with glasses" << std::endl;
207
208 return tiltfive::kSuccess;
209}
210
212 auto printGameboardDimensions(Client& client) -> tiltfive::Result<void> {
213 auto result = client->getGameboardSize(kT5_GameboardType_LE);
214 if (!result) {
215 return result.error();
216 }
217
218 float width = result->viewableExtentPositiveX + result->viewableExtentNegativeX;
219 float length = result->viewableExtentPositiveY + result->viewableExtentNegativeY;
220 float height = result->viewableExtentPositiveZ;
221
222 std::cout << "LE Gameboard size : " << width << "m x " << length << "m x " << height << "m"
223 << std::endl;
224
225 return tiltfive::kSuccess;
226}
227
229 auto printServiceVersion(Client& client) -> tiltfive::Result<void> {
230 auto result = client->getServiceVersion();
231 if (!result) {
232 return result.error();
233 }
234
235 std::cout << "Service version : " << result << std::endl;
236 return tiltfive::kSuccess;
237}
240
241 auto printUiStatusFlags(Client& client) -> tiltfive::Result<void> {
242 auto result = client->isTiltFiveUiRequestingAttention();
243 if (!result) {
244 return result.error();
245 }
246 std::cout << "Tilt Five UI (Attention Requested) : " << ((*result) ? "TRUE" : "FALSE")
247 << std::endl;
248
249 return tiltfive::kSuccess;
250}
251
253// Convenience function to repeatedly call another function if it returns 'service unavailable'
254 template <typename T>
255 auto waitForService(Client& client, const std::function<tiltfive::Result<T>(Client& client)>& func)
256 -> tiltfive::Result<T> {
257
258 bool waitingForService = false;
259 for (;;) {
260 auto result = func(client);
261 if (result) {
262 return result;
263 } else if (result.error() != tiltfive::Error::kNoService) {
264 return result.error();
265 }
266
267 std::cout << (waitingForService ? "." : "Waiting for service...") << std::flush;
268 waitingForService = true;
269 std::this_thread::sleep_for(100_ms);
270 }
271}
273
274 class MyParamChangeListener : public tiltfive::ParamChangeListener {
275 auto onSysParamChanged(const std::vector<T5_ParamSys>& changed) -> void override {
276 for (const auto& param : changed) {
277 std::cout << "System Parameter changed : [" << param << "]" << std::endl;
278 }
279 }
280
281 auto onGlassesParamChanged(const Glasses& glasses, const std::vector<T5_ParamGlasses>& changed)
282 -> void override {
283 for (const auto& param : changed) {
284 std::cout << "Glasses Parameter changed : " << glasses << " => [" << param << "]"
285 << std::endl;
286 }
287 }
288};
289
290 int main(int /* argc */, char** /* argv */) {
292 // Create the client
293 auto client = tiltfive::obtainClient("com.tiltfive.test", "0.1.0", nullptr);
294 if (!client) {
295 std::cerr << "Failed to create client : " << client << std::endl;
296 std::exit(EXIT_FAILURE);
297 }
298 std::cout << "Obtained client : " << client << std::endl;
300
301 // Create a parameter change helper
302 std::shared_ptr<MyParamChangeListener> paramChangeListener(new MyParamChangeListener());
303 auto paramChangeHelper = (*client)->createParamChangedHelper(paramChangeListener);
304
305 // Get the gameboard dimensions
306 auto result = printGameboardDimensions(*client);
307 if (!result) {
308 std::cerr << "Failed to print gameboard dimensions : " << result << std::endl;
309 std::exit(EXIT_FAILURE);
310 }
311
312 // Get the service version
314 result = waitForService<void>(*client, printServiceVersion);
315 if (!result) {
316 std::cerr << "Failed to get service version : " << result << std::endl;
317 std::exit(EXIT_FAILURE);
318 }
320
321 // Get the UI flags
322 result = waitForService<void>(*client, printUiStatusFlags);
323 if (!result) {
324 std::cerr << "Failed to print UI status flags : " << result << std::endl;
325 std::exit(EXIT_FAILURE);
326 }
327
328 // Wait for glasses
329 {
330 auto glasses = waitForService<Glasses>(*client, waitForGlasses);
331 if (!glasses) {
332 std::cerr << "Failed to wait for glasses : " << glasses << std::endl;
333 std::exit(EXIT_FAILURE);
334 }
335
336 // Add the glasses to the parameter change listener
337 paramChangeHelper->registerGlasses(*glasses);
338
339 // Do things with the glasses
340 result = doThingsWithGlasses(*glasses);
341 if (!result) {
342 std::cerr << "Failed to do things with glasses : " << result << std::endl;
343 }
344 }
345
346 std::cout << "Waiting a little..." << std::endl;
347 std::this_thread::sleep_for(5000_ms);
348
349 std::cout << "ALL DONE!" << std::endl;
350}
tiltfive::kSuccess
static constexpr success_t kSuccess
Indicates 'success' for a Result<void> function.
Definition: result.hpp:324
tiltfive::Error::kTryAgain
@ kTryAgain
Target is temporarily unavailable.
tiltfive::Error::kNotConnected
@ kNotConnected
Target is not connected.
tiltfive::Error::kSettingUnknown
@ kSettingUnknown
The requested param is unknown.
tiltfive::Error::kNoService
@ kNoService
Service isn't connected.
tiltfive::obtainClient
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.
Definition: TiltFiveNative.hpp:1351
tiltfive::obtainGlasses
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.
Definition: TiltFiveNative.hpp:1365
kT5_GameboardType_LE
@ kT5_GameboardType_LE
An LE gameboard.
Definition: types.h:103
kT5_GlassesPoseUsage_GlassesPresentation
@ kT5_GlassesPoseUsage_GlassesPresentation
The pose will be used to render images to be presented on the glasses.
Definition: types.h:176
chrono
iostream
std::chrono::milliseconds
duration< int64_t, milli > milliseconds
start
size_t start() const
std::cerr
ostream cerr
std::endl
basic_ostream< _CharT, _Traits > & endl(basic_ostream< _CharT, _Traits > &__os)
std::flush
basic_ostream< _CharT, _Traits > & flush(basic_ostream< _CharT, _Traits > &__os)
std::cout
ostream cout
std::this_thread::sleep_for
void sleep_for(const chrono::duration< _Rep, _Period > &__rtime)
std::chrono::duration
tiltfive::Result
Templated return type with support for error conditions.
Definition: result.hpp:37
tiltfive::Result< void >
Specialization of tiltfive::Result for functions with 'no return'.
Definition: result.hpp:199
tiltfive::ParamChangeListener
Virtual base class for use with tiltfive::ParamChangeHelper.
Definition: TiltFiveNative.hpp:1129
tiltfive::ParamChangeListener::onSysParamChanged
virtual auto onSysParamChanged(const std::vector< T5_ParamSys > &changed) -> void=0
Called by a tiltfive::ParamChangeHelper when system-wide (T5_ParamSys) params have changed.
tiltfive::ParamChangeListener::onGlassesParamChanged
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.
std::shared_ptr< tiltfive::Client >
std::vector< T5_ParamSys >