Laelaps  2.3.5
RoadNarrows Robotics Small Outdoor Mobile Robot Project
laeXmlCfg.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Laelaps
4 //
5 // Library: liblaelaps
6 //
7 // File: laeXmlCfg.cxx
8 //
9 /*! \file
10  *
11  * \brief \h_laelaps XML configuration class implementation.
12  *
13  * \author Robin Knight (robin.knight@roadnarrows.com)
14  *
15  * \par Copyright
16  * \h_copy 2014-2017. RoadNarrows LLC.\n
17  * http://www.roadnarrows.com\n
18  * All Rights Reserved
19  */
20 /*
21  * @EulaBegin@
22  *
23  * Unless otherwise stated explicitly, all materials contained are copyrighted
24  * and may not be used without RoadNarrows LLC's written consent,
25  * except as provided in these terms and conditions or in the copyright
26  * notice (documents and software) or other proprietary notice provided with
27  * the relevant materials.
28  *
29  * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY
30  * MEMBERS/EMPLOYEES/CONTRACTORS OF ROADNARROWS OR DISTRIBUTORS OF THIS SOFTWARE
31  * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
32  * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
33  * DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN
34  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  *
36  * THE AUTHORS AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
37  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
38  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
39  * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
40  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
41  *
42  * @EulaEnd@
43  */
44 ////////////////////////////////////////////////////////////////////////////////
45 
46 #include <unistd.h>
47 
48 #include <string>
49 
50 #include "rnr/rnrconfig.h"
51 #include "rnr/log.h"
52 #include "rnr/appkit/Xml.h"
53 
54 #include "Laelaps/laelaps.h"
55 #include "Laelaps/laeUtils.h"
56 #include "Laelaps/laeMotor.h"
57 #include "Laelaps/laeDesc.h"
58 #include "Laelaps/laeXmlCfg.h"
59 
60 
61 using namespace std;
62 using namespace rnr;
63 using namespace laelaps;
64 
65 int LaeXmlCfg::load(LaeDesc &desc,
66  const string &strSearchPath,
67  const string &strXmlFileName,
68  bool bAllInstances)
69 {
70  vector<string> vecPath; // vector of search paths
71  string fqname; // fully qualified file name
72  bool bFoundInstance; // [not] found instance
73  size_t i; // working index
74  int rc; // return code
75 
76  split(strSearchPath, ':', vecPath);
77 
78  bFoundInstance = false;
79  rc = LAE_OK;
80 
81  desc.clear();
82 
83  for(i=0; i<vecPath.size(); ++i)
84  {
85  fqname = vecPath[i] + '/' + strXmlFileName;
86  if( access(fqname.c_str(), F_OK) == 0 )
87  {
88  LOGDIAG3("Loading Laelaps description XML file: %s.", fqname.c_str());
89 
90  bFoundInstance = true;
91 
92  if( (rc = Xml::loadFile(fqname)) < 0 )
93  {
94  LOGERROR("Parse of Laelaps description from XML file %s failed.",
95  fqname.c_str());
96  rc = -LAE_ECODE_XML;
97  }
98  else
99  {
100  rc = setDescFromDOM(desc);
101  }
102 
103  if( rc == LAE_OK )
104  {
105  LOGDIAG2("Loaded Laelaps description from XML file %s.",
106  fqname.c_str());
107  }
108 
109  if( !bAllInstances )
110  {
111  break;
112  }
113  }
114  }
115 
116  if( !bFoundInstance )
117  {
118  LOGERROR("XML file %s not found.", strXmlFileName.c_str());
119  rc = -LAE_ECODE_XML;
120  }
121 
122  return rc;
123 }
124 
125 int LaeXmlCfg::loadFile(const string &strXmlFileName)
126 {
127  int rc;
128 
129  rc = Xml::loadFile(strXmlFileName);
130 
131  return rc < 0? -LAE_ECODE_XML: LAE_OK;
132 }
133 
134 int LaeXmlCfg::loadFile(LaeDesc &desc, const string &strXmlFileName)
135 {
136  int rc;
137 
138  if( (rc = Xml::loadFile(strXmlFileName)) == OK )
139  {
140  rc = setDescFromDOM(desc);
141  }
142 
143  return rc < 0? -LAE_ECODE_XML: LAE_OK;
144 }
145 
146 int LaeXmlCfg::saveFile(const string &strXmlFileName)
147 {
148  int rc;
149 
150  rc = Xml::saveFile(strXmlFileName);
151 
152  return rc < 0? -LAE_ECODE_XML: LAE_OK;
153 }
154 
155 int LaeXmlCfg::saveFile(const LaeDesc &desc, const string &strXmlFileName)
156 {
157  int rc;
158 
159  if( (rc = setDOMFromDesc(desc)) == LAE_OK )
160  {
161  rc = Xml::saveFile(strXmlFileName);
162  }
163 
164  return rc < 0? -LAE_ECODE_XML: LAE_OK;
165 }
166 
167 int LaeXmlCfg::createTemplateFile(const string &strXmlFileName)
168 {
169  FILE *fp; // opened file pointer
170 
171  if( strXmlFileName.empty() )
172  {
173  setErrorMsg("No file name.");
174  LOGERROR("%s", m_bufErrMsg);
175  return -LAE_ECODE_XML;
176  }
177 
178  m_strXmlFileName = strXmlFileName;
179 
180  // open file
181  if( (fp = fopen(m_strXmlFileName.c_str(), "w+")) == NULL )
182  {
183  setErrorMsg("%s: %s(errno=%d).",
184  m_strXmlFileName.c_str(), strerror(errno), errno);
185  LOGERROR("%s", m_bufErrMsg);
186  return -LAE_ECODE_XML;
187  }
188 
189  makeXmlHead();
190  makeXmlTail();
191 
192  //
193  // XML head.
194  //
195  fprintf(fp, " <!-- RoadNarrows Laelaps Top-Level Description -->\n");
196  fprintf(fp, "%s", m_strXmlHead.c_str());
197 
198  //
199  // Robotic base major element.
200  //
201  fprintf(fp, " <!-- Laelaps robotic mobile base -->\n");
202  fprintf(fp, " <%s>\n", m_strMajElemBase.c_str());
203 
204  fprintf(fp, " <!-- DESCRIPTION ELEMENTS HERE -->\n");
205 
206  fprintf(fp, " </%s>\n\n", m_strMajElemBase.c_str());
207 
208  //
209  // Package options major element.
210  //
211  fprintf(fp, " <!-- Laelaps package options -->\n");
212  fprintf(fp, " <%s>\n", m_strMajElemOptions.c_str());
213 
214  fprintf(fp, " <!-- OPTION ELEMENTS HERE -->\n");
215 
216  fprintf(fp, " </%s>\n\n", m_strMajElemOptions.c_str());
217 
218  //
219  // XML tail
220  //
221  fprintf(fp, "%s", m_strXmlTail.c_str());
222 
223  fclose(fp);
224 
225  LOGDIAG3("Created file %s.", m_strXmlFileName.c_str());
226 
227  return LAE_OK;
228 }
229 
230 int LaeXmlCfg::setDescFromDOM(LaeDesc &desc)
231 {
232  TiXmlElement *pElem;
233  const char *sValue;
234  const char *sAttr;
235  const char *sText;
236  int n;
237  int rc;
238 
239  // root element
240  if( m_pElemRoot == NULL )
241  {
242  setErrorMsg("Missing DOM and/or <%s> root element missing.",
243  m_strRootElemName.c_str());
244  LOGERROR("%s", m_bufErrMsg);
245  return -LAE_ECODE_XML;
246  }
247 
248  // search secion elements
249  for(pElem = m_pElemRoot->FirstChildElement();
250  pElem != NULL;
251  pElem = pElem->NextSiblingElement())
252  {
253  if( (sValue = pElem->Value()) == NULL )
254  {
255  continue;
256  }
257 
258  // robotic base description
259  if( !strcasecmp(sValue, m_strMajElemBase.c_str()) )
260  {
261  setBaseDesc(pElem, desc);
262  }
263 
264  // robotic package options descriptions
265  else if( !strcasecmp(sValue, m_strMajElemOptions.c_str()) )
266  {
267  setOptionsDesc(pElem, desc);
268  }
269 
270  else
271  {
272  warnUnknownElem(sValue);
273  }
274  }
275 
276  return LAE_OK;
277 }
278 
279 int LaeXmlCfg::setBaseDesc(TiXmlElement *pElemMaj, LaeDesc &desc)
280 {
281  // sub-elements
282  string strAttrProdId("product_id");
283  string strElemProdName("product_name");
284  string strElemProdBrief("product_brief");
285  string strElemProdFamily("product_family");
286  string strElemProdModel("product_model");
287  string strElemProdHwVer("hw_version");
288 
289  TiXmlElement *pElem;
290  const char *sValue;
291  string str;
292  int iVal;
293  int rc;
294 
295  if( (rc = strToInt(elemAttr(pElemMaj, strAttrProdId), iVal)) < 0 )
296  {
297  setErrorMsg("%s: No %s attribute of <%s> found or value not an integer.",
298  m_strXmlFileName.c_str(),
299  strAttrProdId.c_str(),
300  m_strMajElemBase.c_str());
301  LOGERROR("%s", m_bufErrMsg);
302  return -LAE_ECODE_XML;
303  }
304 
305  desc.m_eProdId = iVal;
306 
307  // child elements
308  for(pElem = pElemMaj->FirstChildElement(), rc = LAE_OK;
309  (pElem != NULL) && (rc == LAE_OK);
310  pElem = pElem->NextSiblingElement())
311  {
312  if( (sValue = pElem->Value()) == NULL )
313  {
314  continue;
315  }
316 
317  // product name
318  else if( !strcasecmp(sValue, strElemProdName.c_str()) )
319  {
320  desc.m_strProdName = elemText(pElem);
321  }
322 
323  // product brief
324  else if( !strcasecmp(sValue, strElemProdBrief.c_str()) )
325  {
326  desc.m_strProdBrief = elemText(pElem);
327  }
328 
329  // product family
330  else if( !strcasecmp(sValue, strElemProdFamily.c_str()) )
331  {
332  desc.m_strProdFamily = elemText(pElem);
333  }
334 
335  // product model
336  else if( !strcasecmp(sValue, strElemProdModel.c_str()) )
337  {
338  desc.m_strProdModel = elemText(pElem);
339  }
340 
341  // product hardware version
342  else if( !strcasecmp(sValue, strElemProdHwVer.c_str()) )
343  {
344  desc.m_strProdHwVer = elemText(pElem);
346  }
347 
348  else
349  {
350  warnUnknownElem(sValue);
351  }
352  }
353 
354  LOGDIAG3("%s: Laelaps robotic base description set.",
355  m_strXmlFileName.c_str());
356 
357  return LAE_OK;
358 }
359 
360 int LaeXmlCfg::setOptionsDesc(TiXmlElement *pElemMaj, LaeDesc &desc)
361 {
362  // sub-elements
363  string strElemOptToF("tof_option");
364  string strElemOptFCam("fcam_option");
365 
366  TiXmlElement *pElem;
367  const char *sValue;
368  string strText;
369 
370  // child elements
371  for(pElem = pElemMaj->FirstChildElement();
372  pElem != NULL;
373  pElem = pElem->NextSiblingElement())
374  {
375  if( (sValue = pElem->Value()) == NULL )
376  {
377  continue;
378  }
379 
380  // time-of-flight range sensor package
381  else if( !strcasecmp(sValue, strElemOptToF.c_str()) )
382  {
383  strText = elemText(pElem);
384  if( !strcasecmp(strText.c_str(), LaeDescOptions::PkgOptStd) )
385  {
386  desc.m_options.m_strPkgToF = LaeDescOptions::PkgOptStd;
387  }
388  else if( !strcasecmp(strText.c_str(), LaeDescOptions::PkgOptDeluxe) )
389  {
390  desc.m_options.m_strPkgToF = LaeDescOptions::PkgOptDeluxe;
391  }
392  else
393  {
394  LOGWARN("%s: unknown %s package option - assuming %s.",
395  strText.c_str(), strElemOptToF.c_str(), LaeDescOptions::PkgOptStd);
396  desc.m_options.m_strPkgToF = LaeDescOptions::PkgOptStd;
397  }
398  }
399 
400  // front camera sensor package
401  else if( !strcasecmp(sValue, strElemOptFCam.c_str()) )
402  {
403  strText = elemText(pElem);
404  if( !strcasecmp(strText.c_str(), LaeDescOptions::PkgOptStd) )
405  {
406  desc.m_options.m_strPkgFCam = LaeDescOptions::PkgOptStd;
407  }
408  else
409  {
410  LOGWARN("%s: unknown %s package option - assuming %s.",
411  strText.c_str(), strElemOptFCam.c_str(), LaeDescOptions::PkgOptStd);
412  desc.m_options.m_strPkgFCam = LaeDescOptions::PkgOptStd;
413  }
414  }
415 
416  else
417  {
418  warnUnknownElem(sValue);
419  }
420  }
421 
422  LOGDIAG3("%s: Laelaps package options set.", m_strXmlFileName.c_str());
423 
424  return LAE_OK;
425 }
426 
427 int LaeXmlCfg::setDOMFromDesc(const LaeDesc &desc)
428 {
429  // TODO
430  return -LAE_ECODE_GEN;
431 }
Laelaps robotic mobile platform full description class.
Definition: laeDesc.h:451
uint_t strToVersion(const std::string &str)
Convert version dotted string to integer equivalent.
std::string m_strProdBrief
product brief
Definition: laeDesc.h:515
void clear()
Clear description to the "unitialized" values.
Definition: laeDesc.cxx:748
std::string m_strPkgToF
range time-of-flight package
Definition: laeDesc.h:404
std::vector< std::string > & split(const std::string &s, char delim, std::vector< std::string > &elems)
Split string at the delimiter character.
std::string m_strProdModel
product model
Definition: laeDesc.h:513
The <b><i>Laelaps</i></b> namespace encapsulates all <b><i>Laelaps</i></b> related constructs...
Definition: laeAlarms.h:64
Laelaps robotic base mobile platform description class interface.
std::string m_strProdHwVer
product hardware version string
Definition: laeDesc.h:516
Laelaps common utilities.
std::string m_strProdFamily
product family
Definition: laeDesc.h:512
uint_t m_uProdHwVer
product hardware version number
Definition: laeDesc.h:517
int m_eProdId
base product id
Definition: laeDesc.h:511
std::string m_strPkgFCam
front camera package
Definition: laeDesc.h:405
Laelaps motors, encoder, and controllers hardware abstraction interfaces.
<b><i>Laelaps</i></b> XML configuration class interface.
Top-level package include file.
std::string m_strProdName
product name
Definition: laeDesc.h:514