vrpn 07.36
Virtual Reality Peripheral Network
Loading...
Searching...
No Matches
vrpn_Tracker_DTrack.C
Go to the documentation of this file.
1// vrpn_Tracker_DTrack.C
2//
3// Advanced Realtime Tracking (https://www.ar-tracking.com) DTrack/DTrack2/DTRACK3 client
4
5// developed by David Nahon for Virtools VR Pack (http://www.virtools.com)
6// (07/20/2004) improved by Advanced Realtime Tracking GmbH
7// (07/02/2007, 06/29/2009) upgraded by Advanced Realtime Tracking GmbH to support new devices
8// (08/25/2010) a correction added by Advanced Realtime Tracking GmbH
9// (12/01/2010) support of 3dof objects added by Advanced Realtime Tracking GmbH
10// (2024-01-25) support of extended timestamp, multicast UDP and stateful firewall added
11// by Advanced Realtime Tracking GmbH & Co. KG
12//
13// Recommended settings within DTrack's 'Settings / Network' or DTrack2's 'Settings / Output' or
14// DTRACK3's 'Tracking / Output' dialog:
15// 'ts2' (or 'ts'), '6d', '6df2' (or '6df'), '6dcal', '3d' (optional)
16
17/* Configuration file:
18
19################################################################################
20# Advanced Realtime Tracking (https://www.ar-tracking.com) DTrack/DTrack2/DTRACK3 client
21#
22# creates as many vrpn_Tracker as there are bodies or Flysticks, starting with the bodies
23# creates 2 analogs per Flystick
24# creates 8 buttons per Flystick
25#
26# NOTE: when using DTrack's older output format for Flystick data ('6df'), the numbering
27# of Flystick buttons differs from DTrack documentation (for compatibility with
28# older vrpn releases)
29#
30# Arguments:
31# char name_of_this_device[]
32# char dtrack_connection[] (connection to DTRACK Controller, can be:
33# <data port> (DTRACK is sending data to this UDP port)
34# <multicast ip>:<data port> (plus optional multicast IP address)
35# <hostname or ip>:<data port>:fw (plus hostname/IP address of
36# DTRACK Controller, for use with stateful firewall) )
37#
38# Optional arguments:
39# float time_to_reach_joy (in seconds; see below)
40# int number_of_bodies, number_of_flysticks (fixed numbers of bodies and Flysticks)
41# int renumbered_ids[] (vrpn_Tracker IDs of bodies and Flysticks)
42# char "3d" (activates 3dof marker output if available;
43# always last argument if "-" is not present)
44# char "-" (activates tracing; always last argument)
45#
46# NOTE: to use multicast UDP or enabling UDP traffic through a stateful firewall, the VRPN server
47# needs to be built with option VRPN_USE_WINSOCK2
48#
49# NOTE: time_to_reach_joy is the time needed to reach the maximum value (1.0 or -1.0) of the
50# joystick of older 'Flystick' devices when the corresponding button is pressed
51# (one of the last buttons amongst the 8); not necessary for 'Flystick2' or newer devices
52# with its analog joystick
53#
54# NOTE: if fixed numbers of bodies and Flysticks should be used, both arguments
55# number_of_bodies and number_of_flysticks have to be set
56#
57# NOTE: renumbering of tracker IDs is only possible, if fixed numbers of bodies and
58# Flysticks are set; there has to be an argument present for each body/Flystick
59
60#vrpn_Tracker_DTrack DTrack 5000
61#vrpn_Tracker_DTrack DTrack 225.1.1.1:5000
62#vrpn_Tracker_DTrack DTrack 10.10.1.1:5000:fw
63#vrpn_Tracker_DTrack DTrack atc-302401001:5000:fw
64#vrpn_Tracker_DTrack DTrack 5000 -
65#vrpn_Tracker_DTrack DTrack 5000 3d
66#vrpn_Tracker_DTrack DTrack 5000 3d -
67#vrpn_Tracker_DTrack DTrack 5000 0.5
68#vrpn_Tracker_DTrack DTrack 5000 0.5 2 2
69#vrpn_Tracker_DTrack DTrack 5000 0.5 2 2 2 1 0 3
70#vrpn_Tracker_DTrack DTrack 5000 0.5 2 2 2 1 0 3 3d -
71
72################################################################################
73*/
74
75#include <stdio.h> // for NULL, printf, fprintf, etc
76#include <stdlib.h> // for strtod, exit, free, malloc, etc
77#include <string.h> // for strncmp, memset, strcat, etc
78#include <math.h> // for fabs, etc
79
80#include "quat.h" // for Q_RAD_TO_DEG, etc
81#include "vrpn_Connection.h" // for vrpn_CONNECTION_LOW_LATENCY, etc
82#include "vrpn_Shared.h" // for timeval, INVALID_SOCKET, etc
83#include "vrpn_Tracker_DTrack.h"
84#include "vrpn_Types.h" // for vrpn_float64
85#include "vrpn_MessageMacros.h" // for VRPN_MSG_INFO, VRPN_MSG_WARNING, VRPN_MSG_ERROR
86
87#ifdef VRPN_USE_WINSOCK_SOCKETS
88 #ifdef VRPN_USE_WINSOCK2
89 #include <winsock2.h> // struct timeval is defined here
90 #include <ws2tcpip.h> // for getaddrinfo, etc
91 #else
92 #include <winsock.h> // struct timeval is defined here
93 #endif
94#else
95 #include <netinet/in.h> // for sockaddr_in, INADDR_ANY, etc
96 #include <sys/socket.h> // for bind, recv, socket, AF_INET, etc
97 #include <unistd.h> // for close
98 #include <sys/select.h> // for select, FD_SET, FD_SETSIZE, etc
99 #include <netdb.h> // for getaddrinfo, etc
100#endif
101
102
103// There is a problem with linking on SGIs related to standard libraries.
104#ifndef sgi
105
106// --------------------------------------------------------------------------
107// Globals:
108
109#define DTRACK2VRPN_BUTTONS_PER_FLYSTICK 8 // number of vrpn buttons per Flystick (fixed)
110#define DTRACK2VRPN_ANALOGS_PER_FLYSTICK 2 // number of vrpn analogs per Flystick (fixed)
111
112#define UDPRECEIVE_BUFSIZE 20000 // size of udp buffer for DTrack data (one frame; in bytes)
113
114// --------------------------------------------------------------------------
115
116// Local error codes:
117
118#define DTRACK_ERR_NONE 0 // no error
119#define DTRACK_ERR_TIMEOUT 1 // timeout while receiving data
120#define DTRACK_ERR_UDP 2 // UDP receive error
121#define DTRACK_ERR_PARSE 3 // error in UDP packet
122
123// Local prototypes:
124
125static char* string_nextline(char* str, char* start, int len);
126static char* string_get_i(char* str, int* i);
127static char* string_get_ui(char* str, unsigned int* ui);
128static char* string_get_d(char* str, double* d);
129static char* string_get_f(char* str, float* f);
130static char* string_get_block(char* str, const char* fmt, int* idat, float* fdat);
131
132static unsigned int ip_name2ip( const char* name );
133static vrpn_SOCKET udp_init( unsigned short port, unsigned int multicastIp );
134static int udp_exit( vrpn_SOCKET sock, unsigned int multicastIp );
135static int udp_receive( vrpn_SOCKET sock, void *buffer, int maxlen, int tout_us );
136static int udp_send( vrpn_SOCKET sock, const void* buffer, int len, unsigned int ip, unsigned short port, int toutUs );
137
138
139// --------------------------------------------------------------------------
140// Constructor:
141// name (i): device name
142// c (i): vrpn_Connection
143// dtrackHost (i): (optional) DTRACK hostname/IP address or multicast IP address or NULL (if not given)
144// dtrackPort (i): DTRACK UDP port
145// doFirewall (i): enable UDP traffic through stateful firewall
146// timeToReachJoy (i): time needed to reach the maximum value of the joystick
147// fixNbody, fixNflystick (i): fixed numbers of DTrack bodies and Flysticks (-1 if not wanted)
148// fixId (i): renumbering of targets; must have exactly (fixNbody + fixNflystick) elements (NULL if not wanted)
149// actTracing (i): activate trace output
150
152 const char* dtrackHost, int dtrackPort, bool doFirewall,
153 float timeToReachJoy,
154 int fixNbody, int fixNflystick, int* fixId,
155 bool act3DOFout, bool actTracing ) :
156 vrpn_Tracker(name, c),
157 vrpn_Button_Filter(name, c),
158 vrpn_Analog(name, c)
159{
160 int i;
161 unsigned int ip;
162
163 // Dunno how many of these there are yet...
164
165 num_sensors = 0;
166 num_channel = 0;
167 num_buttons = 0;
168
169 // init variables: general
170 output_3dof_marker = act3DOFout;
171 tracing = actTracing;
172 tracing_frames = 0;
173
174 tim_first.tv_sec = tim_first.tv_usec = 0; // also used to recognize the first frame
175 tim_last.tv_sec = tim_last.tv_usec = 0;
176
177 // init variables: DTrack data
178
179 if(fixNbody >= 0 && fixNflystick >= 0){ // fixed numbers of bodies and Flysticks should be used
180 use_fix_numbering = true;
181
182 fix_nbody = fixNbody;
183 fix_nflystick = fixNflystick;
184
185 fix_idbody.resize(fix_nbody + fix_nflystick);
186 fix_idflystick.resize(fix_nflystick);
187
188 if(fixId){ // take the renumbering information for bodies and Flysticks
189 for(i=0; i<fix_nbody + fix_nflystick; i++){ // take the renumbering information for bodies
190 fix_idbody[i] = fixId[i];
191 }
192
193 for(i=0; i<fix_nflystick; i++){ // take the renumbering information for Flysticks (vrpn button data)
194 fix_idflystick[i] = fixId[i + fix_nbody];
195 }
196
197 for(i=0; i<fix_nbody; i++){ // remove all bodies from the Flystick renumbering data
198 for(int j=0; j<fix_nflystick; j++){
199 if(fixId[i] < fixId[j + fix_nbody] && fix_idflystick[j] > 0){ // be sure to avoid crazy numbers...
200 fix_idflystick[j]--;
201 }
202 }
203 }
204 }else{ // take identity numbering for bodies and Flysticks
205 for(i=0; i<fix_nbody + fix_nflystick; i++){
206 fix_idbody[i] = i;
207 }
208 for(i=0; i<fix_nflystick; i++){
209 fix_idflystick[i] = i;
210 }
211 }
212 }else{ // no fixed numbers
213 use_fix_numbering = false;
214 }
215
216 warning_nbodycal = false;
217
218 // init variables: preparing data for VRPN
219
220 if(timeToReachJoy > 1e-20){
221 joy_incPerSec = 1.f / timeToReachJoy; // increase of 'joystick' channel
222 }else{
223 joy_incPerSec = 1e20f; // so it reaches immediately
224 }
225
226 // init: communicating with DTrack
227
228 ip = 0;
229 if ( dtrackHost != NULL )
230 {
231 ip = ip_name2ip( dtrackHost );
232 if ( ip == 0 )
233 {
234 fprintf( stderr, "vrpn_Tracker_DTrack: Cannot resolve hostname/IP '%s'.\n", dtrackHost );
235 exit( EXIT_FAILURE );
236 }
237 }
238
239 if ( ! dtrack_init( ip, dtrackPort, doFirewall ) )
240 {
241 exit( EXIT_FAILURE );
242 }
243}
244
245
246// Destructor:
247
249{
250 dtrack_exit();
251}
252
253
254// --------------------------------------------------------------------------
255// Main loop:
256
257// This function should be called each time through the main loop
258// of the server code. It checks for a report from the tracker and
259// sends it if there is one.
260
262{
263 struct timeval timestamp;
264 long tts, ttu;
265 float dt;
266 int nbody, nflystick, i;
267 int newid;
268
269 // call the generic server mainloop, since we are a server:
270
272
273 // get data from DTrack:
274
275 if(!dtrack_receive()){
276 if(d_lasterror != DTRACK_ERR_TIMEOUT){
277 fprintf(stderr, "vrpn_Tracker_DTrack: Receive Error from DTrack.\n");
278 }
279 return;
280 }
281
282 tracing_frames++;
283
284 // get time stamp:
285
287
288 if ( act_timestamp_sec > 0 ) // use DTRACK3 extended timestamp, if available
289 {
290 struct timeval timestamp_dt;
291 timestamp_dt.tv_sec = act_timestamp_sec;
292 timestamp_dt.tv_usec = act_timestamp_usec;
293
294 if ( fabs( vrpn_TimevalDurationSeconds( timestamp, timestamp_dt ) ) > 0.1 ) // clocks are not synchronized
295 {
296 if ( timestamp.tv_usec < ( int )act_latency_usec )
297 {
298 timestamp.tv_usec += 1000000 - act_latency_usec;
299 timestamp.tv_sec--;
300 }
301 else
302 {
303 timestamp.tv_usec -= act_latency_usec;
304 }
305 }
306 else
307 {
308 timestamp = timestamp_dt;
309 }
310 }
311 else if ( act_timestamp >= 0 ) // use DTrack time stamp if available
312 {
313 tts = (long )act_timestamp;
314 ttu = (long )((act_timestamp - tts) * 1000000);
315 tts += timestamp.tv_sec - timestamp.tv_sec % 86400; // add day part of vrpn time stamp
316
317 if(tts >= timestamp.tv_sec + 43200 - 1800){ // shift closer to vrpn time stamp
318 tts -= 86400;
319 }else if(tts <= timestamp.tv_sec - 43200 - 1800){
320 tts += 86400;
321 }
322
323 timestamp.tv_sec = tts;
324 timestamp.tv_usec = ttu;
325 }
326
327 if(tim_first.tv_sec == 0 && tim_first.tv_usec == 0){
328 tim_first = tim_last = timestamp;
329 }
330
331 dt = (float )vrpn_TimevalDurationSeconds(timestamp, tim_last);
332 tim_last = timestamp;
333
334 if ( tracing && ( ( tracing_frames % 10 ) == 0 ) )
335 {
336 printf( "framenr %u ts %d.%06d dtime %.6lf\n", act_framecounter, ( int )timestamp.tv_sec, ( int )timestamp.tv_usec,
338 }
339
340 // find number of targets visible for vrpn to choose the correct vrpn ID numbers:
341 // (1) takes fixed number of bodies and Flysticks, if defined in the configuration file
342 // (2) otherwise uses the '6dcal' line in DTrack's output, that gives the total number of
343 // calibrated targets, if available
344 // (3) otherwise tracks the maximum number of appeared targets
345
346 if(use_fix_numbering){ // fixed numbers should be used
347 nbody = fix_nbody; // number of bodies visible for vrpn
348 nflystick = fix_nflystick; // number of Flysticks visible for vrpn
349 }else if(act_has_bodycal_format){ // DTrack/DTrack2 sent information about the number of calibrated targets
350 nbody = act_num_bodycal; // number of bodies visible for vrpn
351 nflystick = act_num_flystick; // number of Flysticks visible for vrpn
352 }else{ // else track the maximum number of appeared targets (at least)
353 if(!warning_nbodycal){ // mention warning (once)
354 fprintf(stderr, "vrpn_Tracker_DTrack warning: no DTrack '6dcal' data available.\n");
355 warning_nbodycal = true;
356 }
357
358 nbody = act_num_body; // number of bodies visible for vrpn
359 nflystick = act_num_flystick; // number of Flysticks visible for vrpn
360 }
361
362 // report tracker data to vrpn:
363
364 num_sensors = nbody + nflystick; // total number of targets visible for vrpn
365 num_buttons = nflystick * DTRACK2VRPN_BUTTONS_PER_FLYSTICK; // 8 buttons per Flystick
366 num_channel = nflystick * DTRACK2VRPN_ANALOGS_PER_FLYSTICK; // 2 channels per joystick/Flystick
367
368 for(i=0; i<act_num_body; i++){ // DTrack standard bodies
369 if(act_body[i].id < nbody){ // there might be more DTrack standard bodies than wanted
370 if(act_body[i].quality >= 0){ // report position only if body is tracked
371 if(use_fix_numbering){
372 newid = fix_idbody[act_body[i].id]; // renumbered ID
373 }else{
374 newid = act_body[i].id;
375 }
376
377 dtrack2vrpn_body(newid, "", act_body[i].id, act_body[i].loc, act_body[i].rot, timestamp);
378 }
379 }
380 }
381
382 if(num_channel >= static_cast<int>(joy_last.size())){ // adjust length of vector for current joystick value
383 size_t j0 = joy_last.size();
384
385 joy_simulate.resize(num_channel);
386 joy_last.resize(num_channel);
387
388 for(size_t j=j0; j< static_cast<size_t>(num_channel); j++){
389 joy_simulate[j] = false;
390 joy_last[j] = 0;
391 }
392 }
393
394 for(i=0; i<(int)act_num_flystick; i++){ // DTrack Flysticks
395 if(act_flystick[i].id < nflystick){ // there might be more DTrack Flysticks than wanted
396 if(act_flystick[i].quality >= 0){ // report position only if Flystick is tracked
397 if(use_fix_numbering){
398 newid = fix_idbody[act_flystick[i].id + nbody]; // renumbered ID for position
399 }else{
400 newid = act_flystick[i].id + nbody;
401 }
402
403 dtrack2vrpn_body(newid, "f", act_flystick[i].id, act_flystick[i].loc, act_flystick[i].rot,
404 timestamp);
405 }
406
407 if(use_fix_numbering){
408 newid = fix_idflystick[act_flystick[i].id]; // renumbered ID for buttons and analogs
409 }else{
410 newid = act_flystick[i].id;
411 }
412
413 dtrack2vrpn_flystickbuttons(newid, act_flystick[i].id,
414 act_flystick[i].num_button, act_flystick[i].button, timestamp);
415
416 dtrack2vrpn_flystickanalogs(newid, act_flystick[i].id,
417 act_flystick[i].num_joystick, act_flystick[i].joystick, dt, timestamp);
418 }
419 }
420
421 if (output_3dof_marker) {
422 int offset = num_sensors;
423 num_sensors += act_num_marker;
424 for(i=0; i<act_num_marker; i++){ // DTrack 3dof marker
425 dtrack2vrpn_marker(offset + i, "m", act_marker[i].id, act_marker[i].loc, timestamp);
426 }
427 }
428
429 // finish main loop:
430
431 vrpn_Analog::report_changes(); // report any analog event;
432 vrpn_Button::report_changes(); // report any button event;
433}
434
435
436// -----------------------------------------------------------------------------------------
437// Helpers:
438
439
440// ---------------------------------------------------------------------------------------------------
441// ---------------------------------------------------------------------------------------------------
442// Preparing data for VRPN:
443// these functions convert DTrack data to vrpn data
444
445// Preparing marker data:
446// id (i): VRPN body ID
447// str_dtrack (i): DTrack marker name (just used for trace output)
448// id_dtrack (i): DTrack marker ID (just used for trace output)
449// loc (i): position
450// timestamp (i): timestamp for body data
451// return value (o): 0 ok, -1 error
452
453int vrpn_Tracker_DTrack::dtrack2vrpn_marker(int id, const char* str_dtrack, int id_dtrack,
454 const float* loc, struct timeval timestamp)
455{
456
457 d_sensor = id;
458
459 // position (plus converting to unit meter):
460
461 pos[0] = loc[0] / 1000.;
462 pos[1] = loc[1] / 1000.;
463 pos[2] = loc[2] / 1000.;
464
465 // orientation: none
466
467 q_make(d_quat, 1, 0, 0, 0);
468
469 // pack and deliver tracker report:
470
471 if(d_connection){
472 char msgbuf[1000];
473 int len = vrpn_Tracker::encode_to(msgbuf);
474
477 {
478 fprintf(stderr, "vrpn_Tracker_DTrack: cannot write message: tossing.\n");
479 }
480 }
481
482 // tracing:
483
484 if(tracing && ((tracing_frames % 10) == 0)){
485
486 printf("marker id (DTrack vrpn): %s%d %d pos (x y z): %.4f %.4f %.4f\n",
487 str_dtrack, id_dtrack, id, pos[0], pos[1], pos[2]);
488 }
489
490 return 0;
491}
492
493
494// Preparing body data:
495// id (i): VRPN body ID
496// str_dtrack (i): DTrack body name ('body' or 'Flystick'; just used for trace output)
497// id_dtrack (i): DTrack body ID (just used for trace output)
498// loc (i): position
499// rot (i): orientation (3x3 rotation matrix)
500// timestamp (i): timestamp for body data
501// return value (o): 0 ok, -1 error
502
503int vrpn_Tracker_DTrack::dtrack2vrpn_body(int id, const char* str_dtrack, int id_dtrack,
504 const float* loc, const float* rot, struct timeval timestamp)
505{
506
507 d_sensor = id;
508
509 // position (plus converting to unit meter):
510
511 pos[0] = loc[0] / 1000.;
512 pos[1] = loc[1] / 1000.;
513 pos[2] = loc[2] / 1000.;
514
515 // orientation:
516
517 q_matrix_type destMatrix; // if this is not good, just build the matrix and do a matrixToQuat
518
519 destMatrix[0][0] = rot[0];
520 destMatrix[0][1] = rot[1];
521 destMatrix[0][2] = rot[2];
522 destMatrix[0][3] = 0.0;
523
524 destMatrix[1][0] = rot[3];
525 destMatrix[1][1] = rot[4];
526 destMatrix[1][2] = rot[5];
527 destMatrix[1][3] = 0.0;
528
529 destMatrix[2][0] = rot[6];
530 destMatrix[2][1] = rot[7];
531 destMatrix[2][2] = rot[8];
532 destMatrix[2][3] = 0.0;
533
534 destMatrix[3][0] = 0.0;
535 destMatrix[3][1] = 0.0;
536 destMatrix[3][2] = 0.0;
537 destMatrix[3][3] = 1.0;
538
539 q_from_row_matrix(d_quat, destMatrix);
540
541 // pack and deliver tracker report:
542
543 if(d_connection){
544 char msgbuf[1000];
545 int len = vrpn_Tracker::encode_to(msgbuf);
546
547 if(d_connection->pack_message(len, timestamp, position_m_id, d_sender_id, msgbuf,
549 {
550 fprintf(stderr, "vrpn_Tracker_DTrack: cannot write message: tossing.\n");
551 }
552 }
553
554 // tracing:
555
556 if(tracing && ((tracing_frames % 10) == 0)){
557 q_vec_type yawPitchRoll;
558
559 q_to_euler(yawPitchRoll, d_quat);
560
561 printf("body id (DTrack vrpn): %s%d %d pos (x y z): %.4f %.4f %.4f euler (y p r): %.3f %.3f %.3f\n",
562 str_dtrack, id_dtrack, id, pos[0], pos[1], pos[2],
563 Q_RAD_TO_DEG(yawPitchRoll[0]), Q_RAD_TO_DEG(yawPitchRoll[1]), Q_RAD_TO_DEG(yawPitchRoll[2]));
564 }
565
566 return 0;
567}
568
569
570// Preparing Flystick button data:
571// id (i): VRPN Flystick ID
572// id_dtrack (i): DTrack Flystick ID (just used for trace output)
573// num_but (i): number of buttons
574// but (i): button state (1 pressed, 0 not pressed)
575// timestamp (i): timestamp for button data
576// return value (o): 0 ok, -1 error
577
578int vrpn_Tracker_DTrack::dtrack2vrpn_flystickbuttons(int id, int id_dtrack,
579 int num_but, const int* but, struct timeval timestamp)
580{
581 int n, i, ind;
582
584
585 // buttons:
586 // NOTE: numbering of two buttons (B2 and B4) differs from DTrack documentation, as long as the 'older'
587 // output format '6df' is used by DTrack!
588
590 i = 0;
591 while(i < n){
592 buttons[ind++] = but[i];
593 i++;
594 }
595 while(i < DTRACK2VRPN_BUTTONS_PER_FLYSTICK){ // fill remaining buttons
596 buttons[ind++] = 0;
597 i++;
598 }
599
600 if(act_has_old_flystick_format){ // for backward compatibility!
601 // NOTE: numbering of two buttons (button 2 and button 4) differs from DTrack documentation!
602 buttons[id * DTRACK2VRPN_BUTTONS_PER_FLYSTICK + 1] = but[3];
603 buttons[id * DTRACK2VRPN_BUTTONS_PER_FLYSTICK + 3] = but[1];
604 }
605
606 vrpn_Button::timestamp = timestamp; // timestamp for button event (explicitly necessary)
607
608 // tracing:
609
610 if(tracing && ((tracing_frames % 10) == 0)){
611 printf("flystick id (DTrack vrpn): f%d %d but ", id_dtrack, id);
612 for(i=0; i<n; i++){
613 printf(" %d", but[i]);
614 }
615 printf("\n");
616 }
617
618 return 0;
619}
620
621
622// Preparing Flystick analog data:
623// id (i): VRPN Flystick ID
624// id_dtrack (i): DTrack Flystick ID (just used for trace output)
625// num_ana (i): number of analogs
626// ana (i): analog state (-1 <= ana <= 1)
627// dt (i): time since last change
628// timestamp (i): timestamp for analog data
629// return value (o): 0 ok, -1 error
630
631int vrpn_Tracker_DTrack::dtrack2vrpn_flystickanalogs(int id, int id_dtrack,
632 int num_ana, const float* ana, float dt, struct timeval timestamp)
633{
634 int n, i, ind;
635 float f;
636
638
639 // analogs:
640 // NOTE: simulation of time varying floating values, if a joystick action of an older
641 // 'Flystick' device is recognized!
642
644 i = 0;
645 while(i < n){
646 f = ana[i];
647
648 // simulation of time varying floating values (actually just necessary for older
649 // 'Flystick' devices and for backward compatibility):
650
651 if(f == 0){ // zero position: reset everything
652 joy_simulate[ind] = false;
653 }else if((f > 0.99 || f < -0.99) && joy_last[ind] == 0){ // extreme change: start simulation
654 joy_simulate[ind] = true;
655 }
656
657 if(joy_simulate[ind]){ // simulation of time varying floating values
658 if(f > 0){
659 f = joy_last[ind] + joy_incPerSec * dt;
660
661 if(f >= 1){
662 f = 1;
663 joy_simulate[ind] = false;
664 }
665 }else{
666 f = joy_last[ind] - joy_incPerSec * dt;
667
668 if(f <= -1){
669 f = -1;
670 joy_simulate[ind] = false;
671 }
672 }
673 }
674
675 joy_last[ind] = f;
676 channel[ind++] = f;
677 i++;
678 }
679 while(i < DTRACK2VRPN_ANALOGS_PER_FLYSTICK){ // fill remaining analogs
680 channel[ind++] = 0;
681 i++;
682 }
683
684 vrpn_Analog::timestamp = timestamp; // timestamp for analog event (explicitly necessary)
685
686 // tracing:
687
688 if(tracing && ((tracing_frames % 10) == 0)){
689 printf("flystick id (DTrack vrpn): f%d %d ana ", id_dtrack, id);
690 for(i=0; i<n; i++){
691 printf(" %.2f", ana[i]);
692 }
693 printf("\n");
694 }
695
696 return 0;
697}
698
699
700// ---------------------------------------------------------------------------------------------------
701// ---------------------------------------------------------------------------------------------------
702// Communication with DTrack:
703// these functions receive and parse data packets from DTrack
704
705// Initializing communication with DTrack:
706//
707// serverIp (i): IP address of Controller, or multicast IP address, or NULL
708// udpport (i): UDP port number to receive data from DTrack
709// doFirewall (i): enable UDP traffic through stateful firewall
710//
711// return value (o): initialization was successful (boolean)
712
713bool vrpn_Tracker_DTrack::dtrack_init( unsigned int serverIp, int udpport, bool doFirewall )
714{
715 d_multicastIp = 0;
716 if ( serverIp != 0 )
717 {
718 if ( ( serverIp & 0xf0000000 ) == 0xe0000000 ) // check if multicast IP
719 {
720 d_multicastIp = serverIp;
721
722 if ( doFirewall )
723 {
724 fprintf( stderr, "vrpn_Tracker_DTrack: Cannot enable UDP traffic through stateful firewall.\n" );
725 return false;
726 }
727 }
728 else if ( ! doFirewall )
729 {
730 fprintf( stderr, "vrpn_Tracker_DTrack: Cannot connect to DTRACK in communicating mode.\n" );
731 return false;
732 }
733 }
734
735 d_udpbuf = NULL;
736 d_lasterror = DTRACK_ERR_NONE;
737
738 // create UDP socket:
739
740 if(udpport <= 0 || udpport > 65535){
741 fprintf(stderr, "vrpn_Tracker_DTrack: Illegal UDP port %d.\n", udpport);
742 return false;
743 }
744
745 d_udpsock = udp_init( ( unsigned short )udpport, d_multicastIp );
746
747 if(d_udpsock == INVALID_SOCKET){
748 fprintf(stderr, "vrpn_Tracker_DTrack: Cannot Initialize UDP Socket.\n");
749 return false;
750 }
751
752 d_udptimeout_us = 0;
753
754 // create UDP buffer:
755
756 d_udpbufsize = UDPRECEIVE_BUFSIZE;
757
758 d_udpbuf = (char *)malloc(d_udpbufsize);
759
760 if(d_udpbuf == NULL){
761 udp_exit( d_udpsock, d_multicastIp );
762 d_udpsock = INVALID_SOCKET;
763 fprintf(stderr, "vrpn_Tracker_DTrack: Cannot Allocate Memory for UDP Buffer.\n");
764 return false;
765 }
766
767 // reset actual DTrack data:
768
769 act_framecounter = 0;
770 act_timestamp = -1;
771 act_timestamp_sec = 0;
772 act_timestamp_usec = 0;
773 act_latency_usec = 0;
774
775 act_num_marker = act_num_body = act_num_flystick = 0;
776 act_has_bodycal_format = false;
777 act_has_old_flystick_format = false;
778
779 // (optionally) enable UDP traffic through a stateful firewall:
780
781 if ( doFirewall )
782 {
783 const char* txt = "fw4vrpndt";
784
785 udp_send( d_udpsock, ( void* )txt, ( int )strlen( txt ) + 1, serverIp, 50107, 100000 );
786 }
787
788 return true;
789}
790
791
792// Deinitializing communication with DTrack:
793//
794// return value (o): deinitialization was successful (boolean)
795
796bool vrpn_Tracker_DTrack::dtrack_exit()
797{
798
799 // release buffer:
800
801 if(d_udpbuf != NULL){
802 free(d_udpbuf);
803 }
804
805 // release UDP socket:
806
807 if ( d_udpsock != INVALID_SOCKET )
808 udp_exit( d_udpsock, d_multicastIp );
809
810 return true;
811}
812
813
814// ---------------------------------------------------------------------------------------------------
815// Receive and process one DTrack data packet (UDP; ASCII protocol):
816//
817// return value (o): receiving was successful (boolean)
818
819bool vrpn_Tracker_DTrack::dtrack_receive()
820{
821 char* s;
822 int i, j, k, l, n, len, id;
823 char sfmt[20];
824 int iarr[3];
825 float f;
826 int loc_num_bodycal, loc_num_flystick1, loc_num_meatool;
827
828 if(d_udpsock == INVALID_SOCKET){
829 d_lasterror = DTRACK_ERR_UDP;
830 return false;
831 }
832
833 // defaults:
834
835 act_framecounter = 0;
836 act_timestamp = -1;
837 act_timestamp_sec = 0;
838 act_timestamp_usec = 0;
839 act_latency_usec = 0;
840
841 loc_num_bodycal = -1; // i.e. not available
842 loc_num_flystick1 = loc_num_meatool = 0;
843
844 act_has_bodycal_format = false;
845
846 // receive UDP packet:
847
848 len = udp_receive(d_udpsock, d_udpbuf, d_udpbufsize-1, d_udptimeout_us);
849
850 if(len == -1){
851 d_lasterror = DTRACK_ERR_TIMEOUT;
852 return false;
853 }
854 if(len <= 0){
855 d_lasterror = DTRACK_ERR_UDP;
856 return false;
857 }
858
859 s = d_udpbuf;
860 s[len] = '\0';
861
862 // process lines:
863
864 d_lasterror = DTRACK_ERR_PARSE;
865
866 do{
867 // line for frame counter:
868
869 if(!strncmp(s, "fr ", 3)){
870 s += 3;
871
872 if(!(s = string_get_ui(s, &act_framecounter))){ // get frame counter
873 act_framecounter = 0;
874 return false;
875 }
876
877 continue;
878 }
879
880 // line for timestamp:
881
882 if(!strncmp(s, "ts ", 3)){
883 s += 3;
884
885 if(!(s = string_get_d(s, &act_timestamp))){ // get time stamp
886 act_timestamp = -1;
887 return false;
888 }
889
890 continue;
891 }
892
893 // line for extended timestamp:
894
895 if ( strncmp( s, "ts2 ", 4 ) == 0 )
896 {
897 s += 4;
898
899 s = string_get_ui( s, &act_timestamp_sec );
900
901 if ( s != NULL )
902 s = string_get_ui( s, &act_timestamp_usec );
903
904 if ( s != NULL )
905 s = string_get_ui( s, &act_latency_usec );
906
907 if ( s == NULL )
908 {
909 act_timestamp_sec = 0;
910 act_timestamp_usec = 0;
911 act_latency_usec = 0;
912 return false;
913 }
914
915 continue;
916 }
917
918 // line for additional information about number of calibrated bodies:
919
920 if(!strncmp(s, "6dcal ", 6)){
921 s += 6;
922
923 act_has_bodycal_format = true;
924
925 if(!(s = string_get_i(s, &loc_num_bodycal))){ // get number of calibrated bodies
926 return false;
927 }
928
929 continue;
930 }
931
932 // line for 3dof marker data:
933
934 if(!strncmp(s, "3d ", 3)){
935 s += 3;
936 act_num_marker = 0;
937
938 if(!(s = string_get_i(s, &n))){ // get number of standard bodies (in line)
939 return false;
940 }
941
942 if (static_cast<unsigned>(n) > act_marker.size()) {
943 act_marker.resize(n);
944 }
945
946 for(i=0; i<n; i++){ // get data of standard bodies
947 if(!(s = string_get_block(s, "if", &id, &f))){
948 return false;
949 }
950
951 act_marker[act_num_marker].id = id;
952
953 if(!(s = string_get_block(s, "fff", NULL, act_marker[act_num_marker].loc))){
954 return false;
955 }
956
957 act_num_marker++;
958 }
959
960 continue;
961 }
962
963 // line for standard body data:
964
965 if(!strncmp(s, "6d ", 3)){
966 s += 3;
967
968 for(i=0; i<act_num_body; i++){ // disable all existing data
969 memset(&act_body[i], 0, sizeof(vrpn_dtrack_body_type));
970 act_body[i].id = i;
971 act_body[i].quality = -1;
972 }
973
974 if(!(s = string_get_i(s, &n))){ // get number of standard bodies (in line)
975 return false;
976 }
977
978 for(i=0; i<n; i++){ // get data of standard bodies
979 if(!(s = string_get_block(s, "if", &id, &f))){
980 return false;
981 }
982
983 if(id >= act_num_body){ // adjust length of vector
984 act_body.resize(id + 1);
985
986 for(j=act_num_body; j<=id; j++){
987 memset(&act_body[j], 0, sizeof(vrpn_dtrack_body_type));
988 act_body[j].id = j;
989 act_body[j].quality = -1;
990 }
991
992 act_num_body = id + 1;
993 }
994
995 act_body[id].id = id;
996 act_body[id].quality = f;
997
998 if(!(s = string_get_block(s, "fff", NULL, act_body[id].loc))){
999 return false;
1000 }
1001
1002 if(!(s = string_get_block(s, "fffffffff", NULL, act_body[id].rot))){
1003 return false;
1004 }
1005 }
1006
1007 continue;
1008 }
1009
1010 // line for Flystick data (older format):
1011
1012 if(!strncmp(s, "6df ", 4)){
1013 s += 4;
1014
1015 act_has_old_flystick_format = true;
1016
1017 if(!(s = string_get_i(s, &n))){ // get number of calibrated Flysticks
1018 return false;
1019 }
1020
1021 loc_num_flystick1 = n;
1022
1023 if(n > act_num_flystick){ // adjust length of vector
1024 act_flystick.resize(n);
1025
1026 act_num_flystick = n;
1027 }
1028
1029 for(i=0; i<n; i++){ // get data of Flysticks
1030 if(!(s = string_get_block(s, "ifi", iarr, &f))){
1031 return false;
1032 }
1033
1034 if(iarr[0] != i){ // not expected
1035 return false;
1036 }
1037
1038 act_flystick[i].id = iarr[0];
1039 act_flystick[i].quality = f;
1040
1041 act_flystick[i].num_button = 8;
1042 k = iarr[1];
1043 for(j=0; j<8; j++){
1044 act_flystick[i].button[j] = k & 0x01;
1045 k >>= 1;
1046 }
1047
1048 act_flystick[i].num_joystick = 2; // additionally to buttons 5-8
1049 if(iarr[1] & 0x20){
1050 act_flystick[i].joystick[0] = -1;
1051 }else if(iarr[1] & 0x80){
1052 act_flystick[i].joystick[0] = 1;
1053 }else{
1054 act_flystick[i].joystick[0] = 0;
1055 }
1056 if(iarr[1] & 0x10){
1057 act_flystick[i].joystick[1] = -1;
1058 }else if(iarr[1] & 0x40){
1059 act_flystick[i].joystick[1] = 1;
1060 }else{
1061 act_flystick[i].joystick[1] = 0;
1062 }
1063
1064 if(!(s = string_get_block(s, "fff", NULL, act_flystick[i].loc))){
1065 return false;
1066 }
1067
1068 if(!(s = string_get_block(s, "fffffffff", NULL, act_flystick[i].rot))){
1069 return false;
1070 }
1071 }
1072
1073 continue;
1074 }
1075
1076 // line for Flystick data (newer format):
1077
1078 if(!strncmp(s, "6df2 ", 5)){
1079 s += 5;
1080
1081 act_has_old_flystick_format = false;
1082
1083 if(!(s = string_get_i(s, &n))){ // get number of calibrated Flysticks
1084 return false;
1085 }
1086
1087 if(n > act_num_flystick){ // adjust length of vector
1088 act_flystick.resize(n);
1089
1090 act_num_flystick = n;
1091 }
1092
1093 if(!(s = string_get_i(s, &n))){ // get number of Flysticks
1094 return false;
1095 }
1096
1097 for(i=0; i<n; i++){ // get data of Flysticks
1098 if(!(s = string_get_block(s, "ifii", iarr, &f))){
1099 return false;
1100 }
1101
1102 if(iarr[0] != i){ // not expected
1103 return false;
1104 }
1105
1106 act_flystick[i].id = iarr[0];
1107 act_flystick[i].quality = f;
1108
1109 if(iarr[1] > vrpn_DTRACK_FLYSTICK_MAX_BUTTON){
1110 return false;
1111 }
1113 return false;
1114 }
1115 act_flystick[i].num_button = iarr[1];
1116 act_flystick[i].num_joystick = iarr[2];
1117
1118 if(!(s = string_get_block(s, "fff", NULL, act_flystick[i].loc))){
1119 return false;
1120 }
1121
1122 if(!(s = string_get_block(s, "fffffffff", NULL, act_flystick[i].rot))){
1123 return false;
1124 }
1125
1126 vrpn_strcpy(sfmt, "");
1127 j = 0;
1128 while(j < act_flystick[i].num_button){
1129 strcat(sfmt, "i");
1130 j += 32;
1131 }
1132 j = 0;
1133 while(j < act_flystick[i].num_joystick){
1134 strcat(sfmt, "f");
1135 j++;
1136 }
1137
1138 if(!(s = string_get_block(s, sfmt, iarr, act_flystick[i].joystick))){
1139 return false;
1140 }
1141
1142 k = l = 0;
1143 for(j=0; j<act_flystick[i].num_button; j++){
1144 act_flystick[i].button[j] = iarr[k] & 0x01;
1145 iarr[k] >>= 1;
1146
1147 l++;
1148 if(l == 32){
1149 k++;
1150 l = 0;
1151 }
1152 }
1153 }
1154
1155 continue;
1156 }
1157
1158 // line for measurement tool data:
1159
1160 if(!strncmp(s, "6dmt ", 5)){
1161 s += 5;
1162
1163 if(!(s = string_get_i(s, &n))){ // get number of calibrated measurement tools
1164 return false;
1165 }
1166
1167 loc_num_meatool = n;
1168
1169 continue;
1170 }
1171
1172 // ignore unknown line identifiers (could be valid in future DTracks)
1173
1174 }while((s = string_nextline(d_udpbuf, s, d_udpbufsize)) != NULL);
1175
1176 // set number of calibrated standard bodies, if necessary:
1177
1178 if(loc_num_bodycal >= 0){ // '6dcal' information was available
1179 act_num_bodycal = loc_num_bodycal - loc_num_flystick1 - loc_num_meatool;
1180 }
1181
1182 d_lasterror = DTRACK_ERR_NONE;
1183 return true;
1184}
1185
1186
1187// ---------------------------------------------------------------------------------------------------
1188// ---------------------------------------------------------------------------------------------------
1189// Parsing DTrack data:
1190
1191// Search next line in buffer:
1192// str (i): buffer (total)
1193// start (i): start position within buffer
1194// len (i): buffer length in bytes
1195// return (i): begin of line, NULL if no new line in buffer
1196
1197static char* string_nextline(char* str, char* start, int len)
1198{
1199 char* s = start;
1200 char* se = str + len;
1201 int crlffound = 0;
1202
1203 while(s < se){
1204 if(*s == '\r' || *s == '\n'){ // crlf
1205 crlffound = 1;
1206 }else{
1207 if(crlffound){ // begin of new line found
1208 return (*s) ? s : NULL; // first character is '\0': end of buffer
1209 }
1210 }
1211
1212 s++;
1213 }
1214
1215 return NULL; // no new line found in buffer
1216}
1217
1218
1219// Read next 'int' value from string:
1220// str (i): string
1221// i (o): read value
1222// return value (o): pointer behind read value in str; NULL in case of error
1223
1224static char* string_get_i(char* str, int* i)
1225{
1226 char* s;
1227
1228 *i = (int )strtol(str, &s, 0);
1229 return (s == str) ? NULL : s;
1230}
1231
1232
1233// Read next 'unsigned int' value from string:
1234// str (i): string
1235// ui (o): read value
1236// return value (o): pointer behind read value in str; NULL in case of error
1237
1238static char* string_get_ui(char* str, unsigned int* ui)
1239{
1240 char* s;
1241
1242 *ui = ( unsigned int )strtoul( str, &s, 10 );
1243 return (s == str) ? NULL : s;
1244}
1245
1246
1247// Read next 'double' value from string:
1248// str (i): string
1249// d (o): read value
1250// return value (o): pointer behind read value in str; NULL in case of error
1251
1252static char* string_get_d(char* str, double* d)
1253{
1254 char* s;
1255
1256 *d = strtod(str, &s);
1257 return (s == str) ? NULL : s;
1258}
1259
1260
1261// Read next 'float' value from string:
1262// str (i): string
1263// f (o): read value
1264// return value (o): pointer behind read value in str; NULL in case of error
1265
1266static char* string_get_f(char* str, float* f)
1267{
1268 char* s;
1269
1270 *f = (float )strtod(str, &s); // strtof() only available in GNU-C
1271 return (s == str) ? NULL : s;
1272}
1273
1274
1275// Process next block '[...]' in string:
1276// str (i): string
1277// fmt (i): format string ('i' for 'int', 'f' for 'float')
1278// idat (o): array for 'int' values (long enough due to fmt)
1279// fdat (o): array for 'float' values (long enough due to fmt)
1280// return value (o): pointer behind read value in str; NULL in case of error
1281
1282static char* string_get_block(char* str, const char* fmt, int* idat, float* fdat)
1283{
1284 char* strend;
1285 int index_i, index_f;
1286
1287 if((str = strchr(str, '[')) == NULL){ // search begin of block
1288 return NULL;
1289 }
1290 if((strend = strchr(str, ']')) == NULL){ // search end of block
1291 return NULL;
1292 }
1293
1294 str++; // (temporarily) remove delimiters
1295 *strend = '\0';
1296
1297 index_i = index_f = 0;
1298
1299 while(*fmt){
1300 switch(*fmt++){
1301 case 'i':
1302 if((str = string_get_i(str, &idat[index_i++])) == NULL){
1303 *strend = ']';
1304 return NULL;
1305 }
1306 break;
1307
1308 case 'f':
1309 if((str = string_get_f(str, &fdat[index_f++])) == NULL){
1310 *strend = ']';
1311 return NULL;
1312 }
1313 break;
1314
1315 default: // unknown format character
1316 *strend = ']';
1317 return NULL;
1318 }
1319 }
1320
1321 // ignore additional data inside the block
1322
1323 *strend = ']';
1324 return strend + 1;
1325}
1326
1327
1328// ---------------------------------------------------------------------------------------------------
1329// ---------------------------------------------------------------------------------------------------
1330// Handling UDP data:
1331
1332// Convert string to IP address:
1333// name (i): ipv4 dotted decimal address or hostname
1334// return value (o): IP address, 0 if error occured
1335
1336static unsigned int ip_name2ip( const char* name )
1337{
1338#if defined( VRPN_USE_WINSOCK_SOCKETS ) && ! defined( VRPN_USE_WINSOCK2 )
1339 fprintf( stderr, "vrpn_Tracker_DTrack: This build does not support multicast UDP; needs VRPN_USE_WINSOCK2.\n" );
1340 return 0;
1341#else
1342 int err;
1343 struct addrinfo hints, *res;
1344
1345 memset( &hints, 0, sizeof( hints ) );
1346 hints.ai_family = AF_INET; // only IPv4 supported
1347 hints.ai_socktype = SOCK_STREAM;
1348
1349 res = NULL;
1350 err = getaddrinfo( name, NULL, &hints, &res );
1351 if ( err != 0 || res == NULL )
1352 return 0;
1353
1354 unsigned int ip;
1355 struct sockaddr_in sin;
1356 memcpy( &sin, res->ai_addr, sizeof( sin ) ); // casting is causing warnings (-Wcast-align) by some compilers
1357 ip = ntohl( ( ( struct in_addr )( sin.sin_addr ) ).s_addr );
1358
1359 freeaddrinfo( res );
1360 return ip;
1361#endif
1362}
1363
1364
1365// Initialize UDP socket:
1366// port (i): port number
1367// multicastIp (i): multicast IP to listen, or 0
1368// return value (o): socket number, INVALID_SOCKET if error
1369
1370static vrpn_SOCKET udp_init( unsigned short port, unsigned int multicastIp )
1371{
1372 vrpn_SOCKET sock;
1373 struct sockaddr_in name;
1374
1375 // initialize socket dll (only Windows):
1376
1377#ifdef VRPN_USE_WINSOCK_SOCKETS
1378 {
1379 WORD vreq;
1380 WSADATA wsa;
1381
1382 vreq = MAKEWORD(2, 0);
1383
1384 if(WSAStartup(vreq, &wsa) != 0){
1385 return INVALID_SOCKET;
1386 }
1387 }
1388#endif
1389
1390 // create socket:
1391
1392 sock = socket( AF_INET, SOCK_DGRAM, 0 );
1393
1394 if ( sock == INVALID_SOCKET )
1395 {
1396#ifdef VRPN_USE_WINSOCK_SOCKETS
1397 WSACleanup();
1398#endif
1399 return INVALID_SOCKET;
1400 }
1401
1402 if ( multicastIp != 0 )
1403 {
1404 // set reuse port to on to allow multiple binds per host
1405 int flag_on = 1;
1406 if ( setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, ( char* )&flag_on, sizeof( flag_on ) ) < 0 )
1407 {
1408 udp_exit( sock, 0 );
1409 return INVALID_SOCKET;
1410 }
1411 }
1412
1413 // name socket:
1414
1415 name.sin_family = AF_INET;
1416 name.sin_port = htons(port);
1417 name.sin_addr.s_addr = htonl(INADDR_ANY);
1418
1419 if(bind(sock, (struct sockaddr *) &name, sizeof(name)) < 0){
1420 udp_exit( sock, 0 );
1421 return INVALID_SOCKET;
1422 }
1423
1424 if ( multicastIp != 0 )
1425 {
1426 // construct an IGMP join request structure
1427 struct ip_mreq ipmreq;
1428 ipmreq.imr_multiaddr.s_addr = htonl( multicastIp );
1429 ipmreq.imr_interface.s_addr = htonl( INADDR_ANY );
1430
1431 // send an ADD MEMBERSHIP message via setsockopt
1432 if ( setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, ( char* )&ipmreq, sizeof( ipmreq ) ) < 0 )
1433 {
1434 udp_exit( sock, 0 );
1435 return INVALID_SOCKET;
1436 }
1437 }
1438
1439 return sock;
1440}
1441
1442
1443// Deinitialize UDP socket:
1444// sock (i): socket number
1445// multicastIp (i): multicast IP to listen, or 0
1446// return value (o): 0 ok, -1 error
1447
1448static int udp_exit( vrpn_SOCKET sock, unsigned int multicastIp )
1449{
1450 int err;
1451
1452 if ( multicastIp != 0 )
1453 {
1454 struct ip_mreq ipmreq;
1455 ipmreq.imr_multiaddr.s_addr = htonl( multicastIp );
1456 ipmreq.imr_interface.s_addr = htonl( INADDR_ANY );
1457
1458 // send a DROP MEMBERSHIP message via setsockopt
1459 setsockopt( sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, ( char* )&ipmreq, sizeof( ipmreq ) );
1460 }
1461
1462#ifdef VRPN_USE_WINSOCK_SOCKETS
1463 err = closesocket(sock);
1464 WSACleanup();
1465#else
1466 err = close(sock);
1467#endif
1468
1469 if(err < 0){
1470 return -1;
1471 }
1472
1473 return 0;
1474}
1475
1476
1477// Receive UDP data:
1478// - tries to receive packets, as long as data are available
1479// sock (i): socket number
1480// buffer (o): buffer for UDP data
1481// maxlen (i): length of buffer
1482// tout_us (i): timeout in us (micro sec)
1483// return value (o): number of received bytes, <0 if error/timeout occurred
1484
1485// Don't tell us about the FD_SET causing a conditional expression to be constant
1486#ifdef VRPN_USE_WINSOCK_SOCKETS
1487#pragma warning ( disable : 4127 )
1488#endif
1489
1490static int udp_receive( vrpn_SOCKET sock, void *buffer, int maxlen, int tout_us )
1491{
1492 int nbytes, err;
1493 fd_set set;
1494 struct timeval tout;
1495
1496 // waiting for data:
1497
1498 FD_ZERO(&set);
1499 FD_SET(sock, &set);
1500
1501 tout.tv_sec = tout_us / 1000000;
1502 tout.tv_usec = tout_us % 1000000;
1503
1504 switch((err = select(FD_SETSIZE, &set, NULL, NULL, &tout))){
1505 case 1:
1506 break; // data available
1507 case 0:
1508 return -1; // timeout
1509 default:
1510 return -2; // error
1511 }
1512
1513 // receiving packet:
1514
1515 while(1){
1516
1517 // receive one packet:
1518
1519 nbytes = recv(sock, (char *)buffer, maxlen, 0);
1520
1521 if(nbytes < 0){ // receive error
1522 return -3;
1523 }
1524
1525 // check, if more data available: if so, receive another packet
1526
1527 FD_ZERO(&set);
1528 FD_SET(sock, &set);
1529
1530 tout.tv_sec = 0; // timeout with value of zero, thus no waiting
1531 tout.tv_usec = 0;
1532
1533 if(select(FD_SETSIZE, &set, NULL, NULL, &tout) != 1){
1534
1535 // no more data available: check length of received packet and return
1536
1537 if(nbytes >= maxlen){ // buffer overflow
1538 return -4;
1539 }
1540
1541 return nbytes;
1542 }
1543 }
1544}
1545
1546
1547// Send UDP data:
1548// buffer (i): buffer for UDP data
1549// len (i): length of buffer
1550// ip (i): IPv4 address to send data to
1551// port (i): port number to send data to
1552// toutUs (i): timeout in us (micro sec)
1553// return value (o): 0 if ok, <0 if error/timeout occured
1554
1555static int udp_send( vrpn_SOCKET sock, const void* buffer, int len, unsigned int ip, unsigned short port, int toutUs )
1556{
1557 fd_set set;
1558 struct timeval tout;
1559 int err;
1560 struct sockaddr_in addr;
1561
1562 // building address:
1563 addr.sin_family = AF_INET;
1564 addr.sin_addr.s_addr = htonl( ip );
1565 addr.sin_port = htons( port );
1566
1567 // waiting to send data:
1568 FD_ZERO( &set );
1569 FD_SET( sock, &set );
1570 tout.tv_sec = toutUs / 1000000;
1571 tout.tv_usec = toutUs % 1000000;
1572
1573 err = select( FD_SETSIZE, NULL, &set, NULL, &tout );
1574 switch ( err )
1575 {
1576 case 1:
1577 break;
1578 case 0:
1579 return -1; // timeout
1580 default:
1581 return -2; // error
1582 }
1583
1584 // sending data:
1585 int nbytes = static_cast< int >( sendto( sock, ( const char* )buffer, len, 0, ( struct sockaddr* )&addr,
1586 ( size_t )sizeof( struct sockaddr_in ) ) );
1587 if ( nbytes < len )
1588 { // send error
1589 return -3;
1590 }
1591 return 0;
1592}
1593
1594
1595#endif // sgi
1596
vrpn_float64 channel[vrpn_CHANNEL_MAX]
Definition vrpn_Analog.h:38
vrpn_Analog(const char *name, vrpn_Connection *c=NULL)
Definition vrpn_Analog.C:14
struct timeval timestamp
Definition vrpn_Analog.h:41
vrpn_int32 num_channel
Definition vrpn_Analog.h:40
virtual void report_changes(vrpn_uint32 class_of_service=vrpn_CONNECTION_LOW_LATENCY, const struct timeval time=vrpn_ANALOG_NOW)
Send a report only if something has changed (for servers) Optionally, tell what time to stamp the val...
Definition vrpn_Analog.C:71
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...
vrpn_Button_Filter(const char *, vrpn_Connection *c=NULL)
vrpn_int32 num_buttons
Definition vrpn_Button.h:48
struct timeval timestamp
Definition vrpn_Button.h:49
virtual void report_changes(void)
unsigned char buttons[vrpn_BUTTON_MAX_BUTTONS]
Definition vrpn_Button.h:45
virtual int pack_message(vrpn_uint32 len, struct timeval time, vrpn_int32 type, vrpn_int32 sender, const char *buffer, vrpn_uint32 class_of_service)
Pack a message that will be sent the next time mainloop() is called. Turn off the RELIABLE flag if yo...
vrpn_Tracker_DTrack(const char *name, vrpn_Connection *c, const char *dtrackHost, int dtrackPort, bool doFirewall, float timeToReachJoy=0.f, int fixNbody=-1, int fixNflystick=-1, int *fixId=NULL, bool act3DOFout=false, bool actTracing=false)
virtual void mainloop()
This function should be called each time through the main loop of the server code....
virtual int encode_to(char *buf)
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
vrpn_float64 pos[3]
vrpn_int32 num_sensors
vrpn_int32 position_m_id
#define INVALID_SOCKET
const vrpn_uint32 vrpn_CONNECTION_LOW_LATENCY
Header containing macros formerly duplicated in a lot of implementation files.
double vrpn_TimevalDurationSeconds(struct timeval endT, struct timeval startT)
Return the number of seconds between startT and endT as a floating-point value.
#define vrpn_SOCKET
Definition vrpn_Shared.h:54
void vrpn_strcpy(char(&to)[charCount], const char *pSrc)
Null-terminated-string copy function that both guarantees not to overrun the buffer and guarantees th...
#define vrpn_gettimeofday
#define DTRACK2VRPN_ANALOGS_PER_FLYSTICK
#define DTRACK_ERR_TIMEOUT
#define DTRACK_ERR_UDP
#define DTRACK2VRPN_BUTTONS_PER_FLYSTICK
#define DTRACK_ERR_PARSE
#define UDPRECEIVE_BUFSIZE
#define DTRACK_ERR_NONE
#define vrpn_DTRACK_FLYSTICK_MAX_BUTTON
#define vrpn_DTRACK_FLYSTICK_MAX_JOYSTICK
class VRPN_API vrpn_Connection