xml_configuration_parsing.cpp
Go to the documentation of this file.
1 // Copyright (c) 2021 Pilz GmbH & Co. KG
2 //
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU Lesser General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public License
14 // along with this program. If not, see <https://www.gnu.org/licenses/>.
15 
16 #include <tinyxml2.h>
17 #include <fmt/format.h>
18 
21 
23 {
24 namespace configuration
25 {
26 namespace xml_config_parsing
27 {
28 inline const tinyxml2::XMLElement* getFirstChildElement(const tinyxml2::XMLElement* parent, const char* name)
29 {
30  const tinyxml2::XMLElement* child = parent->FirstChildElement(name);
31  if (!child)
32  {
34  fmt::format("Could not parse. Element <{}> is missing a child <{}>.", parent->Name(), name));
35  }
36 
37  return child;
38 }
39 
40 const char* getText(const tinyxml2::XMLElement* element)
41 {
42  const char* element_str = element->GetText();
43  if (element_str == nullptr || strlen(element_str) == 0)
44  {
45  throw XMLConfigurationParserException(fmt::format("Could not parse. <{}> element is empty.", element->Name()));
46  }
47 
48  return element_str;
49 }
50 
51 inline bool textIsEqual(const tinyxml2::XMLElement* element, const char* str)
52 {
53  return strcmp(getText(element), str) == 0;
54 }
55 
56 ZoneSet parseZoneSet(const tinyxml2::XMLElement* xml_set_element)
57 {
58  ZoneSet set;
59 
60  const tinyxml2::XMLElement* xml_set_detail_element = getFirstChildElement(xml_set_element, "zoneSetDetail");
61 
62  while (xml_set_detail_element)
63  {
64  const tinyxml2::XMLElement* xml_set_detail_type_element = getFirstChildElement(xml_set_detail_element, "type");
65  const tinyxml2::XMLElement* xml_set_detail_ro_element = getFirstChildElement(xml_set_detail_element, "ro");
66 
67  if (textIsEqual(xml_set_detail_type_element, "roOSSD1"))
68  {
69  set.safety1_ = ro_string_to_vec(getText(xml_set_detail_ro_element));
70  }
71  else if (textIsEqual(xml_set_detail_type_element, "roOSSD2"))
72  {
73  set.safety2_ = ro_string_to_vec(getText(xml_set_detail_ro_element));
74  }
75  else if (textIsEqual(xml_set_detail_type_element, "roOSSD3"))
76  {
77  set.safety3_ = ro_string_to_vec(getText(xml_set_detail_ro_element));
78  }
79  else if (textIsEqual(xml_set_detail_type_element, "warn1"))
80  {
81  set.warn1_ = ro_string_to_vec(getText(xml_set_detail_ro_element));
82  }
83  else if (textIsEqual(xml_set_detail_type_element, "warn2"))
84  {
85  set.warn2_ = ro_string_to_vec(getText(xml_set_detail_ro_element));
86  }
87  else if (textIsEqual(xml_set_detail_type_element, "muting1"))
88  {
89  set.muting1_ = ro_string_to_vec(getText(xml_set_detail_ro_element));
90  }
91  else if (textIsEqual(xml_set_detail_type_element, "muting2"))
92  {
93  set.muting2_ = ro_string_to_vec(getText(xml_set_detail_ro_element));
94  }
95  else
96  {
97  throw XMLConfigurationParserException("Could not parse. Invalid <type> must be \"roOSSD1\", \"roOSSD2\", "
98  "\"roOSSD3\", \"warn1\", \"warn2\", \"muting1\" or \"muting2\".");
99  }
100 
101  // Move to next <zoneSetDetail>
102  xml_set_detail_element = xml_set_detail_element->NextSiblingElement("zoneSetDetail");
103  }
104 
105  // Set default resolution for now this is only known implicitly
106  set.resolution_ = DEFAULT_ZONESET_ANGLE_STEP;
107 
108  return set;
109 }
110 
111 ZoneSetSpeedRange parseZoneSetSpeedRange(const tinyxml2::XMLElement* xml_zone_set_select_element)
112 {
113  const tinyxml2::XMLElement* xml_zone_set_speed_range_element =
114  getFirstChildElement(xml_zone_set_select_element, "zoneSetSpeedRange");
115 
116  const tinyxml2::XMLElement* xml_zone_set_select_element_min =
117  getFirstChildElement(xml_zone_set_speed_range_element, "minSpeed");
118 
119  const tinyxml2::XMLElement* xml_zone_set_select_element_max =
120  getFirstChildElement(xml_zone_set_speed_range_element, "maxSpeed");
121 
122  unsigned int min_speed, max_speed;
123  if (xml_zone_set_select_element_min->QueryUnsignedText(&min_speed) != tinyxml2::XML_SUCCESS)
124  {
125  throw XMLConfigurationParserException("Could not parse. Value <minSpeed> invalid.");
126  }
127 
128  if (xml_zone_set_select_element_max->QueryUnsignedText(&max_speed) != tinyxml2::XML_SUCCESS)
129  {
130  throw XMLConfigurationParserException("Could not parse. Value <maxSpeed> invalid.");
131  }
132 
133  return ZoneSetSpeedRange(min_speed, max_speed);
134 }
135 
136 bool isEncoderEnabled(const tinyxml2::XMLConstHandle& doc_handle)
137 {
138  const tinyxml2::XMLElement* enc_enabled_element = doc_handle.FirstChildElement("MIB")
139  .FirstChildElement("clusterDescr")
140  .FirstChildElement("zoneSetConfiguration")
141  .FirstChildElement("encEnable")
142  .ToElement();
143  if (!enc_enabled_element)
144  {
146  "Could not parse. Chain MIB->clusterDescr->zoneSetConfiguration->encEnabled is broken.");
147  }
148 
149  bool enc_enabled;
150  if (enc_enabled_element->QueryBoolText(&enc_enabled) != tinyxml2::XML_SUCCESS)
151  {
153  "Could not parse. Value inside <encEnable> could not be evaluated to true or false");
154  }
155 
156  return enc_enabled;
157 }
158 
159 std::vector<ZoneSet> parseZoneSets(const tinyxml2::XMLConstHandle& doc_handle)
160 {
161  tinyxml2::XMLConstHandle xml_set_info_handle = doc_handle.FirstChildElement("MIB")
162  .FirstChildElement("scannerDescr")
163  .FirstChildElement("zoneSetDefinition")
164  .FirstChildElement("zoneSetInfo");
165 
166  const tinyxml2::XMLElement* xml_set_element = xml_set_info_handle.ToElement();
167 
168  if (!xml_set_element)
169  {
171  "Could not parse. Chain MIB->scannerDescr->zoneSetDefinition->zoneSetInfo not complete.");
172  }
173 
174  std::vector<ZoneSet> zonesets;
175 
176  while (xml_set_element)
177  {
178  ZoneSet set = parseZoneSet(xml_set_element);
179 
180  zonesets.push_back(set);
181  xml_set_element = xml_set_element->NextSiblingElement("zoneSetInfo");
182  }
183 
184  return zonesets;
185 }
186 
187 std::vector<ZoneSetSpeedRange> parseSpeedRanges(const tinyxml2::XMLConstHandle& doc_handle)
188 {
189  const tinyxml2::XMLElement* xml_zone_set_select_element = doc_handle.FirstChildElement("MIB")
190  .FirstChildElement("clusterDescr")
191  .FirstChildElement("zoneSetConfiguration")
192  .FirstChildElement("zoneSetSelCode")
193  .FirstChildElement("zoneSetSelector")
194  .ToElement();
195 
196  if (!xml_zone_set_select_element)
197  {
199  "Could not parse. Chain MIB->clusterDescr->zoneSetConfiguration->zoneSetSelCode->zoneSetSelector is "
200  "broken.");
201  }
202 
203  std::vector<ZoneSetSpeedRange> speed_ranges;
204 
205  while (xml_zone_set_select_element)
206  {
207  ZoneSetSpeedRange speed_range = parseZoneSetSpeedRange(xml_zone_set_select_element);
208  speed_ranges.push_back(speed_range);
209 
210  xml_zone_set_select_element = xml_zone_set_select_element->NextSiblingElement("zoneSetSelector");
211  }
212 
213  return speed_ranges;
214 }
215 
216 ZoneSetConfiguration parseTinyXML(const tinyxml2::XMLDocument& doc)
217 {
218  tinyxml2::XMLConstHandle doc_handle(&doc);
219 
220  std::vector<ZoneSet> zonesets = parseZoneSets(doc_handle);
221 
222  if (isEncoderEnabled(doc_handle))
223  {
224  std::vector<ZoneSetSpeedRange> speed_ranges = parseSpeedRanges(doc_handle);
225 
226  if (zonesets.size() == speed_ranges.size())
227  {
228  for (size_t i = 0; i < zonesets.size(); i++)
229  {
230  zonesets.at(i).speed_range_ = speed_ranges.at(i);
231  }
232  }
233  else
234  {
236  fmt::format("Parsing failed. SpeedRanges are enabled by <encEnable>true</Enable>"
237  "but there are {} speedRanges and {} defined zones.",
238  speed_ranges.size(),
239  zonesets.size()));
240  }
241  }
242 
243  ZoneSetConfiguration zoneset_config;
244 
245  zoneset_config.zonesets_ = zonesets;
246 
247  return zoneset_config;
248 }
249 
250 ZoneSetConfiguration parseFile(const char* filename)
251 {
252  tinyxml2::XMLDocument doc;
253  auto parse_result = doc.LoadFile(filename);
254  if (parse_result != tinyxml2::XML_SUCCESS)
255  {
256  throw XMLConfigurationParserException(fmt::format("Could not parse {}.", filename));
257  }
258 
259  return parseTinyXML(doc);
260 }
261 
263 {
264  tinyxml2::XMLDocument doc;
265  auto parse_result = doc.Parse(xml);
266  if (parse_result != tinyxml2::XML_SUCCESS)
267  {
268  throw XMLConfigurationParserException("Could not parse content.");
269  }
270 
271  return parseTinyXML(doc);
272 }
273 
274 } // namespace xml_config_parsing
275 } // namespace configuration
276 } // namespace psen_scan_v2_standalone
std::vector< ZoneSet > parseZoneSets(const tinyxml2::XMLConstHandle &doc_handle)
const char * getText(const tinyxml2::XMLElement *element)
ZoneSet parseZoneSet(const tinyxml2::XMLElement *xml_set_element)
std::vector< ZoneSetSpeedRange > parseSpeedRanges(const tinyxml2::XMLConstHandle &doc_handle)
ZoneSetConfiguration parseTinyXML(const tinyxml2::XMLDocument &doc)
ZoneSetSpeedRange parseZoneSetSpeedRange(const tinyxml2::XMLElement *xml_zone_set_select_element)
bool textIsEqual(const tinyxml2::XMLElement *element, const char *str)
Root namespace in which the software components to communicate with the scanner (firmware-version: 2)...
Definition: udp_client.h:41
bool isEncoderEnabled(const tinyxml2::XMLConstHandle &doc_handle)
A set of simultanously active zones.
Definition: zoneset.h:71
static const util::TenthOfDegree DEFAULT_ZONESET_ANGLE_STEP(5)
The speedrange at which a ZoneSet is active.
Definition: zoneset.h:44
const tinyxml2::XMLElement * getFirstChildElement(const tinyxml2::XMLElement *parent, const char *name)
std::vector< unsigned long > ro_string_to_vec(const std::string &ro_string)
Convert string from a <ro> element to values.


psen_scan_v2
Author(s): Pilz GmbH + Co. KG
autogenerated on Sat Nov 5 2022 02:13:36