blob: f96e6b4955ec762a51f1f0fe6eb7a41f0e8dd304 [file] [log] [blame]
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05001/**
2 * Copyright © 2020 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#pragma once
17
18#include "action.hpp"
19#include "chassis.hpp"
Bob Kingf617f892020-03-30 19:03:35 +080020#include "i2c_write_bit_action.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050021#include "pmbus_write_vout_command_action.hpp"
22#include "rule.hpp"
23
24#include <nlohmann/json.hpp>
25
26#include <cstdint>
27#include <filesystem>
28#include <memory>
29#include <stdexcept>
30#include <string>
31#include <tuple>
32#include <vector>
33
34namespace phosphor::power::regulators::config_file_parser
35{
36
37/**
38 * Parses the specified JSON configuration file.
39 *
40 * Returns the corresponding C++ Rule and Chassis objects.
41 *
42 * Throws a ConfigFileParserError if an error occurs.
43 *
44 * @param pathName configuration file path name
45 * @return tuple containing vectors of Rule and Chassis objects
46 */
47std::tuple<std::vector<std::unique_ptr<Rule>>,
48 std::vector<std::unique_ptr<Chassis>>>
49 parse(const std::filesystem::path& pathName);
50
51/*
52 * Internal implementation details for parse()
53 */
54namespace internal
55{
56
57/**
58 * Returns the specified property of the specified JSON element.
59 *
60 * Throws an invalid_argument exception if the property does not exist.
61 *
62 * @param element JSON element
63 * @param property property name
64 */
65inline const nlohmann::json& getRequiredProperty(const nlohmann::json& element,
66 const std::string& property)
67{
68 auto it = element.find(property);
69 if (it == element.end())
70 {
71 throw std::invalid_argument{"Required property missing: " + property};
72 }
73 return *it;
74}
75
76/**
77 * Parses a JSON element containing an action.
78 *
79 * Returns the corresponding C++ Action object.
80 *
81 * Throws an exception if parsing fails.
82 *
83 * @param element JSON element
84 * @return Action object
85 */
86std::unique_ptr<Action> parseAction(const nlohmann::json& element);
87
88/**
89 * Parses a JSON element containing an array of actions.
90 *
91 * Returns the corresponding C++ Action objects.
92 *
93 * Throws an exception if parsing fails.
94 *
95 * @param element JSON element
96 * @return vector of Action objects
97 */
98std::vector<std::unique_ptr<Action>>
99 parseActionArray(const nlohmann::json& element);
100
101/**
Bob Kingf617f892020-03-30 19:03:35 +0800102 * Parses a JSON element containing a bit position (from 0-7).
103 *
104 * Returns the corresponding C++ uint8_t value.
105 *
106 * Throws an exception if parsing fails.
107 *
108 * @param element JSON element
109 * @return uint8_t value
110 */
111inline uint8_t parseBitPosition(const nlohmann::json& element)
112{
113 // Verify element contains an integer
114 if (!element.is_number_integer())
115 {
116 throw std::invalid_argument{"Element is not an integer"};
117 }
118 int value = element;
119 if ((value < 0) || (value > 7))
120 {
121 throw std::invalid_argument{"Element is not a bit position"};
122 }
123 return static_cast<uint8_t>(value);
124}
125
126/**
127 * Parses a JSON element containing a bit value (0 or 1).
128 *
129 * Returns the corresponding C++ uint8_t value.
130 *
131 * Throws an exception if parsing fails.
132 *
133 * @param element JSON element
134 * @return uint8_t value
135 */
136inline uint8_t parseBitValue(const nlohmann::json& element)
137{
138 // Verify element contains an integer
139 if (!element.is_number_integer())
140 {
141 throw std::invalid_argument{"Element is not an integer"};
142 }
143 int value = element;
144 if ((value < 0) || (value > 1))
145 {
146 throw std::invalid_argument{"Element is not a bit value"};
147 }
148 return static_cast<uint8_t>(value);
149}
150
151/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500152 * Parses a JSON element containing a boolean.
153 *
154 * Returns the corresponding C++ boolean value.
155 *
156 * Throws an exception if parsing fails.
157 *
158 * @param element JSON element
159 * @return boolean value
160 */
161inline bool parseBoolean(const nlohmann::json& element)
162{
163 // Verify element contains a boolean
164 if (!element.is_boolean())
165 {
166 throw std::invalid_argument{"Element is not a boolean"};
167 }
168 return element.get<bool>();
169}
170
171/**
172 * Parses a JSON element containing an array of chassis.
173 *
174 * Returns the corresponding C++ Chassis objects.
175 *
176 * Throws an exception if parsing fails.
177 *
178 * @param element JSON element
179 * @return vector of Chassis objects
180 */
181std::vector<std::unique_ptr<Chassis>>
182 parseChassisArray(const nlohmann::json& element);
183
184/**
185 * Parses a JSON element containing a double (floating point number).
186 *
187 * Returns the corresponding C++ double value.
188 *
189 * Throws an exception if parsing fails.
190 *
191 * @param element JSON element
192 * @return double value
193 */
194inline double parseDouble(const nlohmann::json& element)
195{
196 // Verify element contains a number (integer or floating point)
197 if (!element.is_number())
198 {
199 throw std::invalid_argument{"Element is not a number"};
200 }
201 return element.get<double>();
202}
203
204/**
Bob Kingf617f892020-03-30 19:03:35 +0800205 * Parses a JSON element containing an i2c_write_bit action.
206 *
207 * Returns the corresponding C++ I2CWriteBitAction object.
208 *
209 * Throws an exception if parsing fails.
210 *
211 * @param element JSON element
212 * @return I2CWriteBitAction object
213 */
214std::unique_ptr<I2CWriteBitAction>
215 parseI2CWriteBit(const nlohmann::json& element);
216
217/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500218 * Parses a JSON element containing an 8-bit signed integer.
219 *
220 * Returns the corresponding C++ int8_t value.
221 *
222 * Throws an exception if parsing fails.
223 *
224 * @param element JSON element
225 * @return int8_t value
226 */
227inline int8_t parseInt8(const nlohmann::json& element)
228{
229 // Verify element contains an integer
230 if (!element.is_number_integer())
231 {
232 throw std::invalid_argument{"Element is not an integer"};
233 }
234 int value = element;
235 if ((value < INT8_MIN) || (value > INT8_MAX))
236 {
237 throw std::invalid_argument{"Element is not an 8-bit signed integer"};
238 }
239 return static_cast<int8_t>(value);
240}
241
242/**
243 * Parses a JSON element containing a pmbus_write_vout_command action.
244 *
245 * Returns the corresponding C++ PMBusWriteVoutCommandAction object.
246 *
247 * Throws an exception if parsing fails.
248 *
249 * @param element JSON element
250 * @return PMBusWriteVoutCommandAction object
251 */
252std::unique_ptr<PMBusWriteVoutCommandAction>
253 parsePMBusWriteVoutCommand(const nlohmann::json& element);
254
255/**
256 * Parses the JSON root element of the entire configuration file.
257 *
258 * Returns the corresponding C++ Rule and Chassis objects.
259 *
260 * Throws an exception if parsing fails.
261 *
262 * @param element JSON element
263 * @return tuple containing vectors of Rule and Chassis objects
264 */
265std::tuple<std::vector<std::unique_ptr<Rule>>,
266 std::vector<std::unique_ptr<Chassis>>>
267 parseRoot(const nlohmann::json& element);
268
269/**
270 * Parses a JSON element containing a rule.
271 *
272 * Returns the corresponding C++ Rule object.
273 *
274 * Throws an exception if parsing fails.
275 *
276 * @param element JSON element
277 * @return Rule object
278 */
279std::unique_ptr<Rule> parseRule(const nlohmann::json& element);
280
281/**
282 * Parses a JSON element containing an array of rules.
283 *
284 * Returns the corresponding C++ Rule objects.
285 *
286 * Throws an exception if parsing fails.
287 *
288 * @param element JSON element
289 * @return vector of Rule objects
290 */
291std::vector<std::unique_ptr<Rule>>
292 parseRuleArray(const nlohmann::json& element);
293
294/**
295 * Parses a JSON element containing a string.
296 *
297 * Returns the corresponding C++ string.
298 *
299 * Throws an exception if parsing fails.
300 *
301 * @param element JSON element
302 * @param isEmptyValid indicates whether an empty string value is valid
303 * @return string value
304 */
305inline std::string parseString(const nlohmann::json& element,
306 bool isEmptyValid = false)
307{
308 if (!element.is_string())
309 {
310 throw std::invalid_argument{"Element is not a string"};
311 }
312 std::string value = element;
313 if (value.empty() && !isEmptyValid)
314 {
315 throw std::invalid_argument{"Element contains an empty string"};
316 }
317 return value;
318}
319
320/**
Bob Kingf617f892020-03-30 19:03:35 +0800321 * Parses a JSON element containing a hexadecimal string.
322 *
323 * Returns the corresponding C++ uint8_t value.
324 *
325 * Throws an exception if parsing fails.
326 *
327 * @param element JSON element
328 * @return uint8_t value
329 */
330inline uint8_t parseStringToUint8(const nlohmann::json& element)
331{
332 std::string value = parseString(element);
333
334 bool isHex = (value.compare(0, 2, "0x") == 0) && (value.size() > 2) &&
335 (value.size() < 5) &&
336 (value.find_first_not_of("0123456789abcdefABCDEF", 2) ==
337 std::string::npos);
338 if (!isHex)
339 {
340 throw std::invalid_argument{"Element is not hexadecimal string"};
341 }
342 return static_cast<uint8_t>(std::stoul(value, 0, 0));
343}
344
345/**
346 * Parses a JSON element containing an 8-bit unsigned integer.
347 *
348 * Returns the corresponding C++ uint8_t value.
349 *
350 * Throws an exception if parsing fails.
351 *
352 * @param element JSON element
353 * @return uint8_t value
354 */
355inline uint8_t parseUint8(const nlohmann::json& element)
356{
357 // Verify element contains an integer
358 if (!element.is_number_integer())
359 {
360 throw std::invalid_argument{"Element is not an integer"};
361 }
362 int value = element;
363 if ((value < 0) || (value > UINT8_MAX))
364 {
365 throw std::invalid_argument{"Element is not an 8-bit unsigned integer"};
366 }
367 return static_cast<uint8_t>(value);
368}
369
370/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500371 * Verifies that the specified JSON element is a JSON array.
372 *
373 * Throws an invalid_argument exception if the element is not an array.
374 *
375 * @param element JSON element
376 */
377inline void verifyIsArray(const nlohmann::json& element)
378{
379 if (!element.is_array())
380 {
381 throw std::invalid_argument{"Element is not an array"};
382 }
383}
384
385/**
386 * Verifies that the specified JSON element is a JSON object.
387 *
388 * Throws an invalid_argument exception if the element is not an object.
389 *
390 * @param element JSON element
391 */
392inline void verifyIsObject(const nlohmann::json& element)
393{
394 if (!element.is_object())
395 {
396 throw std::invalid_argument{"Element is not an object"};
397 }
398}
399
400/**
401 * Verifies that the specified JSON element contains the expected number of
402 * properties.
403 *
404 * Throws an invalid_argument exception if the element contains a different
405 * number of properties. This indicates the element contains an invalid
406 * property.
407 *
408 * @param element JSON element
409 * @param expectedCount expected number of properties in element
410 */
411inline void verifyPropertyCount(const nlohmann::json& element,
412 unsigned int expectedCount)
413{
414 if (element.size() != expectedCount)
415 {
416 throw std::invalid_argument{"Element contains an invalid property"};
417 }
418}
419
420} // namespace internal
421
422} // namespace phosphor::power::regulators::config_file_parser