Dynamixel  2.9.5
RoadNarrows Robotics Dynamixel Package
dynashell.h
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Dynamixel
4 //
5 // Program: dynashell
6 //
7 // File: dynashell.h
8 //
9 /*! \file
10  *
11  * $LastChangedDate: 2015-01-12 10:56:06 -0700 (Mon, 12 Jan 2015) $
12  * $Rev: 3845 $
13  *
14  * \brief The simple dynashell declarations.
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 #ifndef _DYNASHELL_H
50 #define _DYNASHELL_H
51 
52 #include <stdio.h>
53 #include <string.h>
54 
55 #include <iostream>
56 #include <fstream>
57 #include <string>
58 #include <map>
59 #include <vector>
60 
61 #include "rnr/rnrconfig.h"
62 #include "rnr/opts.h"
63 #include "rnr/log.h"
64 
65 #include "Dynamixel/Dynamixel.h"
66 #include "Dynamixel/DynaComm.h"
67 #include "Dynamixel/DynaChain.h"
68 #include "Dynamixel/DynaBgThread.h"
69 
70 #include "dynashell_readline.h"
71 #include "dynashell_recording.h"
72 #include "dynashell_util.h"
73 
74 using namespace std;
75 
76 #define SH_C_COMMENT '#'
77 
78 /*
79  * Forward declarations
80  */
81 class DynaShellCmd;
82 class ShCmdNode;
83 
84 /*!
85  * \brief Shell command node map key compare helper class.
86  */
88 {
89 public:
90  /*!
91  * \brief Compare operator required by <map>.
92  *
93  * \param lhs Left hand side key.
94  * \param rhs Right had side key.
95  *
96  * \return Returns true if lhs \h_lt rhs, lexicographically.
97  */
98  bool operator()(const char* const &lhs, const char* const &rhs) const
99  {
100  return strcmp(lhs, rhs) < 0;
101  }
102 };
103 
104 /*!
105  * \brief Shell command map type.
106  */
107 typedef map<const char *, ShCmdNode, ShCmdNodeKeyCmp> ShCmdMap;
108 
109 
110 // ----------------------------------------------------------------------------
111 // ShCmdNode Class
112 // ----------------------------------------------------------------------------
113 
114 /*!
115  * \brief Shell command node class.
116  *
117  * Each node holds either a command or a map of commands.
118  */
120 {
121 public:
122  /*!
123  * \brief Node type.
124  */
125  enum NodeType { NodeTypeNull, NodeTypeCmd, NodeTypeMap };
126 
127  /*!
128  * \brief Default constructor.
129  */
131  {
132  m_obj.m_pCmd = NULL;
133  m_eType = NodeTypeNull;
134  }
135 
136  /*!
137  * \brief Shell command initialization constructor.
138  *
139  * \param pCmd Allocated shell command.
140  */
142  {
143  m_obj.m_pCmd = pCmd;
144  m_eType = NodeTypeCmd;
145  }
146 
147  /*!
148  * \brief Map of commands initialization constructor.
149  *
150  * \param pMap Allocated map of commands.
151  */
153  {
154  m_obj.m_pMap = pMap;
155  m_eType = NodeTypeMap;
156  }
157 
158  /*!
159  * \brief Default destructor.
160  */
162 
163  /*!
164  * \brief Shell command assignment operator.
165  *
166  * \param rhs Pointer to allocated shell command right hand side.
167  *
168  * \return Reference to this.
169  */
171  {
172  m_obj.m_pCmd = rhs;
173  m_eType = NodeTypeCmd;
174  return *this;
175  }
176 
177  /*!
178  * \brief Shell map assignment operator.
179  *
180  * \param rhs Pointer to allocated map of commands right hand side.
181  *
182  * \return Reference to this.
183  */
185  {
186  m_obj.m_pMap = rhs;
187  m_eType = NodeTypeMap;
188  return *this;
189  }
190 
191  /*!
192  * \brief Get command object.
193  *
194  * \return Pointer to shell command.
195  */
197  {
198  return m_eType == NodeTypeCmd? m_obj.m_pCmd: NULL;
199  }
200 
201  /*!
202  * \brief Get map object.
203  *
204  * \return Pointer to map of commands.
205  */
207  {
208  return m_eType == NodeTypeMap? m_obj.m_pMap: NULL;
209  }
210 
211  /*
212  * \brief Get map's brief description.
213  *
214  * \return strBrief Brief description.
215  */
216  string GetMapBrief()
217  {
218  return m_strMapBrief;
219  }
220 
221  /*
222  * \brief Set map's brief description.
223  *
224  * \param strBrief Brief description.
225  */
226  void SetMapBrief(const string &strBrief)
227  {
228  m_strMapBrief = strBrief;
229  }
230 
231  /*!
232  * \brief Test if node type is null.
233  *
234  * \return Returns true or false.
235  */
236  bool IsNull() { return m_eType == NodeTypeNull; }
237 
238  /*!
239  * \brief Test if node type is shell command.
240  *
241  * \return Returns true or false.
242  */
243  bool IsCmd() { return m_eType == NodeTypeCmd; }
244 
245  /*!
246  * \brief Test if node type is map of commands.
247  *
248  * \return Returns true or false.
249  */
250  bool IsMap() { return m_eType == NodeTypeMap; }
251 
252 protected:
253  NodeType m_eType; ///< node type
254  union
255  {
256  DynaShellCmd *m_pCmd; ///< pointer to allocated shell command
257  ShCmdMap *m_pMap; ///< pointer to allocated map of commands
258  } m_obj; ///< node object
259  string m_strMapBrief; ///< map brief description
260 };
261 
262 
263 // ----------------------------------------------------------------------------
264 // ShScript Class
265 // ----------------------------------------------------------------------------
266 
267 /*!
268  * \brief Shell Script Class.
269  */
270 class ShScript
271 {
272 public:
273  /*!
274  * \brief Initialization constructor.
275  *
276  * \param sScripsFile Script file name.
277  * \param fp Opened file pointer to script file.
278  */
279  ShScript(const char *sScriptFile, FILE *fp)
280  {
281  m_sScriptFile = NEWSTR(sScriptFile);
282  m_fpScript = fp;
283  m_nLineNum = 0;
284  }
285 
286  /*!
287  * \brief Default destructor.
288  */
290  {
291  if( m_fpScript != NULL )
292  {
293  fclose(m_fpScript);
294  }
295  DELSTR(m_sScriptFile);
296  }
297 
298  /*!
299  * \brief Get script file name.
300  *
301  * \return char*
302  */
303  const char *GetScriptName() const
304  {
305  return m_sScriptFile;
306  }
307 
308  /*!
309  * \brief Get file pointer.
310  *
311  * \return FILE*
312  */
313  FILE *GetFp()
314  {
315  return m_fpScript;
316  }
317 
318  /*!
319  * \brief Get current line number.
320  *
321  * \return int
322  */
323  const int GetLineNum() const
324  {
325  return m_nLineNum;
326  }
327 
328  /*!
329  * \brief Bump line number by one.
330  */
331  void BumpLineNum()
332  {
333  m_nLineNum++;
334  }
335 
336 protected:
337  char *m_sScriptFile; ///< script file name
338  FILE *m_fpScript; ///< open file pointer
339  int m_nLineNum; ///< current line number
340 };
341 
342 
343 // ----------------------------------------------------------------------------
344 // DynaShell Class
345 // ----------------------------------------------------------------------------
346 
347 /*!
348  * The Dynamixel shell class.
349  */
351 {
352 public:
353  static const int m_nMaxScriptDepth = 5; ///< maximum script stack depth
354 
355  bool m_bRun; ///< do [not] run shell
356  bool m_bIsInteractive; ///< [not] user interactive
357  bool m_bXTrace; ///< do [not] trace script
358  bool m_bSilent; ///< do [not] silence non-error responses
359  DynaComm *m_pDynaComm; ///< dynamixel bus communication
360  DynaChain *m_pDynaChain; ///< dynamixel chain
361  DynaBgThread *m_pDynaBgThread; ///< dynamixel chain
362  DynaRecording *m_pRecording; ///< dynamixel recording
363 
364  DynaShell();
365 
366  ~DynaShell();
367 
368  void PublishMap(const char *sParent, const string &strBrief);
369  void PublishCommand(const char *sParent, DynaShellCmd *pNewCmd);
370  void DeleteCommands(ShCmdMap &cmdMap);
371 
372  DynaShellCmd *MatchCmd(int argc, char *argv[], ShCmdMap &cmdMap);
373 
374  /*!
375  * \brief (Re)Initialize recording.
376  *
377  * If the shell does not have a recording object, it is created.
378  * Any previously recorded data is 'erased'.
379  *
380  * \param nSamplePeriod Recording sample period (msec).
381  * \param sData Recording date string.
382  */
383  void RecordingInit(int nSamplePeriod, const char *sDate = NULL)
384  {
385  if( m_pRecording == NULL )
386  {
387  m_pRecording = new DynaRecording;
388  }
389  m_pRecording->Init(nSamplePeriod, sDate);
390  }
391 
392  /*!
393  * \brief Replace recording.
394  *
395  * \param pNewRecording Allocated new recording.
396  */
397  void RecordingReplace(DynaRecording *pNewRecording)
398  {
399  if( m_pRecording != NULL )
400  {
401  delete m_pRecording;
402  }
403  m_pRecording = pNewRecording;
404  }
405 
406  void ScriptPush(const char *sScriptFile, FILE *fp);
407  void ScriptPop();
408  void ScriptFlush();
409  void ScriptTrace(const char *sLine);
410 
411  /*!
412  * \brief Test if executing a script.
413  *
414  * \return true or false.
415  */
417  {
418  return m_vecScripts.empty()? false: true;
419  }
420 
421 
422  /*!
423  * \brief Print standard ok success response.
424  */
425  virtual void Ok()
426  {
427  if( !m_bSilent )
428  {
429  printf("ok\n");
430  }
431  }
432 
433  void Response(const char *sFmt, ...);
434  void Warning(const char *sFmt, ...);
435  void Error(int rc, const char *sFmt, ...);
436  void Error(int nServoId, uint_t uAlarms);
437  void Error(const char *sFmt, ...);
438 
439  int Run();
440 
441  /*!
442  * Get map of shell root commands.
443  *
444  * \return Returns command map.
445  */
447  {
448  return m_mapCmds;
449  }
450 
451  char *CmdListGenerator(int nUid,
452  const char *sText,
453  size_t uTextLen,
454  int nState,
455  const char *sContext);
456 
457  char *CmdSpecGenerator(int nUid,
458  const char *sText,
459  size_t uTextLen,
460  int nState,
461  const char *sContext);
462 
463 protected:
464  typedef map<int,DynaShellCmd*> MapTabCompleteGen;
465 
466  const char *m_sShellName; ///< shell name
467  const char *m_sPS1; ///< primary user prompt
468  const char *m_sPS2; ///< secondary user prompt
469  bool m_bNoExec; ///< parse only, no execution
470  char *m_sInputLine; ///< working, allocated line of input
471  ReadLine m_ReadLine; ///< readline object
472  ShCmdMap m_mapCmds; ///< map of published commnds
473  MapTabCompleteGen m_mapTabGen; ///< command tab-completion generators map
474  vector<ShScript*> m_vecScripts; ///< script stack
475  int m_rc; ///< last command executed return code
476 
477  void InputInit();
478 
479  char *GetInputLine();
480 
481  int GetInput();
482 
483  /*!
484  * \brief Test if line is a potential executable statement.
485  *
486  * \note Assumes line has been stripped of leading white space.
487  *
488  * \param sLine Line to test.
489  *
490  * \return true or false.
491  */
492  bool IsExecStmt(const char *sLine)
493  {
494  return (sLine!=NULL) && (*sLine!=0) && (*sLine!=SH_C_COMMENT)? true: false;
495  }
496 
497  static char *CmdListGeneratorWrap(int nUid,
498  const char *sText,
499  size_t uTextLen,
500  int nState,
501  const char *sContext,
502  void *pArg);
503 
504  static char *CmdSpecGeneratorWrap(int nUid,
505  const char *sText,
506  size_t uTextLen,
507  int nState,
508  const char *sContext,
509  void *pArg);
510 
511  void AddToHistory(char *sLine);
512 
513  /*!
514  * \brief Get the current input file pointer.
515  *
516  * \return File pointer.
517  */
518  FILE *InputFp()
519  {
520  return !m_vecScripts.empty()? m_vecScripts.back()->GetFp(): stdin;
521  }
522 
523  /*!
524  * \brief Bump the line number of the current executing script, if any,
525  * by one.
526  */
528  {
529  if( !m_vecScripts.empty() )
530  {
531  m_vecScripts.back()->BumpLineNum();
532  }
533  }
534 
535  /*!
536  * \brief Test if input is at End Of File condition.
537  *
538  * \return Returns true or false.
539  */
540  bool IsEOF()
541  {
542  return feof(InputFp())? true: false;
543  }
544 };
545 
546 
547 #endif // _DYNASHELL_H
ShCmdNode()
Default constructor.
Definition: dynashell.h:130
RoadNarrows Dynamixel Bus Communications Abstract Base Class Interface.
ShCmdMap * GetMap()
Get map object.
Definition: dynashell.h:206
FILE * GetFp()
Get file pointer.
Definition: dynashell.h:313
#define NEWSTR(s)
Allocate a new duplicated string convenience macro.
void ScriptBumpLineNum()
Bump the line number of the current executing script, if any, by one.
Definition: dynashell.h:527
Shell command node map key compare helper class.
Definition: dynashell.h:87
FILE * InputFp()
Get the current input file pointer.
Definition: dynashell.h:518
bool IsRunningScript()
Test if executing a script.
Definition: dynashell.h:416
const char * m_sPS2
secondary user prompt
Definition: dynashell.h:468
Dynamixel shell utilities.
int m_nLineNum
current line number
Definition: dynashell.h:339
const char * GetScriptName() const
Get script file name.
Definition: dynashell.h:303
DynaShellCmd * GetCmd()
Get command object.
Definition: dynashell.h:196
DynaComm * m_pDynaComm
dynamixel bus communication
Definition: dynashell.h:359
void RecordingReplace(DynaRecording *pNewRecording)
Replace recording.
Definition: dynashell.h:397
ShCmdMap m_mapCmds
map of published commnds
Definition: dynashell.h:472
MapTabCompleteGen m_mapTabGen
command tab-completion generators map
Definition: dynashell.h:473
RoadNarrows Dynamixel Servo Chain Container Base Class Interface.
bool IsExecStmt(const char *sLine)
Test if line is a potential executable statement.
Definition: dynashell.h:492
NodeType
Node type.
Definition: dynashell.h:125
Dynamixel shell command abstract base class.
Definition: dynashell_cmd.h:80
string m_strMapBrief
map brief description
Definition: dynashell.h:259
bool IsNull()
Test if node type is null.
Definition: dynashell.h:236
DynaRecording * m_pRecording
dynamixel recording
Definition: dynashell.h:362
Dynamixel background thread class declarations.
vector< ShScript * > m_vecScripts
script stack
Definition: dynashell.h:474
ShScript(const char *sScriptFile, FILE *fp)
Initialization constructor.
Definition: dynashell.h:279
Shell Script Class.
Definition: dynashell.h:270
map< const char *, ShCmdNode, ShCmdNodeKeyCmp > ShCmdMap
Shell command map type.
Definition: dynashell.h:107
bool m_bIsInteractive
[not] user interactive
Definition: dynashell.h:356
ShCmdNode(DynaShellCmd *pCmd)
Shell command initialization constructor.
Definition: dynashell.h:141
virtual void Ok()
Print standard ok success response.
Definition: dynashell.h:425
DynaShellCmd * m_pCmd
pointer to allocated shell command
Definition: dynashell.h:256
bool m_bXTrace
do [not] trace script
Definition: dynashell.h:357
const char * m_sPS1
primary user prompt
Definition: dynashell.h:467
void BumpLineNum()
Bump line number by one.
Definition: dynashell.h:331
The Dynamixel Recording Class.
ReadLine m_ReadLine
readline object
Definition: dynashell.h:471
ShCmdMap & GetRootCmds()
Definition: dynashell.h:446
bool operator()(const char *const &lhs, const char *const &rhs) const
Compare operator required by <map>.
Definition: dynashell.h:98
ShCmdMap * m_pMap
pointer to allocated map of commands
Definition: dynashell.h:257
bool IsMap()
Test if node type is map of commands.
Definition: dynashell.h:250
Dynamixel Chain Container Base Class.
Definition: DynaChain.h:75
ShCmdNode & operator=(ShCmdMap *rhs)
Shell map assignment operator.
Definition: dynashell.h:184
bool IsEOF()
Test if input is at End Of File condition.
Definition: dynashell.h:540
FILE * m_fpScript
open file pointer
Definition: dynashell.h:338
~ShScript()
Default destructor.
Definition: dynashell.h:289
virtual void Init(int nSamplePeriod, const char *sDate=NULL)
(Re)Initialize recording.
DynaBgThread * m_pDynaBgThread
dynamixel chain
Definition: dynashell.h:361
NodeType m_eType
node type
Definition: dynashell.h:253
ReadLine class provides a c++ wrapper around the readline c library.
bool m_bSilent
do [not] silence non-error responses
Definition: dynashell.h:358
The Dynamixel Shell ReadLine Class.
RoadNarrows Dynamixel Top-Level Package Header File.
ShCmdNode(ShCmdMap *pMap)
Map of commands initialization constructor.
Definition: dynashell.h:152
#define DELSTR(s)
Delete an allocated string convenience macro.
const int GetLineNum() const
Get current line number.
Definition: dynashell.h:323
~ShCmdNode()
Default destructor.
Definition: dynashell.h:161
bool m_bRun
do [not] run shell
Definition: dynashell.h:355
DynaChain * m_pDynaChain
dynamixel chain
Definition: dynashell.h:360
Shell command node class.
Definition: dynashell.h:119
int m_rc
last command executed return code
Definition: dynashell.h:475
ShCmdNode & operator=(DynaShellCmd *rhs)
Shell command assignment operator.
Definition: dynashell.h:170
char * m_sScriptFile
script file name
Definition: dynashell.h:337
bool IsCmd()
Test if node type is shell command.
Definition: dynashell.h:243
void RecordingInit(int nSamplePeriod, const char *sDate=NULL)
(Re)Initialize recording.
Definition: dynashell.h:383
const char * m_sShellName
shell name
Definition: dynashell.h:466
bool m_bNoExec
parse only, no execution
Definition: dynashell.h:469
char * m_sInputLine
working, allocated line of input
Definition: dynashell.h:470
Dynamixel Bus Communications Abstract Base Class.
Definition: DynaComm.h:80