DTrackSDK  v2.9.0
DTrackSDK.cpp
1 /* DTrackSDK in C++: DTrackSDK.cpp
2  *
3  * Functions to receive and process DTrack UDP packets (ASCII protocol), as
4  * well as to exchange DTrack2/DTRACK3 TCP command strings.
5  *
6  * Copyright (c) 2007-2024 Advanced Realtime Tracking GmbH & Co. KG
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in the
15  * documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of copyright holder nor the names of its contributors
17  * may be used to endorse or promote products derived from this software
18  * without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * Version v2.9.0
32  *
33  * Purpose:
34  * - receives DTrack UDP packets (ASCII protocol) and converts them into easier to handle data
35  * - sends and receives DTrack2/DTRACK3 commands (TCP)
36  * - DTrack network protocol according to:
37  * 'DTrack2 User Manual, Technical Appendix' or 'DTRACK3 Programmer's Guide'
38  */
39 
40 #include <sstream>
41 
42 #include "DTrackSDK.hpp"
43 #include "DTrackParse.hpp"
44 
45 #include <cstring>
46 #include <cstdlib>
47 #include <clocale>
48 
49 #if ! defined( _MSC_VER )
50  #define strcpy_s( a, b, c ) strcpy( a, c ) // map 'strcpy_s' if not Visual Studio
51 #endif
52 
53 using namespace DTrackNet;
54 using namespace DTrackSDK_Parse;
55 
56 
57 /*
58  * Universal constructor. Can be used for any mode.
59  */
60 DTrackSDK::DTrackSDK( const std::string& connection )
61 {
62  std::vector< std::string > args; // parse connection string
63  size_t ind = 0;
64  while ( true )
65  {
66  size_t ind1 = connection.find_first_of( ':', ind );
67  if ( ind1 == std::string::npos )
68  {
69  args.push_back( connection.substr( ind ) );
70  break;
71  }
72  else
73  {
74  args.push_back( connection.substr( ind, ind1 - ind ) );
75  ind = ind1 + 1;
76 
77  if ( ind >= connection.length() )
78  {
79  args.push_back( std::string() );
80  break;
81  }
82  }
83  }
84  if ( ( args.size() == 0 ) || ( args.size() > 3 ) ) return; // invalid connection string
85 
86  std::string host;
87  std::istringstream portstream;
88  bool isFw = false;
89 
90  if ( args.size() == 1 ) // argument "<data port>"
91  {
92  portstream.str( args[ 0 ] );
93  }
94  else // arguments at least "<ip/host>:<data port>"
95  {
96  host = args[ 0 ];
97  portstream.str( args[ 1 ] );
98 
99  if ( args.size() == 3 ) // arguments "<ip/host>:<data port>:fw"
100  {
101  if ( args[ 2 ].compare( "fw" ) != 0 ) return; // invalid suffix in connection string
102 
103  isFw = true;
104  }
105  }
106 
107  unsigned short port;
108  portstream >> port; // data port
109  if ( portstream.fail() || ( ! portstream.eof() ) ) return; // invalid port number
110 
111  if ( host.empty() )
112  {
113  init( "", 0, port, SYS_DTRACK_UNKNOWN );
114  }
115  else
116  {
117  if ( isFw )
118  {
119  init( "", 0, port, SYS_DTRACK_UNKNOWN );
120 
121  d_udpSenderIp = ip_name2ip( host.c_str() );
122 
123  sendStatefulFirewallPacket(); // try enabling UDP connection at once
124  }
125  else
126  {
127  init( host, 0, port, SYS_DTRACK_2 );
128  }
129  }
130 }
131 
132 
133 /*
134  * Constructor. Use for pure listening mode.
135  */
136 DTrackSDK::DTrackSDK(unsigned short data_port)
137  : DTrackParser()
138 {
139  init( "", 0, data_port, SYS_DTRACK_UNKNOWN );
140 }
141 
142 
143 /*
144  * Constructor. Use for communicating mode with DTrack2/DTRACK3.
145  */
146 DTrackSDK::DTrackSDK(const std::string& server_host, unsigned short data_port)
147  : DTrackParser()
148 {
149  init( server_host, 0, data_port, SYS_DTRACK_2 );
150 }
151 
152 
153 /*
154  * Constructor. Use for communicating mode with DTrack1.
155  */
156 DTrackSDK::DTrackSDK(const std::string& server_host, unsigned short server_port, unsigned short data_port)
157  : DTrackParser()
158 {
159  if ( server_port == DTRACK2_PORT_COMMAND )
160  {
161  init( server_host, server_port, data_port, SYS_DTRACK_UNKNOWN ); // due to compatibility to DTrackSDK v2.0.0
162  }
163  else
164  {
165  init( server_host, server_port, data_port, SYS_DTRACK );
166  }
167 }
168 
169 
170 /*
171  * General constructor. DEPRECATED.
172  */
173 DTrackSDK::DTrackSDK(const std::string& server_host, unsigned short server_port, unsigned short data_port,
174  RemoteSystemType remote_type, int data_bufsize, int data_timeout_us, int srv_timeout_us)
175  : DTrackParser()
176 {
177  init( server_host, server_port, data_port, remote_type );
178 
179  setDataTimeoutUS( data_timeout_us );
180  setCommandTimeoutUS( srv_timeout_us );
181  setDataBufferSize( data_bufsize ); // updates also UDP buffer
182 }
183 
184 
185 /*
186  * Private init called by constructor.
187  */
188 void DTrackSDK::init( const std::string& server_host, unsigned short server_port, unsigned short data_port,
189  RemoteSystemType remote_type )
190 {
191  setlocale( LC_NUMERIC, "C" );
192 
193  rsType = remote_type;
194 
195  d_udp = NULL;
196  d_tcp = NULL;
197  d_udpbuf = NULL;
198  d_udpbufsize = 0;
199 
200  lastDataError = ERR_NONE;
201  lastServerError = ERR_NONE;
202  setLastDTrackError();
203 
204  setDataTimeoutUS( 0 );
205  setCommandTimeoutUS( 0 );
206  setDataBufferSize( 0 ); // creates also UDP buffer
207 
208  d_remoteIp = 0;
209  d_remoteDT1Port = 0;
210  d_udpSenderIp = 0;
211  d_udpSenderPort = DTRACK2_PORT_UDPSENDER;
212 
213  net_init();
214 
215  // parse remote address if available
216  unsigned int remoteIp = 0;
217  if ( ! server_host.empty() )
218  remoteIp = ip_name2ip( server_host.c_str() );
219 
220  bool isMulticast = false;
221  if ( ( remoteIp & 0xf0000000 ) == 0xe0000000 ) // check if multicast IP
222  {
223  isMulticast = true;
224  rsType = SYS_DTRACK_UNKNOWN;
225  }
226 
227  // create UDP socket:
228 
229  if ( isMulticast ) // listen to multicast case
230  {
231  d_udp = new DTrackNet::UDP( data_port, remoteIp );
232  } else { // normal case
233  d_udp = new DTrackNet::UDP( data_port );
234  }
235  if ( ! d_udp->isValid() )
236  return;
237 
238  if ( ( remoteIp != 0 ) && ( ! isMulticast ) ) // IP of Controller/DTrack1 PC is known
239  {
240  d_remoteIp = remoteIp;
241  d_udpSenderIp = remoteIp;
242 
243  if ( rsType == SYS_DTRACK ) // server is DTrack1 PC
244  {
245  d_remoteDT1Port = server_port;
246  }
247  else // server is DTrack2/DTRACK3 or unknown: try TCP connection
248  {
249  d_tcp = new DTrackNet::TCP( remoteIp, DTRACK2_PORT_COMMAND );
250  if ( ! d_tcp->isValid() ) // no connection to DTrack2/DTRACK3 server
251  {
252  // on error assuming DTrack1 if system is unknown
253  if ( rsType == SYS_DTRACK_UNKNOWN )
254  {
255  rsType = SYS_DTRACK; // DTrack1 will not listen to tcp port 50105 -> ignore tcp connection
256  d_remoteDT1Port = server_port;
257  }
258  }
259  else
260  {
261  rsType = SYS_DTRACK_2; // TCP connection up, should be DTrack2/DTRACK3
262  }
263 
264  sendStatefulFirewallPacket(); // try enabling UDP connection at once
265  }
266  }
267 
268  d_message_origin = "";
269  d_message_status = "";
270  d_message_framenr = 0;
271  d_message_errorid = 0;
272  d_message_msg = "";
273 }
274 
275 
276 /*
277  * Destructor.
278  */
280 {
281  // release buffer
282  free(d_udpbuf);
283 
284  // release sockets & net
285  delete d_udp;
286  delete d_tcp;
287  net_exit();
288 }
289 
290 
291 /*
292  * Returns if constructor was successful due to the wanted mode.
293  */
295 {
296  if ( ! isDataInterfaceValid() ) return false;
297 
298  if ( rsType == SYS_DTRACK_2 )
299  {
300  if ( ! isCommandInterfaceFullAccess() ) return false; // calls also isCommandInterfaceValid()
301  }
302 
303  return true;
304 }
305 
306 
307 /*
308  * Returns if UDP socket is open to receive tracking data on local machine.
309  */
311 {
312  if ( d_udp == NULL ) return false;
313 
314  return d_udp->isValid();
315 }
316 
317 
318 /*
319  * Get UDP data port where tracking data is received.
320  */
321 unsigned short DTrackSDK::getDataPort() const
322 {
323  return d_udp->getPort();
324 }
325 
326 
327 /*
328  * Returns if TCP connection for DTrack2/DTRACK3 commands is active.
329  */
331 {
332  if ( d_tcp == NULL ) return false;
333 
334  return d_tcp->isValid();
335 }
336 
337 
338 /*
339  * Returns if TCP connection has full access for DTrack2/DTRACK3 commands.
340  */
342 {
343  if ( ! isCommandInterfaceValid() ) return false;
344 
345  std::string par;
346  bool isOk = getParam( "system", "access", par ); // ensure full access for DTrack2/DTRACK3 commands
347  if ( ( ! isOk ) || ( par.compare( "full" ) != 0 ) ) return false;
348 
349  return true;
350 }
351 
352 
353 /*
354  * Get current remote system type (e.g. DTrack1, DTrack2/DTRACK3).
355  */
357 {
358  return rsType;
359 }
360 
361 
362 /*
363  * Set UDP timeout for receiving tracking data.
364  */
365 bool DTrackSDK::setDataTimeoutUS( int timeout )
366 {
367  if ( timeout <= 0 )
368  {
369  d_udptimeout_us = DEFAULT_UDP_TIMEOUT;
370  }
371  else
372  {
373  d_udptimeout_us = timeout;
374  }
375  return true;
376 }
377 
378 
379 /*
380  * Set TCP timeout for exchanging commands with Controller.
381  */
383 {
384  if ( timeout <= 0 )
385  {
386  d_tcptimeout_us = DEFAULT_TCP_TIMEOUT;
387  }
388  else
389  {
390  d_tcptimeout_us = timeout;
391  }
392  return true;
393 }
394 
395 
396 /*
397  * Set UDP buffer size for receiving tracking data.
398  */
399 bool DTrackSDK::setDataBufferSize( int bufSize )
400 {
401  int newBufSize;
402  if ( bufSize <= 0 )
403  {
404  newBufSize = DEFAULT_UDP_BUFSIZE;
405  }
406  else
407  {
408  newBufSize = bufSize;
409  }
410 
411  if ( newBufSize != d_udpbufsize )
412  {
413  free( d_udpbuf );
414 
415  d_udpbufsize = newBufSize;
416  d_udpbuf = (char *)malloc( d_udpbufsize );
417  }
418  return ( d_udpbuf != NULL );
419 }
420 
421 
422 /*
423  * Enable UDP connection through a stateful firewall.
424  */
425 bool DTrackSDK::enableStatefulFirewallConnection( const std::string& senderHost, unsigned short senderPort )
426 {
427  if ( ! senderHost.empty() )
428  d_udpSenderIp = ip_name2ip( senderHost.c_str() );
429 
430  d_udpSenderPort = senderPort;
431 
432  sendStatefulFirewallPacket(); // try enabling UDP connection
433 
434  return ( d_udpSenderIp != 0 );
435 }
436 
437 
438 /*
439  * Receive and process one tracking data packet.
440  */
442 {
443  char* s;
444  int len;
445 
446  lastDataError = ERR_NONE;
447  lastServerError = ERR_NONE;
448 
449  if ( ! isDataInterfaceValid() )
450  {
451  lastDataError = ERR_NET;
452  return false;
453  }
454 
455  // defaults:
456  startFrame();
457 
458  // receive UDP packet:
459  len = d_udp->receive( d_udpbuf, d_udpbufsize - 1, d_udptimeout_us );
460  if (len == -1) {
461  lastDataError = ERR_TIMEOUT;
462  return false;
463  }
464 
465  if (len <= 0) {
466  lastDataError = ERR_NET;
467  return false;
468  }
469 
470  s = d_udpbuf;
471  s[len] = '\0';
472 
473  // process lines:
474  lastDataError = ERR_PARSE;
475 
476  do {
477  if (!parseLine(&s))
478  return false;
479 
480  s = string_nextline( d_udpbuf, s, d_udpbufsize );
481  } while ( s != NULL );
482 
483  endFrame();
484 
485  lastDataError = ERR_NONE;
486  return true;
487 }
488 
489 
490 /*
491  * Process one tracking packet manually.
492  */
493 bool DTrackSDK::processPacket( const std::string& data )
494 {
495  char* sBuf;
496  char* s;
497 
498  lastDataError = ERR_NONE;
499  lastServerError = ERR_NONE;
500 
501  // defaults:
502  startFrame();
503 
504  if ( data.length() == 0 )
505  {
506  lastDataError = ERR_PARSE;
507  return false;
508  }
509 
510  sBuf = (char *)malloc( data.length() + 1 );
511  if ( sBuf == NULL ) return false;
512 
513  strcpy_s( sBuf, data.length() + 1, data.c_str() );
514 
515  s = sBuf;
516 
517  // process lines:
518  lastDataError = ERR_PARSE;
519 
520  do {
521  if (!parseLine(&s))
522  return false;
523 
524  s = string_nextline( sBuf, s, static_cast< int >( data.length() ) );
525  } while( s != NULL );
526 
527  endFrame();
528 
529  lastDataError = ERR_NONE;
530  return true;
531 }
532 
533 
534 /*
535  * Get content of the UDP buffer.
536  */
537 std::string DTrackSDK::getBuf() const
538 {
539  if ( d_udpbuf == NULL )
540  return std::string( "" );
541 
542  return std::string( d_udpbuf );
543 }
544 
545 
546 /*
547  * Get last error at receiving tracking data (data transmission).
548  */
550 {
551  return lastDataError;
552 }
553 
554 
555 /*
556  * Get last error at exchanging commands with Controller (command transmission).
557  */
559 {
560  return lastServerError;
561 }
562 
563 
564 /*
565  * Get last DTrack2/DTRACK3 command error code.
566  */
568 {
569  return lastDTrackError;
570 }
571 
572 
573 /*
574  * Get last DTrack2/DTRACK3 command error description.
575  */
577 {
578  return lastDTrackErrorString;
579 }
580 
581 
582 /*
583  * Set last DTrack2/DTRACK3 command error.
584  */
585 void DTrackSDK::setLastDTrackError(int newError, const std::string& newErrorString)
586 {
587  lastDTrackError = newError;
588  lastDTrackErrorString = newErrorString;
589 }
590 
591 
592 /*
593  * Start measurement.
594  */
596 {
597  // Check for special DTrack handling
598  if ( rsType == SYS_DTRACK )
599  {
600  if ( ! sendDTrack1Command( "dtrack 10 3" ) ) return false;
601 
602  return sendDTrack1Command( "dtrack 31" );
603  }
604 
605  sendStatefulFirewallPacket(); // try enabling UDP connection
606 
607  // start tracking, 1 means answer "dtrack2 ok"
608  return (1 == sendDTrack2Command("dtrack2 tracking start"));
609 }
610 
611 
612 /*
613  * Stop measurement.
614  */
616 {
617  // Check for special DTrack handling
618  if ( rsType == SYS_DTRACK )
619  {
620  if ( ! sendDTrack1Command( "dtrack 32" ) ) return false;
621 
622  return sendDTrack1Command( "dtrack 10 0" );
623  }
624 
625  // stop tracking, 1 means answer "dtrack2 ok"
626  return (1 == sendDTrack2Command("dtrack2 tracking stop"));
627 }
628 
629 
630 /*
631  * Send DTrack1 command via UDP.
632  */
633 bool DTrackSDK::sendDTrack1Command( const std::string& command )
634 {
635  int err;
636 
637  if ( ! isDataInterfaceValid() )
638  return false;
639 
640  lastDataError = ERR_NONE;
641  // dest is dtrack2
642  if (rsType == SYS_DTRACK_2) {
643  // command style is dtrack?
644  if (0 == strncmp(command.c_str(), "dtrack ", 7)) {
645  std::string c = command.substr(7);
646  // start measurement
647  if (0 == strncmp(c.c_str(), "10 3",4)) {
648  return startMeasurement();
649  }
650  // stop measurement
651  if ( (0 == strncmp(c.c_str(), "10 0",4))
652  || (0 == strncmp(c.c_str(), "10 1",4)))
653  {
654  return stopMeasurement();
655  }
656  // simulate success of other old commands
657  return true;
658  }
659  }
660 
661  if ( ( d_remoteIp == 0 ) || ( d_remoteDT1Port == 0 ) )
662  return false;
663 
664  err = d_udp->send( ( void* )command.c_str(), ( int )command.length() + 1, d_remoteIp, d_remoteDT1Port, d_udptimeout_us );
665  if ( err != 0 )
666  {
667  lastDataError = ERR_NET;
668  return false;
669  }
670  if (strcmp(command.c_str(), "dtrack 10 3") == 0) {
671 #ifdef OS_UNIX
672  sleep(1); // some delay (actually only necessary for older DTrack versions...)
673 #endif
674 #ifdef OS_WIN
675  Sleep(1000); // some delay (actually only necessary for older DTrack versions...)
676 #endif
677  }
678  return true;
679 }
680 
681 
682 /*
683  * Send DTrack2/DTRACK3 command to DTrack and receive answer (TCP command interface).
684  */
685 int DTrackSDK::sendDTrack2Command(const std::string& command, std::string* answer)
686 {
687  // Params via TCP are not supported in DTrack
688  if (rsType != SYS_DTRACK_2)
689  return -2;
690 
691  // reset dtrack error
692  setLastDTrackError();
693 
694  // command too long?
695  if ( static_cast< int >( command.length() ) > DTRACK2_PROT_MAXLEN )
696  {
697  lastServerError = ERR_NET;
698  return -3;
699  }
700 
701  // connection invalid
702  if (!isCommandInterfaceValid()) {
703  lastServerError = ERR_NET;
704  return -10;
705  }
706 
707  // send TCP command string:
708  if ( d_tcp->send( command.c_str(), static_cast< int >( command.length() ) + 1, d_tcptimeout_us ) != 0 )
709  {
710  lastServerError = ERR_NET;
711  return -11;
712  }
713 
714  // receive TCP response string:
715  char ans[ DTRACK2_PROT_MAXLEN ];
716  int err;
717  err = d_tcp->receive( ans, DTRACK2_PROT_MAXLEN, d_tcptimeout_us );
718  if ( err < 0 )
719  {
720  if (err == -1) { // timeout
721  lastServerError = ERR_TIMEOUT;
722  }
723  else
724  if (err == -9) { // broken connection
725  delete d_tcp;
726  d_tcp = NULL;
727  }
728  else
729  lastServerError = ERR_NET; // network error
730 
731  if (answer)
732  *answer = "";
733 
734  return err;
735  }
736 
737  // parse answer:
738 
739  // check for "dtrack2 ok" / no error
740  if (0 == strcmp(ans, "dtrack2 ok"))
741  return 1;
742 
743  // got error msg?
744  if (0 == strncmp(ans, "dtrack2 err ", 12)) {
745  char *s = ans + 12;
746  int i;
747 
748  // parse error code
749  s = string_get_i( (char *)s, &i );
750  if ( s == NULL )
751  {
752  setLastDTrackError(-1100, "SDK error -1100");
753  lastServerError = ERR_PARSE;
754  return -1100;
755  }
756  lastDTrackError = i;
757 
758  // parse error string
759  s = string_get_quoted_text( (char *)s, lastDTrackErrorString );
760  if ( s == NULL )
761  {
762  setLastDTrackError(-1100, "SDK error -1100");
763  lastServerError = ERR_PARSE;
764  return -1101;
765  }
766 
767  return 2;
768  }
769 
770  // not 'dtrack2 ok'/'dtrack2 err ..' -> return msg
771  if (answer)
772  *answer = ans;
773 
774  lastServerError = ERR_NONE;
775  return 0;
776 }
777 
778 
779 /*
780  * Send dummy UDP packet for stateful firewall.
781  */
782 bool DTrackSDK::sendStatefulFirewallPacket()
783 {
784  int err;
785 
786  if ( ! isDataInterfaceValid() )
787  return false;
788 
789  if ( d_udpSenderIp == 0 ) return false;
790 
791  const char* txt = "fw4dtsdkc";
792 
793  err = d_udp->send( ( void* )txt, ( int )strlen( txt ) + 1, d_udpSenderIp, d_udpSenderPort, d_udptimeout_us );
794  if ( err != 0 )
795  {
796  lastDataError = ERR_NET;
797  return false;
798  }
799 
800  return true;
801 }
802 
803 
804 /*
805  * Set DTrack2/DTRACK3 parameter.
806  */
807 bool DTrackSDK::setParam(const std::string& category, const std::string& name, const std::string& value)
808 {
809  return setParam(category + " " + name + " " + value);
810 }
811 
812 
813 /*
814  * Set DTrack2/DTRACK3 parameter using a string containing parameter category, name and new value.
815  */
816 bool DTrackSDK::setParam(const std::string& parameter)
817 {
818  // send command, 1 means answer "dtrack2 ok"
819  return (1 == sendDTrack2Command("dtrack2 set " + parameter));
820 }
821 
822 
823 /*
824  * Get DTrack2/DTRACK3 parameter.
825  */
826 bool DTrackSDK::getParam(const std::string& category, const std::string& name, std::string& value)
827 {
828  return getParam(category + " " + name, value);
829 }
830 
831 
832 /*
833  * Get DTrack2/DTRACK3 parameter using a string containing parameter category and name.
834  */
835 bool DTrackSDK::getParam( const std::string& parameter, std::string& value )
836 {
837  std::string res;
838  if ( sendDTrack2Command( "dtrack2 get " + parameter, &res ) != 0 ) // checks also for 'err' answer
839  return false;
840 
841  // parse parameter from answer (expected answer starts with "dtrack2 set")
842  if ( res.compare( 0, 12, "dtrack2 set " ) != 0 )
843  {
844  lastServerError = ERR_PARSE;
845  return false;
846  }
847 
848  size_t pos = string_cmp_parameter( res, 12, parameter );
849  if ( pos == std::string::npos )
850  {
851  lastServerError = ERR_PARSE;
852  return false;
853  }
854 
855  // assign result
856  value = res.substr( pos );
857  return true;
858 }
859 
860 
861 /*
862  * Get DTrack2/DTRACK3 event message from the Controller.
863  */
865 {
866  // Messages via TCP are not supported in DTrack
867  if (rsType != SYS_DTRACK_2)
868  return false;
869 
870  // send request
871  std::string res;
872  if (0 != sendDTrack2Command("dtrack2 getmsg", &res))
873  return false;
874 
875  // check answer
876  if (0 != strncmp(res.c_str(), "dtrack2 msg ", 12))
877  return false;
878 
879  // reset values
880  d_message_origin = d_message_msg = d_message_status = "";
881  d_message_framenr = d_message_errorid = 0;
882 
883  // parse message
884  const char* s = res.c_str() + 12;
885  // get 'origin'
886  s = string_get_word( (char *)s, d_message_origin );
887  if ( s == NULL )
888  return false;
889 
890  // get 'status'
891  s = string_get_word( (char *)s, d_message_status );
892  if ( s == NULL )
893  return false;
894 
895  unsigned int ui;
896  // get 'frame counter'
897  s = string_get_ui( (char *)s, &ui );
898  if ( s == NULL )
899  return false;
900 
901  d_message_framenr = ui;
902 
903  // get 'error id'
904  s = string_get_ui( (char *)s, &ui );
905  if ( s == NULL )
906  return false;
907 
908  d_message_errorid = ui;
909 
910  // get 'message'
911  s = string_get_quoted_text( (char *)s, d_message_msg );
912  if ( s == NULL )
913  return false;
914 
915  return true;
916 }
917 
918 
919 /*
920  * Get frame counter of last DTrack2/DTRACK3 event message.
921  */
922 unsigned int DTrackSDK::getMessageFrameNr() const
923 {
924  return d_message_framenr;
925 }
926 
927 
928 /*
929  * Get error id of last DTrack2/DTRACK3 event message.
930  */
931 unsigned int DTrackSDK::getMessageErrorId() const
932 {
933  return d_message_errorid;
934 }
935 
936 
937 /*
938  * Get origin of last DTrack2/DTRACK3 event message.
939  */
940 std::string DTrackSDK::getMessageOrigin() const
941 {
942  return d_message_origin;
943 }
944 
945 
946 /*
947  * Get status of last DTrack2/DTRACK3 event message.
948  */
949 std::string DTrackSDK::getMessageStatus() const
950 {
951  return d_message_status;
952 }
953 
954 
955 /*
956  * Get message text of last DTrack2/DTRACK3 event message.
957  */
958 std::string DTrackSDK::getMessageMsg() const
959 {
960  return d_message_msg;
961 }
962 
963 
964 /*
965  * Send tactile FINGERTRACKING command to set feedback on a specific finger of a specific hand.
966  */
967 bool DTrackSDK::tactileFinger( int handId, int fingerId, double strength )
968 {
969  setLastDTrackError();
970 
971  if ( strength > 1.0 || strength < 0.0 )
972  {
973  lastServerError = ERR_NET;
974  return false;
975  }
976 
977  std::ostringstream os;
978  os << "tfb 1 [" << handId << " " << fingerId << " 1.0 " << strength << "]";
979 
980  return sendFeedbackCommand( os.str() );
981 }
982 
983 
984 /*
985  * Send tactile FINGERTRACKING command to set tactile feedback on all fingers of a specific hand.
986  */
987 bool DTrackSDK::tactileHand( int handId, const std::vector< double >& strength )
988 {
989  setLastDTrackError();
990 
991  std::ostringstream os;
992  os << "tfb " << strength.size() << " ";
993 
994  for ( size_t i = 0; i < strength.size(); i++ )
995  {
996  if ( strength[ i ] > 1.0 || strength[ i ] < 0.0 )
997  {
998  lastServerError = ERR_NET;
999  return false;
1000  }
1001 
1002  os << "[" << handId << " " << i << " 1.0 " << strength[ i ] << "]";
1003  }
1004 
1005  return sendFeedbackCommand( os.str() );
1006 }
1007 
1008 
1009 /*
1010  * Send tactile FINGERTRACKING command to turn off tactile feedback on all fingers of a specific hand.
1011  */
1012 bool DTrackSDK::tactileHandOff( int handId, int numFinger )
1013 {
1014  setLastDTrackError();
1015 
1016  std::vector< double > strength( numFinger, 0.0 );
1017 
1018  return tactileHand( handId, strength );
1019 }
1020 
1021 
1022 /*
1023  * Send Flystick feedback command to start a beep on a specific Flystick.
1024  */
1025 bool DTrackSDK::flystickBeep( int flystickId, double durationMs, double frequencyHz )
1026 {
1027  setLastDTrackError();
1028 
1029  std::ostringstream os;
1030  os << "ffb 1 ";
1031  os << "[" << flystickId << " " << ( int )durationMs << " " << ( int )frequencyHz << " 0 0][]";
1032 
1033  return sendFeedbackCommand( os.str() );
1034 }
1035 
1036 
1037 /*
1038  * Send Flystick feedback command to start a vibration pattern on a specific Flystick.
1039  */
1040 bool DTrackSDK::flystickVibration( int flystickId, int vibrationPattern )
1041 {
1042  setLastDTrackError();
1043 
1044  std::ostringstream os;
1045  os << "ffb 1 ";
1046  os << "[" << flystickId << " 0 0 " << vibrationPattern << " 0][]";
1047 
1048  return sendFeedbackCommand( os.str() );
1049 }
1050 
1051 
1052 /*
1053  * Send feedback command via UDP.
1054  */
1055 bool DTrackSDK::sendFeedbackCommand( const std::string& command )
1056 {
1057  int err;
1058 
1059  if ( ! isDataInterfaceValid() )
1060  return false;
1061 
1062  unsigned int ip = d_remoteIp;
1063  if ( ip == 0 ) // if IP of Controller is not known, try IP of latest received UDP data
1064  {
1065  ip = d_udp->getRemoteIp();
1066 
1067  if ( ip == 0 )
1068  return false;
1069  }
1070 
1071  err = d_udp->send( ( void* )command.c_str(), ( int )command.length() + 1, ip, DTRACK2_PORT_FEEDBACK, d_udptimeout_us );
1072  if ( err != 0 )
1073  {
1074  lastDataError = ERR_NET;
1075  return false;
1076  }
1077 
1078  return true;
1079 }
1080 
bool setDataBufferSize(int bufSize)
Set UDP buffer size for receiving tracking data.
Definition: DTrackSDK.cpp:399
Errors
Error codes.
Definition: DTrackSDK.hpp:91
std::string getBuf() const
Get content of the UDP buffer.
Definition: DTrackSDK.cpp:537
int send(const void *buffer, int len, unsigned int ip, unsigned short port, int toutUs)
Send UDP data.
Definition: DTrackNet.cpp:347
DTrack Parser class.
bool receive()
Receive and process one tracking data packet.
Definition: DTrackSDK.cpp:441
unsigned short getDataPort() const
Get UDP data port where tracking data is received.
Definition: DTrackSDK.cpp:321
bool isCommandInterfaceFullAccess()
Returns if TCP connection has full access for DTrack2/DTRACK3 commands.
Definition: DTrackSDK.cpp:341
bool setParam(const std::string &category, const std::string &name, const std::string &value)
Set DTrack2/DTRACK3 parameter.
Definition: DTrackSDK.cpp:807
std::string getMessageOrigin() const
Get origin of last DTrack2/DTRACK3 event message.
Definition: DTrackSDK.cpp:940
DTrackSDK(const std::string &connection)
Universal constructor. Can be used for any mode. Recommended for new applications.
Definition: DTrackSDK.cpp:60
bool enableStatefulFirewallConnection(const std::string &senderHost, unsigned short senderPort=DTRACK2_PORT_UDPSENDER)
Enable UDP connection through a stateful firewall.
Definition: DTrackSDK.cpp:425
bool setDataTimeoutUS(int timeout)
Set UDP timeout for receiving tracking data.
Definition: DTrackSDK.cpp:365
Handling TCP data.
Definition: DTrackNet.hpp:139
unsigned short getPort()
Get UDP data port where data is received.
Definition: DTrackNet.cpp:260
std::string getLastDTrackErrorDescription() const
Get last DTrack2/DTRACK3 command error description.
Definition: DTrackSDK.cpp:576
unsigned int getMessageErrorId() const
Get error id of last DTrack2/DTRACK3 event message.
Definition: DTrackSDK.cpp:931
RemoteSystemType getRemoteSystemType() const
Get current remote system type (e.g. DTrack1, DTrack2/DTRACK3).
Definition: DTrackSDK.cpp:356
bool tactileFinger(int handId, int fingerId, double strength)
Send tactile FINGERTRACKING command to set feedback on a specific finger of a specific hand...
Definition: DTrackSDK.cpp:967
int receive(void *buffer, int maxLen, int toutUs)
Receive TCP data.
Definition: DTrackNet.cpp:461
int receive(void *buffer, int maxLen, int toutUs)
Receive UDP data.
Definition: DTrackNet.cpp:278
bool getParam(const std::string &category, const std::string &name, std::string &value)
Get DTrack2/DTRACK3 parameter.
Definition: DTrackSDK.cpp:826
unsigned int getMessageFrameNr() const
Get frame counter of last DTrack2/DTRACK3 event message.
Definition: DTrackSDK.cpp:922
unsigned int getRemoteIp()
Get IP address of sender of latest received data.
Definition: DTrackNet.cpp:269
std::string getMessageStatus() const
Get status of last DTrack2/DTRACK3 event message.
Definition: DTrackSDK.cpp:949
bool processPacket(const std::string &data)
Process one tracking packet manually.
Definition: DTrackSDK.cpp:493
static const int DTRACK2_PROT_MAXLEN
max. length of &#39;dtrack2&#39; command
Definition: DTrackSDK.hpp:81
Errors getLastServerError() const
Get last error at exchanging commands with Controller (command transmission).
Definition: DTrackSDK.cpp:558
bool isCommandInterfaceValid() const
Returns if TCP connection for DTrack2/DTRACK3 commands is active.
Definition: DTrackSDK.cpp:330
bool flystickVibration(int flystickId, int vibrationPattern)
Send Flystick feedback command to start a vibration pattern on a specific Flystick.
Definition: DTrackSDK.cpp:1040
bool sendDTrack1Command(const std::string &command)
Send DTrack1 command via UDP.
Definition: DTrackSDK.cpp:633
std::string getMessageMsg() const
Get message text of last DTrack2/DTRACK3 event message.
Definition: DTrackSDK.cpp:958
DTrack2/DTRACK3 system.
Definition: DTrackSDK.hpp:87
bool flystickBeep(int flystickId, double durationMs, double frequencyHz)
Send Flystick feedback command to start a beep on a specific Flystick.
Definition: DTrackSDK.cpp:1025
Timeout occured.
Definition: DTrackSDK.hpp:93
RemoteSystemType
Compatibility modes for older DTrack systems.
Definition: DTrackSDK.hpp:84
Error while parsing command.
Definition: DTrackSDK.hpp:95
bool isDataInterfaceValid() const
Returns if UDP socket is open to receive tracking data on local machine.
Definition: DTrackSDK.cpp:310
bool getMessage()
Get DTrack2/DTRACK3 event message from the Controller.
Definition: DTrackSDK.cpp:864
Errors getLastDataError() const
Get last error at receiving tracking data (data transmission).
Definition: DTrackSDK.cpp:549
bool tactileHandOff(int handId, int numFinger)
Send tactile FINGERTRACKING command to turn off tactile feedback on all fingers of a specific hand...
Definition: DTrackSDK.cpp:1012
DTrack1 system.
Definition: DTrackSDK.hpp:86
bool stopMeasurement()
Stop measurement.
Definition: DTrackSDK.cpp:615
bool startMeasurement()
Start measurement.
Definition: DTrackSDK.cpp:595
bool parseLine(char **line)
Parses a single line of data in one tracking data packet.
bool isValid()
Returns if UDP socket is open to receive data.
Definition: DTrackNet.cpp:251
Handling UDP data.
Definition: DTrackNet.hpp:64
void startFrame()
Set default values at start of a new frame.
int send(const void *buffer, int len, int toutUs)
Send TCP data.
Definition: DTrackNet.cpp:505
int getLastDTrackError() const
Get last DTrack2/DTRACK3 command error code.
Definition: DTrackSDK.cpp:567
bool isValid()
Returns if TCP connection is active.
Definition: DTrackNet.cpp:452
~DTrackSDK()
Destructor.
Definition: DTrackSDK.cpp:279
bool setCommandTimeoutUS(int timeout)
Set TCP timeout for exchanging commands with Controller.
Definition: DTrackSDK.cpp:382
Network error.
Definition: DTrackSDK.hpp:94
int sendDTrack2Command(const std::string &command, std::string *answer=NULL)
Send DTrack2/DTRACK3 command to DTrack and receive answer (TCP command interface).
Definition: DTrackSDK.cpp:685
bool isValid()
Returns if constructor was successful due to the wanted mode.
Definition: DTrackSDK.cpp:294
void endFrame()
Final adjustments after processing all data for a frame.
bool tactileHand(int handId, const std::vector< double > &strength)
Send tactile FINGERTRACKING command to set tactile feedback on all fingers of a specific hand...
Definition: DTrackSDK.cpp:987