Laelaps  2.3.5
RoadNarrows Robotics Small Outdoor Mobile Robot Project
laeUtils.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Laelaps
4 //
5 // Library: liblaelaps
6 //
7 // File: laeUtils.cxx
8 //
9 //
10 /*! \file
11  *
12  * $LastChangedDate: 2015-08-07 11:55:07 -0600 (Fri, 07 Aug 2015) $
13  * $Rev: 4050 $
14  *
15  * \brief Laelaps utilities.
16  *
17  * \author Robin Knight (robin.knight@roadnarrows.com)
18  *
19  * \par Copyright
20  * \h_copy 2015-2017. RoadNarrows LLC.\n
21  * http://www.roadnarrows.com\n
22  * All Rights Reserved
23  */
24 /*
25  * @EulaBegin@
26  *
27  * Unless otherwise stated explicitly, all materials contained are copyrighted
28  * and may not be used without RoadNarrows LLC's written consent,
29  * except as provided in these terms and conditions or in the copyright
30  * notice (documents and software) or other proprietary notice provided with
31  * the relevant materials.
32  *
33  * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY
34  * MEMBERS/EMPLOYEES/CONTRACTORS OF ROADNARROWS OR DISTRIBUTORS OF THIS SOFTWARE
35  * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
36  * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
37  * DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN
38  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39  *
40  * THE AUTHORS AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
41  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
42  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
43  * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
44  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
45  *
46  * @EulaEnd@
47  */
48 ////////////////////////////////////////////////////////////////////////////////
49 
50 
51 #include <sys/types.h>
52 #include <sys/stat.h>
53 #include <sys/time.h>
54 #include <time.h>
55 #include <fcntl.h>
56 #include <unistd.h>
57 #include <libgen.h>
58 #include <stdio.h>
59 #include <errno.h>
60 
61 #include <string>
62 #include <sstream>
63 #include <vector>
64 
65 #include "rnr/rnrconfig.h"
66 #include "rnr/log.h"
67 
68 #include "Laelaps/laelaps.h"
69 #include "Laelaps/laeUtils.h"
70 
71 using namespace std;
72 
73 
74 //------------------------------------------------------------------------------
75 // Private Interface
76 //------------------------------------------------------------------------------
77 
78 /*!
79  * \ingroup liblaelaps
80  * \brief \h_laelaps Error Code String Table.
81  *
82  * Table is indexed by \h_laelaps error codes (see \ref lae_ecodes). Keep
83  * in sync.
84  */
85 static const char *EcodeStrTbl[] =
86 {
87  "Ok", ///< [LAE_OK]
88 
89  "Error", ///< [LAE_ECODE_GEN]
90  "System error", ///< [LAE_ECODE_SYS]
91  "Internal error", ///< [LAE_ECODE_INTERNAL]
92  "Bad value", ///< [LAE_ECODE_BAD_VAL]
93  "Too big", ///< [LAE_ECODE_TOO_BIG]
94  "Too small", ///< [LAE_ECODE_TOO_SMALL]
95  "Value out-of-range", ///< [LAE_ECODE_RANGE]
96  "Invalid operation", ///< [LAE_ECODE_BAD_OP]
97  "Operation timed out", ///< [LAE_ECODE_TIMEDOUT]
98  "Device not found", ///< [LAE_ECODE_NO_DEV]
99  "No resource available", ///< [LAE_ECODE_NO_RSRC]
100  "Resource busy", ///< [LAE_ECODE_BUSY]
101  "Cannot execute", ///< [LAE_ECODE_NO_EXEC]
102  "Permissions denied", ///< [LAE_ECODE_PERM]
103  "Dynamixel chain or servo error", ///< [LAE_ECODE_DYNA]
104  "Video error", ///< [LAE_ECODE_VIDEO]
105  "Bad format", ///< [LAE_ECODE_FORMAT]
106  "BotSense error", ///< [LAE_ECODE_BOTSENSE]
107  "File not found", ///< [LAE_ECODE_NO_FILE]
108  "XML error", ///< [LAE_ECODE_XML]
109  "Robot is in an alarmed state", ///< [LAE_ECODE_ALARMED]
110  "Operation interrupted", ///< [LAE_ECODE_INTR]
111  "Robotic link(s) movement obstructed", ///< [LAE_ECODE_COLLISION]
112  "Robot emergency stopped", ///< [LAE_ECODE_ESTOP]
113  "Motor controller or motor error", ///< [LAE_ECODE_MOT_CTLR]
114  "I/O error", ///< [LAE_ECODE_IO]
115 
116  "Invalid error code" ///< [LAE_ECODE_BADEC]
117 };
118 
119 
120 //------------------------------------------------------------------------------
121 // Public Interface
122 //------------------------------------------------------------------------------
123 
124 const char *laelaps::getStrError(const int ecode)
125 {
126  int ec = ecode >= 0 ? ecode : -ecode;
127 
128  if( ec >= arraysize(EcodeStrTbl) )
129  {
130  ec = LAE_ECODE_BADEC;
131  }
132 
133  return EcodeStrTbl[ec];
134 }
135 
136 uint_t laelaps::strToVersion(const string &str)
137 {
138  int nMajor = 0;
139  int nMinor = 0;
140  int nRevision = 0;
141 
142  sscanf(str.c_str(), "%d.%d.%d", &nMajor, &nMinor, &nRevision);
143 
144  return LAE_VERSION(nMajor, nMinor, nRevision);
145 }
146 
147 bool laelaps::operator<(const struct timeval& lhs, const struct timeval& rhs)
148 {
149  if( lhs.tv_sec < rhs.tv_sec )
150  {
151  return true;
152  }
153  else if( (lhs.tv_sec == rhs.tv_sec) && (lhs.tv_usec < rhs.tv_usec) )
154  {
155  return true;
156  }
157  else
158  {
159  return false;
160  }
161 }
162 
163 bool laelaps::operator==(const struct timeval& lhs, const struct timeval& rhs)
164 {
165  return (lhs.tv_sec == rhs.tv_sec) && (lhs.tv_usec == rhs.tv_usec)?
166  true: false;
167 }
168 
169 bool laelaps::operator>(const struct timeval& lhs, const struct timeval& rhs)
170 {
171  return !(lhs < rhs) && !(lhs == rhs);
172 }
173 
174 bool laelaps::operator<=(const struct timeval& lhs, const struct timeval& rhs)
175 {
176  return lhs < rhs || lhs == rhs;
177 }
178 
179 bool laelaps::operator>=(const struct timeval& lhs, const struct timeval& rhs)
180 {
181  return lhs > rhs || lhs == rhs;
182 }
183 
184 struct timeval laelaps::operator+(const struct timeval& op1,
185  const struct timeval& op2)
186 {
187  struct timeval sum = op1;
188 
189  sum.tv_sec += op2.tv_sec;
190  sum.tv_usec += op2.tv_usec;
191 
192  if( sum.tv_usec > MILLION )
193  {
194  ++sum.tv_sec;
195  sum.tv_usec -= MILLION;
196  }
197 
198  return sum;
199 }
200 
201 struct timeval laelaps::operator-(const struct timeval& op1,
202  const struct timeval& op2)
203 {
204  struct timeval diff;
205 
206  diff.tv_sec = op1.tv_sec - op2.tv_sec;
207 
208  if( op1.tv_usec >= op2.tv_usec)
209  {
210  diff.tv_usec = op1.tv_usec - op2.tv_usec;
211  }
212  else
213  {
214  --diff.tv_sec;
215  diff.tv_usec = MILLION + op1.tv_usec - op2.tv_usec;
216  }
217 
218  return diff;
219 }
220 
221 long laelaps::dt_usec(struct timeval& t1, struct timeval& t0)
222 {
223  struct timeval dt = t1 - t0;
224 
225  return (long)dt.tv_sec * MILLION + (long)dt.tv_usec;
226 }
227 
228 double laelaps::dt(struct timeval& t1, struct timeval& t0)
229 {
230  if( t0 < t1 )
231  {
232  return (double)dt_usec(t1, t0) / (double)MILLION;
233  }
234  else
235  {
236  return -(double)dt_usec(t0, t1) / (double)MILLION;
237  }
238 }
239 
240 bool laelaps::operator<(const struct timespec& lhs, const struct timespec& rhs)
241 {
242  if( lhs.tv_sec < rhs.tv_sec )
243  {
244  return true;
245  }
246  else if( (lhs.tv_sec == rhs.tv_sec) && (lhs.tv_nsec < rhs.tv_nsec) )
247  {
248  return true;
249  }
250  else
251  {
252  return false;
253  }
254 }
255 
256 bool laelaps::operator==(const struct timespec& lhs, const struct timespec& rhs)
257 {
258  return (lhs.tv_sec == rhs.tv_sec) && (lhs.tv_nsec == rhs.tv_nsec)?
259  true: false;
260 }
261 
262 bool laelaps::operator>(const struct timespec& lhs, const struct timespec& rhs)
263 {
264  return !(lhs < rhs) && !(lhs == rhs);
265 }
266 
267 bool laelaps::operator<=(const struct timespec& lhs, const struct timespec& rhs)
268 {
269  return lhs < rhs || lhs == rhs;
270 }
271 
272 bool laelaps::operator>=(const struct timespec& lhs, const struct timespec& rhs)
273 {
274  return lhs > rhs || lhs == rhs;
275 }
276 
277 struct timespec laelaps::operator+(const struct timespec& op1,
278  const struct timespec& op2)
279 {
280  struct timespec sum = op1;
281 
282  sum.tv_sec += op2.tv_sec;
283  sum.tv_nsec += op2.tv_nsec;
284 
285  if( sum.tv_nsec > BILLION )
286  {
287  ++sum.tv_sec;
288  sum.tv_nsec -= BILLION;
289  }
290 
291  return sum;
292 }
293 
294 struct timespec laelaps::operator-(const struct timespec& op1,
295  const struct timespec& op2)
296 {
297  struct timespec diff;
298 
299  diff.tv_sec = op1.tv_sec - op2.tv_sec;
300 
301  if( op1.tv_nsec >= op2.tv_nsec)
302  {
303  diff.tv_nsec = op1.tv_nsec - op2.tv_nsec;
304  }
305  else
306  {
307  --diff.tv_sec;
308  diff.tv_nsec = BILLION + op1.tv_nsec - op2.tv_nsec;
309  }
310 
311  return diff;
312 }
313 
314 long long laelaps::dt_nsec(struct timespec& t1, struct timespec& t0)
315 {
316  struct timespec dt = t1 - t0;
317 
318  return (long long)dt.tv_sec * BILLION + (long long)dt.tv_nsec;
319 }
320 
321 double laelaps::dt(struct timespec& t1, struct timespec& t0)
322 {
323  if( t0 < t1 )
324  {
325  return (double)dt_nsec(t1, t0) / (double)BILLION;
326  }
327  else
328  {
329  return -(double)dt_nsec(t0, t1) / (double)BILLION;
330  }
331 }
332 
333 string laelaps::getRealDeviceName(const string &strDevName)
334 {
335  char buf[MAX_PATH+1];
336  ssize_t len;
337 
338  //
339  // Symbolic link.
340  //
341  if( (len = readlink(strDevName.c_str(), buf, MAX_PATH)) > 0 )
342  {
343  buf[len] = 0;
344 
345  // absollute path
346  if( buf[0] == '/' )
347  {
348  string strRealDevName(buf);
349  return strRealDevName;
350  }
351 
352  // relative path
353  else
354  {
355  char s[strDevName.size()+1];
356  stringstream ss;
357 
358  strcpy(s, strDevName.c_str());
359 
360  char *sDirName = dirname(s);
361 
362  ss << sDirName << "/" << buf;
363 
364  return ss.str();
365  }
366  }
367 
368  //
369  // Real device.
370  //
371  else
372  {
373  return strDevName;
374  }
375 }
376 
377 vector<string> &laelaps::split(const string &s,
378  char delim,
379  vector<string> &elems)
380 {
381  stringstream ss(s);
382  string item;
383 
384  while( getline(ss, item, delim) )
385  {
386  elems.push_back(item);
387  }
388  return elems;
389 }
390 
391 vector<string> laelaps::split(const string &s, char delim)
392 {
393  vector<string> elems;
394 
395  split(s, delim, elems);
396 
397  return elems;
398 }
bool operator>=(const struct timeval &lhs, const struct timeval &rhs)
Greater than or equal to compare operator.
double dt(struct timeval &t1, struct timeval &t0)
Calculate delta time.
uint_t strToVersion(const std::string &str)
Convert version dotted string to integer equivalent.
bool operator>(const struct timeval &lhs, const struct timeval &rhs)
Greater than compare operator.
const char * getStrError(const int ecode)
Get the error string describing the <b><i>Laelaps</i></b> error code.
std::vector< std::string > & split(const std::string &s, char delim, std::vector< std::string > &elems)
Split string at the delimiter character.
bool operator<=(const struct timeval &lhs, const struct timeval &rhs)
Less than or equal to compare operator.
bool operator<(const struct timeval &lhs, const struct timeval &rhs)
Less than compare operator.
The <b><i>Laelaps</i></b> namespace encapsulates all <b><i>Laelaps</i></b> related constructs...
Definition: laeAlarms.h:64
Laelaps common utilities.
long long dt_nsec(struct timespec &t1, struct timespec &t0)
Calculate delta time in nanoseconds.
bool operator==(const struct timeval &lhs, const struct timeval &rhs)
Equality compare operator.
static const char * EcodeStrTbl[]
<b><i>Laelaps</i></b> Error Code String Table.
Definition: laeUtils.cxx:85
#define LAE_VERSION(major, minor, revision)
Convert version triplet to integer equivalent.
Definition: laelaps.h:158
std::string getRealDeviceName(const std::string &strDevName)
Get real device name.
Top-level package include file.
long dt_usec(struct timeval &t1, struct timeval &t0)
Calculate delta time in microseconds.