Argus Camera Sample
Argus Camera Sample
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
XMLConfig.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016-2024, NVIDIA CORPORATION. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of NVIDIA CORPORATION nor the names of its
13  * contributors may be used to endorse or promote products derived
14  * from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <string>
30 #include <fstream>
31 #include <stdio.h>
32 
33 #include <expat.h>
34 
35 #include "XMLConfig.h"
36 #include "Dispatcher.h"
37 #include "UniquePointer.h"
38 
39 namespace ArgusSamples
40 {
41 
42 // XML version
43 static const char *VERSION = "1.0";
44 
45 // element names
46 static const char *ELEMENT_DEVICE_INDEX = "deviceIndex";
47 static const char *ELEMENT_SENSOR_MODE_INDEX = "sensorModeIndex";
48 static const char *ELEMENT_VERBOSE = "verbose";
49 static const char *ELEMENT_KPI = "kpi";
50 static const char *ELEMENT_EXPOSURE_TIME_RANGE = "exposureTimeRange";
51 static const char *ELEMENT_GAIN_RANGE = "gainRange";
52 static const char *ELEMENT_FRAME_RATE = "frameRate";
53 static const char *ELEMENT_FRAME_RATE_RANGE = "frameRateRange";
54 static const char *ELEMENT_FOCUS_POSITION = "focusPosition";
55 static const char *ELEMENT_APERTURE_POSITION = "aperturePosition";
56 static const char *ELEMENT_APERTURE_MOTOR_SPEED = "apertureMotorSpeed";
57 static const char *ELEMENT_CAPTURE_YUV_FORMAT = "captureYuvFormat";
58 static const char *ELEMENT_AE_ANTIBANDING_MODE = "aeAntibandingMode";
59 static const char *ELEMENT_AE_LOCK = "aeLock";
60 static const char *ELEMENT_AWB_LOCK = "awbLock";
61 static const char *ELEMENT_AWB_MODE = "awbMode";
62 static const char *ELEMENT_EXPOSURE_COMPENSATION = "exposureCompensation";
63 static const char *ELEMENT_ISP_DIGITAL_GAIN_RANGE = "ispDigitalGainRange";
64 static const char *ELEMENT_DENOISE_MODE = "denoiseMode";
65 static const char *ELEMENT_DENOISE_STRENGTH = "denoiseStrength";
66 static const char *ELEMENT_EDGE_ENHANCE_MODE = "edgeEnhanceMode";
67 static const char *ELEMENT_EDGE_ENHANCE_STRENGTH = "edgeEnhanceStrength";
68 static const char *ELEMENT_STILL_FILE_TYPE = "stillFileType";
69 static const char *ELEMENT_VIDEO_FORMAT = "videoFormat";
70 static const char *ELEMENT_VIDEO_FILE_TYPE = "videoFileType";
71 static const char *ELEMENT_VIDEO_BIT_RATE = "videoBitRate";
72 static const char *ELEMENT_OUTPUT_SIZE = "outputSize";
73 static const char *ELEMENT_OUTPUT_PATH = "outputPath";
74 static const char *ELEMENT_DE_FOG_ENABLE = "deFogEnable";
75 static const char *ELEMENT_DE_FOG_AMOUNT = "deFogAmount";
76 static const char *ELEMENT_DE_FOG_QUALITY = "deFogQaulity";
77 
78 static void XMLCALL xmlHandleData(void *parser, const char *s, int len)
79 {
80  XML_Parser p = (XML_Parser)parser;
81  std::string *data = reinterpret_cast<std::string*>(XML_GetUserData(p));
82 
83  data->append(s, len);
84 }
85 
86 static void XMLCALL xmlStartElement(void *parser, const char *name, const char **atts)
87 {
88  XML_Parser p = (XML_Parser)parser;
89 
90  if (strcmp(name, "argusconfig") == 0)
91  {
92  const char **curAtt = atts;
93 
94  while (*curAtt != NULL)
95  {
96  const char *attribute = curAtt[0];
97  const char *value = curAtt[1];
98 
99  if (strcmp(attribute, "version") == 0)
100  {
101  if (strcmp(value, VERSION) != 0)
102  {
103  ORIGINATE_ERROR_FAIL("Unsupported version '%s' expected version '%s'",
104  value, VERSION);
105  }
106  }
107  else
108  ORIGINATE_ERROR_FAIL("Found unexpected attribute '%s'", attribute);
109  curAtt += 2;
110  }
111  }
112 
113  XML_SetCharacterDataHandler(p, xmlHandleData);
114 
115  return;
116 
117 fail:
118  XML_StopParser(p, XML_FALSE);
119 }
120 
121 /**
122  * Check if an element matches the value name, if this is the case set the value to 'dataStr'
123  * @param [in] elementName current element
124  * @param [in] dataStr data for that element
125  * @param [in] valueName value name
126  * @param [in] value value to update with dataStr if there is a match
127  * @param [out] match set if there was a match
128  */
129 template<typename T> static bool checkValue(const char *elementName, const char *dataStr,
130  const char *valueName, Value<T> &value, bool *match)
131 {
132  if (strcmp(elementName, valueName) == 0)
133  {
134  PROPAGATE_ERROR(value.setFromString(dataStr));
135  *match = true;
136  }
137 
138  return true;
139 }
140 
141 static void XMLCALL xmlEndElement(void *parser, const char *name)
142 {
143  Dispatcher &dispatcher = Dispatcher::getInstance();
144  XML_Parser p = (XML_Parser)parser;
145  std::string *data = reinterpret_cast<std::string*>(XML_GetUserData(p));
146 
147  if (strcmp(name, ELEMENT_DEVICE_INDEX) == 0)
148  {
149  PROPAGATE_ERROR_FAIL(dispatcher.m_deviceIndex.setFromString(data->c_str()));
150  }
151  else if (strcmp(name, ELEMENT_SENSOR_MODE_INDEX) == 0)
152  {
153  PROPAGATE_ERROR_FAIL(dispatcher.m_sensorModeIndex.setFromString(data->c_str()));
154  }
155  else if (strcmp(name, ELEMENT_VERBOSE) == 0)
156  {
157  PROPAGATE_ERROR_FAIL(dispatcher.m_verbose.setFromString(data->c_str()));
158  }
159  else if (strcmp(name, ELEMENT_KPI) == 0)
160  {
161  PROPAGATE_ERROR_FAIL(dispatcher.m_kpi.setFromString(data->c_str()));
162  }
163  else if (strcmp(name, ELEMENT_EXPOSURE_TIME_RANGE) == 0)
164  {
165  PROPAGATE_ERROR_FAIL(dispatcher.m_exposureTimeRange.setFromString(data->c_str()));
166  }
167  else if (strcmp(name, ELEMENT_GAIN_RANGE) == 0)
168  {
169  PROPAGATE_ERROR_FAIL(dispatcher.m_gainRange.setFromString(data->c_str()));
170  }
171  else if (strcmp(name, ELEMENT_FRAME_RATE) == 0)
172  {
173  PROPAGATE_ERROR_FAIL(dispatcher.m_frameRate.setFromString(data->c_str()));
174  }
175  else if (strcmp(name, ELEMENT_FRAME_RATE_RANGE) == 0)
176  {
177  PROPAGATE_ERROR_FAIL(dispatcher.m_frameRateRange.setFromString(data->c_str()));
178  }
179  else if (strcmp(name, ELEMENT_FOCUS_POSITION) == 0)
180  {
181  PROPAGATE_ERROR_FAIL(dispatcher.m_focusPosition.setFromString(data->c_str()));
182  }
183  else if (strcmp(name, ELEMENT_APERTURE_POSITION) == 0)
184  {
185  PROPAGATE_ERROR_FAIL(dispatcher.m_aperturePosition.setFromString(data->c_str()));
186  }
187  else if (strcmp(name, ELEMENT_APERTURE_MOTOR_SPEED) == 0)
188  {
189  PROPAGATE_ERROR_FAIL(dispatcher.m_apertureMotorSpeed.setFromString(data->c_str()));
190  }
191  else if (strcmp(name, ELEMENT_CAPTURE_YUV_FORMAT) == 0)
192  {
193  PROPAGATE_ERROR_FAIL(dispatcher.m_captureYuvFormat.setFromString(data->c_str()));
194  }
195  else if (strcmp(name, ELEMENT_DENOISE_MODE) == 0)
196  {
197  PROPAGATE_ERROR_FAIL(dispatcher.m_denoiseMode.setFromString(data->c_str()));
198  }
199  else if (strcmp(name, ELEMENT_DENOISE_STRENGTH) == 0)
200  {
201  PROPAGATE_ERROR_FAIL(dispatcher.m_denoiseStrength.setFromString(data->c_str()));
202  }
203  else if (strcmp(name, ELEMENT_EDGE_ENHANCE_MODE) == 0)
204  {
205  PROPAGATE_ERROR_FAIL(dispatcher.m_edgeEnhanceMode.setFromString(data->c_str()));
206  }
207  else if (strcmp(name, ELEMENT_EDGE_ENHANCE_STRENGTH) == 0)
208  {
209  PROPAGATE_ERROR_FAIL(dispatcher.m_edgeEnhanceStrength.setFromString(data->c_str()));
210  }
211  else if (strcmp(name, ELEMENT_AE_ANTIBANDING_MODE) == 0)
212  {
213  PROPAGATE_ERROR_FAIL(dispatcher.m_aeAntibandingMode.setFromString(data->c_str()));
214  }
215  else if (strcmp(name, ELEMENT_AE_LOCK) == 0)
216  {
217  PROPAGATE_ERROR_FAIL(dispatcher.m_aeLock.setFromString(data->c_str()));
218  }
219  else if (strcmp(name, ELEMENT_AWB_LOCK) == 0)
220  {
221  PROPAGATE_ERROR_FAIL(dispatcher.m_awbLock.setFromString(data->c_str()));
222  }
223  else if (strcmp(name, ELEMENT_AWB_MODE) == 0)
224  {
225  PROPAGATE_ERROR_FAIL(dispatcher.m_awbMode.setFromString(data->c_str()));
226  }
227  else if (strcmp(name, ELEMENT_EXPOSURE_COMPENSATION) == 0)
228  {
229  PROPAGATE_ERROR_FAIL(dispatcher.m_exposureCompensation.setFromString(data->c_str()));
230  }
231  else if (strcmp(name, ELEMENT_ISP_DIGITAL_GAIN_RANGE) == 0)
232  {
233  PROPAGATE_ERROR_FAIL(dispatcher.m_ispDigitalGainRange.setFromString(data->c_str()));
234  }
235  else if (strcmp(name, ELEMENT_STILL_FILE_TYPE) == 0)
236  {
237  PROPAGATE_ERROR_FAIL(dispatcher.m_stillFileType.setFromString(data->c_str()));
238  }
239  else if (strcmp(name, ELEMENT_VIDEO_FORMAT) == 0)
240  {
241  PROPAGATE_ERROR_FAIL(dispatcher.m_videoFormat.setFromString(data->c_str()));
242  }
243  else if (strcmp(name, ELEMENT_VIDEO_FILE_TYPE) == 0)
244  {
245  PROPAGATE_ERROR_FAIL(dispatcher.m_videoFileType.setFromString(data->c_str()));
246  }
247  else if (strcmp(name, ELEMENT_VIDEO_BIT_RATE) == 0)
248  {
249  PROPAGATE_ERROR_FAIL(dispatcher.m_videoBitRate.setFromString(data->c_str()));
250  }
251  else if (strcmp(name, ELEMENT_OUTPUT_SIZE) == 0)
252  {
253  PROPAGATE_ERROR_FAIL(dispatcher.m_outputSize.setFromString(data->c_str()));
254  }
255  else if (strcmp(name, ELEMENT_OUTPUT_PATH) == 0)
256  {
257  PROPAGATE_ERROR_FAIL(dispatcher.m_outputPath.set(*data));
258  }
259  else if (strcmp(name, ELEMENT_DE_FOG_ENABLE) == 0)
260  {
261  PROPAGATE_ERROR_FAIL(dispatcher.m_deFogEnable.setFromString(data->c_str()));
262  }
263  else if (strcmp(name, ELEMENT_DE_FOG_AMOUNT) == 0)
264  {
265  PROPAGATE_ERROR_FAIL(dispatcher.m_deFogAmount.setFromString(data->c_str()));
266  }
267  else if (strcmp(name, ELEMENT_DE_FOG_QUALITY) == 0)
268  {
269  PROPAGATE_ERROR_FAIL(dispatcher.m_deFogQuality.setFromString(data->c_str()));
270  }
271  else if (strcmp(name, "argusconfig") == 0)
272  {
273  }
274  else
275  {
276  ORIGINATE_ERROR_FAIL("Unhandled element '%s'.", name);
277  }
278 
279  XML_SetCharacterDataHandler(p, NULL);
280  data->clear();
281 
282  return;
283 
284 fail:
285  XML_StopParser(p, XML_FALSE);
286 }
287 
288 bool loadConfig(const char *configFile)
289 {
290  if (configFile == NULL)
291  ORIGINATE_ERROR("'configFile' is NULL");
292 
293  FILE *xmlFile;
294  bool success = true;
295  long ftellResult;
296  size_t fileSize;
297  UniquePointer<char> fileData;
298  XML_Parser parser = NULL;
299  std::string data;
300 
301  // open the file
302  xmlFile = fopen(configFile, "rb");
303  if (xmlFile == NULL)
304  ORIGINATE_ERROR_FAIL("Failed to open file %s", configFile);
305 
306  // get file size
307  if (fseek(xmlFile, 0, SEEK_END) != 0)
308  ORIGINATE_ERROR_FAIL("Failed to read buffer file %s", configFile);
309 
310  ftellResult = ftell(xmlFile);
311  if (ftellResult == -1)
312  ORIGINATE_ERROR_FAIL("Failed to read buffer file %s", configFile);
313  if (ftellResult == 0)
314  ORIGINATE_ERROR_FAIL("Empty file %s", configFile);
315 
316  fileSize = ftellResult;
317 
318  if (fseek(xmlFile, 0, SEEK_SET) != 0)
319  ORIGINATE_ERROR_FAIL("Failed to read buffer file %s", configFile);
320 
321  // allocate buffer
322  fileData.reset(new char[fileSize + 1]);
323  if (!fileData)
324  ORIGINATE_ERROR_FAIL("Out of memory");
325 
326  // read from file to buffer
327  if (fread(fileData.get(), fileSize, 1, xmlFile) != 1)
328  ORIGINATE_ERROR_FAIL("Failed to read buffer file %s", configFile);
329  // terminate string
330  fileData.get()[fileSize] = 0;
331 
332  // create XML parser
333  parser = XML_ParserCreate(NULL);
334  if (parser == NULL)
335  ORIGINATE_ERROR_FAIL("Failed to create parser");
336 
337  XML_UseParserAsHandlerArg(parser);
338  // the user data is a string, the XML data handler appens to this, the end element handler
339  // then uses it to set the values
340  XML_SetUserData(parser, &data);
341  XML_SetElementHandler(parser, xmlStartElement, xmlEndElement);
342 
343  // start parsing
344  if (XML_Parse(parser, fileData.get(), (int)fileSize, 1) == XML_STATUS_ERROR)
345  {
346  // on failure print the line and column number and the line in which the error occured
347  const XML_Size lineNumber = XML_GetCurrentLineNumber(parser);
348  const XML_Size columnNumber = XML_GetCurrentColumnNumber(parser);
349  const XML_Index byteIndex = XML_GetCurrentByteIndex(parser);
350 
351  std::string line;
352 
353  if ((byteIndex >= 0) && (static_cast<size_t>(byteIndex) < fileSize))
354  {
355  // find line start
356  size_t lineStart = static_cast<size_t>(byteIndex);
357  while ((lineStart > 0) && (fileData.get()[lineStart] != '\n'))
358  --lineStart;
359  // point after new line
360  if (fileData.get()[lineStart] == '\n')
361  ++lineStart;
362 
363  // find line end
364  size_t lineEnd = static_cast<size_t>(lineStart);
365  while ((lineEnd < fileSize) && (fileData.get()[lineEnd] != '\n'))
366  ++lineEnd;
367 
368  line.append(&fileData.get()[lineStart], lineEnd - lineStart);
369  }
370  else
371  {
372  line += "-";
373  }
374 
375  ORIGINATE_ERROR_FAIL("%s at line %lu:%lu:\n%s",
376  XML_ErrorString(XML_GetErrorCode(parser)),
377  lineNumber, columnNumber, line.c_str());
378  }
379 
380  goto succeeded;
381 
382 fail:
383  success = false;
384 
385 succeeded:
386  if (parser != 0)
387  XML_ParserFree(parser);
388  if (xmlFile != NULL)
389  fclose(xmlFile);
390 
391  return success;
392 }
393 
394 // write an string to XML
395 static void writeValue(std::ofstream &stream, const char *name, const std::string& string)
396 {
397  stream << " <" << name << ">" << string << "</" << name << ">" << std::endl;
398 }
399 
400 // write an value to XML
401 template<typename T> static void writeValue(std::ofstream &stream, const char *name,
402  const Value<T> &value)
403 {
404  writeValue(stream, name, value.toString());
405 }
406 
407 bool saveConfig(const char *configFile)
408 {
409  if (configFile == NULL)
410  ORIGINATE_ERROR("'configFile' is NULL");
411 
412  Dispatcher &dispatcher = Dispatcher::getInstance();
413 
414  // open the stream
415  std::ofstream stream(configFile, std::ofstream::out);
416  if (!stream.is_open())
417  ORIGINATE_ERROR("Failed to open file '%s' for saving.", configFile);
418 
419  // header
420  stream << "<?xml version='1.0' encoding='utf-8'?>" << std::endl;
421  stream << "<argusconfig version='" << VERSION << "'>" << std::endl;
422 
423  // write the value
424  writeValue(stream, ELEMENT_DEVICE_INDEX, dispatcher.m_deviceIndex);
425  writeValue(stream, ELEMENT_SENSOR_MODE_INDEX, dispatcher.m_sensorModeIndex);
426  writeValue(stream, ELEMENT_VERBOSE, dispatcher.m_verbose);
427  writeValue(stream, ELEMENT_KPI, dispatcher.m_kpi);
428  writeValue(stream, ELEMENT_EXPOSURE_TIME_RANGE, dispatcher.m_exposureTimeRange);
429  writeValue(stream, ELEMENT_GAIN_RANGE, dispatcher.m_gainRange);
430  writeValue(stream, ELEMENT_FRAME_RATE, dispatcher.m_frameRate);
431  writeValue(stream, ELEMENT_FRAME_RATE_RANGE, dispatcher.m_frameRateRange);
432  writeValue(stream, ELEMENT_FOCUS_POSITION, dispatcher.m_focusPosition);
433  writeValue(stream, ELEMENT_APERTURE_POSITION, dispatcher.m_aperturePosition);
434  writeValue(stream, ELEMENT_APERTURE_MOTOR_SPEED, dispatcher.m_apertureMotorSpeed);
435  writeValue(stream, ELEMENT_CAPTURE_YUV_FORMAT, dispatcher.m_captureYuvFormat);
436  writeValue(stream, ELEMENT_DENOISE_MODE, dispatcher.m_denoiseMode);
437  writeValue(stream, ELEMENT_DENOISE_STRENGTH, dispatcher.m_denoiseStrength);
438  writeValue(stream, ELEMENT_EDGE_ENHANCE_MODE, dispatcher.m_edgeEnhanceMode);
439  writeValue(stream, ELEMENT_EDGE_ENHANCE_STRENGTH, dispatcher.m_edgeEnhanceStrength);
440  writeValue(stream, ELEMENT_AE_ANTIBANDING_MODE, dispatcher.m_aeAntibandingMode);
441  writeValue(stream, ELEMENT_AE_LOCK, dispatcher.m_aeLock);
442  writeValue(stream, ELEMENT_AWB_LOCK, dispatcher.m_awbLock);
443  writeValue(stream, ELEMENT_AWB_MODE, dispatcher.m_awbMode);
444  writeValue(stream, ELEMENT_EXPOSURE_COMPENSATION, dispatcher.m_exposureCompensation);
445  writeValue(stream, ELEMENT_ISP_DIGITAL_GAIN_RANGE, dispatcher.m_ispDigitalGainRange);
446  writeValue(stream, ELEMENT_STILL_FILE_TYPE, dispatcher.m_stillFileType);
447  writeValue(stream, ELEMENT_VIDEO_FORMAT, dispatcher.m_videoFormat);
448  writeValue(stream, ELEMENT_VIDEO_FILE_TYPE, dispatcher.m_videoFileType);
449  writeValue(stream, ELEMENT_VIDEO_BIT_RATE, dispatcher.m_videoBitRate);
450  writeValue(stream, ELEMENT_OUTPUT_SIZE, dispatcher.m_outputSize);
451  writeValue(stream, ELEMENT_OUTPUT_PATH, dispatcher.m_outputPath.get());
452  writeValue(stream, ELEMENT_DE_FOG_ENABLE, dispatcher.m_deFogEnable);
453  writeValue(stream, ELEMENT_DE_FOG_AMOUNT, dispatcher.m_deFogAmount);
454  writeValue(stream, ELEMENT_DE_FOG_QUALITY, dispatcher.m_deFogQuality);
455 
456  // footer
457  stream << "</argusconfig>" << std::endl;
458 
459  stream.close();
460 
461  return true;
462 }
463 
464 }; // namespace ArgusSamples