forked from jeffsp/matleap
-
Notifications
You must be signed in to change notification settings - Fork 3
/
LeapConnection.cpp
336 lines (303 loc) · 10.8 KB
/
LeapConnection.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
#include "LeapConnection.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#if defined(_MSC_VER)
#include <Windows.h>
#include <process.h>
#define LockMutex EnterCriticalSection
#define UnlockMutex LeaveCriticalSection
#else
#include <unistd.h>
#include <pthread.h>
#define LockMutex pthread_mutex_lock
#define UnlockMutex pthread_mutex_unlock
#endif
//Forward declarations
const char* ResultString(eLeapRS r);
#if defined(_MSC_VER)
void serviceMessageLoop(void* unused);
#else
void* serviceMessageLoop(void* unused);
#endif
void setFrame(const LEAP_TRACKING_EVENT* frame);
void setImage(const LEAP_IMAGE_EVENT* imageEvent);
void setDevice(const LEAP_DEVICE_INFO* deviceProps);
//External state
bool IsConnected = false;
//Internal state
print_t logger;
bool _isRunning = false;
LEAP_CONNECTION connectionHandle;
LEAP_TRACKING_EVENT* lastFrame = NULL;
LEAP_IMAGE_EVENT* lastImage = NULL;
LEAP_DEVICE_INFO* lastDevice = NULL;
//Callback function pointers
struct Callbacks ConnectionCallbacks;
//Threading variables
#if defined(_MSC_VER)
uintptr_t pollingThread;
CRITICAL_SECTION dataLock;
#else
pthread_t pollingThread;
pthread_mutex_t dataLock;
#endif
/**
* Creates the connection handle and opens a connection to the Leap Motion
* service. On success, creates a thread to service the LeapC message pump.
*/
LEAP_CONNECTION* OpenConnection(print_t log) {
eLeapRS result = LeapCreateConnection(NULL, &connectionHandle);
if (result == eLeapRS_Success) {
logger = log;
logger("INIT STARTED");
result = LeapOpenConnection(connectionHandle);
if (result == eLeapRS_Success) {
_isRunning = true;
#if defined(_MSC_VER)
InitializeCriticalSection(&dataLock);
pollingThread = _beginthread(serviceMessageLoop, 0, NULL);
#else
pthread_create(&pollingThread, NULL, serviceMessageLoop, NULL);
#endif
}
}
return &connectionHandle;
}
void CloseConnection() {
CloseConnectionHandle(&connectionHandle);
}
/** Close the connection and let message thread function end. */
void CloseConnectionHandle(LEAP_CONNECTION* connectionHandle) {
LeapDestroyConnection(*connectionHandle);
_isRunning = false;
}
/** Called by serviceMessageLoop() when a connection event is returned by LeapPollConnection(). */
void handleConnectionEvent(const LEAP_CONNECTION_EVENT* connection_event) {
IsConnected = true;
if (ConnectionCallbacks.on_connection) {
ConnectionCallbacks.on_connection();
}
}
/** Called by serviceMessageLoop() when a connection lost event is returned by LeapPollConnection(). */
void handleConnectionLostEvent(const LEAP_CONNECTION_LOST_EVENT* connection_lost_event) {
IsConnected = false;
if (ConnectionCallbacks.on_connection_lost) {
ConnectionCallbacks.on_connection_lost();
}
}
/**
* Called by serviceMessageLoop() when a device event is returned by LeapPollConnection()
* Demonstrates how to access device properties.
*/
void handleDeviceEvent(const LEAP_DEVICE_EVENT* device_event) {
LEAP_DEVICE deviceHandle;
//Open device using LEAP_DEVICE_REF from event struct.
eLeapRS result = LeapOpenDevice(device_event->device, &deviceHandle);
if (result != eLeapRS_Success) {
printf("Could not open device %s.\n", ResultString(result));
return;
}
//Create a struct to hold the device properties, we have to provide a buffer for the serial string
LEAP_DEVICE_INFO deviceProperties = { sizeof(deviceProperties) };
// Start with a length of 1 (pretending we don't know a priori what the length is).
// Currently device serial numbers are all the same length, but that could change in the future
deviceProperties.serial_length = 1;
deviceProperties.serial = (char*)malloc(deviceProperties.serial_length);
//This will fail since the serial buffer is only 1 character long
// But deviceProperties is updated to contain the required buffer length
result = LeapGetDeviceInfo(deviceHandle, &deviceProperties);
if (result == eLeapRS_InsufficientBuffer) {
//try again with correct buffer size
free(deviceProperties.serial);
deviceProperties.serial = (char*)malloc(deviceProperties.serial_length);
result = LeapGetDeviceInfo(deviceHandle, &deviceProperties);
if (result != eLeapRS_Success) {
printf("Failed to get device info %s.\n", ResultString(result));
free(deviceProperties.serial);
return;
}
}
setDevice(&deviceProperties);
if (ConnectionCallbacks.on_device_found) {
ConnectionCallbacks.on_device_found(&deviceProperties);
}
free(deviceProperties.serial);
LeapCloseDevice(deviceHandle);
}
/** Called by serviceMessageLoop() when a device lost event is returned by LeapPollConnection(). */
void handleDeviceLostEvent(const LEAP_DEVICE_EVENT* device_event) {
if (ConnectionCallbacks.on_device_lost) {
ConnectionCallbacks.on_device_lost();
}
}
/** Called by serviceMessageLoop() when a device failure event is returned by LeapPollConnection(). */
void handleDeviceFailureEvent(const LEAP_DEVICE_FAILURE_EVENT* device_failure_event) {
if (ConnectionCallbacks.on_device_failure) {
ConnectionCallbacks.on_device_failure(device_failure_event->status, device_failure_event->hDevice);
}
}
/** Called by serviceMessageLoop() when a tracking event is returned by LeapPollConnection(). */
void handleTrackingEvent(const LEAP_TRACKING_EVENT* tracking_event) {
setFrame(tracking_event); //support polling tracking data from different thread
}
/** Called by serviceMessageLoop() when a image event is returned by LeapPollConnection(). */
void handleImageEvent(const LEAP_IMAGE_EVENT *imageEvent){
setImage(imageEvent);
}
/** Called by serviceMessageLoop() when a policy event is returned by LeapPollConnection(). */
void handlePolicyEvent(const LEAP_POLICY_EVENT* policy_event) {
if (ConnectionCallbacks.on_policy) {
ConnectionCallbacks.on_policy(policy_event->current_policy);
}
}
/**
* Services the LeapC message pump by calling LeapPollConnection().
* The average polling time is determined by the framerate of the Leap Motion service.
*/
#if defined(_MSC_VER)
void serviceMessageLoop(void* unused) {
#else
void* serviceMessageLoop(void* unused) {
#endif
eLeapRS result;
LEAP_CONNECTION_MESSAGE msg;
while (_isRunning) {
unsigned int timeout = 1000;
result = LeapPollConnection(connectionHandle, timeout, &msg);
if (result != eLeapRS_Success) {
printf("LeapC PollConnection call was %s.\n", ResultString(result));
continue;
}
//logger("EVENT:");
switch (msg.type) {
case eLeapEventType_Connection:
handleConnectionEvent(msg.connection_event);
break;
case eLeapEventType_ConnectionLost:
handleConnectionLostEvent(msg.connection_lost_event);
break;
case eLeapEventType_Device:
handleDeviceEvent(msg.device_event);
break;
case eLeapEventType_DeviceLost:
handleDeviceLostEvent(msg.device_event);
break;
case eLeapEventType_DeviceFailure:
handleDeviceFailureEvent(msg.device_failure_event);
break;
case eLeapEventType_Tracking:
//logger("Tracking");
handleTrackingEvent(msg.tracking_event);
break;
case eLeapEventType_Image:
//logger("Image");
handleImageEvent(msg.image_event);
break;
case eLeapEventType_Policy:
//logger("Policy");
handlePolicyEvent(msg.policy_event);
break;
default:
//discard unknown message types
printf("Unhandled message type %i.\n", msg.type);
} //switch on msg.type
}
#if !defined(_MSC_VER)
return NULL;
#endif
}
/* Used in Polling Example: */
/**
* Caches the newest frame by copying the tracking event struct returned by
* LeapC.
*/
void setFrame(const LEAP_TRACKING_EVENT * frame) {
LockMutex(&dataLock);
if (!lastFrame) lastFrame = (LEAP_TRACKING_EVENT*)malloc(sizeof(*frame));
*lastFrame = *frame;
UnlockMutex(&dataLock);
}
/**
* Caches the newest frame by copying the tracking event struct returned by
* LeapC.
*/
void setImage(const LEAP_IMAGE_EVENT * imageEvent) {
LockMutex(&dataLock);
if (!lastImage) lastImage = (LEAP_IMAGE_EVENT*)malloc(sizeof(*imageEvent));
*lastImage = *imageEvent;
UnlockMutex(&dataLock);
}
/** Returns a pointer to the cached tracking frame. */
LEAP_TRACKING_EVENT* GetFrame() {
LEAP_TRACKING_EVENT* currentFrame;
LockMutex(&dataLock);
currentFrame = lastFrame;
UnlockMutex(&dataLock);
return currentFrame;
}
/** Returns a pointer to the cached tracking image. */
LEAP_IMAGE_EVENT* GetImage() {
LEAP_IMAGE_EVENT* currentImage;
LockMutex(&dataLock);
currentImage = lastImage;
UnlockMutex(&dataLock);
return currentImage;
}
/**
* Caches the last device found by copying the device info struct returned by
* LeapC.
*/
void setDevice(const LEAP_DEVICE_INFO * deviceProps) {
LockMutex(&dataLock);
if (lastDevice) {
free(lastDevice->serial);
}
else {
lastDevice = (LEAP_DEVICE_INFO * )malloc(sizeof(*deviceProps));
}
*lastDevice = *deviceProps;
lastDevice->serial = (char*)malloc(deviceProps->serial_length);
memcpy(lastDevice->serial, deviceProps->serial, deviceProps->serial_length);
UnlockMutex(&dataLock);
}
/** Returns a pointer to the cached device info. */
LEAP_DEVICE_INFO* GetDeviceProperties() {
LEAP_DEVICE_INFO* currentDevice;
LockMutex(&dataLock);
currentDevice = lastDevice;
UnlockMutex(&dataLock);
return currentDevice;
}
//End of polling example-specific code
/** Translates eLeapRS result codes into a human-readable string. */
const char* ResultString(eLeapRS r) {
switch (r) {
case eLeapRS_Success: return "eLeapRS_Success";
case eLeapRS_UnknownError: return "eLeapRS_UnknownError";
case eLeapRS_InvalidArgument: return "eLeapRS_InvalidArgument";
case eLeapRS_InsufficientResources: return "eLeapRS_InsufficientResources";
case eLeapRS_InsufficientBuffer: return "eLeapRS_InsufficientBuffer";
case eLeapRS_Timeout: return "eLeapRS_Timeout";
case eLeapRS_NotConnected: return "eLeapRS_NotConnected";
case eLeapRS_HandshakeIncomplete: return "eLeapRS_HandshakeIncomplete";
case eLeapRS_BufferSizeOverflow: return "eLeapRS_BufferSizeOverflow";
case eLeapRS_ProtocolError: return "eLeapRS_ProtocolError";
case eLeapRS_InvalidClientID: return "eLeapRS_InvalidClientID";
case eLeapRS_UnexpectedClosed: return "eLeapRS_UnexpectedClosed";
case eLeapRS_UnknownImageFrameRequest: return "eLeapRS_UnknownImageFrameRequest";
case eLeapRS_UnknownTrackingFrameID: return "eLeapRS_UnknownTrackingFrameID";
case eLeapRS_RoutineIsNotSeer: return "eLeapRS_RoutineIsNotSeer";
case eLeapRS_TimestampTooEarly: return "eLeapRS_TimestampTooEarly";
case eLeapRS_ConcurrentPoll: return "eLeapRS_ConcurrentPoll";
case eLeapRS_NotAvailable: return "eLeapRS_NotAvailable";
case eLeapRS_NotStreaming: return "eLeapRS_NotStreaming";
case eLeapRS_CannotOpenDevice: return "eLeapRS_CannotOpenDevice";
default: return "unknown result type.";
}
}
/** Cross-platform sleep function */
void millisleep(int milliseconds) {
usleep(milliseconds * 1000);
}
//End-of-ExampleConnection.c