Hekateros  3.4.3
RoadNarrows Robotics Robot Arm Project
hekXmlCfg.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Hekateros
4 //
5 // Library: libhekateros
6 //
7 // File: hekXmlCfg.cxx
8 //
9 /*! \file
10  *
11  * $LastChangedDate: 2015-04-24 13:06:48 -0600 (Fri, 24 Apr 2015) $
12  * $Rev: 3959 $
13  *
14  * \brief HekXmlCfg - \h_hek XML configuration class implementation.
15  *
16  * \author Robin Knight (robin.knight@roadnarrows.com)
17  *
18  * \copyright
19  * \h_copy 2013-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 #include <unistd.h>
50 
51 #include <string>
52 
53 #include "rnr/rnrconfig.h"
54 #include "rnr/log.h"
55 #include "rnr/appkit/Xml.h"
56 
57 #include "Hekateros/hekateros.h"
58 #include "Hekateros/hekDescArm.h"
59 #include "Hekateros/hekDescEE.h"
60 #include "Hekateros/hekDesc.h"
61 #include "Hekateros/hekUtils.h"
62 #include "Hekateros/hekXmlCfg.h"
63 
64 
65 using namespace std;
66 using namespace rnr;
67 using namespace hekateros;
68 
69 int HekXmlCfg::load(HekDesc &desc,
70  const string &strSearchPath,
71  const string &strXmlFileName,
72  bool bAllInstances)
73 {
74  vector<string> vecPath; // vector of search paths
75  string fqname; // fully qualified file name
76  bool bFoundInstance; // [not] found instance
77  size_t i; // working index
78  int rc; // return code
79 
80  split(strSearchPath, ':', vecPath);
81 
82  bFoundInstance = false;
83  rc = HEK_OK;
84 
85  for(i=0; i<vecPath.size(); ++i)
86  {
87  fqname = vecPath[i] + '/' + strXmlFileName;
88  if( access(fqname.c_str(), F_OK) == 0 )
89  {
90  LOGDIAG3("Loading Hekateros description XML file: %s.", fqname.c_str());
91 
92  bFoundInstance = true;
93 
94  if( (rc = Xml::loadFile(fqname)) < 0 )
95  {
96  LOGERROR("Parse of Hekateros description from XML file %s failed.",
97  fqname.c_str());
98  rc = -HEK_ECODE_XML;
99  }
100  else
101  {
102  rc = setHekDescFromDOM(desc);
103  }
104 
105  if( rc == HEK_OK )
106  {
107  LOGDIAG2("Hekateros description from XML file %s loaded.",
108  fqname.c_str());
109  }
110 
111  if( !bAllInstances )
112  {
113  break;
114  }
115  }
116  }
117 
118  if( !bFoundInstance )
119  {
120  LOGERROR("XML file %s not found.", strXmlFileName.c_str());
121  rc = -HEK_ECODE_XML;
122  }
123 
124  return rc;
125 }
126 
127 
128 int HekXmlCfg::createTemplateFile(const string &strXmlFileName)
129 {
130  FILE *fp;
131 
132  if( strXmlFileName.empty() )
133  {
134  setErrorMsg("No file name.");
135  LOGERROR("%s", m_bufErrMsg);
136  return -HEK_ECODE_XML;
137  }
138 
139  m_strXmlFileName = strXmlFileName;
140 
141  // open file
142  if( (fp = fopen(m_strXmlFileName.c_str(), "w+")) == NULL )
143  {
144  setErrorMsg("%s: %s(errno=%d).",
145  m_strXmlFileName.c_str(), strerror(errno), errno);
146  LOGERROR("%s", m_bufErrMsg);
147  return -HEK_ECODE_XML;
148  }
149 
150  makeXmlHead();
151  makeXmlTail();
152 
153  //
154  // XML head.
155  //
156  fprintf(fp, " <!-- RoadNarrows Hekateros Top-Level Configuration -->\n");
157  fprintf(fp, "%s", m_strXmlHead.c_str());
158 
159  //
160  // Robotic base major element.
161  //
162  fprintf(fp, " <!-- Hekateros robotic base -->\n");
163  fprintf(fp, " <%s product_id=\"PRODID\">\n", m_strMajElemArm.c_str());
164 
165  fprintf(fp, " <%s>PRODNAME</%s>\n",
166  m_strElemProdName.c_str(), m_strElemProdName.c_str());
167 
168  fprintf(fp, " <%s>\n PRODBRIEF\n </%s>\n",
169  m_strElemProdBrief.c_str(), m_strElemProdBrief.c_str());
170 
171  fprintf(fp, " <%s>PRODHWVER</%s>\n",
172  m_strElemProdHwVer.c_str(), m_strElemProdHwVer.c_str());
173 
174  fprintf(fp, " <%s>DOF</%s>\n",
175  m_strElemProdDoF.c_str(), m_strElemProdDoF.c_str());
176 
177  fprintf(fp, " <%s>PRODSIZE</%s>\n",
178  m_strElemProdSize.c_str(), m_strElemProdSize.c_str());
179 
180  fprintf(fp, " </%s>\n\n", m_strMajElemArm.c_str());
181 
182  //
183  // End effector major element.
184  //
185  fprintf(fp, " <!-- Hekateros end effector tool -->\n");
186  fprintf(fp, " <%s product_id=\"EEPRODID\">\n", m_strMajElemEE.c_str());
187 
188  fprintf(fp, " <%s>PRODNAME</%s>\n",
189  m_strElemProdName.c_str(), m_strElemProdName.c_str());
190 
191  fprintf(fp, " <%s>\n EEPRODBRIEF\n </%s>\n",
192  m_strElemProdBrief.c_str(), m_strElemProdBrief.c_str());
193 
194  fprintf(fp, " <%s>EEPRODHWVER</%s>\n",
195  m_strElemProdHwVer.c_str(), m_strElemProdHwVer.c_str());
196 
197  fprintf(fp, " <%s>EEDOF</%s>\n",
198  m_strElemProdDoF.c_str(), m_strElemProdDoF.c_str());
199 
200  fprintf(fp, " <%s>EEPRODSIZE</%s>\n",
201  m_strElemProdSize.c_str(), m_strElemProdSize.c_str());
202 
203  fprintf(fp, " </%s>\n\n", m_strMajElemEE.c_str());
204 
205 
206  //
207  // XML tail
208  //
209  fprintf(fp, "%s", m_strXmlTail.c_str());
210 
211  fclose(fp);
212 
213  LOGDIAG3("Created file %s.", m_strXmlFileName.c_str());
214 
215  return HEK_OK;
216 }
217 
218 int HekXmlCfg::setHekDescFromDOM(HekDesc &desc)
219 {
220  HekDescArm *pDescArm;
221  HekDescEE *pDescEE;
222  TiXmlElement *pElem;
223  const char *sValue;
224  const char *sAttr;
225  const char *sText;
226  int n;
227  int rc;
228 
229  //
230  // Subsection descriptions.
231  //
232  pDescArm = desc.getArmDesc();
233  pDescEE = desc.getEEDesc();
234 
235  pDescArm->resetDesc();
236  pDescEE->resetDesc();
237 
238  if( m_pElemRoot == NULL )
239  {
240  setErrorMsg("Missing DOM and/or <%s> root element missing.",
241  m_strRootElemName.c_str());
242  LOGERROR("%s", m_bufErrMsg);
243  return -HEK_ECODE_XML;
244  }
245 
246  // search secion elements
247  for(pElem = m_pElemRoot->FirstChildElement();
248  pElem != NULL;
249  pElem = pElem->NextSiblingElement())
250  {
251  if( (sValue = pElem->Value()) == NULL )
252  {
253  continue;
254  }
255 
256  // robotic base description
257  else if( !strcasecmp(sValue, m_strMajElemArm.c_str()) )
258  {
259  setHekArmDescFromDOM(pElem, pDescArm);
260  }
261 
262  // end effecotr description
263  else if( !strcasecmp(sValue, m_strMajElemEE.c_str()) )
264  {
265  setHekEEDescFromDOM(pElem, pDescEE);
266  }
267  }
268 
269  return HEK_OK;
270 }
271 
272 int HekXmlCfg::setDOMFromHekDesc(const HekDesc &desc)
273 {
274  // TODO
275  return -HEK_ECODE_GEN;
276 }
277 
278 int HekXmlCfg::setHekArmDescFromDOM(TiXmlElement *pElemMaj, HekDescArm *pDesc)
279 {
280  TiXmlElement *pElem;
281  const char *sValue;
282  string str;
283  int eProdId;
284  string strProdName;
285  string strProdBrief;
286  string strHwVer;
287  int nDoF = 0;
288  int eProdSize = HekProdSizeUnknown;
289  int rc;
290 
291  if( (rc = strToInt(elemAttr(pElemMaj, m_strAttrProdId), eProdId)) < 0 )
292  {
293  setErrorMsg("%s: No %s attribute of <%s> found or value not an integer.",
294  m_strXmlFileName.c_str(),
295  m_strAttrProdId.c_str(),
296  m_strMajElemArm.c_str());
297  LOGERROR("%s", m_bufErrMsg);
298  return -HEK_ECODE_XML;
299  }
300 
301  // child elements
302  for(pElem = pElemMaj->FirstChildElement();
303  pElem != NULL;
304  pElem = pElem->NextSiblingElement())
305  {
306  if( (sValue = pElem->Value()) == NULL )
307  {
308  continue;
309  }
310 
311  // product name
312  else if( !strcasecmp(sValue, m_strElemProdName.c_str()) )
313  {
314  strProdName = elemText(pElem);
315  }
316 
317  // product brief
318  else if( !strcasecmp(sValue, m_strElemProdBrief.c_str()) )
319  {
320  strProdBrief = elemText(pElem);
321  }
322 
323  // product hardware version
324  else if( !strcasecmp(sValue, m_strElemProdHwVer.c_str()) )
325  {
326  strHwVer = elemText(pElem);
327  }
328 
329  // degrees of freedom
330  else if( !strcasecmp(sValue, m_strElemProdDoF.c_str()) )
331  {
332  str = elemText(pElem);
333  if( !str.empty() )
334  {
335  if( (rc = strToInt(str, nDoF)) < 0 )
336  {
337  setErrorMsg("%s: Element <%s> text \"%s\" not an integer.",
338  m_strXmlFileName.c_str(), m_strElemProdDoF.c_str(), str.c_str());
339  LOGERROR("%s", m_bufErrMsg);
340  return -HEK_ECODE_XML;
341  }
342  }
343  }
344 
345  // product size
346  else if( !strcasecmp(sValue, m_strElemProdSize.c_str()) )
347  {
348  str = elemText(pElem);
349  if( !str.empty() )
350  {
351  if( (rc = strToProdSizeCode(str, eProdSize)) < 0 )
352  {
353  setErrorMsg("%s: Element <%s> text \"%s\" not a recognized "
354  "product size.",
355  m_strXmlFileName.c_str(), m_strElemProdSize.c_str(), str.c_str());
356  LOGERROR("%s", m_bufErrMsg);
357  return -HEK_ECODE_XML;
358  }
359  }
360  }
361  }
362 
363  pDesc->setDesc(eProdId, strProdName, strProdBrief, strHwVer, nDoF, eProdSize);
364 
365  LOGDIAG3("%s: Hekateros robotic base description set.",
366  m_strXmlFileName.c_str());
367 
368  return HEK_OK;
369 }
370 
371 int HekXmlCfg::setHekEEDescFromDOM(TiXmlElement *pElemMaj, HekDescEE *pDesc)
372 {
373  TiXmlElement *pElem;
374  const char *sValue;
375  string str;
376  int eProdId;
377  string strProdName;
378  string strProdBrief;
379  string strHwVer;
380  int nDoF = 0;
381  int eProdSize = HekProdSizeUnknown;
382  int rc;
383 
384  if( (rc = strToInt(elemAttr(pElemMaj, m_strAttrProdId), eProdId)) < 0 )
385  {
386  setErrorMsg("%s: No %s attribute of <%s> found or value not an integer.",
387  m_strXmlFileName.c_str(),
388  m_strAttrProdId.c_str(),
389  m_strMajElemArm.c_str());
390  LOGERROR("%s", m_bufErrMsg);
391  return -HEK_ECODE_XML;
392  }
393 
394  // child elements
395  for(pElem = pElemMaj->FirstChildElement();
396  pElem != NULL;
397  pElem = pElem->NextSiblingElement())
398  {
399  if( (sValue = pElem->Value()) == NULL )
400  {
401  continue;
402  }
403 
404  // product name
405  else if( !strcasecmp(sValue, m_strElemProdName.c_str()) )
406  {
407  strProdName = elemText(pElem);
408  }
409 
410  // product brief
411  else if( !strcasecmp(sValue, m_strElemProdBrief.c_str()) )
412  {
413  strProdBrief = elemText(pElem);
414  }
415 
416  // product hardware version
417  else if( !strcasecmp(sValue, m_strElemProdHwVer.c_str()) )
418  {
419  strHwVer = elemText(pElem);
420  }
421 
422  // degrees of freedom
423  else if( !strcasecmp(sValue, m_strElemProdDoF.c_str()) )
424  {
425  str = elemText(pElem);
426  if( !str.empty() )
427  {
428  if( (rc = strToInt(str, nDoF)) < 0 )
429  {
430  setErrorMsg("%s: Element <%s> text \"%s\" not an integer.",
431  m_strXmlFileName.c_str(), m_strElemProdDoF.c_str(), str.c_str());
432  LOGERROR("%s", m_bufErrMsg);
433  return -HEK_ECODE_XML;
434  }
435  }
436  }
437 
438  // product size
439  else if( !strcasecmp(sValue, m_strElemProdSize.c_str()) )
440  {
441  str = elemText(pElem);
442  if( !str.empty() )
443  {
444  if( (rc = strToProdSizeCode(str, eProdSize)) < 0 )
445  {
446  setErrorMsg("%s: Element <%s> text \"%s\" not a recognized "
447  "product size.",
448  m_strXmlFileName.c_str(), m_strElemProdSize.c_str(), str.c_str());
449  LOGERROR("%s", m_bufErrMsg);
450  return -HEK_ECODE_XML;
451  }
452  }
453  }
454  }
455 
456  pDesc->setDesc(eProdId, strProdName, strProdBrief, strHwVer, nDoF, eProdSize);
457 
458  LOGDIAG3("%s: Hekateros end effector description set.",
459  m_strXmlFileName.c_str());
460 
461  return HEK_OK;
462 }
463 
464 int HekXmlCfg::strToProdSizeCode(const string &str, int &val)
465 {
466  int rc = HEK_OK;
467 
468  if( str.empty() )
469  {
470  val = HekProdSizeUnknown;
471  }
472  else if( !strcmp(str.c_str(), HekProdSizeStrUnknown) )
473  {
474  val = HekProdSizeUnknown;
475  }
476  else if( !strcmp(str.c_str(), HekProdSizeStrStd) )
477  {
478  val = HekProdSizeStd;
479  }
480  else if( !strcmp(str.c_str(), HekProdSizeStrShort) )
481  {
482  val = HekProdSizeShort;
483  }
484  else if( !strcmp(str.c_str(), HekProdSizeStrLong) )
485  {
486  val = HekProdSizeLong;
487  }
488  else
489  {
490  LOGERROR("%s: Unknown product size code.", str.c_str());
491  rc = -HEK_ECODE_XML;
492  }
493 
494  return rc;
495 }
496 
497 int HekXmlCfg::prodSizeToStr(const int val, string &str)
498 {
499  int rc = HEK_OK;
500 
501  switch(val)
502  {
503  case HekProdSizeUnknown:
504  str = "?";
505  break;
506  case HekProdSizeStd:
507  str = "N";
508  break;
509  case HekProdSizeShort:
510  str = "S";
511  break;
512  case HekProdSizeLong:
513  str = "L";
514  break;
515  default:
516  LOGERROR("%c: Unknown product size code.", val);
517  rc = -HEK_ECODE_XML;
518  break;
519  }
520 
521  return rc;
522 }
HekDesc - Hekateros full robotic manipulator descripition class interface.
Hekateros end effector tool description class.
Definition: hekDescEE.h:71
HekXmlCfg - <b><i>Hekateros</i></b> XML configuration class interface.
HekDescArm * getArmDesc()
Get the <b><i>Hekateros</i></b> base product description.
Definition: hekDesc.h:177
void resetDesc()
Reset base description to the "unitialized" values.
Definition: hekDescArm.cxx:98
Hekateros robotic arm (manipulator) description class.
Definition: hekDescArm.h:77
Hekateros robotic manipulator full description class.
Definition: hekDesc.h:75
std::vector< std::string > & split(const std::string &s, char delim, std::vector< std::string > &elems)
Split string at the delimiter character.
HekDescEE * getEEDesc()
Get the <b><i>Hekateros</i></b> end effector product description.
Definition: hekDesc.h:187
Top-level package include file.
void resetDesc()
Reset base description to the "unitialized" values.
Definition: hekDescEE.cxx:97
HekDescEE - Hekateros end effector tool description class interface.
HekDescArm - Hekateros robotic arm description class interface.
Hekateros common utilities.
The <b><i>Hekateros</i></b> namespace encapsulates all <b><i>Hekateros</i></b> related constructs...
Definition: hekateros.h:56