vrpn 07.36
Virtual Reality Peripheral Network
Loading...
Searching...
No Matches
vrpn_Tracker_MotionNode.C
Go to the documentation of this file.
1/*
2Copyright (C) Motion Workshop 2014. Public domain.
3
4Permission is hereby granted, free of charge, to any person or organization
5obtaining a copy of the software and accompanying documentation covered by
6this license (the "Software") to use, reproduce, display, distribute,
7execute, and transmit the Software, and to prepare derivative works of the
8Software, and to permit third-parties to whom the Software is furnished to
9do so, all subject to the following:
10
11The copyright notices in the Software and this entire statement, including
12the above license grant, this restriction and the following disclaimer,
13must be included in all copies of the Software, in whole or in part, and
14all derivative works of the Software, unless such copies or derivative
15works are solely in the form of machine-executable object code generated by
16a source language processor.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
21SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
22FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
23ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24DEALINGS IN THE SOFTWARE.
25*/
27
29
30#ifdef VRPN_USE_MOTIONNODE
31
32// Option to print out more information for run-time testing.
33//#define TRACKER_MOTIONNODE_TEST 1
34
35//
36// Use the binary Motion C API library provided by Motion Workshop. The library
37// is loaded dynamically at run-time and is not required to compile this
38// tracker The C API is available in your software installation or directly
39// from Motion Workshop at:
40//
41// http://www.motionnode.com/sdk.html#capi
42//
43// The API is not required to compile this tracker class. The binary
44// library is required at run-time to connect to the MotionNode data
45// streams.
46//
47//#include <MotionNodeCAPI.h>
48
49// For convenience, the functions we will use are included directly in this
50// file. No external compile time dependencies.
51#if !defined(MNCAPI_PREVIEW_SIZE)
52
53#if defined(_WIN32)
54# define MNCAPI_IMPORT_API __declspec(dllimport)
55# define MNCAPI_CALL_API __cdecl
56#else
57# define MNCAPI_IMPORT_API
58# define MNCAPI_CALL_API
59#endif // defined(_WIN32)
60
61extern "C" {
62
63#define MNCAPI_PREVIEW_SIZE (14)
64
69
75
76}
77
78#endif // !defined(MNCAPI_PREVIEW_SIZE)
79
80#include <string>
81
82#if defined(_WIN32)
83# include <windows.h>
84# define MOTION_C_API_LIBRARY "MotionCAPI.dll"
85#else
86# include <dlfcn.h>
87# include <stdlib.h>
88# if defined(__APPLE__)
89# define MOTION_C_API_LIBRARY "libMotionCAPI.dylib"
90# else
91# define MOTION_C_API_LIBRARY "libMotionCAPI.so"
92# endif // __APPLE__
93# define GetProcAddress dlsym
94#endif // _WIN32
95
96typedef int (MNCAPI_CALL_API *MNCAPI_OPEN_HOST_FN)(enum mncapi_stream_t, const char *, int);
97typedef int (MNCAPI_CALL_API *MNCAPI_SAMPLE_FN)(int, float *, int);
98typedef void (MNCAPI_CALL_API *MNCAPI_CLOSE_FN)(int);
99
100
110class Sampler {
111public:
112 typedef vrpn_vector<float> data_type;
113
114 Sampler(const std::string &address, unsigned port);
115 ~Sampler();
116
117 bool get_data_block(data_type &data, const unsigned &num_sensor);
118
119private:
120 int m_handle;
121#if defined(_WIN32)
122 HMODULE m_library_handle;
123#else
124 void *m_library_handle;
125#endif // WIN32
126 MNCAPI_SAMPLE_FN m_mncapi_sample;
127}; // class Sampler
128
129typedef Sampler sampler_type;
130
131
134 unsigned num_sensor,
135 const char *address,
136 unsigned port)
137 : vrpn_Tracker(name, c), m_num_sensor(num_sensor), m_handle(NULL)
138{
139#if defined(TRACKER_MOTIONNODE_TEST)
140 printf("vrpn_Tracker_MotionNode {\n");
141#endif // TRACKER_MOTIONNODE_TEST
142
144
145 {
146 std::string remote_address = "127.0.0.1";
147 unsigned remote_port = 32079;
148 if (NULL != address) {
149 remote_address = address;
150 }
151 if (port > 0) {
152 remote_port = port;
153 }
154
155 sampler_type *sampler = NULL;
156 try { sampler = new sampler_type(address, port); }
157 catch (...) {
159 return;
160 }
161
162 // Attempt to read a single sample from
163 // the stream.
164 for (int i=0; i<4; i++) {
165 sampler_type::data_type data;
166 if (sampler->get_data_block(data, m_num_sensor) && !data.empty()) {
167 m_handle = sampler;
168 sampler = NULL;
169 break;
170 }
171 }
172
173 if (NULL == m_handle) {
174 fprintf(stderr, "MotionNode driver failed to start sampling, device not currently reading\n");
175 }
176#if defined(TRACKER_MOTIONNODE_TEST)
177 else {
178 printf(
179 "Connected to Motion data service at \"%s:%d\"\n",
180 remote_address.c_str(), remote_port);
181 }
182#endif // TRACKER_MOTIONNODE_TEST
183
184 // Clean up resources now if the sampler was never
185 // copied into this object.
186 if ((NULL == m_handle) && (NULL != sampler)) {
187 try {
188 delete sampler;
189 } catch (...) {
190 fprintf(stderr, "vrpn_Tracker_MotionNode::vrpn_Tracker_MotionNode(): delete failed\n");
191 return;
192 }
193 }
194 }
195
196 if (NULL != m_handle) {
198 } else {
200 }
201
202#if defined(TRACKER_MOTIONNODE_TEST)
203 printf("} vrpn_Tracker_MotionNode, status=%d\n", vrpn_Tracker::status);
204#endif // TRACKER_MOTIONNODE_TEST
205}
206
208{
209#if defined(TRACKER_MOTIONNODE_TEST)
210 printf("~vrpn_Tracker_MotionNode() {\n");
211#endif // TRACKER_MOTIONNODE_TEST
212
213 if (NULL != m_handle) {
214 sampler_type *sampler = reinterpret_cast<sampler_type *>(m_handle);
215 try {
216 delete sampler;
217 } catch (...) {
218 fprintf(stderr, "vrpn_Tracker_MotionNode::~vrpn_Tracker_MotionNode(): delete failed\n");
219 return;
220 }
221
222 m_handle = NULL;
223 }
224
225#if defined(TRACKER_MOTIONNODE_TEST)
226 printf("} ~vrpn_Tracker_MotionNode()\n");
227#endif // TRACKER_MOTIONNODE_TEST
228}
229
231{
232 // Call the generic server mainloop, since we are a server
234
235 get_report();
236}
237
238void vrpn_Tracker_MotionNode::get_report()
239{
240 if (NULL != m_handle) {
241 sampler_type *sampler = reinterpret_cast<sampler_type *>(m_handle);
242
243 sampler_type::data_type data;
244 if (sampler->get_data_block(data, m_num_sensor) && !data.empty()) {
245
246 for (std::size_t i=0; i<m_num_sensor; i++) {
247 const std::size_t index = i * MNCAPI_PREVIEW_SIZE;
248 if (index + 4 < data.size()) {
249
251 vrpn_Tracker::d_quat[0] = data[index + 1];
252 vrpn_Tracker::d_quat[1] = data[index + 2];
253 vrpn_Tracker::d_quat[2] = data[index + 3];
254 vrpn_Tracker::d_quat[3] = data[index + 0];
255
256 send_report();
257 }
258 }
259
260 }
261 }
262
263}
264
265void vrpn_Tracker_MotionNode::send_report()
266{
267 // Send the message on the connection
268 if (NULL != vrpn_Tracker::d_connection) {
269 char buffer[1024];
270 int len = encode_to(buffer);
272 fprintf(stderr, "MotionNode: cannot write message: tossing\n");
273 }
274 }
275}
276
277
278Sampler::Sampler(const std::string &address, unsigned port)
279 : m_handle(0), m_library_handle(NULL), m_mncapi_sample(NULL)
280{
281 // Load the dynamic library. This will use the search paths
282 // and fail if the library can not be found.
283#if defined(_WIN32)
284
285 HMODULE library_handle = LoadLibrary(MOTION_C_API_LIBRARY);
286 if (NULL == library_handle) {
287 library_handle = LoadLibrary("C:/Program Files/Motion/tools/plugin/capi/" MOTION_C_API_LIBRARY);
288 }
289
290#else
291
292 // Manually search for the shared library in likely locations.
293 const char *SearchPaths[3] = {
296#if defined(__APPLE__)
297 "/Applications/Motion.app/Contents/Resources/tools/plugin/capi" MOTION_C_API_LIBRARY
298#else
299 "/opt/Motion/tools/plugin/capi" MOTION_C_API_LIBRARY
300#endif // defined(__APPLE__)
301 };
302
303 void *library_handle = NULL;
304 for (int i=0; i<3; i++) {
305 library_handle = dlopen(SearchPaths[i], RTLD_LAZY);
306 if (NULL != library_handle) {
307#if defined(TRACKER_MOTIONNODE_TEST)
308 printf("Loaded Motion C API library, \"%s\"\n", SearchPaths[i]);
309#endif // TRACKER_MOTIONNODE_TEST
310 break;
311 }
312 }
313
314#endif // defined(_WIN32)
315
316 if (NULL != library_handle) {
317 m_library_handle = library_handle;
318
319 // Bind the open function and connect to the data service.
320 MNCAPI_OPEN_HOST_FN mncapi_open_host =
321 reinterpret_cast<MNCAPI_OPEN_HOST_FN>(GetProcAddress(m_library_handle, "mncapi_open_host"));
322 if (NULL != mncapi_open_host) {
323 // Connect and get the integer handle back.
324 int handle = mncapi_open_host(MNCAPI_PREVIEW, address.c_str(), static_cast<int>(port));
325 if (handle > 0) {
326 m_handle = handle;
327
328 // Bind the sampling function that we will reuse many times in the get_data_block method.
329 MNCAPI_SAMPLE_FN mncapi_sample =
330 reinterpret_cast<MNCAPI_SAMPLE_FN>(GetProcAddress(m_library_handle, "mncapi_sample"));
331 if (NULL != mncapi_sample) {
332 m_mncapi_sample = mncapi_sample;
333 } else {
334 fprintf(
335 stderr,
336 "failed to bind function \"mncapi_sample\" from Motion C API library\n");
337 }
338
339 } else {
340 fprintf(
341 stderr,
342 "failed to connect to Motion data service at \"%s:%d\"\n",
343 address.c_str(), port);
344 }
345
346 } else {
347 fprintf(
348 stderr,
349 "failed to bind function \"mncapi_open_host\" from Motion C API library\n");
350 }
351 } else {
352 fprintf(
353 stderr,
354 "failed to find Motion C API library, \"" MOTION_C_API_LIBRARY "\"\n");
355 }
356}
357
358Sampler::~Sampler()
359{
360 // Clean up resource. Unload the dynamic library after closing the active connection.
361 if (NULL != m_library_handle) {
362 if (m_handle > 0) {
363 MNCAPI_CLOSE_FN mncapi_close =
364 reinterpret_cast<MNCAPI_CLOSE_FN>(GetProcAddress(m_library_handle, "mncapi_close"));
365 if (NULL != mncapi_close) {
366 mncapi_close(m_handle);
367 m_handle = 0;
368 } else {
369 fprintf(
370 stderr,
371 "failed to bind function \"mncapi_close\" from Motion C API library\n");
372 }
373 }
374
375 m_mncapi_sample = NULL;
376
377#if defined(_WIN32)
378 if (FreeLibrary(m_library_handle)) {
379#else
380 if (0 == dlclose(m_library_handle)) {
381#endif // defined(_WIN32)
382 } else {
383 fprintf(stderr, "failed to unload Motion C API library\n");
384 }
385
386 m_library_handle = NULL;
387 }
388}
389
390bool Sampler::get_data_block(data_type &data, const unsigned &num_sensor)
391{
392 bool result = false;
393
394 if ((m_handle > 0) && (NULL != m_mncapi_sample) && (num_sensor > 0)) {
395 // Accept up to num_sensor results. We may not receive that many.
396 data.resize(MNCAPI_PREVIEW_SIZE * num_sensor);
397
398 int sample_result = m_mncapi_sample(m_handle, &data[0], data.size());
399 if (sample_result > MNCAPI_FAILURE) {
400 result = true;
401 }
402 }
403
404 return result;
405}
406
407#endif // VRPN_USE_MOTIONNODE
vrpn_Connection * d_connection
Connection that this object talks to.
vrpn_int32 d_sender_id
Sender ID registered with the connection.
void server_mainloop(void)
Handles functions that all servers should provide in their mainloop() (ping/pong, for example) Should...
Generic connection class not specific to the transport mechanism.
virtual void mainloop()
Called once through each main loop iteration to handle updates. Remote object mainloop() should call ...
vrpn_Tracker_MotionNode(const char *name, vrpn_Connection *c, unsigned num_sensor, const char *address, unsigned port)
virtual int encode_to(char *buf)
int register_server_handlers(void)
vrpn_float64 d_quat[4]
vrpn_Tracker(const char *name, vrpn_Connection *c=NULL, const char *tracker_cfg_file_name=NULL)
vrpn_int32 d_sensor
struct timeval timestamp
vrpn_int32 position_m_id
bool empty() const
size_type size() const
#define VRPN_SUPPRESS_EMPTY_OBJECT_WARNING()
const vrpn_uint32 vrpn_CONNECTION_LOW_LATENCY
const int vrpn_TRACKER_FAIL
const int vrpn_TRACKER_SYNCING
Sampler sampler_type
#define MNCAPI_CALL_API
#define MOTION_C_API_LIBRARY
int(MNCAPI_CALL_API * MNCAPI_OPEN_HOST_FN)(enum mncapi_stream_t, const char *, int)
int(MNCAPI_CALL_API * MNCAPI_SAMPLE_FN)(int, float *, int)
void(MNCAPI_CALL_API * MNCAPI_CLOSE_FN)(int)
#define MNCAPI_PREVIEW_SIZE
#define GetProcAddress