Tilt Five NDK
sample.c
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#ifdef _WIN32
23#include <windows.h>
24#define SLEEP(ms) Sleep(ms)
25#elif __unix
26// For linux, OSX, and other unixes
27#define _POSIX_C_SOURCE 199309L // or greater
28#include <time.h>
29#define SLEEP(ms) \
30 do { \
31 struct timespec ts; \
32 ts.tv_sec = (ms) / 1000; \
33 ts.tv_nsec = (ms) % 1000 * 1000000; \
34 nanosleep(&ts, NULL); \
35 } while (0)
36#else
37#warning Unsupported platform - sleep unavailable, code may run too fast
38#define SLEEP(ms) \
39 {}
40#endif
41
42#include "include/TiltFiveNative.h"
43
44#include <assert.h>
45#include <stdbool.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49
50#define IDENTIFIER_BUFFER_SIZE 1024
51#define GLASSES_BUFFER_SIZE 1024
52#define PARAM_BUFFER_SIZE 1024
53#define WAND_BUFFER_SIZE 4
54
55bool checkConnection(T5_Glasses glassesHandle, const char* id) {
56 T5_ConnectionState connectionState;
57 T5_Result err = t5GetGlassesConnectionState(glassesHandle, &connectionState);
58 if (err) {
59 printf("Glasses connection : '%s' -> Error: %s\n", id, t5GetResultMessage(err));
60 return false;
61 }
62
63 switch (connectionState) {
65 printf("Glasses connection : '%s' -> Connected\n", id);
66 return true;
67
69 printf("Glasses connection : '%s' -> Reserved\n", id);
70 return true;
71
73 printf("Glasses connection : '%s' -> Not Connected\n", id);
74 return true;
75
77 printf("Glasses connection : '%s' -> Device Lost\n", id);
78 return true;
79
80 default:
81 printf("Glasses connection : '%s' -> Unexpected state!\n", id);
82 return false;
83 }
84}
85
86void findWands(T5_Glasses glassesHandle) {
87 uint8_t count = WAND_BUFFER_SIZE;
88 T5_WandHandle wandListBuffer[WAND_BUFFER_SIZE];
89
90 T5_Result err = t5ListWandsForGlasses(glassesHandle, wandListBuffer, &count);
91 if (err) {
92 printf("Wand list : Error : %s\n", t5GetResultMessage(err));
93 return;
94 }
95
96 printf("Wand list : %u wand(s)\n", count);
97 for (int i = 0; i < count; i++) {
98 printf(" Wand found : ID=%d\n", wandListBuffer[i]);
99 }
100
102 if (count > 0) {
103 // Enable wand stream
104 T5_WandStreamConfig config;
105 config.enabled = true;
106 err = t5ConfigureWandStreamForGlasses(glassesHandle, &config);
107 if (err) {
108 printf("Failed to enable stream : %s\n", t5GetResultMessage(err));
109 return;
110 }
111
112 T5_WandStreamEvent event;
113 for (int i = 0; i < 100; i++) {
114 err = t5ReadWandStreamForGlasses(glassesHandle, &event, 100);
115 if (err) {
116 if (err == T5_TIMEOUT) {
117 continue;
118 }
119
120 printf("Failed to read stream : %s\n", t5GetResultMessage(err));
121 return;
122 }
123
124 switch (event.type) {
126 printf("WAND EVENT : CONNECT [%u]\n", event.wandId);
127 break;
128
130 printf("WAND EVENT : DISCONNECT [%u]\n", event.wandId);
131 break;
132
134 printf("WAND EVENT : DESYNC [%u]\n", event.wandId);
135 break;
136
138 printf("WAND EVENT : REPORT [%u] %fx%f\n",
139 event.wandId,
140 event.report.stick.x,
141 event.report.stick.y);
142 break;
143 }
144 }
145
146 // Disable wand stream
147 config.enabled = false;
148 err = t5ConfigureWandStreamForGlasses(glassesHandle, &config);
149 if (err) {
150 printf("Failed to disable stream : %s\n", t5GetResultMessage(err));
151 return;
152 }
153 }
155}
156
157const char* gameboardTypeString(T5_GameboardType gameboardType) {
158 switch (gameboardType) {
160 return "None";
162 return "LE";
164 return "XE";
166 return "XE Raised";
167 default:
168 return "<Unknown>";
169 }
170}
171
173void getPoses(T5_Glasses glassesHandle) {
174 T5_Result err;
175 T5_GlassesPose pose;
176 T5_GameboardPose gameboardPoses[3];
177
178 printf("Getting some poses");
179
180 bool waiting = false;
181 for (int i = 0; i < 1000; i++) {
183 if (err) {
184 if (err == T5_ERROR_TRY_AGAIN) {
185 if (!waiting) {
186 printf("\nWaiting...");
187 fflush(stdout);
188 } else {
189 printf(".");
190 fflush(stdout);
191 }
192 SLEEP(100);
193 i--;
194 waiting = true;
195 continue;
196 } else {
197 printf("Failed to get pose : %s\n", t5GetResultMessage(err));
198 return;
199 }
200 }
201
202 uint16_t count = 3;
203 err = t5GetGameboardPoses(glassesHandle, gameboardPoses, &count);
204 if (err) {
205 if (err == T5_ERROR_TRY_AGAIN) {
206 if (!waiting) {
207 printf("\nWaiting for gameboard poses...");
208 fflush(stdout);
209 } else {
210 printf(".");
211 fflush(stdout);
212 }
213 SLEEP(100);
214 i--;
215 waiting = true;
216 continue;
217 } else {
218 printf("Failed to get gameboard poses : %s\n", t5GetResultMessage(err));
219 return;
220 }
221 }
222
223 waiting = false;
224
225 printf("\nGLASSES POSE : [%lu] (Board:%s) "
226 "[%6.4f, %6.4f, %6.4f] [%6.4f, %6.4f, %6.4f, %6.4f]",
227 pose.timestampNanos,
228 gameboardTypeString(pose.gameboardType),
229 pose.posGLS_STAGE.x,
230 pose.posGLS_STAGE.y,
231 pose.posGLS_STAGE.z,
232 pose.rotToGLS_STAGE.w,
233 pose.rotToGLS_STAGE.x,
234 pose.rotToGLS_STAGE.y,
235 pose.rotToGLS_STAGE.z);
236
237 printf("\nPRIMARY GAMEBOARD POSE : [%lu] (Board:%s) "
238 "[%6.4f, %6.4f, %6.4f] [%6.4f, %6.4f, %6.4f, %6.4f]",
239 gameboardPoses[0].timestampNanos,
240 gameboardTypeString(gameboardPoses[0].gameboardType),
241 gameboardPoses[0].posBOARD_STAGE.x,
242 gameboardPoses[0].posBOARD_STAGE.y,
243 gameboardPoses[0].posBOARD_STAGE.z,
244 gameboardPoses[0].rotToBOARD_STAGE.w,
245 gameboardPoses[0].rotToBOARD_STAGE.x,
246 gameboardPoses[0].rotToBOARD_STAGE.y,
247 gameboardPoses[0].rotToBOARD_STAGE.z);
248
249 SLEEP(16);
250 }
251
252 printf("\n");
253}
255
257T5_Result endlesslyWatchSettings(T5_Glasses glassesHandle, const char* id) {
258 T5_Result err;
259
260 printf("Watching for changes to settings... (forever)\n");
261 for (;;) {
262 uint16_t count = PARAM_BUFFER_SIZE;
263 T5_ParamGlasses paramBuffer[PARAM_BUFFER_SIZE];
264 err = t5GetChangedGlassesParams(glassesHandle, paramBuffer, &count);
265 if (err) {
266 printf("Error getting changed params for '%s' : %s\n", id, t5GetResultMessage(err));
267 return err;
268 }
269
270 // Get the values of the changed params
271 for (int i = 0; i < count; i++) {
272 switch (paramBuffer[i]) {
274 double value = 0.0;
275 err = t5GetGlassesFloatParam(glassesHandle, 0, paramBuffer[i], &value);
276 if (err) {
277 printf("Error getting changed IPD for '%s' : %s\n",
278 id,
279 t5GetResultMessage(err));
280 return err;
281 }
282
283 printf("IPD changed for '%s' : %f\n", id, value);
284 } break;
285
287 char buffer[T5_MAX_STRING_PARAM_LEN];
288 size_t bufferSize = T5_MAX_STRING_PARAM_LEN;
290 glassesHandle, paramBuffer[i], 0, buffer, &bufferSize);
291 if (err) {
292 printf("Error getting changed friendly name for '%s' : %s\n",
293 id,
294 t5GetResultMessage(err));
295 return err;
296 }
297
298 printf("Friendly name changed for '%s' : '%s'\n", id, buffer);
299 } break;
300
301 default:
302 // Ignore other parameters
303 break;
304 }
305 }
306 }
307}
309
310void connectGlasses(T5_Context t5ctx, const char* id) {
312
313 // CREATE GLASSES
314 T5_Glasses glassesHandle;
315 T5_Result err = t5CreateGlasses(t5ctx, id, &glassesHandle);
316 if (err) {
317 printf("Error creating glasses '%s' : %s\n", id, t5GetResultMessage(err));
318 return;
319 } else {
320 printf("Created glasses : '%s'\n", id);
321 }
323
324 // CHECK CONNECTION STATE
325 if (!checkConnection(glassesHandle, id)) {
326 return;
327 }
328
330 err = t5ReserveGlasses(glassesHandle, "My Awesome Application");
331 if (err) {
332 printf("Error acquiring glasses '%s': %s\n", id, t5GetResultMessage(err));
333 return;
334 }
336
337 printf("Glasses reserved : '%s'\n", id);
338
340 if (!checkConnection(glassesHandle, id)) {
341 return;
342 }
343
345 // ENSURE GLASSES ARE READY
346 for (;;) {
347 err = t5EnsureGlassesReady(glassesHandle);
348 if (err) {
349 if (err == T5_ERROR_TRY_AGAIN) {
350 // A non-sample program would probably sleep here or retry on another frame pass.
351 continue;
352 }
353 printf("Error ensure glasses ready '%s': %s\n", id, t5GetResultMessage(err));
354 return;
355 }
356
357 printf("Glasses ready : '%s'\n", id);
358 break;
359 }
361
362 // CHECK CONNECTION STATE
363 if (!checkConnection(glassesHandle, id)) {
364 return;
365 }
366
367 // RECALL THE IDENTIFIER FOR GLASSES
368 size_t bufferSize = IDENTIFIER_BUFFER_SIZE;
369 char recalledId[IDENTIFIER_BUFFER_SIZE];
370 err = t5GetGlassesIdentifier(glassesHandle, recalledId, &bufferSize);
371 if (err) {
372 printf("Error getting ID for glasses '%s' : %s\n", id, t5GetResultMessage(err));
373 return;
374 } else if (strcmp(id, recalledId) != 0) {
375 printf("Mismatch getting ID for glasses : '%s' -> '%s'\n", id, recalledId);
376 } else {
377 printf("Got ID for glasses : '%s' -> '%s'\n", id, recalledId);
378 }
379
380 // BRIEFLY PERFORM AN EXCLUSIVE OPERATION ON THE GLASSES
381 if (true) {
382 getPoses(glassesHandle);
383 }
384
385 // FIND AND BRIEFLY WATCH CONNECTED WANDS
386 if (true) {
387 findWands(glassesHandle);
388 }
389
390 // CHECK CONNECTION STATE
391 if (!checkConnection(glassesHandle, id)) {
392 return;
393 }
394
395 printf("Glasses ready : '%s'\n", id);
396
397 // Enable this to watch for changes to the glasses settings
398 if (false) {
399 err = endlesslyWatchSettings(glassesHandle, id);
400 if (err) {
401 printf("Error watching settings for glasses '%s' : %s\n", id, t5GetResultMessage(err));
402 return;
403 }
404 }
405
407 // RELEASE THE GLASSES
408 t5ReleaseGlasses(glassesHandle);
410
411 // CHECK CONNECTION STATE
412 if (!checkConnection(glassesHandle, id)) {
413 return;
414 }
415
416 // FIND AND BRIEFLY WATCH CONNECTED WANDS
417 // Note that the glasses are not reserved here!
418 if (true) {
419 findWands(glassesHandle);
420 }
421
422 // DESTROY THE GLASSES
423 t5DestroyGlasses(&glassesHandle);
424 printf("Destroyed glasses : '%s'\n", id);
425}
426
427size_t strnlen(const char* str, size_t maxLen) {
428 size_t len = 0;
429 while ((len < maxLen) && (str[len] != '\0')) {
430 len++;
431 }
432 return len;
433}
434
435int main(int argc, char** argv) {
437 T5_ClientInfo clientInfo = {
438 .applicationId = "com.MyCompany.MyApplication",
439 .applicationVersion = "1.0.0",
440 .sdkType = 0,
441 .reserved = 0,
442 };
443
444 T5_Context t5ctx;
445 T5_Result err = t5CreateContext(&t5ctx, &clientInfo, 0);
446 if (err) {
447 printf("Failed to create context\n");
448 }
450 printf("Init complete\n");
451
452 {
454 T5_GameboardSize gameboardSize;
455 err = t5GetGameboardSize(t5ctx, kT5_GameboardType_LE, &gameboardSize);
456 if (err) {
457 printf("Failed to get gameboard size\n");
458 } else {
459 printf("LE Gameboard size : %fm x %fm x %fm\n",
460 gameboardSize.viewableExtentPositiveX + gameboardSize.viewableExtentNegativeX,
461 gameboardSize.viewableExtentPositiveY + gameboardSize.viewableExtentNegativeY,
462 gameboardSize.viewableExtentPositiveZ);
463 }
465 }
466
468 bool waiting = false;
469 for (;;) {
470 char serviceVersion[T5_MAX_STRING_PARAM_LEN];
471 size_t bufferSize = T5_MAX_STRING_PARAM_LEN;
473 t5ctx, kT5_ParamSys_UTF8_Service_Version, serviceVersion, &bufferSize);
474 if (!err) {
475 printf("Service version : %s\n", serviceVersion);
476 break;
477 }
478
479 if (err == T5_ERROR_NO_SERVICE) {
480 if (!waiting) {
481 printf("Waiting for service...\n");
482 waiting = true;
483 }
484 } else {
485 printf("Error getting service version : %s\n", t5GetResultMessage(err));
486 exit(EXIT_FAILURE);
487 }
488 }
490
492 for (;;) {
493 size_t bufferSize = GLASSES_BUFFER_SIZE;
494 char glassesListBuffer[GLASSES_BUFFER_SIZE];
495 err = t5ListGlasses(t5ctx, glassesListBuffer, &bufferSize);
496 if (!err) {
497 size_t glassesCount = 0;
498
499 const char* buffPtr = glassesListBuffer;
500 size_t remainingSize = bufferSize;
501 for (;;) {
502 // Get the length of the string and exit if we've read the
503 // terminal string (Zero length)
504 size_t stringLength = strnlen(buffPtr, remainingSize);
505 if (stringLength == 0) {
506 break;
507 } else if (stringLength == remainingSize) {
508 // no null terminator encountered in the provided buffer!
509 printf("Warning: list may be missing null terminator");
510 break;
511 }
512
513 fprintf(stderr, "Glasses : %s\n", buffPtr);
514 glassesCount++;
515
517 connectGlasses(t5ctx, buffPtr);
519
520 // Advance through the returned values
521 buffPtr += stringLength + 1;
522 remainingSize -= stringLength + 1;
523 assert(buffPtr <= (glassesListBuffer + bufferSize));
524 }
525
526 printf("Listed glasses [%zu found]\n", glassesCount);
527 break;
528 }
529
530 if (err == T5_ERROR_NO_SERVICE) {
531 if (!waiting) {
532 printf("Waiting for service...\n");
533 waiting = true;
534 }
535 } else {
536 printf("Error listing glasses : %s\n", t5GetResultMessage(err));
537 exit(EXIT_FAILURE);
538 }
539 }
541
543 t5DestroyContext(&t5ctx);
545 printf("Shutdown complete\n");
546}
uint32_t T5_Result
Represents an error code that may be returned by the Tilt Fiveā„¢ API.
Definition: errors.h:47
#define T5_ERROR_TRY_AGAIN
Target is not currently available.
Definition: errors.h:120
#define T5_TIMEOUT
Timeout.
Definition: errors.h:57
T5_EXPORT const char * t5GetResultMessage(T5_Result result)
#define T5_ERROR_NO_SERVICE
Service isn't connected.
Definition: errors.h:72
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 t5ReleaseGlasses(T5_Glasses glasses)
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 t5GetGlassesIdentifier(T5_Glasses glasses, char *buffer, size_t *bufferSize)
Get the device identifier of a glasses.
T5_EXPORT T5_Result t5EnsureGlassesReady(T5_Glasses glasses)
Ensure that reserved glasses are ready for exclusive operations.
T5_EXPORT T5_Result t5GetGameboardPoses(T5_Glasses glasses, T5_GameboardPose *buffer, uint16_t *count)
Get the latest set of gameboard poses.
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.
#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:312
T5_ParamGlasses
Possible parameters that can be retrieved for glasses.
Definition: types.h:673
uint8_t T5_WandHandle
Opaque handle used with wands.
Definition: types.h:143
struct T5_ContextImpl * T5_Context
Opaque handle used with system-wide functions.
Definition: types.h:131
T5_GameboardType
Possible gameboard types.
Definition: types.h:257
struct T5_GlassesImpl * T5_Glasses
Opaque handle used with glasses.
Definition: types.h:137
@ kT5_ConnectionState_Disconnected
Glasses were previously exclusively connected, but the device has disconnected.
Definition: types.h:323
@ kT5_ConnectionState_ExclusiveConnection
Glasses are connected for exclusive use.
Definition: types.h:314
@ kT5_ConnectionState_NotExclusivelyConnected
Glasses have not been exclusively connected or reserved.
Definition: types.h:320
@ kT5_ConnectionState_ExclusiveReservation
Glasses are reserved for exclusive use.
Definition: types.h:317
@ kT5_ParamGlasses_Float_IPD
Interpupillary distance - Float, millimeters
Definition: types.h:676
@ kT5_ParamGlasses_UTF8_FriendlyName
User-facing name of the glasses - UTF8.
Definition: types.h:679
@ kT5_ParamSys_UTF8_Service_Version
Version of the service software - UTF8.
Definition: types.h:685
@ kT5_GameboardType_LE
An LE gameboard.
Definition: types.h:262
@ kT5_GameboardType_XE
An XE gameboard, flap laid flat.
Definition: types.h:265
@ kT5_GameboardType_None
No gameboard.
Definition: types.h:259
@ kT5_GameboardType_XE_Raised
An XE gameboard, flap raised at an angle on the kickstand.
Definition: types.h:268
@ kT5_WandStreamEventType_Connect
Wand connected.
Definition: types.h:575
@ kT5_WandStreamEventType_Disconnect
Wand disconnected.
Definition: types.h:578
@ kT5_WandStreamEventType_Report
Wand report (Pose, Buttons, Trigger, Stick, Battery)
Definition: types.h:584
@ kT5_WandStreamEventType_Desync
Stream has desynchronized.
Definition: types.h:581
@ kT5_GlassesPoseUsage_GlassesPresentation
The pose will be used to render images to be presented on the glasses.
Definition: types.h:335
constexpr iterator_traits< _InputIterator >::difference_type count(_InputIterator __first, _InputIterator __last, const _Tp &__value)
Physical dimensions of a gameboard.
Definition: types.h:272
float viewableExtentNegativeY
The distance in meters from the gameboard origin to the edge of the viewable area in the negative Y d...
Definition: types.h:287
float viewableExtentPositiveZ
The distance in meters above the gameboard origin that the viewable area extends in the positive Z di...
Definition: types.h:291
float viewableExtentPositiveY
The distance in meters from the gameboard origin to the edge of the viewable area in the positive Y d...
Definition: types.h:283
float viewableExtentNegativeX
The distance in meters from the gameboard origin to the edge of the viewable area in the negative X d...
Definition: types.h:279
float viewableExtentPositiveX
The distance in meters from the gameboard origin to the edge of the viewable area in the positive X d...
Definition: types.h:275
Client provided information for use with t5CreateGlasses()
Definition: types.h:295
const char * applicationId
The application ID.
Definition: types.h:297
Glasses pose information to be retrieved with t5GetGlassesPose()
Definition: types.h:358
uint64_t timestampNanos
The timestamp of the pose.
Definition: types.h:360
T5_GameboardType gameboardType
The type of gameboard visible for this pose.
Definition: types.h:371
T5_Quat rotToGLS_STAGE
The rotation that transforms points in the STAGE frame orientation to the GLS (glasses) frame orienta...
Definition: types.h:368
T5_Vec3 posGLS_STAGE
The position of the origin of the GLS (glasses) frame relative to the STAGE frame.
Definition: types.h:364
Gameboard pose information to be retrieved by enumerating the output of t5GetGameboardPoses()
Definition: types.h:392
Wand stream configuration.
Definition: types.h:566
bool enabled
Enable or disable the entire stream. True = enabled.
Definition: types.h:568
T5_Vec2 stick
Stick (X/Y) - Analog, Range [-1.0 - 1.0], 0 = Centered, 1.0 = Top/Right.
Definition: types.h:620
Represents an event from the wand stream.
Definition: types.h:658
T5_WandReport report
Report (Valid if type = kT5_WandStreamEventType_Report)
Definition: types.h:669
T5_WandStreamEventType type
Type of event.
Definition: types.h:663
T5_WandHandle wandId
Opaque identifier for the wand.
Definition: types.h:660