blob: 251f236c19a723253f3f5209d4818a0d35e109e7 [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 King9c36c5f2020-04-06 11:34:09 +080020#include "configuration.hpp"
Bob King0e701132020-04-03 21:50:31 +080021#include "device.hpp"
Bob King9c36c5f2020-04-06 11:34:09 +080022#include "i2c_interface.hpp"
Bob Kingf617f892020-03-30 19:03:35 +080023#include "i2c_write_bit_action.hpp"
Bob King87ff9d72020-03-31 14:02:55 +080024#include "i2c_write_byte_action.hpp"
Bob Kingbafcb862020-03-31 16:39:00 +080025#include "i2c_write_bytes_action.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050026#include "pmbus_write_vout_command_action.hpp"
Bob King9c36c5f2020-04-06 11:34:09 +080027#include "presence_detection.hpp"
28#include "rail.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050029#include "rule.hpp"
Bob King315b0b62020-04-03 21:47:58 +080030#include "run_rule_action.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050031
32#include <nlohmann/json.hpp>
33
34#include <cstdint>
35#include <filesystem>
36#include <memory>
37#include <stdexcept>
38#include <string>
39#include <tuple>
40#include <vector>
41
42namespace phosphor::power::regulators::config_file_parser
43{
44
45/**
46 * Parses the specified JSON configuration file.
47 *
48 * Returns the corresponding C++ Rule and Chassis objects.
49 *
50 * Throws a ConfigFileParserError if an error occurs.
51 *
52 * @param pathName configuration file path name
53 * @return tuple containing vectors of Rule and Chassis objects
54 */
55std::tuple<std::vector<std::unique_ptr<Rule>>,
56 std::vector<std::unique_ptr<Chassis>>>
57 parse(const std::filesystem::path& pathName);
58
59/*
60 * Internal implementation details for parse()
61 */
62namespace internal
63{
64
65/**
66 * Returns the specified property of the specified JSON element.
67 *
68 * Throws an invalid_argument exception if the property does not exist.
69 *
70 * @param element JSON element
71 * @param property property name
72 */
73inline const nlohmann::json& getRequiredProperty(const nlohmann::json& element,
74 const std::string& property)
75{
76 auto it = element.find(property);
77 if (it == element.end())
78 {
79 throw std::invalid_argument{"Required property missing: " + property};
80 }
81 return *it;
82}
83
84/**
85 * Parses a JSON element containing an action.
86 *
87 * Returns the corresponding C++ Action object.
88 *
89 * Throws an exception if parsing fails.
90 *
91 * @param element JSON element
92 * @return Action object
93 */
94std::unique_ptr<Action> parseAction(const nlohmann::json& element);
95
96/**
97 * Parses a JSON element containing an array of actions.
98 *
99 * Returns the corresponding C++ Action objects.
100 *
101 * Throws an exception if parsing fails.
102 *
103 * @param element JSON element
104 * @return vector of Action objects
105 */
106std::vector<std::unique_ptr<Action>>
107 parseActionArray(const nlohmann::json& element);
108
109/**
Bob Kingf617f892020-03-30 19:03:35 +0800110 * Parses a JSON element containing a bit position (from 0-7).
111 *
112 * Returns the corresponding C++ uint8_t value.
113 *
114 * Throws an exception if parsing fails.
115 *
116 * @param element JSON element
117 * @return uint8_t value
118 */
119inline uint8_t parseBitPosition(const nlohmann::json& element)
120{
121 // Verify element contains an integer
122 if (!element.is_number_integer())
123 {
124 throw std::invalid_argument{"Element is not an integer"};
125 }
126 int value = element;
127 if ((value < 0) || (value > 7))
128 {
129 throw std::invalid_argument{"Element is not a bit position"};
130 }
131 return static_cast<uint8_t>(value);
132}
133
134/**
135 * Parses a JSON element containing a bit value (0 or 1).
136 *
137 * Returns the corresponding C++ uint8_t value.
138 *
139 * Throws an exception if parsing fails.
140 *
141 * @param element JSON element
142 * @return uint8_t value
143 */
144inline uint8_t parseBitValue(const nlohmann::json& element)
145{
146 // Verify element contains an integer
147 if (!element.is_number_integer())
148 {
149 throw std::invalid_argument{"Element is not an integer"};
150 }
151 int value = element;
152 if ((value < 0) || (value > 1))
153 {
154 throw std::invalid_argument{"Element is not a bit value"};
155 }
156 return static_cast<uint8_t>(value);
157}
158
159/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500160 * Parses a JSON element containing a boolean.
161 *
162 * Returns the corresponding C++ boolean value.
163 *
164 * Throws an exception if parsing fails.
165 *
166 * @param element JSON element
167 * @return boolean value
168 */
169inline bool parseBoolean(const nlohmann::json& element)
170{
171 // Verify element contains a boolean
172 if (!element.is_boolean())
173 {
174 throw std::invalid_argument{"Element is not a boolean"};
175 }
176 return element.get<bool>();
177}
178
179/**
Bob King0e701132020-04-03 21:50:31 +0800180 * Parses a JSON element containing a chassis.
181 *
182 * Returns the corresponding C++ Chassis object.
183 *
184 * Throws an exception if parsing fails.
185 *
186 * @param element JSON element
187 * @return Chassis object
188 */
189std::unique_ptr<Chassis> parseChassis(const nlohmann::json& element);
190
191/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500192 * Parses a JSON element containing an array of chassis.
193 *
194 * Returns the corresponding C++ Chassis objects.
195 *
196 * Throws an exception if parsing fails.
197 *
198 * @param element JSON element
199 * @return vector of Chassis objects
200 */
201std::vector<std::unique_ptr<Chassis>>
202 parseChassisArray(const nlohmann::json& element);
203
204/**
Bob King33e7eaa2020-04-01 18:09:34 +0800205 * Parses a JSON element containing a configuration.
206 *
207 * Returns the corresponding C++ Configuration object.
208 *
209 * Throws an exception if parsing fails.
210 *
211 * @param element JSON element
212 * @return Configuration object
213 */
214std::unique_ptr<Configuration>
215 parseConfiguration(const nlohmann::json& element);
216
217/**
Bob King9c36c5f2020-04-06 11:34:09 +0800218 * Parses a JSON element containing a device.
219 *
220 * Returns the corresponding C++ Device object.
221 *
222 * Throws an exception if parsing fails.
223 *
224 * @param element JSON element
225 * @return Device object
226 */
227std::unique_ptr<Device> parseDevice(const nlohmann::json& element);
228
229/**
Bob King0e701132020-04-03 21:50:31 +0800230 * Parses a JSON element containing an array of devices.
231 *
232 * Returns the corresponding C++ Device objects.
233 *
234 * Throws an exception if parsing fails.
235 *
236 * @param element JSON element
237 * @return vector of Device objects
238 */
239std::vector<std::unique_ptr<Device>>
240 parseDeviceArray(const nlohmann::json& element);
241
242/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500243 * Parses a JSON element containing a double (floating point number).
244 *
245 * Returns the corresponding C++ double value.
246 *
247 * Throws an exception if parsing fails.
248 *
249 * @param element JSON element
250 * @return double value
251 */
252inline double parseDouble(const nlohmann::json& element)
253{
254 // Verify element contains a number (integer or floating point)
255 if (!element.is_number())
256 {
257 throw std::invalid_argument{"Element is not a number"};
258 }
259 return element.get<double>();
260}
261
262/**
Bob Kingbafcb862020-03-31 16:39:00 +0800263 * Parses a JSON element containing a byte value expressed as a hexadecimal
264 * string.
265 *
266 * The JSON number data type does not support the hexadecimal format. For this
267 * reason, hexadecimal byte values are stored as strings in the configuration
268 * file.
269 *
270 * Returns the corresponding C++ uint8_t value.
271 *
272 * Throws an exception if parsing fails.
273 *
274 * @param element JSON element
275 * @return uint8_t value
276 */
277inline uint8_t parseHexByte(const nlohmann::json& element)
278{
279 if (!element.is_string())
280 {
281 throw std::invalid_argument{"Element is not a string"};
282 }
283 std::string value = element;
284
285 bool isHex = (value.compare(0, 2, "0x") == 0) && (value.size() > 2) &&
286 (value.size() < 5) &&
287 (value.find_first_not_of("0123456789abcdefABCDEF", 2) ==
288 std::string::npos);
289 if (!isHex)
290 {
291 throw std::invalid_argument{"Element is not hexadecimal string"};
292 }
293 return static_cast<uint8_t>(std::stoul(value, 0, 0));
294}
295
296/**
297 * Parses a JSON element containing an array of byte values expressed as a
298 * hexadecimal strings.
299 *
300 * Returns the corresponding C++ uint8_t values.
301 *
302 * Throws an exception if parsing fails.
303 *
304 * @param element JSON element
305 * @return vector of uint8_t
306 */
307std::vector<uint8_t> parseHexByteArray(const nlohmann::json& element);
308
309/**
Bob King9c36c5f2020-04-06 11:34:09 +0800310 * Parses a JSON element containing an i2c_interface.
311 *
312 * Returns the corresponding C++ i2c::I2CInterface object.
313 *
314 * Throws an exception if parsing fails.
315 *
316 * @param element JSON element
317 * @return i2c::I2CInterface object
318 */
319std::unique_ptr<i2c::I2CInterface>
320 parseI2CInterface(const nlohmann::json& element);
321
322/**
Bob Kingf617f892020-03-30 19:03:35 +0800323 * Parses a JSON element containing an i2c_write_bit action.
324 *
325 * Returns the corresponding C++ I2CWriteBitAction object.
326 *
327 * Throws an exception if parsing fails.
328 *
329 * @param element JSON element
330 * @return I2CWriteBitAction object
331 */
332std::unique_ptr<I2CWriteBitAction>
333 parseI2CWriteBit(const nlohmann::json& element);
334
335/**
Bob King87ff9d72020-03-31 14:02:55 +0800336 * Parses a JSON element containing an i2c_write_byte action.
337 *
338 * Returns the corresponding C++ I2CWriteByteAction object.
339 *
340 * Throws an exception if parsing fails.
341 *
342 * @param element JSON element
343 * @return I2CWriteByteAction object
344 */
345std::unique_ptr<I2CWriteByteAction>
346 parseI2CWriteByte(const nlohmann::json& element);
347
348/**
Bob Kingbafcb862020-03-31 16:39:00 +0800349 * Parses a JSON element containing an i2c_write_bytes action.
350 *
351 * Returns the corresponding C++ I2CWriteBytesAction object.
352 *
353 * Throws an exception if parsing fails.
354 *
355 * @param element JSON element
356 * @return I2CWriteBytesAction object
357 */
358std::unique_ptr<I2CWriteBytesAction>
359 parseI2CWriteBytes(const nlohmann::json& element);
360
361/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500362 * Parses a JSON element containing an 8-bit signed integer.
363 *
364 * Returns the corresponding C++ int8_t value.
365 *
366 * Throws an exception if parsing fails.
367 *
368 * @param element JSON element
369 * @return int8_t value
370 */
371inline int8_t parseInt8(const nlohmann::json& element)
372{
373 // Verify element contains an integer
374 if (!element.is_number_integer())
375 {
376 throw std::invalid_argument{"Element is not an integer"};
377 }
378 int value = element;
379 if ((value < INT8_MIN) || (value > INT8_MAX))
380 {
381 throw std::invalid_argument{"Element is not an 8-bit signed integer"};
382 }
383 return static_cast<int8_t>(value);
384}
385
386/**
387 * Parses a JSON element containing a pmbus_write_vout_command action.
388 *
389 * Returns the corresponding C++ PMBusWriteVoutCommandAction object.
390 *
391 * Throws an exception if parsing fails.
392 *
393 * @param element JSON element
394 * @return PMBusWriteVoutCommandAction object
395 */
396std::unique_ptr<PMBusWriteVoutCommandAction>
397 parsePMBusWriteVoutCommand(const nlohmann::json& element);
398
399/**
Bob King9c36c5f2020-04-06 11:34:09 +0800400 * Parses a JSON element containing an array of rails.
401 *
402 * Returns the corresponding C++ Rail objects.
403 *
404 * Throws an exception if parsing fails.
405 *
406 * @param element JSON element
407 * @return vector of Rail objects
408 */
409std::vector<std::unique_ptr<Rail>>
410 parseRailArray(const nlohmann::json& element);
411
412/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500413 * Parses the JSON root element of the entire configuration file.
414 *
415 * Returns the corresponding C++ Rule and Chassis objects.
416 *
417 * Throws an exception if parsing fails.
418 *
419 * @param element JSON element
420 * @return tuple containing vectors of Rule and Chassis objects
421 */
422std::tuple<std::vector<std::unique_ptr<Rule>>,
423 std::vector<std::unique_ptr<Chassis>>>
424 parseRoot(const nlohmann::json& element);
425
426/**
427 * Parses a JSON element containing a rule.
428 *
429 * Returns the corresponding C++ Rule object.
430 *
431 * Throws an exception if parsing fails.
432 *
433 * @param element JSON element
434 * @return Rule object
435 */
436std::unique_ptr<Rule> parseRule(const nlohmann::json& element);
437
438/**
439 * Parses a JSON element containing an array of rules.
440 *
441 * Returns the corresponding C++ Rule objects.
442 *
443 * Throws an exception if parsing fails.
444 *
445 * @param element JSON element
446 * @return vector of Rule objects
447 */
448std::vector<std::unique_ptr<Rule>>
449 parseRuleArray(const nlohmann::json& element);
450
451/**
Bob King33e7eaa2020-04-01 18:09:34 +0800452 * Parses the "rule_id" or "actions" property in a JSON element.
453 *
454 * The element must contain one property or the other but not both.
455 *
456 * If the element contains a "rule_id" property, the corresponding C++
457 * RunRuleAction object is returned.
458 *
459 * If the element contains an "actions" property, the corresponding C++ Action
460 * objects are returned.
461 *
462 * Throws an exception if parsing fails.
463 *
464 * @param element JSON element
465 * @return vector of Action objects
466 */
467std::vector<std::unique_ptr<Action>>
468 parseRuleIDOrActionsProperty(const nlohmann::json& element);
469
470/**
Bob King315b0b62020-04-03 21:47:58 +0800471 * Parses a JSON element containing a run_rule action.
472 *
473 * Returns the corresponding C++ RunRuleAction object.
474 *
475 * Throws an exception if parsing fails.
476 *
477 * @param element JSON element
478 * @return RunRuleAction object
479 */
480std::unique_ptr<RunRuleAction> parseRunRule(const nlohmann::json& element);
481
482/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500483 * Parses a JSON element containing a string.
484 *
485 * Returns the corresponding C++ string.
486 *
487 * Throws an exception if parsing fails.
488 *
489 * @param element JSON element
490 * @param isEmptyValid indicates whether an empty string value is valid
491 * @return string value
492 */
493inline std::string parseString(const nlohmann::json& element,
494 bool isEmptyValid = false)
495{
496 if (!element.is_string())
497 {
498 throw std::invalid_argument{"Element is not a string"};
499 }
500 std::string value = element;
501 if (value.empty() && !isEmptyValid)
502 {
503 throw std::invalid_argument{"Element contains an empty string"};
504 }
505 return value;
506}
507
508/**
Bob Kingf617f892020-03-30 19:03:35 +0800509 * Parses a JSON element containing an 8-bit unsigned integer.
510 *
511 * Returns the corresponding C++ uint8_t value.
512 *
513 * Throws an exception if parsing fails.
514 *
515 * @param element JSON element
516 * @return uint8_t value
517 */
518inline uint8_t parseUint8(const nlohmann::json& element)
519{
520 // Verify element contains an integer
521 if (!element.is_number_integer())
522 {
523 throw std::invalid_argument{"Element is not an integer"};
524 }
525 int value = element;
526 if ((value < 0) || (value > UINT8_MAX))
527 {
528 throw std::invalid_argument{"Element is not an 8-bit unsigned integer"};
529 }
530 return static_cast<uint8_t>(value);
531}
532
533/**
Bob King0e701132020-04-03 21:50:31 +0800534 * Parses a JSON element containing an unsigned integer.
535 *
536 * Returns the corresponding C++ unsigned int value.
537 *
538 * Throws an exception if parsing fails.
539 *
540 * @param element JSON element
541 * @return unsigned int value
542 */
543inline unsigned int parseUnsignedInteger(const nlohmann::json& element)
544{
545 // Verify element contains an unsigned integer
546 if (!element.is_number_unsigned())
547 {
548 throw std::invalid_argument{"Element is not an unsigned integer"};
549 }
550 return element.get<unsigned int>();
551}
552
553/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500554 * Verifies that the specified JSON element is a JSON array.
555 *
556 * Throws an invalid_argument exception if the element is not an array.
557 *
558 * @param element JSON element
559 */
560inline void verifyIsArray(const nlohmann::json& element)
561{
562 if (!element.is_array())
563 {
564 throw std::invalid_argument{"Element is not an array"};
565 }
566}
567
568/**
569 * Verifies that the specified JSON element is a JSON object.
570 *
571 * Throws an invalid_argument exception if the element is not an object.
572 *
573 * @param element JSON element
574 */
575inline void verifyIsObject(const nlohmann::json& element)
576{
577 if (!element.is_object())
578 {
579 throw std::invalid_argument{"Element is not an object"};
580 }
581}
582
583/**
584 * Verifies that the specified JSON element contains the expected number of
585 * properties.
586 *
587 * Throws an invalid_argument exception if the element contains a different
588 * number of properties. This indicates the element contains an invalid
589 * property.
590 *
591 * @param element JSON element
592 * @param expectedCount expected number of properties in element
593 */
594inline void verifyPropertyCount(const nlohmann::json& element,
595 unsigned int expectedCount)
596{
597 if (element.size() != expectedCount)
598 {
599 throw std::invalid_argument{"Element contains an invalid property"};
600 }
601}
602
603} // namespace internal
604
605} // namespace phosphor::power::regulators::config_file_parser