Tilt Five NDK
sample.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2020-2023 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
33
34// Shim C++14 chrono_literals ms
35constexpr std::chrono::milliseconds operator""_ms(unsigned long long ms) {
37}
38
40//
44auto 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;
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
73auto 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
87auto 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;
106 }
107}
108
110auto 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 std::cout << "\n";
126
127 start = std::chrono::steady_clock::now();
128 do {
129 auto poses = glasses->getLatestGameboardPoses();
130 if (!poses) {
131 if (poses.error() == tiltfive::Error::kTryAgain) {
132 std::cout << "\rGameboard poses unavailable - Is gameboard visible? "
133 " ";
134 } else {
135 return poses.error();
136 }
137 } else {
138 for (auto& pose : *poses) {
139 std::cout << "\r" << pose;
140 }
141 }
142 } while ((std::chrono::steady_clock::now() - start) < 10000_ms);
143
144 return tiltfive::kSuccess;
145}
147
148auto doThingsWithGlasses(Glasses& glasses) -> tiltfive::Result<void> {
149 std::cout << "Doing something with : " << glasses << std::endl;
150
152 // Get the friendly name for the glasses
153 // This is the name that's user set in the Tilt Five™ control panel.
154 auto friendlyName = glasses->getFriendlyName();
155 if (friendlyName) {
156 std::cout << "Obtained friendly name : " << friendlyName << std::endl;
157 } else if (friendlyName.error() == tiltfive::Error::kSettingUnknown) {
158 std::cerr << "Couldn't get friendly name : Service reports it's not set" << std::endl;
159 } else {
160 std::cerr << "Error obtaining friendly name : " << friendlyName << std::endl;
161 }
162
163 // Get the IPD for the glasses
164 // This is user set IPD in the Tilt Five™ control panel.
165 auto ipd = glasses->getIpd();
166 if (ipd) {
167 std::cout << "Obtained IPD : " << ipd << "m" << std::endl;
168 } else if (ipd.error() == tiltfive::Error::kSettingUnknown) {
169 std::cerr << "Couldn't get IPD : Service reports it's not set" << std::endl;
170 } else {
171 std::cerr << "Error obtaining IPD : " << ipd << std::endl;
172 return ipd.error();
173 }
175
176 // Wait for a wand to connect
177 auto wand = waitForWand(glasses);
178 if (wand) {
179 auto result = doThingsWithWands(*wand);
180 if (!result) {
181 std::cerr << "Error doing things with wands : " << result << std::endl;
182 return result.error();
183 }
184 } else {
185 std::cerr << "Error waiting for wand : " << wand << std::endl;
186 return wand.error();
187 }
188
189 {
191 // Wait for exclusive glasses connection
192 auto connectionHelper = glasses->createConnectionHelper("Awesome game - Player 1");
193 auto connectionResult = connectionHelper->awaitConnection(10000_ms);
194 if (connectionResult) {
195 std::cout << "Glasses connected for exclusive use" << std::endl;
196 } else {
197 std::cerr << "Error connecting glasses for exclusive use : " << connectionResult
198 << std::endl;
199 return connectionResult.error();
200 }
202
203 // Reading poses
204 auto result = readPoses(glasses);
205 if (!result) {
206 std::cerr << "Error reading poses : " << result << std::endl;
207 return result.error();
208 }
209 }
210
211 // The connectionHelper is destroyed at the end of the previous scope, but the glasses are still
212 // reserved. Let's release them, then confirm that exclusive ops such as reading poses fails.
213 auto releaseResult = glasses->release();
214 if (!releaseResult) {
215 std::cerr << "Failed to release glasses : " << releaseResult << std::endl;
216 return releaseResult.error();
217 }
218 auto readPosesResult = readPoses(glasses);
219 if (readPosesResult) {
220 std::cerr << "Reading poses unexpectedly succeeded after glasses release\n";
221 } else if (readPosesResult.error() != tiltfive::Error::kNotConnected) {
222 std::cerr << "Unexpected pose read error: " << readPosesResult << "\n";
223 }
224
225 std::cout << std::endl << "Done with glasses" << std::endl;
226
227 return tiltfive::kSuccess;
228}
229
231auto printGameboardDimensions(Client& client) -> tiltfive::Result<void> {
232 auto result = client->getGameboardSize(kT5_GameboardType_LE);
233 if (!result) {
234 return result.error();
235 }
236
237 float width = result->viewableExtentPositiveX + result->viewableExtentNegativeX;
238 float length = result->viewableExtentPositiveY + result->viewableExtentNegativeY;
239 float height = result->viewableExtentPositiveZ;
240
241 std::cout << "LE Gameboard size : " << width << "m x " << length << "m x " << height << "m"
242 << std::endl;
243
244 return tiltfive::kSuccess;
245}
246
248auto printServiceVersion(Client& client) -> tiltfive::Result<void> {
249 auto result = client->getServiceVersion();
250 if (!result) {
251 return result.error();
252 }
253
254 std::cout << "Service version : " << result << std::endl;
255 return tiltfive::kSuccess;
256}
259
260auto printUiStatusFlags(Client& client) -> tiltfive::Result<void> {
261 auto result = client->isTiltFiveUiRequestingAttention();
262 if (!result) {
263 return result.error();
264 }
265 std::cout << "Tilt Five UI (Attention Requested) : " << ((*result) ? "TRUE" : "FALSE")
266 << std::endl;
267
268 return tiltfive::kSuccess;
269}
270
272// Convenience function to repeatedly call another function if it returns 'service unavailable'
273template <typename T>
274auto waitForService(Client& client, const std::function<tiltfive::Result<T>(Client& client)>& func)
276
277 bool waitingForService = false;
278 for (;;) {
279 auto result = func(client);
280 if (result) {
281 return result;
282 } else if (result.error() != tiltfive::Error::kNoService) {
283 return result.error();
284 }
285
286 std::cout << (waitingForService ? "." : "Waiting for service...") << std::flush;
287 waitingForService = true;
289 }
290}
292
293class MyParamChangeListener : public tiltfive::ParamChangeListener {
294 auto onSysParamChanged(const std::vector<T5_ParamSys>& changed) -> void override {
295 for (const auto& param : changed) {
296 std::cout << "System Parameter changed : [" << param << "]" << std::endl;
297 }
298 }
299
300 auto onGlassesParamChanged(const Glasses& glasses, const std::vector<T5_ParamGlasses>& changed)
301 -> void override {
302 for (const auto& param : changed) {
303 std::cout << "Glasses Parameter changed : " << glasses << " => [" << param << "]"
304 << std::endl;
305 }
306 }
307};
308
309int main(int /* argc */, char** /* argv */) {
311 // Create the client
312 auto client = tiltfive::obtainClient("com.tiltfive.test", "0.1.0", nullptr);
313 if (!client) {
314 std::cerr << "Failed to create client : " << client << std::endl;
315 std::exit(EXIT_FAILURE);
316 }
317 std::cout << "Obtained client : " << client << std::endl;
319
320 // Create a parameter change helper
321 std::shared_ptr<MyParamChangeListener> paramChangeListener(new MyParamChangeListener());
322 auto paramChangeHelper = (*client)->createParamChangedHelper(paramChangeListener);
323
324 // Get the gameboard dimensions
325 auto result = printGameboardDimensions(*client);
326 if (!result) {
327 std::cerr << "Failed to print gameboard dimensions : " << result << std::endl;
328 std::exit(EXIT_FAILURE);
329 }
330
331 // Get the service version
333 result = waitForService<void>(*client, printServiceVersion);
334 if (!result) {
335 std::cerr << "Failed to get service version : " << result << std::endl;
336 std::exit(EXIT_FAILURE);
337 }
339
340 // Get the UI flags
341 result = waitForService<void>(*client, printUiStatusFlags);
342 if (!result) {
343 std::cerr << "Failed to print UI status flags : " << result << std::endl;
344 std::exit(EXIT_FAILURE);
345 }
346
347 // Wait for glasses
348 {
349 auto glasses = waitForService<Glasses>(*client, waitForGlasses);
350 if (!glasses) {
351 std::cerr << "Failed to wait for glasses : " << glasses << std::endl;
352 std::exit(EXIT_FAILURE);
353 }
354
355 // Add the glasses to the parameter change listener
356 paramChangeHelper->registerGlasses(*glasses);
357
358 // Do things with the glasses
359 result = doThingsWithGlasses(*glasses);
360 if (!result) {
361 std::cerr << "Failed to do things with glasses : " << result << std::endl;
362 }
363 }
364
365 std::cout << "Waiting a little..." << std::endl;
367
368 std::cout << "ALL DONE!" << std::endl;
369}
static constexpr success_t kSuccess
Indicates 'success' for a Result<void> function.
Definition: result.hpp:324
@ kTryAgain
Target is temporarily unavailable.
@ kNotConnected
Target is not connected.
@ kSettingUnknown
The requested param is unknown.
@ kNoService
Service isn't connected.
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 obtainGlasses(const std::string &identifier, const std::shared_ptr< Client > &client) -> Result< std::shared_ptr< Glasses > >
Obtain an instance of the Tilt Five™ Glasses.
@ kT5_GameboardType_LE
An LE gameboard.
Definition: types.h:262
@ kT5_GlassesPoseUsage_GlassesPresentation
The pose will be used to render images to be presented on the glasses.
Definition: types.h:335
duration< int64_t, milli > milliseconds
size_t start() const
ostream cerr
basic_ostream< _CharT, _Traits > & endl(basic_ostream< _CharT, _Traits > &__os)
basic_ostream< _CharT, _Traits > & flush(basic_ostream< _CharT, _Traits > &__os)
ostream cout
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
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.