Dynamixel  2.9.5
RoadNarrows Robotics Dynamixel Package
dynashell_cmd_core.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Dynamixel
4 //
5 // Program: dynashell
6 //
7 // File: dynashell_cmd.cxx
8 //
9 /*! \file
10  *
11  * $LastChangedDate: 2015-01-12 10:56:06 -0700 (Mon, 12 Jan 2015) $
12  * $Rev: 3845 $
13  *
14  * \brief The Dynamixel Shell Command Base and Derived Core Classes.
15  *
16  * \author Robin Knight (robin.knight@roadnarrows.com)
17  *
18  * \copyright
19  * \h_copy 2011-2017. RoadNarrows LLC.\n
20  * http://www.roadnarrows.com\n
21  * All Rights Reserved
22  */
23 /*
24  * @EulaBegin@
25  *
26  * Unless otherwise stated explicitly, all materials contained are copyrighted
27  * and may not be used without RoadNarrows LLC's written consent,
28  * except as provided in these terms and conditions or in the copyright
29  * notice (documents and software) or other proprietary notice provided with
30  * the relevant materials.
31  *
32  * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY
33  * MEMBERS/EMPLOYEES/CONTRACTORS OF ROADNARROWS OR DISTRIBUTORS OF THIS SOFTWARE
34  * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
35  * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
36  * DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN
37  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38  *
39  * THE AUTHORS AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
40  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
41  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
42  * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
43  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
44  *
45  * @EulaEnd@
46  */
47 ////////////////////////////////////////////////////////////////////////////////
48 
49 
50 #include <sys/time.h>
51 #include <sys/types.h>
52 #include <stdio.h>
53 #include <unistd.h>
54 #include <ctype.h>
55 
56 #include <cstring>
57 #include <iostream>
58 #include <fstream>
59 
60 #include "rnr/rnrconfig.h"
61 #include "rnr/log.h"
62 
63 #include "Dynamixel/Dynamixel.h"
64 #include "Dynamixel/DynaComm.h"
65 #include "Dynamixel/DynaServo.h"
66 #include "Dynamixel/DynaChain.h"
67 #include "Dynamixel/DynaBgThread.h"
68 
69 #include "dynashell.h"
70 #include "dynashell_cmd.h"
71 #include "dynashell_util.h"
72 
73 using namespace std;
74 
75 
76 // -----------------------------------------------------------------------------
77 // DynaShellCmdNULL Class
78 // -----------------------------------------------------------------------------
79 
80 /*!
81  * \brief NULL command.
82  */
84 {
85 public:
86 
87  /*
88  * \brief Default constructor.
89  */
91  {
92  m_sCmdName = "";
93  m_sCmdHelpArgs = "";
94  m_sCmdHelpDesc = "";
95  }
96 
97  /*!
98  * \brief NULL
99  *
100  * \param shell Dynamixel shell.
101  * \param argc Command argument count.
102  * \param argv Array of arguments.
103  */
104  void Exec(DynaShell &shell, int argc, char *argv[])
105  {
106  }
107 };
108 
109 
110 // -----------------------------------------------------------------------------
111 // DynaShellCmdHelp Class
112 // -----------------------------------------------------------------------------
113 
114 /*!
115  * \brief Help command.
116  */
118 {
119 public:
120 
121  /*
122  * \brief Default constructor.
123  */
125  {
126  m_sCmdName = "help";
127  m_sCmdHelpBrief = "Print command help.";
128  m_sCmdHelpArgs = "[<cmd> [object]]";
129  m_sCmdHelpDesc = "Print list of commands or command long help. "
130  "If no arguments are "
131  "specified, then only the list of commands is printed. "
132  "If only the <cmd> argument is specified, and <cmd> is "
133  "of the form:\n"
134  " verb object [qualifiers]\n"
135  "then a list of the command objects is printed. "
136  "Otherwise, the long help is printed for the given "
137  "command.\n"
138  " <cmd> Root command name (verb).\n"
139  " <object> Sub-command name (object).";
140 
141  }
142 
143  /*!
144  * \brief Print help.
145  *
146  * \param shell Dynamixel shell.
147  * \param argc Command argument count.
148  * \param argv Array of arguments.
149  */
150  void Exec(DynaShell &shell, int argc, char *argv[])
151  {
152  ShCmdNode cmdNode;
153 
154  TRY( ChkArgCnt(shell, argc) );
155 
156  // print root command list
157  if( argc == 0 )
158  {
159  //PrintHelpWordList(shell, shell.GetRootCmds());
160  PrintHelpSummaryList(shell, shell.GetRootCmds());
161  printf("\n");
162  return;
163  }
164 
165  cmdNode = MatchHelp(shell, argc, argv, shell.GetRootCmds());
166 
167  // print command object list
168  if( cmdNode.IsMap() )
169  {
170  // PrintHelpWordList(shell, *cmdNode.GetMap());
171  PrintHelpSummaryList(shell, *cmdNode.GetMap());
172  printf("\n");
173  }
174 
175  // print long help.
176  else if( cmdNode.IsCmd() )
177  {
178  cmdNode.GetCmd()->PrintHelp();
179  printf("\n");
180  }
181 
182  // print error 1
183  else if( argc == 1 )
184  {
185  shell.Error("help: Unknown command \"%s\".", argv[0]);
186  }
187 
188  // or print error 2
189  else
190  {
191  shell.Error("help: Unknown command \"%s %s\".", argv[0], argv[1]);
192  }
193  }
194 
195  /*!
196  * \brief Command tab completion generator.
197  *
198  * Completes <group> [object]
199  *
200  * \param shell Dynamixel shell.
201  * \param sText Partial text string to complete.
202  * \param uTextLen Length of text.
203  * \param nState Generator state. If FIRST, then initialize any statics.
204  * \param sContext Generator context (i.e. canonical command path).
205  *
206  * \return
207  * If a first/next match is made, return allocated completed match.\n
208  * Otherwise return NULL.
209  */
210  virtual char *TabCompletion(DynaShell &shell,
211  const char *sText,
212  size_t uTextLen,
213  int nState,
214  const char *sContext)
215  {
216  size_t uCmdLen = strlen(m_sPubName);
217  const char *sSubContext;
218 
219  // this case should not happen
220  if( strlen(sContext) < uCmdLen )
221  {
222  return NULL;
223  }
224 
225  // "help"
226  else if( strlen(sContext) == uCmdLen )
227  {
228  sSubContext = "";
229  }
230 
231  // "help group "
232  else
233  {
234  sSubContext = sContext+uCmdLen+1;
235  }
236 
237  return shell.CmdListGenerator(0, sText, uTextLen, nState, sSubContext);
238  }
239 
240 
241 protected:
242  /*!
243  * \brief Print help list of words.
244  *
245  * \param shell Dynamixel shell.
246  * \param cmdMap Command map to print.
247  */
248  void PrintHelpWordList(DynaShell &shell, ShCmdMap &cmdMap)
249  {
250  ShCmdMap::iterator iter;
251 
252  for(iter=cmdMap.begin(); iter!=cmdMap.end(); iter++)
253  {
254  printf("%s ", iter->first);
255  }
256 
257  printf("\n");
258  }
259 
260  /*!
261  * \brief Print help summary list.
262  *
263  * \param shell Dynamixel shell.
264  * \param cmdMap Command map to print.
265  */
267  {
268  ShCmdMap::iterator iter;
269 
270  for(iter=cmdMap.begin(); iter!=cmdMap.end(); iter++)
271  {
272  printf("%15s - %s\n", iter->first, iter->second.GetMapBrief().c_str());
273  }
274  }
275 
276  /*!
277  * \brief Match command.
278  *
279  * \param shell Dynamixel shell.
280  * \param argc Command argument count.
281  * \param argv Array of arguments.
282  * \param cmdMap Command map to search.
283  *
284  * \return Shell command node.
285  */
287  int argc,
288  char *argv[],
289  ShCmdMap &cmdMap)
290  {
291  static ShCmdNode cmdNull;
292 
293  ShCmdMap::iterator iter1, iter2;
294  char *sPattern;
295  const char *sCmdName1, *sCmdName2;
296  size_t n;
297 
298  if( argc == 0 )
299  {
300  return cmdNull;
301  }
302 
303  sPattern = argv[0];
304 
305  n = strlen(sPattern);
306 
307  // find command
308  for(iter1=cmdMap.begin(); iter1!=cmdMap.end(); iter1++)
309  {
310  sCmdName1 = iter1->first;
311  if( !strncmp(sPattern, sCmdName1, n) )
312  {
313  break;
314  }
315  }
316 
317  // no matching command found
318  if( iter1 == cmdMap.end() )
319  {
320  return cmdNull;
321  }
322 
323  // verify uniqueness
324  for(iter2=cmdMap.begin(); iter2!=cmdMap.end(); iter2++)
325  {
326  if( iter2 == iter1 )
327  {
328  continue;
329  }
330 
331  sCmdName2 = iter2->first;
332 
333  // another match
334  if( !strncmp(sPattern, sCmdName2, n) )
335  {
336  shell.Error("help: %s: (Sub)Command not unique: Matches %s %s ...",
337  sPattern, sCmdName1, sCmdName2);
338  return cmdNull;
339  }
340  }
341 
342  if( argc == 1 )
343  {
344  return iter1->second;
345  }
346  else if( (argc == 2) && iter1->second.IsMap() )
347  {
348  return MatchHelp(shell, argc-1, argv+1, *iter1->second.GetMap());
349  }
350  else
351  {
352  return cmdNull;
353  }
354  }
355 };
356 
357 
358 // -----------------------------------------------------------------------------
359 // DynaShellCmdQuit Class
360 // -----------------------------------------------------------------------------
361 
362 /*!
363  * \brief Quit command.
364  */
366 {
367 public:
368 
369  /*
370  * \brief Default constructor.
371  */
373  {
374  m_sCmdName = "quit";
375  m_sCmdHelpBrief = "Quit (exit) dynashell.";
376  m_sCmdHelpArgs = "";
377  m_sCmdHelpDesc = "";
378  }
379 
380  /*!
381  * \brief Quit shell.
382  *
383  * \param shell Dynamixel shell.
384  * \param argc Command argument count.
385  * \param argv Array of arguments.
386  */
387  void Exec(DynaShell &shell, int argc, char *argv[])
388  {
389  shell.m_bRun = false;
390  }
391 };
392 
393 
394 // -----------------------------------------------------------------------------
395 // DynaShellCmdExit Class
396 // -----------------------------------------------------------------------------
397 
398 /*!
399  * \brief Exit command.
400  */
402 {
403 public:
404 
405  /*
406  * \brief Default constructor.
407  */
409  {
410  m_sCmdName = "exit";
411  m_sCmdHelpBrief = "Exit (quit) dynashell.";
412  m_sCmdHelpArgs = "";
413  m_sCmdHelpDesc = "";
414  }
415 
416  /*!
417  * \brief Exit shell.
418  *
419  * \param shell Dynamixel shell.
420  * \param argc Command argument count.
421  * \param argv Array of arguments.
422  */
423  void Exec(DynaShell &shell, int argc, char *argv[])
424  {
425  shell.m_bRun = false;
426  }
427 };
428 
429 
430 // -----------------------------------------------------------------------------
431 // DynaShellCmdLog Class
432 // -----------------------------------------------------------------------------
433 
434 /*!
435  * \brief Log command
436  */
438 {
439 public:
440 
441  /*
442  * \brief Default constructor.
443  */
444  DynaShellCmdLog() : DynaShellCmd(1, 1)
445  {
446  m_sCmdName = "log";
447  m_sCmdHelpBrief = "Set the logging level.";
448  m_sCmdHelpArgs = "<level>";
449  m_sCmdHelpDesc = "Set the logging level.\n"
450  " <level> 0 | off | 1 | error | 2 | diag1 | ...";
451  }
452 
453  /*!
454  * \brief Set diagnotics logging level.
455  *
456  * \param shell Dynamixel shell.
457  * \param argc Command argument count.
458  * \param argv Array of arguments.
459  */
460  void Exec(DynaShell &shell, int argc, char *argv[])
461  {
462  int nLevel;
463 
464  TRY( ChkArgCnt(shell, argc) );
465 
466  if( !strcmp(argv[0], "off") )
467  {
468  nLevel = 0;
469  }
470  else if( !strcmp(argv[0], "error") )
471  {
472  nLevel = 1;
473  }
474  else if( !strncmp(argv[0], "diag", 3) )
475  {
476  TRY( ToInt(shell, argv[0]+4, &nLevel) );
477  nLevel++;
478  }
479  else
480  {
481  TRY( ToInt(shell, argv[0], &nLevel) );
482  }
483 
484  LOG_SET_THRESHOLD(nLevel);
485  }
486 
487  /*!
488  * \brief Command tab completion generator.
489  *
490  * Completes <log_level>
491  *
492  * \param shell Dynamixel shell.
493  * \param sText Partial text string to complete.
494  * \param uTextLen Length of text.
495  * \param nState Generator state. If FIRST, then initialize any statics.
496  * \param sContext Generator context (i.e. canonical command path).
497  *
498  * \return
499  * If a first/next match is made, return allocated completed match.\n
500  * Otherwise return NULL.
501  */
502  virtual char *TabCompletion(DynaShell &shell,
503  const char *sText,
504  size_t uTextLen,
505  int nState,
506  const char *sContext)
507  {
508  // log level symbolic names table.
509  static const char *logLevelSymTbl[] =
510  {
511  "off", "error", "diag1", "diag2", "diag3", "diag4", "diag5", "diag6"
512  };
513 
514  const char *s;
515 
516  if( (ReadLine::wc(sContext) - ReadLine::wc(m_sPubName)) != 0 )
517  {
518  return NULL;
519  }
520 
521  //
522  // New command to complete - initialize.
523  //
524  if( nState == ReadLine::FIRST )
525  {
526  m_nTabIndex = 0;
527  }
528 
529  // <log_level>
530  while( m_nTabIndex < arraysize(logLevelSymTbl) )
531  {
532  s = logLevelSymTbl[m_nTabIndex++];
533 
534  if( !strncmp(s, sText, uTextLen) )
535  {
536  return ReadLine::dupstr(s);
537  }
538  }
539 
540  // no more matches
541  return NULL;
542  }
543 
544 protected:
545  int m_nTabIndex; ///< tab completion: keyword index
546 
547 };
548 
549 
550 // -----------------------------------------------------------------------------
551 // DynaShellCmdWait Class
552 // -----------------------------------------------------------------------------
553 
554 /*!
555  * \brief Wait command.
556  */
558 {
559 public:
560 
561  /*
562  * \brief Default constructor.
563  */
565  {
566  m_sCmdName = "wait";
567  m_sCmdHelpBrief = "Delay for a specified amount of time.";
568  m_sCmdHelpArgs = "<sec>";
569  m_sCmdHelpDesc = "Block waiting for <sec> seconds.\n"
570  " <sec> Floating-point wait period in seconds.";
571  }
572 
573  /*!
574  * \brief Wait the given number of seconds.
575  *
576  * \param shell Dynamixel shell.
577  * \param argc Command argument count.
578  * \param argv Array of arguments.
579  */
580  void Exec(DynaShell &shell, int argc, char *argv[])
581  {
582  double fWait;
583  struct timeval timeout;
584 
585  TRY( ChkArgCnt(shell, argc) );
586  TRY( ToDouble(shell, argv[0], &fWait) );
587 
588  timeout.tv_sec = (long)fWait;
589  timeout.tv_usec = (long)((fWait - (double)timeout.tv_sec) * 1000000.0);
590 
591  select(0, NULL, NULL, NULL, &timeout);
592  }
593 };
594 
595 
596 // -----------------------------------------------------------------------------
597 // DynaShellCmdScript Class
598 // -----------------------------------------------------------------------------
599 
600 /*!
601  * \brief Script command.
602  * \par Usage: script <em>file</em>
603  */
605 {
606 public:
607 
608  /*
609  * \brief Default constructor.
610  */
612  {
613  m_sCmdName = "script";
614  m_sCmdHelpBrief = "Run a dynamixel shell script.";
615  m_sCmdHelpArgs = "<file>";
616  m_sCmdHelpDesc = "Run a file containing dynamixel shell commands.\n"
617  " <file> Shell text file name.";
618  }
619 
620  /*!
621  * \brief Execute script.
622  *
623  * \param shell Dynamixel shell.
624  * \param argc Command argument count.
625  * \param argv Array of arguments.
626  */
627  void Exec(DynaShell &shell, int argc, char *argv[])
628  {
629  char *sScriptFile;
630  FILE *fp;
631 
632  TRY( ChkArgCnt(shell, argc) );
633 
634  sScriptFile = argv[0];
635 
636  if( access(sScriptFile, F_OK|R_OK) != 0 )
637  {
638  shell.Error("%s: %s.", sScriptFile, strerror(errno));
639  }
640  else if( (fp = fopen(sScriptFile, "r")) == NULL )
641  {
642  shell.Error("%s: %s.", sScriptFile, strerror(errno));
643  }
644  else
645  {
646  shell.ScriptPush(sScriptFile, fp);
647  shell.Ok();
648  }
649  }
650 
651  /*!
652  * \brief Command tab completion generator.
653  *
654  * Completes <script_file>>
655  *
656  * \param shell Dynamixel shell.
657  * \param sText Partial text string to complete.
658  * \param uTextLen Length of text.
659  * \param nState Generator state. If FIRST, then initialize any statics.
660  * \param sContext Generator context (i.e. canonical command path).
661  *
662  * \return
663  * If a first/next match is made, return allocated completed match.\n
664  * Otherwise return NULL.
665  */
666  virtual char *TabCompletion(DynaShell &shell,
667  const char *sText,
668  size_t uTextLen,
669  int nState,
670  const char *sContext)
671  {
672  return ReadLine::FileCompletionGenerator(sText, nState);
673  }
674 };
675 
676 
677 // -----------------------------------------------------------------------------
678 // Public Interface.
679 // -----------------------------------------------------------------------------
680 
681 /*!
682  * \brief Publish shell core commands to shell.
683  *
684  * The core set includes the common shell base commands idependent of
685  * application.
686  *
687  * \brief shell Dynamixel shell.
688  */
690 {
691  shell.PublishCommand(NULL, new DynaShellCmdHelp());
692  shell.PublishCommand(NULL, new DynaShellCmdQuit());
693  //shell.PublishCommand(NULL, new DynaShellCmdExit());
694  shell.PublishCommand(NULL, new DynaShellCmdLog());
695  shell.PublishCommand(NULL, new DynaShellCmdWait());
696  shell.PublishCommand("run", new DynaShellCmdScript());
697 }
RoadNarrows Dynamixel Bus Communications Abstract Base Class Interface.
ShCmdMap * GetMap()
Get map object.
Definition: dynashell.h:206
virtual char * TabCompletion(DynaShell &shell, const char *sText, size_t uTextLen, int nState, const char *sContext)
Command tab completion generator.
Dynamixel shell utilities.
DynaShellCmd * GetCmd()
Get command object.
Definition: dynashell.h:196
void ScriptPush(const char *sScriptFile, FILE *fp)
Push new script on the stack.
Definition: dynashell.cxx:669
void Exec(DynaShell &shell, int argc, char *argv[])
Exit shell.
void Exec(DynaShell &shell, int argc, char *argv[])
Wait the given number of seconds.
void Exec(DynaShell &shell, int argc, char *argv[])
Print help.
void Exec(DynaShell &shell, int argc, char *argv[])
Execute script.
char * CmdListGenerator(int nUid, const char *sText, size_t uTextLen, int nState, const char *sContext)
Command list generator function.
Definition: dynashell.cxx:319
RoadNarrows Dynamixel Servo Chain Container Base Class Interface.
static const int FIRST
first state
void PrintHelpWordList(DynaShell &shell, ShCmdMap &cmdMap)
Print help list of words.
static char * dupstr(const string &str)
Duplicate string.
Dynamixel shell command abstract base class.
Definition: dynashell_cmd.h:80
ShCmdNode & MatchHelp(DynaShell &shell, int argc, char *argv[], ShCmdMap &cmdMap)
Match command.
Dynamixel background thread class declarations.
map< const char *, ShCmdNode, ShCmdNodeKeyCmp > ShCmdMap
Shell command map type.
Definition: dynashell.h:107
virtual char * TabCompletion(DynaShell &shell, const char *sText, size_t uTextLen, int nState, const char *sContext)
Command tab completion generator.
static int wc(const string &str)
Count the words in the string.
virtual void Ok()
Print standard ok success response.
Definition: dynashell.h:425
void PrintHelpSummaryList(DynaShell &shell, ShCmdMap &cmdMap)
Print help summary list.
void Exec(DynaShell &shell, int argc, char *argv[])
NULL.
ShCmdMap & GetRootCmds()
Definition: dynashell.h:446
virtual void PrintHelp(int indent=0, int width=80)
Print command help with the description aligned at the given indentation.
bool IsMap()
Test if node type is map of commands.
Definition: dynashell.h:250
void PublishShellCoreCommands(DynaShell &shell)
Publish shell core commands to shell.
RoadNarrows Dynamixel Archetype Servo Abstract Base Class.
int m_nTabIndex
tab completion: keyword index
#define TRY(boolexpr,...)
Try boolean expression.
Definition: dynashell_cmd.h:89
void PublishCommand(const char *sParent, DynaShellCmd *pNewCmd)
Publish new command to shell.
Definition: dynashell.cxx:192
RoadNarrows Dynamixel Top-Level Package Header File.
The dynashell Command Class Interface.
virtual char * TabCompletion(DynaShell &shell, const char *sText, size_t uTextLen, int nState, const char *sContext)
Command tab completion generator.
void Exec(DynaShell &shell, int argc, char *argv[])
Quit shell.
bool m_bRun
do [not] run shell
Definition: dynashell.h:355
void Exec(DynaShell &shell, int argc, char *argv[])
Set diagnotics logging level.
void Error(int rc, const char *sFmt,...)
Raise error on dynamixel error code.
Definition: dynashell.cxx:808
static char * FileCompletionGenerator(const char *sText, int nState)
File name tab completion generator.
Shell command node class.
Definition: dynashell.h:119
bool IsCmd()
Test if node type is shell command.
Definition: dynashell.h:243
The simple dynashell declarations.