DTrackSDK  v2.9.0
DTrackCLI.cpp
1 /* DTrackCLI
2  *
3  * C++ based Command Line Interface for DTrack2 or DTRACK3
4  *
5  * Copyright (c) 2016-2023 Advanced Realtime Tracking GmbH & Co. KG
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of copyright holder nor the names of its contributors
16  * may be used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * Purpose:
31  * - Command Line Interface for DTrack2 or DTRACK3:
32  * processes DTrack2/DTRACK3 commands from command line or read from files
33  * - for DTrackSDK v2.6.0 (or newer)
34  */
35 
36 #include "DTrackSDK.hpp"
37 
38 #include <iostream>
39 #include <fstream>
40 
41 // global DTrackSDK
42 static DTrackSDK* dt = NULL;
43 
44 // version of DTrackCLI
45 static const unsigned int VERSION_MAJOR = 1;
46 static const unsigned int VERSION_MINOR = 1;
47 static const unsigned int VERSION_PATCH = 0;
48 
49 enum ERRORS {
50  ERR_WRONG_INPUT_PARAMETER = -101 ,
51  ERR_WRONG_USAGE = -102 ,
52  ERR_DTRACKSDK_INIT = -103 ,
53  ERR_DTRACK2_CMD_SPELLING = -104 ,
54  ERR_OPEN_FILE = -105 ,
55  ERR_UNKNOWN = -106
56 };
57 
61 static void dtrack2_get_and_print_all_event_messages()
62 {
63  while ( dt->getMessage() )
64  {
65  std::cerr << dt->getMessageOrigin()
66  << " " << dt->getMessageStatus()
67  << " " << dt->getMessageFrameNr()
68  << " 0x" << std::hex << dt->getMessageErrorId() << std::dec
69  << " " << dt->getMessageMsg()
70  << std::endl;
71  }
72 }
73 
74 
82 static int dtrack2_error_to_console()
83 {
84  int dtrack2Error = dt->getLastDTrackError();
85  if ( dtrack2Error )
86  {
87  std::string errorMessage = dt->getLastDTrackErrorDescription();
88  std::cerr << "error " << dtrack2Error << ": " << errorMessage << std::endl;
89  dtrack2_get_and_print_all_event_messages();
90  }
91  return dtrack2Error;
92 }
93 
94 
98 static void show_help( const std::string& programName )
99 {
100  std::cout << "DTrackCLI v" << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_PATCH << std::endl;
101  std::cout << "Usage: " << programName << " <ATC hostname or ip> [<action> ...]" << std::endl;
102  std::cout << "Apply an action to the ART Controller (ATC) specified by ACTION(s)" << std::endl;
103  std::cout << "with <ATC hostname or ip> being either the IP address or the" << std::endl;
104  std::cout << "hostname of the ART Controller e.g.: atc-123456 or 12.34.56.78" << std::endl;
105  std::cout << "Available actions:" << std::endl;
106  std::cout << " -meastart start measurement" << std::endl;
107  std::cout << " -meastop stop measurement" << std::endl;
108  std::cout << " -shutdown shut down the ART Controller" << std::endl;
109  std::cout << " -get <parameter> read and display the value of a DTrack2/DTRACK3 parameter" << std::endl;
110  std::cout << " -set <parameter> <value> change the value of a DTrack2/DTRACK3 parameter" << std::endl;
111  std::cout << " -cmd <dtrack2 command> send DTrack2/DTRACK3 command directly" << std::endl;
112  std::cout << " -f <filename> read and execute DTrack2/DTRACK3 commands from a file" << std::endl;
113  std::cout << " -h, --help, /? display this help" << std::endl;
114 }
115 
116 
120 static int checkInput( int argc, char** argv )
121 {
122  // cursor (points to current processed argument)
123  int iArgument = 2;
124 
125  bool errorOccured = false;
126 
127  // checks each single argument for correctness
128  while ( ( argc >= iArgument ) )
129  {
130  // only occurs the first time this loop is executed
131  if ( iArgument == 2 )
132  ++iArgument;
133 
134  // takes one argument from input
135  std::string command( argv [ iArgument - 1 ] );
136 
137  // check for different possible commands
138  // command with 0 arguments
139  if ( ( command.compare( "-h" ) == 0 ) ||
140  ( command.compare( "--help" ) == 0 ) ||
141  ( command.compare( "/?" ) == 0 ) ||
142  ( command.compare( "-meastart" ) == 0 ) ||
143  ( command.compare( "-meastop" ) == 0 ) ||
144  ( command.compare( "-shutdown" ) == 0 ) )
145  {
146  ++iArgument;
147  }
148  // command with 1 argument
149  else if ( ( command.compare( "-get" ) == 0 ) ||
150  ( command.compare( "-f" ) == 0 ) ||
151  ( command.compare( "-cmd" ) == 0 ) )
152  {
153  bool haveEnoughCommands = ( argc > iArgument );
154  if ( haveEnoughCommands )
155  iArgument += 2;
156  else
157  errorOccured = true;
158  }
159  // command with 2 arguments
160  else if ( ( command.compare( "-set" ) == 0 ) )
161  {
162  bool haveEnoughCommands = ( argc > iArgument + 1 );
163  if ( haveEnoughCommands )
164  iArgument += 3;
165  else
166  errorOccured = true;
167  }
168  // unknown command
169  else
170  errorOccured = true;
171 
172  if ( errorOccured )
173  {
174  std::cerr << "Please check input parameters! (See help)" << std::endl;
175  //show_help( argv[ 0 ] ); // don't show here (clarified with KA, 21.10.2016)
176  return ERR_WRONG_INPUT_PARAMETER;
177  }
178  }
179  return 0;
180 }
181 
182 
186 static int start_measurement()
187 {
188  std::string trackingStatus;
189 
190  // check tracking status
191  bool success = dt->getParam( "status active", trackingStatus );
192  if ( success )
193  {
194  // check the answer (possibilities: none, cal, mea, wait or err)
195  if ( trackingStatus.compare( "mea" ) != 0 && trackingStatus.compare( "wait" ) != 0 )
196  {
197  if ( !dt->startMeasurement() )
198  {
199  int errorOccured = dtrack2_error_to_console();
200  if ( errorOccured )
201  return errorOccured;
202  }
203  }
204  }
205  else
206  {
207  int errorOccured = dtrack2_error_to_console();
208  if ( errorOccured )
209  return errorOccured;
210  }
211  return 0;
212 }
213 
214 
218 static int stop_measurement()
219 {
220  std::string trackingStatus;
221 
222  // check if measurement is already running
223  bool success = dt->getParam( "status active", trackingStatus );
224  if ( success )
225  {
226  // check the answer (possibilities: none, cal, mea, wait or err)
227  if ( trackingStatus.compare( "none" ) != 0 && trackingStatus.compare( "err" ) != 0 )
228  {
229  if ( !dt->stopMeasurement() )
230  {
231  int errorOccured = dtrack2_error_to_console();
232  if ( errorOccured )
233  return errorOccured;
234  }
235  }
236  }
237  else
238  {
239  int errorOccured = dtrack2_error_to_console();
240  if ( errorOccured )
241  return errorOccured;
242  }
243  return 0;
244 }
245 
246 
250 static int get_dtrack2_parameter( const std::string& someParameter )
251 {
252  std::string receivedParameter;
253 
254  bool success = dt->getParam( someParameter, receivedParameter );
255  if ( success )
256  std::cout << receivedParameter << std::endl;
257  else
258  {
259  int errorOccured = dtrack2_error_to_console();
260  if ( errorOccured )
261  return errorOccured;
262  }
263  return 0;
264 }
265 
266 
270 static int set_dtrack2_parameter( const std::string& someParameter )
271 {
272  if ( !dt->setParam( someParameter ) )
273  {
274  int errorOccured = dtrack2_error_to_console();
275  if ( errorOccured )
276  return errorOccured;
277  }
278  return 0;
279 }
280 
281 
285 static int send_dtrack2_command( const std::string& rawDtrack2Command )
286 {
287  std::string dtrack2Response;
288 
289  int isSuccessful = dt->sendDTrack2Command( rawDtrack2Command, &dtrack2Response );
290  if ( isSuccessful == 0 )
291  std::cout << dtrack2Response << std::endl;
292  else
293  {
294  int errorOccured = dtrack2_error_to_console();
295  if ( errorOccured )
296  return errorOccured;
297  }
298  return 0;
299 }
300 
301 
305 static int process_command( std::string someCommand )
306 {
307  // getParam (request parameter value); accepts commands without "dtrack2" in the beginning
308  if ( someCommand.compare( 0, 4, "get " ) == 0 )
309  {
310  someCommand.erase( 0, 4 );
311  int errorOccured = get_dtrack2_parameter( someCommand );
312  if ( errorOccured )
313  return errorOccured;
314  }
315  // getParam (request parameter value)
316  else if ( someCommand.compare( 0, 12, "dtrack2 get " ) == 0 )
317  {
318  someCommand.erase( 0, 12 );
319  int errorOccured = get_dtrack2_parameter( someCommand );
320  if ( errorOccured )
321  return errorOccured;
322  }
323  // setParam (change parameter value); accepts commands without "dtrack2" in the beginning
324  else if ( someCommand.compare( 0, 4, "set " ) == 0 )
325  {
326  someCommand.erase( 0, 4 );
327  int errorOccured = set_dtrack2_parameter( someCommand );
328  if ( errorOccured )
329  return errorOccured;
330  }
331  // setParam (change parameter value)
332  else if ( someCommand.compare( 0, 12, "dtrack2 set " ) == 0 )
333  {
334  someCommand.erase( 0, 12 );
335  int errorOccured = set_dtrack2_parameter( someCommand );
336  if ( errorOccured )
337  return errorOccured;
338  }
339  // raw DTrack2 command
340  else
341  {
342  if ( someCommand.compare( 0, 8, "dtrack2 " ) != 0 )
343  {
344  // inserts "dtrack2" in the beginning of the string if it's missing
345  someCommand = "dtrack2 " + someCommand;
346  }
347  int errorOccured = send_dtrack2_command( someCommand );
348  if ( errorOccured )
349  return errorOccured;
350  }
351  return 0;
352 }
353 
354 
358 static int open_file( const std::string& file_to_open )
359 {
360  std::string readLine;
361  std::ifstream readFile( file_to_open.c_str() );
362 
363  // returns the first occured error after DTrackCLI is finished
364  int firstErrorInFile = 0;
365 
366  // check if file opened correctly
367  if ( readFile.is_open() )
368  {
369  // read commands in file (executed line by line)
370  while ( std::getline( readFile, readLine ) )
371  {
372  if ( readLine.empty() )
373  continue;
374 
375  // errors will be displayed, but DTrackCLI won't stop
376  int errorOccured = process_command( readLine );
377  if ( ( firstErrorInFile == 0 ) && errorOccured )
378  firstErrorInFile = errorOccured;
379  }
380  // close file
381  readFile.close();
382 
383  int errorOccured = dtrack2_error_to_console();
384  if ( errorOccured )
385  return errorOccured;
386  }
387  // file couldn't be opened/found
388  else
389  {
390  std::cerr << "Unable to open file" << std::endl;
391  return ERR_OPEN_FILE;
392  }
393 
394  if ( firstErrorInFile == 0 )
395  return 0;
396  else
397  return firstErrorInFile;
398 }
399 
400 
404 static int process_cmd_line_input( const int& argc, char** argv )
405 {
406  // counter: checks the number of commands (acts as cursor)
407  int nCommands = 2;
408 
409  // enables multiple input commands
410  while ( argc >= nCommands )
411  {
412  // only occurs the first time this loop is executed
413  if ( nCommands == 2 )
414  ++nCommands;
415 
416  // takes one argument from input
417  std::string command( argv[ nCommands - 1 ] );
418 
419  // help
420  if ( ( command.compare( "-h" ) == 0 ) ||
421  ( command.compare( "--help" ) == 0 ) ||
422  ( command.compare( "/?" ) == 0 ) )
423  {
424  ++nCommands;
425  show_help( argv[ 0 ] );
426  }
427  // start measurement
428  else if ( command.compare( "-meastart" ) == 0 )
429  {
430  ++nCommands;
431  int errorOccured = start_measurement();
432  if ( errorOccured )
433  return errorOccured;
434  }
435  // stop measurement
436  else if ( command.compare( "-meastop" ) == 0 )
437  {
438  ++nCommands;
439  int errorOccured = stop_measurement();
440  if ( errorOccured )
441  return errorOccured;
442  }
443  // shutdown controller
444  else if ( command.compare( "-shutdown" ) == 0 )
445  {
446  // if shutdown doesn't work, look for an error
447  if ( send_dtrack2_command( "dtrack2 system shutdown" ) )
448  {
449  int errorOccured = dtrack2_error_to_console();
450  if ( errorOccured )
451  return errorOccured;
452  }
453  return 0;
454  }
455  // getParam (request parameter value)
456  else if ( command.compare( "-get" ) == 0 )
457  {
458  std::string dtrack2Get;
459 
460  dtrack2Get = argv[ nCommands ];
461  nCommands = nCommands + 2;
462 
463  int errorOccured = get_dtrack2_parameter( dtrack2Get );
464  if ( errorOccured )
465  return errorOccured;
466  }
467  // setParam (change parameter value)
468  else if ( command.compare( "-set" ) == 0 )
469  {
470  std::string dtrack2SetParam;
471  std::string dtrack2SetValue;
472  std::string dtrack2Set;
473 
474  dtrack2SetParam = argv[ nCommands ];
475  dtrack2SetValue = argv[ nCommands + 1 ];
476  nCommands = nCommands + 3;
477  dtrack2Set = dtrack2SetParam + " " + dtrack2SetValue;
478 
479  int errorOccured = set_dtrack2_parameter( dtrack2Set );
480  if ( errorOccured )
481  return errorOccured;
482  }
483  // raw DTrack2 command
484  else if ( command.compare( "-cmd" ) == 0 )
485  {
486  std::string dtrack2Cmd;
487 
488  dtrack2Cmd = argv[ nCommands ];
489  nCommands = nCommands + 2;
490 
491  if ( dtrack2Cmd.compare( 0, 8, "dtrack2 " ) != 0 )
492  {
493  // inserts "dtrack2" in the beginning of the string if it's missing
494  dtrack2Cmd = "dtrack2 " + dtrack2Cmd;
495  }
496 
497  int errorOccured = send_dtrack2_command( dtrack2Cmd );
498  if ( errorOccured )
499  return errorOccured;
500  }
501  // read from file
502  else if ( command.compare( "-f" ) == 0 )
503  {
504  std::string filename;
505 
506  filename = argv[ nCommands ];
507  nCommands = nCommands + 2;
508 
509  int errorOccured = open_file( filename );
510  if ( errorOccured )
511  return errorOccured;
512  }
513  else
514  {
515  std::cout << "unknown error occured" << std::endl;
516  return ERR_UNKNOWN;
517  }
518  }
519  return 0;
520 }
521 
522 
526 int main( int argc, char** argv )
527 {
528  // check for correct usage
529  if ( argc <= 1 )
530  {
531  show_help( argv[ 0 ] );
532  return ERR_WRONG_USAGE;
533  }
534 
535  // check if user wanted help
536  std::string command( argv[ 1 ] );
537  if ( ( command.compare( "-h" ) == 0 ) ||
538  ( command.compare( "--help" ) == 0 ) ||
539  ( command.compare( "/?" ) == 0 ) )
540  {
541  show_help( argv[ 0 ] );
542  return 0;
543  }
544 
545  // init library:
546  dt = new DTrackSDK( ( const char * )argv [ 1 ], 0 );
547 
548  if ( !dt->isCommandInterfaceValid() )
549  {
550  std::cerr << "No connection to ART controller! Is \"" << argv[ 1 ] <<
551  "\" a valid controller hostname of ip address?" << std::endl;
552  delete dt;
553  return ERR_DTRACKSDK_INIT;
554  }
555 
556  // runs DTrackCLI without commands, enabling pipes or multiple commands (executed seperately)
557  if ( argc == 2 )
558  {
559  // look for pipe
560  std::string pipeCommand;
561 
562  // returns the first occured error after DTrackCLI is finished
563  int firstErrorInPipe = 0;
564 
565  // checks for different possible commands
566  while ( std::getline( std::cin, pipeCommand ) )
567  {
568  // errors will be displayed, but DTrackCLI won't stop
569  int errorOccured = process_command( pipeCommand );
570  if ( ( firstErrorInPipe == 0 ) && errorOccured )
571  firstErrorInPipe = errorOccured;
572  }
573 
574  if ( firstErrorInPipe != 0 )
575  {
576  delete dt;
577  return firstErrorInPipe;
578  }
579  }
580  // runs DTrackCLI with entered commands
581  else
582  {
583  // check input parameters
584  int paramInputError = checkInput( argc, argv );
585  if ( paramInputError )
586  {
587  delete dt;
588  return paramInputError;
589  }
590 
591  // processes all commands
592  int someError = process_cmd_line_input( argc, argv );
593  if ( someError )
594  {
595  delete dt;
596  return someError;
597  }
598  }
599 
600  delete dt;
601  return 0;
602 }
603 
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
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
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
DTrack SDK main class derived from DTrackParser.
Definition: DTrackSDK.hpp:77
std::string getMessageStatus() const
Get status of last DTrack2/DTRACK3 event message.
Definition: DTrackSDK.cpp:949
bool isCommandInterfaceValid() const
Returns if TCP connection for DTrack2/DTRACK3 commands is active.
Definition: DTrackSDK.cpp:330
std::string getMessageMsg() const
Get message text of last DTrack2/DTRACK3 event message.
Definition: DTrackSDK.cpp:958
bool getMessage()
Get DTrack2/DTRACK3 event message from the Controller.
Definition: DTrackSDK.cpp:864
bool stopMeasurement()
Stop measurement.
Definition: DTrackSDK.cpp:615
bool startMeasurement()
Start measurement.
Definition: DTrackSDK.cpp:595
int getLastDTrackError() const
Get last DTrack2/DTRACK3 command error code.
Definition: DTrackSDK.cpp:567
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