Dynamixel  2.9.5
RoadNarrows Robotics Dynamixel Package
dynashell_recording.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Dynamixel
4 //
5 // Program: dynashell
6 //
7 // File: dynashell_recording.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 Recording Class
15  *
16  * \note May promote this class to libDynamixel library.
17  *
18  * \author Robin Knight (robin.knight@roadnarrows.com)
19  *
20  * \copyright
21  * \h_copy 2011-2017. RoadNarrows LLC.\n
22  * http://www.roadnarrows.com\n
23  * All Rights Reserved
24  */
25 /*
26  * @EulaBegin@
27  *
28  * Unless otherwise stated explicitly, all materials contained are copyrighted
29  * and may not be used without RoadNarrows LLC's written consent,
30  * except as provided in these terms and conditions or in the copyright
31  * notice (documents and software) or other proprietary notice provided with
32  * the relevant materials.
33  *
34  * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY
35  * MEMBERS/EMPLOYEES/CONTRACTORS OF ROADNARROWS OR DISTRIBUTORS OF THIS SOFTWARE
36  * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
37  * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
38  * DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN
39  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40  *
41  * THE AUTHORS AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
42  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
43  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
44  * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
45  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
46  *
47  * @EulaEnd@
48  */
49 ////////////////////////////////////////////////////////////////////////////////
50 
51 #include <time.h>
52 
53 #include <cstring>
54 #include <iostream>
55 #include <fstream>
56 #include <vector>
57 #include <map>
58 
59 #include "rnr/rnrconfig.h"
60 #include "rnr/log.h"
61 
62 #include "Dynamixel/Dynamixel.h"
63 #include "Dynamixel/DynaComm.h"
64 #include "Dynamixel/DynaChain.h"
65 
66 #include "dynashell.h"
67 #include "dynashell_recording.h"
68 #include "dynashell_util.h"
69 
70 using namespace std;
71 
72 
73 //-----------------------------------------------------------------------------
74 // Private Interface
75 //-----------------------------------------------------------------------------
76 
77 
78 
79 // -----------------------------------------------------------------------------
80 // DynaRecord Class
81 // -----------------------------------------------------------------------------
82 
83 
84 /*!
85  * \brief Add a field tuple to the record.
86  *
87  * \param nPos Servo position.
88  * \param nSpeed Servo speed.
89  *
90  * \return
91  * On success, returns the newly added field number.\n
92  * On failure, \ref DynaRecord::END is returned.
93  */
94 int DynaRecord::AddField(int nPos, int nSpeed)
95 {
96  if( m_nFieldCnt < DYNA_ID_NUMOF )
97  {
98  int nFldNum = m_nFieldCnt;
99  m_field[nFldNum].m_nPos = nPos;
100  m_field[nFldNum].m_nSpeed = nSpeed;
101  m_nFieldCnt++;
102  return nFldNum;
103  }
104  else
105  {
106  return DynaRecord::END;
107  }
108 }
109 
110 /*!
111  * \brief Assignment operator.
112  *
113  * \param rhs Right hand side.
114  *
115  * \return Reference to this.
116  */
118 {
119  int i;
120 
121  m_nFieldCnt = rhs.m_nFieldCnt;
122 
123  for(i=0; i<m_nFieldCnt; ++i)
124  {
125  m_field[i] = rhs.m_field[i];
126  }
127 
128  return *this;
129 }
130 
131 /*! 'Not a Field' field. */
132 const DynaRecord::FieldTuple_T DynaRecord::NoField = {INT_MAX, INT_MAX};
133 
134 
135 // -----------------------------------------------------------------------------
136 // DynaRecording Class
137 // -----------------------------------------------------------------------------
138 
139 /*!
140  * \brief (Re)Initialize recording.
141  *
142  * Any previously recorded data is 'erased'.
143  *
144  * \param nSamplePeriod Recording sample period (msec).
145  * \param sData Recording date string.
146  */
147 void DynaRecording::Init(int nSamplePeriod, const char *sDate)
148 {
149  int nRecNum; // working record number
150 
151  // clear vector of information about the servos in recording
152  m_vecServoInfo.clear();
153  m_mapIIdx.clear();
154 
155  SetDate(sDate);
156 
157  m_nSamplePeriod = nSamplePeriod;
158  m_nRecordCnt = 0;
159 
160  // clear any old records
161  for(nRecNum=0; nRecNum<MaxRecords; ++nRecNum)
162  {
163  m_record[nRecNum].ResetFieldCount();
164  }
165 }
166 
167 /*!
168  * \brief Add a new empty record to the recording.
169  *
170  * \return
171  * If the number of records already in the recording is \ref MaxRecords and
172  * there are registered servos listed in the recording header, then
173  * the new record number is returned.\n
174  * Otherwise \ref END is returned.
175  */
177 {
178  int nRecNum;
179 
180  if( (m_nRecordCnt >= MaxRecords) || (GetNumOfServosInRecording() == 0) )
181  {
182  return END;
183  }
184  else
185  {
186  nRecNum = m_nRecordCnt;
187  m_record[nRecNum].ResetFieldCount();
188  ++m_nRecordCnt;
189  return nRecNum;
190  }
191 }
192 
193 /*!
194  * \brief Add new recording field tuple.
195  *
196  * The field position must match the registered servo position listed in the
197  * header.
198  *
199  * \param nRecNum Record number.
200  * \param nServoId Servo id of field tuple data.
201  * \param nPos Servo position.
202  * \param nSpeed Servo speed.
203  *
204  * \return
205  * Returns added field number on success.\n
206  * Returns \ref END of failure to add.
207  */
209  int nServoId,
210  int nPos,
211  int nSpeed)
212 {
213  int nFieldCnt;
214 
215  nFieldCnt = m_record[nRecNum].GetFieldCount();
216 
217  if( nRecNum == END )
218  {
219  return END;
220  }
221  else if( nRecNum >= m_nRecordCnt )
222  {
223  LOGERROR("Record number %d >= record count = %d.", nRecNum, m_nRecordCnt);
224  return END;
225  }
226  else if( nFieldCnt >= GetNumOfServosInRecording() )
227  {
228  LOGERROR("Record %d field count %d at maximum.", nRecNum, nFieldCnt);
229  return END;
230  }
231  else if( !HasServoAt(nFieldCnt, nServoId) )
232  {
233  LOGERROR("Servo %d not found in recording header at field position %d.",
234  nServoId, nFieldCnt);
235  return END;
236  }
237  else
238  {
239  return m_record[nRecNum].AddField(nPos, nSpeed);
240  }
241 }
242 
243 /*!
244  * \brief Register servo information in recording header.
245  *
246  * \note The order of registration is important and must match field order.
247  * \note All relevant servos must be registered prior to adding records.
248  *
249  * \param nServoId Servo Id.
250  * \param uModelNum Servo model number.
251  *
252  * \copydoc doc_return_std
253  */
254 int DynaRecording::RegisterServoInfo(int nServoId, uint_t uModelNum)
255 {
256  ServoInfo_T info;
257 
258  // duplicate servo registration
259  if( m_mapIIdx.find(nServoId) != m_mapIIdx.end() )
260  {
261  return -DYNA_ECODE_BAD_VAL;
262  }
263  else if( (int)m_vecServoInfo.size() >= DYNA_ID_NUMOF )
264  {
265  return -DYNA_ECODE_RSRC;
266  }
267 
268  info.m_nServoId = nServoId;
269  info.m_uModelNum = uModelNum;
270 
271  m_vecServoInfo.push_back(info);
272  m_mapIIdx[nServoId] = (int)m_vecServoInfo.size() - 1;
273 
274  return DYNA_OK;
275 }
276 
277 /*!
278  * \breif Set recording date string.
279  *
280  * \param sData Recording date string. If NULL, then the current local time
281  * and date are used.
282  */
283 void DynaRecording::SetDate(const char *sDate)
284 {
285  size_t n = 32; // size of data buffer
286  time_t tnow; // time now
287  struct tm bdtime; // broken-down time
288 
289  // delete old recording date string
290  DELOBJ(m_sDate);
291 
292  // default recording date string is 'now'
293  if( sDate == NULL )
294  {
295  m_sDate = new char[n];
296  tnow = time(NULL);
297  if( (localtime_r(&tnow, &bdtime) == NULL) ||
298  (strftime(m_sDate, n, "%a %b %H:%M:%S %Y", &bdtime) == 0) )
299  {
300  strcpy(m_sDate, "Unknown Date");
301  }
302  }
303 
304  // set recording date string
305  else
306  {
307  m_sDate = newstr(sDate);
308  }
309 }
RoadNarrows Dynamixel Bus Communications Abstract Base Class Interface.
char * newstr(const char *s)
Allocate new duplicated string.
#define DYNA_OK
not an error, success
Definition: Dynamixel.h:78
Record Field Tuple Structure Type.
virtual int AddRecord()
Add a new empty record to the recording.
Dynamixel shell utilities.
virtual int AddFieldTuple(int nRecNum, int nServoId, int nPos, int nSpeed)
Add new recording field tuple.
#define DELOBJ(p)
Delete an allocated object convenience macro.
RoadNarrows Dynamixel Servo Chain Container Base Class Interface.
DynaRecord & operator=(const DynaRecord &rhs)
Assignment operator.
Key Recorded Servo Information Structure Type.
#define DYNA_ID_NUMOF
number of unique servo id&#39;s
Definition: Dynamixel.h:148
FieldTuple_T m_field[DYNA_ID_NUMOF]
one record of field data
int m_nServoId
servo id
virtual void SetDate(const char *sDate)
static const FieldTuple_T NoField
#define DYNA_ECODE_RSRC
no resource
Definition: Dynamixel.h:96
The Dynamixel Recording Class.
virtual void Init(int nSamplePeriod, const char *sDate=NULL)
(Re)Initialize recording.
static const int END
past-the-end mark
RoadNarrows Dynamixel Top-Level Package Header File.
uint_t m_uModelNum
servo model number
virtual int RegisterServoInfo(int nServoId, uint_t uModelNum)
Register servo information in recording header.
#define DYNA_ECODE_BAD_VAL
bad value
Definition: Dynamixel.h:85
int m_nFieldCnt
number of field tuples
The simple dynashell declarations.
virtual int AddField(int nPos, int nSpeed)
Add a field tuple to the record.