blob: 3ebab4be221f2063a8d3e730583597ec456660e4 [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 King0e701132020-04-03 21:50:31 +080020#include "device.hpp"
Bob Kingf617f892020-03-30 19:03:35 +080021#include "i2c_write_bit_action.hpp"
Bob King87ff9d72020-03-31 14:02:55 +080022#include "i2c_write_byte_action.hpp"
Bob Kingbafcb862020-03-31 16:39:00 +080023#include "i2c_write_bytes_action.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050024#include "pmbus_write_vout_command_action.hpp"
25#include "rule.hpp"
Bob King315b0b62020-04-03 21:47:58 +080026#include "run_rule_action.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050027
28#include <nlohmann/json.hpp>
29
30#include <cstdint>
31#include <filesystem>
32#include <memory>
33#include <stdexcept>
34#include <string>
35#include <tuple>
36#include <vector>
37
38namespace phosphor::power::regulators::config_file_parser
39{
40
41/**
42 * Parses the specified JSON configuration file.
43 *
44 * Returns the corresponding C++ Rule and Chassis objects.
45 *
46 * Throws a ConfigFileParserError if an error occurs.
47 *
48 * @param pathName configuration file path name
49 * @return tuple containing vectors of Rule and Chassis objects
50 */
51std::tuple<std::vector<std::unique_ptr<Rule>>,
52 std::vector<std::unique_ptr<Chassis>>>
53 parse(const std::filesystem::path& pathName);
54
55/*
56 * Internal implementation details for parse()
57 */
58namespace internal
59{
60
61/**
62 * Returns the specified property of the specified JSON element.
63 *
64 * Throws an invalid_argument exception if the property does not exist.
65 *
66 * @param element JSON element
67 * @param property property name
68 */
69inline const nlohmann::json& getRequiredProperty(const nlohmann::json& element,
70 const std::string& property)
71{
72 auto it = element.find(property);
73 if (it == element.end())
74 {
75 throw std::invalid_argument{"Required property missing: " + property};
76 }
77 return *it;
78}
79
80/**
81 * Parses a JSON element containing an action.
82 *
83 * Returns the corresponding C++ Action object.
84 *
85 * Throws an exception if parsing fails.
86 *
87 * @param element JSON element
88 * @return Action object
89 */
90std::unique_ptr<Action> parseAction(const nlohmann::json& element);
91
92/**
93 * Parses a JSON element containing an array of actions.
94 *
95 * Returns the corresponding C++ Action objects.
96 *
97 * Throws an exception if parsing fails.
98 *
99 * @param element JSON element
100 * @return vector of Action objects
101 */
102std::vector<std::unique_ptr<Action>>
103 parseActionArray(const nlohmann::json& element);
104
105/**
Bob Kingf617f892020-03-30 19:03:35 +0800106 * Parses a JSON element containing a bit position (from 0-7).
107 *
108 * Returns the corresponding C++ uint8_t value.
109 *
110 * Throws an exception if parsing fails.
111 *
112 * @param element JSON element
113 * @return uint8_t value
114 */
115inline uint8_t parseBitPosition(const nlohmann::json& element)
116{
117 // Verify element contains an integer
118 if (!element.is_number_integer())
119 {
120 throw std::invalid_argument{"Element is not an integer"};
121 }
122 int value = element;
123 if ((value < 0) || (value > 7))
124 {
125 throw std::invalid_argument{"Element is not a bit position"};
126 }
127 return static_cast<uint8_t>(value);
128}
129
130/**
131 * Parses a JSON element containing a bit value (0 or 1).
132 *
133 * Returns the corresponding C++ uint8_t value.
134 *
135 * Throws an exception if parsing fails.
136 *
137 * @param element JSON element
138 * @return uint8_t value
139 */
140inline uint8_t parseBitValue(const nlohmann::json& element)
141{
142 // Verify element contains an integer
143 if (!element.is_number_integer())
144 {
145 throw std::invalid_argument{"Element is not an integer"};
146 }
147 int value = element;
148 if ((value < 0) || (value > 1))
149 {
150 throw std::invalid_argument{"Element is not a bit value"};
151 }
152 return static_cast<uint8_t>(value);
153}
154
155/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500156 * Parses a JSON element containing a boolean.
157 *
158 * Returns the corresponding C++ boolean value.
159 *
160 * Throws an exception if parsing fails.
161 *
162 * @param element JSON element
163 * @return boolean value
164 */
165inline bool parseBoolean(const nlohmann::json& element)
166{
167 // Verify element contains a boolean
168 if (!element.is_boolean())
169 {
170 throw std::invalid_argument{"Element is not a boolean"};
171 }
172 return element.get<bool>();
173}
174
175/**
Bob King0e701132020-04-03 21:50:31 +0800176 * Parses a JSON element containing a chassis.
177 *
178 * Returns the corresponding C++ Chassis object.
179 *
180 * Throws an exception if parsing fails.
181 *
182 * @param element JSON element
183 * @return Chassis object
184 */
185std::unique_ptr<Chassis> parseChassis(const nlohmann::json& element);
186
187/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500188 * Parses a JSON element containing an array of chassis.
189 *
190 * Returns the corresponding C++ Chassis objects.
191 *
192 * Throws an exception if parsing fails.
193 *
194 * @param element JSON element
195 * @return vector of Chassis objects
196 */
197std::vector<std::unique_ptr<Chassis>>
198 parseChassisArray(const nlohmann::json& element);
199
200/**
Bob King0e701132020-04-03 21:50:31 +0800201 * Parses a JSON element containing an array of devices.
202 *
203 * Returns the corresponding C++ Device objects.
204 *
205 * Throws an exception if parsing fails.
206 *
207 * @param element JSON element
208 * @return vector of Device objects
209 */
210std::vector<std::unique_ptr<Device>>
211 parseDeviceArray(const nlohmann::json& element);
212
213/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500214 * Parses a JSON element containing a double (floating point number).
215 *
216 * Returns the corresponding C++ double value.
217 *
218 * Throws an exception if parsing fails.
219 *
220 * @param element JSON element
221 * @return double value
222 */
223inline double parseDouble(const nlohmann::json& element)
224{
225 // Verify element contains a number (integer or floating point)
226 if (!element.is_number())
227 {
228 throw std::invalid_argument{"Element is not a number"};
229 }
230 return element.get<double>();
231}
232
233/**
Bob Kingbafcb862020-03-31 16:39:00 +0800234 * Parses a JSON element containing a byte value expressed as a hexadecimal
235 * string.
236 *
237 * The JSON number data type does not support the hexadecimal format. For this
238 * reason, hexadecimal byte values are stored as strings in the configuration
239 * file.
240 *
241 * Returns the corresponding C++ uint8_t value.
242 *
243 * Throws an exception if parsing fails.
244 *
245 * @param element JSON element
246 * @return uint8_t value
247 */
248inline uint8_t parseHexByte(const nlohmann::json& element)
249{
250 if (!element.is_string())
251 {
252 throw std::invalid_argument{"Element is not a string"};
253 }
254 std::string value = element;
255
256 bool isHex = (value.compare(0, 2, "0x") == 0) && (value.size() > 2) &&
257 (value.size() < 5) &&
258 (value.find_first_not_of("0123456789abcdefABCDEF", 2) ==
259 std::string::npos);
260 if (!isHex)
261 {
262 throw std::invalid_argument{"Element is not hexadecimal string"};
263 }
264 return static_cast<uint8_t>(std::stoul(value, 0, 0));
265}
266
267/**
268 * Parses a JSON element containing an array of byte values expressed as a
269 * hexadecimal strings.
270 *
271 * Returns the corresponding C++ uint8_t values.
272 *
273 * Throws an exception if parsing fails.
274 *
275 * @param element JSON element
276 * @return vector of uint8_t
277 */
278std::vector<uint8_t> parseHexByteArray(const nlohmann::json& element);
279
280/**
Bob Kingf617f892020-03-30 19:03:35 +0800281 * Parses a JSON element containing an i2c_write_bit action.
282 *
283 * Returns the corresponding C++ I2CWriteBitAction object.
284 *
285 * Throws an exception if parsing fails.
286 *
287 * @param element JSON element
288 * @return I2CWriteBitAction object
289 */
290std::unique_ptr<I2CWriteBitAction>
291 parseI2CWriteBit(const nlohmann::json& element);
292
293/**
Bob King87ff9d72020-03-31 14:02:55 +0800294 * Parses a JSON element containing an i2c_write_byte action.
295 *
296 * Returns the corresponding C++ I2CWriteByteAction object.
297 *
298 * Throws an exception if parsing fails.
299 *
300 * @param element JSON element
301 * @return I2CWriteByteAction object
302 */
303std::unique_ptr<I2CWriteByteAction>
304 parseI2CWriteByte(const nlohmann::json& element);
305
306/**
Bob Kingbafcb862020-03-31 16:39:00 +0800307 * Parses a JSON element containing an i2c_write_bytes action.
308 *
309 * Returns the corresponding C++ I2CWriteBytesAction object.
310 *
311 * Throws an exception if parsing fails.
312 *
313 * @param element JSON element
314 * @return I2CWriteBytesAction object
315 */
316std::unique_ptr<I2CWriteBytesAction>
317 parseI2CWriteBytes(const nlohmann::json& element);
318
319/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500320 * Parses a JSON element containing an 8-bit signed integer.
321 *
322 * Returns the corresponding C++ int8_t value.
323 *
324 * Throws an exception if parsing fails.
325 *
326 * @param element JSON element
327 * @return int8_t value
328 */
329inline int8_t parseInt8(const nlohmann::json& element)
330{
331 // Verify element contains an integer
332 if (!element.is_number_integer())
333 {
334 throw std::invalid_argument{"Element is not an integer"};
335 }
336 int value = element;
337 if ((value < INT8_MIN) || (value > INT8_MAX))
338 {
339 throw std::invalid_argument{"Element is not an 8-bit signed integer"};
340 }
341 return static_cast<int8_t>(value);
342}
343
344/**
345 * Parses a JSON element containing a pmbus_write_vout_command action.
346 *
347 * Returns the corresponding C++ PMBusWriteVoutCommandAction object.
348 *
349 * Throws an exception if parsing fails.
350 *
351 * @param element JSON element
352 * @return PMBusWriteVoutCommandAction object
353 */
354std::unique_ptr<PMBusWriteVoutCommandAction>
355 parsePMBusWriteVoutCommand(const nlohmann::json& element);
356
357/**
358 * Parses the JSON root element of the entire configuration file.
359 *
360 * Returns the corresponding C++ Rule and Chassis objects.
361 *
362 * Throws an exception if parsing fails.
363 *
364 * @param element JSON element
365 * @return tuple containing vectors of Rule and Chassis objects
366 */
367std::tuple<std::vector<std::unique_ptr<Rule>>,
368 std::vector<std::unique_ptr<Chassis>>>
369 parseRoot(const nlohmann::json& element);
370
371/**
372 * Parses a JSON element containing a rule.
373 *
374 * Returns the corresponding C++ Rule object.
375 *
376 * Throws an exception if parsing fails.
377 *
378 * @param element JSON element
379 * @return Rule object
380 */
381std::unique_ptr<Rule> parseRule(const nlohmann::json& element);
382
383/**
384 * Parses a JSON element containing an array of rules.
385 *
386 * Returns the corresponding C++ Rule objects.
387 *
388 * Throws an exception if parsing fails.
389 *
390 * @param element JSON element
391 * @return vector of Rule objects
392 */
393std::vector<std::unique_ptr<Rule>>
394 parseRuleArray(const nlohmann::json& element);
395
396/**
Bob King315b0b62020-04-03 21:47:58 +0800397 * Parses a JSON element containing a run_rule action.
398 *
399 * Returns the corresponding C++ RunRuleAction object.
400 *
401 * Throws an exception if parsing fails.
402 *
403 * @param element JSON element
404 * @return RunRuleAction object
405 */
406std::unique_ptr<RunRuleAction> parseRunRule(const nlohmann::json& element);
407
408/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500409 * Parses a JSON element containing a string.
410 *
411 * Returns the corresponding C++ string.
412 *
413 * Throws an exception if parsing fails.
414 *
415 * @param element JSON element
416 * @param isEmptyValid indicates whether an empty string value is valid
417 * @return string value
418 */
419inline std::string parseString(const nlohmann::json& element,
420 bool isEmptyValid = false)
421{
422 if (!element.is_string())
423 {
424 throw std::invalid_argument{"Element is not a string"};
425 }
426 std::string value = element;
427 if (value.empty() && !isEmptyValid)
428 {
429 throw std::invalid_argument{"Element contains an empty string"};
430 }
431 return value;
432}
433
434/**
Bob Kingf617f892020-03-30 19:03:35 +0800435 * Parses a JSON element containing an 8-bit unsigned integer.
436 *
437 * Returns the corresponding C++ uint8_t value.
438 *
439 * Throws an exception if parsing fails.
440 *
441 * @param element JSON element
442 * @return uint8_t value
443 */
444inline uint8_t parseUint8(const nlohmann::json& element)
445{
446 // Verify element contains an integer
447 if (!element.is_number_integer())
448 {
449 throw std::invalid_argument{"Element is not an integer"};
450 }
451 int value = element;
452 if ((value < 0) || (value > UINT8_MAX))
453 {
454 throw std::invalid_argument{"Element is not an 8-bit unsigned integer"};
455 }
456 return static_cast<uint8_t>(value);
457}
458
459/**
Bob King0e701132020-04-03 21:50:31 +0800460 * Parses a JSON element containing an unsigned integer.
461 *
462 * Returns the corresponding C++ unsigned int value.
463 *
464 * Throws an exception if parsing fails.
465 *
466 * @param element JSON element
467 * @return unsigned int value
468 */
469inline unsigned int parseUnsignedInteger(const nlohmann::json& element)
470{
471 // Verify element contains an unsigned integer
472 if (!element.is_number_unsigned())
473 {
474 throw std::invalid_argument{"Element is not an unsigned integer"};
475 }
476 return element.get<unsigned int>();
477}
478
479/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500480 * Verifies that the specified JSON element is a JSON array.
481 *
482 * Throws an invalid_argument exception if the element is not an array.
483 *
484 * @param element JSON element
485 */
486inline void verifyIsArray(const nlohmann::json& element)
487{
488 if (!element.is_array())
489 {
490 throw std::invalid_argument{"Element is not an array"};
491 }
492}
493
494/**
495 * Verifies that the specified JSON element is a JSON object.
496 *
497 * Throws an invalid_argument exception if the element is not an object.
498 *
499 * @param element JSON element
500 */
501inline void verifyIsObject(const nlohmann::json& element)
502{
503 if (!element.is_object())
504 {
505 throw std::invalid_argument{"Element is not an object"};
506 }
507}
508
509/**
510 * Verifies that the specified JSON element contains the expected number of
511 * properties.
512 *
513 * Throws an invalid_argument exception if the element contains a different
514 * number of properties. This indicates the element contains an invalid
515 * property.
516 *
517 * @param element JSON element
518 * @param expectedCount expected number of properties in element
519 */
520inline void verifyPropertyCount(const nlohmann::json& element,
521 unsigned int expectedCount)
522{
523 if (element.size() != expectedCount)
524 {
525 throw std::invalid_argument{"Element contains an invalid property"};
526 }
527}
528
529} // namespace internal
530
531} // namespace phosphor::power::regulators::config_file_parser