Dynamixel  2.9.5
RoadNarrows Robotics Dynamixel Package
DynaLibInternal.h
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Dynamixel
4 //
5 // Library: libDynamixel
6 //
7 // File: dynaLibInternal.h
8 //
9 /*! \file
10  *
11  * $LastChangedDate: 2015-03-13 13:28:02 -0600 (Fri, 13 Mar 2015) $
12  * $Rev: 3890 $
13  *
14  * \brief The libDynamixel internal 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 _DYNA_LIB_INTERNAL_H
50 #define _DYNA_LIB_INTERNAL_H
51 
52 #include <errno.h>
53 
54 #include "rnr/rnrconfig.h"
55 #include "rnr/new.h"
56 #include "rnr/log.h"
57 
58 #include "Dynamixel/Dynamixel.h"
59 #include "Dynamixel/DynaError.h"
60 
61 
62 // ---------------------------------------------------------------------------
63 // Internal Defines, Macros, Types and Structures
64 // ---------------------------------------------------------------------------
65 
66 /*!
67  * \brief Log Error.
68  *
69  * \param ecode \ref dyna_ecodes error code.
70  * \param efmt Error output format string literal.
71  * \param ... Error variable arguments.
72  */
73 #define DYNA_LOG_ERROR(ecode, efmt, ...) \
74  LOGERROR("%s(ecode=%d): " efmt, \
75  DynaStrError(ecode), (ecode>=0? ecode: -ecode), \
76  ##__VA_ARGS__)
77 
78 /*!
79  * \brief Log System Error.
80  *
81  * \param ecode \ref dyna_ecodes error code.
82  * \param efmt Error output format string literal.
83  * \param ... Error variable arguments.
84  */
85 #define DYNA_LOG_SYS_ERROR(ecode, efmt, ...) \
86  LOGSYSERROR("%s(ecode=%d): " efmt, \
87  DynaStrError(ecode), (ecode>=0? ecode: -ecode), \
88  ##__VA_ARGS__)
89 
90 /*!
91  * \brief Log Error.
92  *
93  * \param estat Errored communication status code.
94  * \param efmt Error output format string literal.
95  * \param ... Error variable arguments.
96  */
97 #define DYNA_LOG_COMM_ERROR(estat, efmt, ...) \
98  LOGERROR("%s(ecode=%d): %s(%d): " efmt, \
99  DynaStrError(DYNA_ECODE_ECOMM), DYNA_ECODE_ECOMM, \
100  dynaCommStatString(estat), estat, \
101  ##__VA_ARGS__)
102 
103 /*!
104  * \brief Log buffer of infrared readings.
105  *
106  * \param sPreface Preface string.
107  * \param buf Buffer contents to log.
108  * \param uCount Number of entries to log.
109  * \param sFmt Buffer entry format string.
110  */
111 #ifdef LOG
112 #define DYNA_LOG_BUF(sPreface, buf, uCount, sFmt) \
113  do \
114  { \
115  if( LOGABLE(LOG_LEVEL_DIAG3) ) \
116  { \
117  DynaLogBuf(sPreface, buf, uCount, sFmt); \
118  } \
119  } while(0)
120 #else
121 #define DYNA_LOG_BUF(sPreface, buf, uCount, sFmt)
122 #endif // LOG
123 
124 /*!
125  * \brief Log servo alarms.
126  *
127  * \param id Servo id.
128  * \param alarms Alarm bits fields.
129  */
130 #ifdef LOG
131 #define DYNA_LOG_SERVO_ALARMS(id, alarms) \
132  do \
133  { \
134  if( LOGABLE(LOG_LEVEL_DIAG3) && ((alarms) != DYNA_ALARM_NONE) ) \
135  { \
136  DynaLogServoAlarms(id, alarms); \
137  } \
138  } while(0)
139 #else
140 #define DYNA_LOG_SERVO_ALARMS(id, alarms)
141 #endif // LOG
142 
143 /*!
144  * \brief Test if Dynamixel return code is not an error.
145  *
146  * If the try fails, an appropriate error is logged and the calling
147  * function is immediately exited by invoking a <b>return</b> with the \h_lt 0
148  * error code.
149  *
150  * \param [in] comm Dynamixel bus communication object.
151  */
152 #define DYNA_TRY_RC(rc, fmt, ...) \
153  do \
154  { \
155  if( (rc) < 0 ) \
156  { \
157  DYNA_LOG_ERROR(rc, fmt, ##__VA_ARGS__); \
158  return rc; \
159  } \
160  } while(0)
161 
162 /*!
163  * \brief Test if bus communication is available exception macro.
164  *
165  * If the try fails, an appropriate error is logged and the calling
166  * function is immediately exited by invoking a <b>return</b> with the \h_lt 0
167  * error code.
168  *
169  * \param [in] comm Dynamixel bus communication object.
170  */
171 #define DYNA_TRY_COMM(comm) \
172  do \
173  { \
174  if( !(comm).IsOpen() ) \
175  { \
176  DYNA_LOG_ERROR(DYNA_ECODE_BADF, "Communication not open."); \
177  return -DYNA_ECODE_BADF; \
178  } \
179  } while(0)
180 
181 /*!
182  * \brief Testing if the servo id is in range exception macro.
183  *
184  * If the try fails, an appropriate error is logged and the calling
185  * function is immediately exited by invoking a <b>return</b> with the \h_lt 0
186  * error code.
187  *
188  * \param [in] id Servo id.
189  */
190 #define DYNA_TRY_SERVO_ID(id) \
191  do \
192  { \
193  if( ((int)(id) < DYNA_ID_MIN) || ((int)(id) > DYNA_ID_MAX) ) \
194  { \
195  DYNA_LOG_ERROR(DYNA_ECODE_BAD_VAL, "Servo id %d: Out-of-range.", \
196  (int)(id)); \
197  return -DYNA_ECODE_BAD_VAL; \
198  } \
199  } while(0)
200 
201 /*!
202  * \brief Test if the servo is a master servo.
203  *
204  * If the try fails, an appropriate error is logged and the calling
205  * function is immediately exited by invoking a <b>return</b> with the \h_lt 0
206  * error code.
207  *
208  * \param [in] pservo Pointer to DynaServo derived object.
209  */
210 #define DYNA_TRY_IS_MASTER(pservo) \
211  do \
212  { \
213  if( !((pservo)->IsMaster()) ) \
214  { \
215  DYNA_LOG_ERROR(DYNA_ECODE_SLAVE, \
216  "Servo %d: Not a master servo.", \
217  (pservo)->m_nServoId); \
218  return -DYNA_ECODE_SLAVE; \
219  } \
220  } while(0)
221 
222 /*!
223  * \brief Test if the servo is unlinked.
224  *
225  * If the try fails, an appropriate error is logged and the calling
226  * function is immediately exited by invoking a <b>return</b> with the \h_lt 0
227  * error code.
228  *
229  * \param [in] pservo Pointer to DynaServo derived object.
230  */
231 #define DYNA_TRY_IS_UNLINKED(pservo) \
232  do \
233  { \
234  if( !((pservo)->IsUnlinked()) ) \
235  { \
236  DYNA_LOG_ERROR(DYNA_ECODE_LINKED, \
237  "Servo %d: Operation not supported: Linked with servo %d.", \
238  (pservo)->m_nServoId, (pservo)->m_link.m_pServoMate->GetServoId()); \
239  return -DYNA_ECODE_LINKED; \
240  } \
241  } while(0)
242 
243 /*!
244  * \brief Test if the servo has one of the required modes exception macro.
245  *
246  * If the try fails, an appropriate error is logged and the calling
247  * function is immediately exited by invoking a <b>return</b> with the \h_lt 0
248  * error code.
249  *
250  * \param [in] pservo Pointer to DynaServo derived object.
251  * \param [in] mode Required servo modes mask.
252  */
253 #define DYNA_TRY_SERVO_HAS_MODE(pservo, mode) \
254  do \
255  { \
256  if( !((pservo)->m_spec.m_uSupportedModes & (mode)) ) \
257  { \
258  DYNA_LOG_ERROR(DYNA_ECODE_NOT_SUPP, \
259  "Servo %d: Required %s mode not supported.",\
260  (pservo)->m_nServoId, \
261  (((mode)&DYNA_MODE_CONTINUOUS)? "continuous": "servo")); \
262  return -DYNA_ECODE_NOT_SUPP; \
263  } \
264  } while(0)
265 
266 /*!
267  * \brief Test if the servo is in the given mode.
268  *
269  * If the try fails, an appropriate error is logged and the calling
270  * function is immediately exited by invoking a <b>return</b> with the \h_lt 0
271  * error code.
272  *
273  * \param [in] pservo Pointer to DynaServo derived object.
274  * \param [in] mode Required servo modes mask.
275  */
276 #define DYNA_TRY_SERVO_IN_MODE(pservo, mode) \
277  do \
278  { \
279  if( ((pservo)->m_cfg.m_uServoMode != (mode)) ) \
280  { \
281  DYNA_LOG_ERROR(DYNA_ECODE_NOT_SUPP, \
282  "Servo %d: Not in required %s mode.",\
283  (pservo)->m_nServoId, \
284  (((mode)&DYNA_MODE_CONTINUOUS)? "continuous": "servo")); \
285  return -DYNA_ECODE_NOT_SUPP; \
286  } \
287  } while(0)
288 
289 /*!
290  * \brief Test if the servo has positiion control.
291  *
292  * A servo has position control if:
293  * \li in servo mode (servo will translate to new position).
294  * \li in continuous mode with 360\h_deg position data (host will translate to
295  * new position).
296  *
297  * If the try fails, an appropriate error is logged and the calling
298  * function is immediately exited by invoking a <b>return</b> with the \h_lt 0
299  * error code.
300  *
301  * \param [in] pservo Pointer to DynaServo derived object.
302  */
303 #define DYNA_TRY_SERVO_HAS_POS_CTL(pservo) \
304  do \
305  { \
306  if( ((pservo)->m_cfg.m_uServoMode != DYNA_MODE_SERVO) && \
307  !(pservo)->m_spec.m_bHas360Pos ) \
308  { \
309  DYNA_LOG_ERROR(DYNA_ECODE_NOT_SUPP, \
310  "Servo %d: Does not support position control.", \
311  (pservo)->m_nServoId); \
312  return -DYNA_ECODE_NOT_SUPP; \
313  } \
314  } while(0)
315 
316 /*!
317  * \brief Test if the servo has a proxy agent.
318  *
319  * The proxy agent is required to do position control for servos in continuous
320  * mode, since the servos do not support this function.
321  *
322  * If the try fails, an appropriate error is logged and the calling
323  * function is immediately exited by invoking a <b>return</b> with the \h_lt 0
324  * error code.
325  *
326  * \param [in] pservo Pointer to DynaServo derived object.
327  */
328 #define DYNA_TRY_SERVO_HAS_AGENT(pservo) \
329  do \
330  { \
331  if( (pservo)->m_pAgent == NULL ) \
332  { \
333  DYNA_LOG_ERROR(DYNA_ECODE_NOT_SUPP, \
334  "Servo %d: No servo proxy agent.", \
335  (pservo)->m_nServoId); \
336  return -DYNA_ECODE_NOT_SUPP; \
337  } \
338  } while(0)
339 
340 /*!
341  * \brief Test if servo address is valid.
342  *
343  * If the try fails, an appropriate error is logged and the calling
344  * function is immediately exited by invoking a <b>return</b> with the \h_lt 0
345  * error code.
346  *
347  * \param [in] addr Servo control table address.
348  */
349 #define DYNA_TRY_ADDR(addr) \
350  do \
351  { \
352  if( !( (((int)(addr) >= DYNA_EEPROM_MIN_ADDR) && \
353  ((int)(addr) <= DYNA_EEPROM_MAX_ADDR)) || \
354  (((int)(addr) >= DYNA_RAM_MIN_ADDR) && \
355  ((int)(addr) <= DYNA_RAM_MAX_ADDR)) ) ) \
356  { \
357  DYNA_LOG_ERROR(DYNA_ECODE_BAD_VAL, \
358  "Control table address 0x%02x: Out of range.", (int)(addr)); \
359  return -DYNA_ECODE_BAD_VAL; \
360  } \
361  } while(0)
362 
363 /*!
364  * \brief Test if the servo id is valid and present in chain exception macro.
365  *
366  * If the try fails, an appropriate error is logged and the calling
367  * function is immediately exited by invoking a <b>return</b> with the \h_lt 0
368  * error code.
369  *
370  * \param [in] pchain Pointer to DynaChain object.
371  * \param [in] id Servo id.
372  */
373 #define DYNA_TRY_SERVO_IN_CHAIN(pchain, id) \
374  do \
375  { \
376  if( ((int)(id) < DYNA_ID_MIN) || ((int)(id) > DYNA_ID_MAX) ) \
377  { \
378  DYNA_LOG_ERROR(DYNA_ECODE_BAD_VAL, "Servo %d: Id out of range.", \
379  (int)(id)); \
380  return -DYNA_ECODE_BAD_VAL; \
381  } \
382  else if( (pchain)->m_pChain[(id)] == NULL ) \
383  { \
384  DYNA_LOG_ERROR(DYNA_ECODE_NO_SERVO, "Servor %d: No servo in chain.", \
385  (int)(id)); \
386  return -DYNA_ECODE_NO_SERVO; \
387  } \
388  } while(0)
389 
390 /*!
391  * \brief Test if the servo is in the required mode(s) exception macro.
392  *
393  * If the check is false, an appropriate error is logged and the calling
394  * function immediately returns with the appropriate \h_lt 0 error code.
395  *
396  * \param expr Expression to evaluate
397  * \param ecode CogniBoost error code.
398  * \param efmt Error output format string literal.
399  * \param ... Variable arguments.
400  */
401 #define DYNA_TRY_EXPR(expr, ecode, efmt, ...) \
402 do \
403 { \
404  if ( !(expr) ) \
405  { \
406  DYNA_LOG_ERROR(ecode, "%s: " efmt, #expr, ##__VA_ARGS__); \
407  return (ecode > 0) ? -(ecode) : ecode; \
408  } \
409 } while(0)
410 
411 
412 // ---------------------------------------------------------------------------
413 // Internal Data
414 // ---------------------------------------------------------------------------
415 
416 // ---------------------------------------------------------------------------
417 // Internal Prototypes
418 // ---------------------------------------------------------------------------
419 
420 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
421 // Utilities
422 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
423 
424 /*!
425  * \brief Allocate new duplicated string.
426  *
427  * \param s String to duplicate.
428  *
429  * \return Returns pointer to allocated string if s is not NULL and the
430  * length of s \h_gt 0.\n Otherwise returns NULL.
431  */
432 inline char *newstr(const char *s)
433 {
434  char *t;
435  if( (s != NULL) && (*s != 0) )
436  {
437  t = new char[strlen(s)+1];
438  strcpy(t, s);
439  }
440  else
441  {
442  t = NULL;
443  }
444  return t;
445 }
446 
447 
448 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
449 // Error, Logging, and Debug Functions
450 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
451 
452 /*!
453  * \brief Map DXL library error code to Dynamixel error code.
454  *
455  * \param nDxlError DXL error code.
456  *
457  * \return Dynamixel library error code.
458  */
459 extern int DynaMapDxlToEcode(int nDxlError);
460 
461 
462 #endif // _DYNA_LIB_INTERNAL_H
char * newstr(const char *s)
Allocate new duplicated string.
Definition: t.py:1
int DynaMapDxlToEcode(int nDxlError)
Map DXL library error code to Dynamixel error code.
Definition: DynaError.cxx:117
RoadNarrows Dynamixel Top-Level Package Header File.
RoadNarrows Dynamixel Library Error and Logging Routines.