blob: b653c00c3423f5a733c9878493980a7bed946efa [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 Kingf09bfe02020-04-13 17:21:15 +080022#include "i2c_compare_bit_action.hpp"
23#include "i2c_compare_byte_action.hpp"
24#include "i2c_compare_bytes_action.hpp"
Bob King9c36c5f2020-04-06 11:34:09 +080025#include "i2c_interface.hpp"
Bob Kingf617f892020-03-30 19:03:35 +080026#include "i2c_write_bit_action.hpp"
Bob King87ff9d72020-03-31 14:02:55 +080027#include "i2c_write_byte_action.hpp"
Bob Kingbafcb862020-03-31 16:39:00 +080028#include "i2c_write_bytes_action.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050029#include "pmbus_write_vout_command_action.hpp"
Bob King9c36c5f2020-04-06 11:34:09 +080030#include "presence_detection.hpp"
31#include "rail.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050032#include "rule.hpp"
Bob King315b0b62020-04-03 21:47:58 +080033#include "run_rule_action.hpp"
Bob Kinga2f2a0d2020-04-09 13:32:14 +080034#include "sensor_monitoring.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050035
36#include <nlohmann/json.hpp>
37
38#include <cstdint>
39#include <filesystem>
40#include <memory>
41#include <stdexcept>
42#include <string>
43#include <tuple>
44#include <vector>
45
46namespace phosphor::power::regulators::config_file_parser
47{
48
49/**
50 * Parses the specified JSON configuration file.
51 *
52 * Returns the corresponding C++ Rule and Chassis objects.
53 *
54 * Throws a ConfigFileParserError if an error occurs.
55 *
56 * @param pathName configuration file path name
57 * @return tuple containing vectors of Rule and Chassis objects
58 */
59std::tuple<std::vector<std::unique_ptr<Rule>>,
60 std::vector<std::unique_ptr<Chassis>>>
61 parse(const std::filesystem::path& pathName);
62
63/*
64 * Internal implementation details for parse()
65 */
66namespace internal
67{
68
69/**
70 * Returns the specified property of the specified JSON element.
71 *
72 * Throws an invalid_argument exception if the property does not exist.
73 *
74 * @param element JSON element
75 * @param property property name
76 */
77inline const nlohmann::json& getRequiredProperty(const nlohmann::json& element,
78 const std::string& property)
79{
80 auto it = element.find(property);
81 if (it == element.end())
82 {
83 throw std::invalid_argument{"Required property missing: " + property};
84 }
85 return *it;
86}
87
88/**
89 * Parses a JSON element containing an action.
90 *
91 * Returns the corresponding C++ Action object.
92 *
93 * Throws an exception if parsing fails.
94 *
95 * @param element JSON element
96 * @return Action object
97 */
98std::unique_ptr<Action> parseAction(const nlohmann::json& element);
99
100/**
101 * Parses a JSON element containing an array of actions.
102 *
103 * Returns the corresponding C++ Action objects.
104 *
105 * Throws an exception if parsing fails.
106 *
107 * @param element JSON element
108 * @return vector of Action objects
109 */
110std::vector<std::unique_ptr<Action>>
111 parseActionArray(const nlohmann::json& element);
112
113/**
Bob Kingf617f892020-03-30 19:03:35 +0800114 * Parses a JSON element containing a bit position (from 0-7).
115 *
116 * Returns the corresponding C++ uint8_t value.
117 *
118 * Throws an exception if parsing fails.
119 *
120 * @param element JSON element
121 * @return uint8_t value
122 */
123inline uint8_t parseBitPosition(const nlohmann::json& element)
124{
125 // Verify element contains an integer
126 if (!element.is_number_integer())
127 {
128 throw std::invalid_argument{"Element is not an integer"};
129 }
Bob King6afbf1a2020-04-06 17:19:01 +0800130 int value = element.get<int>();
Bob Kingf617f892020-03-30 19:03:35 +0800131 if ((value < 0) || (value > 7))
132 {
133 throw std::invalid_argument{"Element is not a bit position"};
134 }
135 return static_cast<uint8_t>(value);
136}
137
138/**
139 * Parses a JSON element containing a bit value (0 or 1).
140 *
141 * Returns the corresponding C++ uint8_t value.
142 *
143 * Throws an exception if parsing fails.
144 *
145 * @param element JSON element
146 * @return uint8_t value
147 */
148inline uint8_t parseBitValue(const nlohmann::json& element)
149{
150 // Verify element contains an integer
151 if (!element.is_number_integer())
152 {
153 throw std::invalid_argument{"Element is not an integer"};
154 }
Bob King6afbf1a2020-04-06 17:19:01 +0800155 int value = element.get<int>();
Bob Kingf617f892020-03-30 19:03:35 +0800156 if ((value < 0) || (value > 1))
157 {
158 throw std::invalid_argument{"Element is not a bit value"};
159 }
160 return static_cast<uint8_t>(value);
161}
162
163/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500164 * Parses a JSON element containing a boolean.
165 *
166 * Returns the corresponding C++ boolean value.
167 *
168 * Throws an exception if parsing fails.
169 *
170 * @param element JSON element
171 * @return boolean value
172 */
173inline bool parseBoolean(const nlohmann::json& element)
174{
175 // Verify element contains a boolean
176 if (!element.is_boolean())
177 {
178 throw std::invalid_argument{"Element is not a boolean"};
179 }
180 return element.get<bool>();
181}
182
183/**
Bob King0e701132020-04-03 21:50:31 +0800184 * Parses a JSON element containing a chassis.
185 *
186 * Returns the corresponding C++ Chassis object.
187 *
188 * Throws an exception if parsing fails.
189 *
190 * @param element JSON element
191 * @return Chassis object
192 */
193std::unique_ptr<Chassis> parseChassis(const nlohmann::json& element);
194
195/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500196 * Parses a JSON element containing an array of chassis.
197 *
198 * Returns the corresponding C++ Chassis objects.
199 *
200 * Throws an exception if parsing fails.
201 *
202 * @param element JSON element
203 * @return vector of Chassis objects
204 */
205std::vector<std::unique_ptr<Chassis>>
206 parseChassisArray(const nlohmann::json& element);
207
208/**
Bob King33e7eaa2020-04-01 18:09:34 +0800209 * Parses a JSON element containing a configuration.
210 *
211 * Returns the corresponding C++ Configuration object.
212 *
213 * Throws an exception if parsing fails.
214 *
215 * @param element JSON element
216 * @return Configuration object
217 */
218std::unique_ptr<Configuration>
219 parseConfiguration(const nlohmann::json& element);
220
221/**
Bob King9c36c5f2020-04-06 11:34:09 +0800222 * Parses a JSON element containing a device.
223 *
224 * Returns the corresponding C++ Device object.
225 *
226 * Throws an exception if parsing fails.
227 *
228 * @param element JSON element
229 * @return Device object
230 */
231std::unique_ptr<Device> parseDevice(const nlohmann::json& element);
232
233/**
Bob King0e701132020-04-03 21:50:31 +0800234 * Parses a JSON element containing an array of devices.
235 *
236 * Returns the corresponding C++ Device objects.
237 *
238 * Throws an exception if parsing fails.
239 *
240 * @param element JSON element
241 * @return vector of Device objects
242 */
243std::vector<std::unique_ptr<Device>>
244 parseDeviceArray(const nlohmann::json& element);
245
246/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500247 * Parses a JSON element containing a double (floating point number).
248 *
249 * Returns the corresponding C++ double value.
250 *
251 * Throws an exception if parsing fails.
252 *
253 * @param element JSON element
254 * @return double value
255 */
256inline double parseDouble(const nlohmann::json& element)
257{
258 // Verify element contains a number (integer or floating point)
259 if (!element.is_number())
260 {
261 throw std::invalid_argument{"Element is not a number"};
262 }
263 return element.get<double>();
264}
265
266/**
Bob Kingbafcb862020-03-31 16:39:00 +0800267 * Parses a JSON element containing a byte value expressed as a hexadecimal
268 * string.
269 *
270 * The JSON number data type does not support the hexadecimal format. For this
271 * reason, hexadecimal byte values are stored as strings in the configuration
272 * file.
273 *
274 * Returns the corresponding C++ uint8_t value.
275 *
276 * Throws an exception if parsing fails.
277 *
278 * @param element JSON element
279 * @return uint8_t value
280 */
281inline uint8_t parseHexByte(const nlohmann::json& element)
282{
283 if (!element.is_string())
284 {
285 throw std::invalid_argument{"Element is not a string"};
286 }
Bob King6afbf1a2020-04-06 17:19:01 +0800287 std::string value = element.get<std::string>();
Bob Kingbafcb862020-03-31 16:39:00 +0800288
289 bool isHex = (value.compare(0, 2, "0x") == 0) && (value.size() > 2) &&
290 (value.size() < 5) &&
291 (value.find_first_not_of("0123456789abcdefABCDEF", 2) ==
292 std::string::npos);
293 if (!isHex)
294 {
295 throw std::invalid_argument{"Element is not hexadecimal string"};
296 }
297 return static_cast<uint8_t>(std::stoul(value, 0, 0));
298}
299
300/**
301 * Parses a JSON element containing an array of byte values expressed as a
302 * hexadecimal strings.
303 *
304 * Returns the corresponding C++ uint8_t values.
305 *
306 * Throws an exception if parsing fails.
307 *
308 * @param element JSON element
309 * @return vector of uint8_t
310 */
311std::vector<uint8_t> parseHexByteArray(const nlohmann::json& element);
312
313/**
Bob Kingf09bfe02020-04-13 17:21:15 +0800314 * Parses a JSON element containing an i2c_compare_bit action.
315 *
316 * Returns the corresponding C++ I2CCompareBitAction object.
317 *
318 * Throws an exception if parsing fails.
319 *
320 * @param element JSON element
321 * @return I2CCompareBitAction object
322 */
323std::unique_ptr<I2CCompareBitAction>
324 parseI2CCompareBit(const nlohmann::json& element);
325
326/**
327 * Parses a JSON element containing an i2c_compare_byte action.
328 *
329 * Returns the corresponding C++ I2CCompareByteAction object.
330 *
331 * Throws an exception if parsing fails.
332 *
333 * @param element JSON element
334 * @return I2CCompareByteAction object
335 */
336std::unique_ptr<I2CCompareByteAction>
337 parseI2CCompareByte(const nlohmann::json& element);
338
339/**
340 * Parses a JSON element containing an i2c_compare_bytes action.
341 *
342 * Returns the corresponding C++ I2CCompareBytesAction object.
343 *
344 * Throws an exception if parsing fails.
345 *
346 * @param element JSON element
347 * @return I2CCompareBytesAction object
348 */
349std::unique_ptr<I2CCompareBytesAction>
350 parseI2CCompareBytes(const nlohmann::json& element);
351
352/**
Bob King9c36c5f2020-04-06 11:34:09 +0800353 * Parses a JSON element containing an i2c_interface.
354 *
355 * Returns the corresponding C++ i2c::I2CInterface object.
356 *
357 * Throws an exception if parsing fails.
358 *
359 * @param element JSON element
360 * @return i2c::I2CInterface object
361 */
362std::unique_ptr<i2c::I2CInterface>
363 parseI2CInterface(const nlohmann::json& element);
364
365/**
Bob Kingf617f892020-03-30 19:03:35 +0800366 * Parses a JSON element containing an i2c_write_bit action.
367 *
368 * Returns the corresponding C++ I2CWriteBitAction object.
369 *
370 * Throws an exception if parsing fails.
371 *
372 * @param element JSON element
373 * @return I2CWriteBitAction object
374 */
375std::unique_ptr<I2CWriteBitAction>
376 parseI2CWriteBit(const nlohmann::json& element);
377
378/**
Bob King87ff9d72020-03-31 14:02:55 +0800379 * Parses a JSON element containing an i2c_write_byte action.
380 *
381 * Returns the corresponding C++ I2CWriteByteAction object.
382 *
383 * Throws an exception if parsing fails.
384 *
385 * @param element JSON element
386 * @return I2CWriteByteAction object
387 */
388std::unique_ptr<I2CWriteByteAction>
389 parseI2CWriteByte(const nlohmann::json& element);
390
391/**
Bob Kingbafcb862020-03-31 16:39:00 +0800392 * Parses a JSON element containing an i2c_write_bytes action.
393 *
394 * Returns the corresponding C++ I2CWriteBytesAction object.
395 *
396 * Throws an exception if parsing fails.
397 *
398 * @param element JSON element
399 * @return I2CWriteBytesAction object
400 */
401std::unique_ptr<I2CWriteBytesAction>
402 parseI2CWriteBytes(const nlohmann::json& element);
403
404/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500405 * Parses a JSON element containing an 8-bit signed integer.
406 *
407 * Returns the corresponding C++ int8_t value.
408 *
409 * Throws an exception if parsing fails.
410 *
411 * @param element JSON element
412 * @return int8_t value
413 */
414inline int8_t parseInt8(const nlohmann::json& element)
415{
416 // Verify element contains an integer
417 if (!element.is_number_integer())
418 {
419 throw std::invalid_argument{"Element is not an integer"};
420 }
Bob King6afbf1a2020-04-06 17:19:01 +0800421 int value = element.get<int>();
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500422 if ((value < INT8_MIN) || (value > INT8_MAX))
423 {
424 throw std::invalid_argument{"Element is not an 8-bit signed integer"};
425 }
426 return static_cast<int8_t>(value);
427}
428
429/**
430 * Parses a JSON element containing a pmbus_write_vout_command action.
431 *
432 * Returns the corresponding C++ PMBusWriteVoutCommandAction object.
433 *
434 * Throws an exception if parsing fails.
435 *
436 * @param element JSON element
437 * @return PMBusWriteVoutCommandAction object
438 */
439std::unique_ptr<PMBusWriteVoutCommandAction>
440 parsePMBusWriteVoutCommand(const nlohmann::json& element);
441
442/**
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800443 * Parses a JSON element containing a rail.
444 *
445 * Returns the corresponding C++ Rail object.
446 *
447 * Throws an exception if parsing fails.
448 *
449 * @param element JSON element
450 * @return Rail object
451 */
452std::unique_ptr<Rail> parseRail(const nlohmann::json& element);
453
454/**
Bob King9c36c5f2020-04-06 11:34:09 +0800455 * Parses a JSON element containing an array of rails.
456 *
457 * Returns the corresponding C++ Rail objects.
458 *
459 * Throws an exception if parsing fails.
460 *
461 * @param element JSON element
462 * @return vector of Rail objects
463 */
464std::vector<std::unique_ptr<Rail>>
465 parseRailArray(const nlohmann::json& element);
466
467/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500468 * Parses the JSON root element of the entire configuration file.
469 *
470 * Returns the corresponding C++ Rule and Chassis objects.
471 *
472 * Throws an exception if parsing fails.
473 *
474 * @param element JSON element
475 * @return tuple containing vectors of Rule and Chassis objects
476 */
477std::tuple<std::vector<std::unique_ptr<Rule>>,
478 std::vector<std::unique_ptr<Chassis>>>
479 parseRoot(const nlohmann::json& element);
480
481/**
482 * Parses a JSON element containing a rule.
483 *
484 * Returns the corresponding C++ Rule object.
485 *
486 * Throws an exception if parsing fails.
487 *
488 * @param element JSON element
489 * @return Rule object
490 */
491std::unique_ptr<Rule> parseRule(const nlohmann::json& element);
492
493/**
494 * Parses a JSON element containing an array of rules.
495 *
496 * Returns the corresponding C++ Rule objects.
497 *
498 * Throws an exception if parsing fails.
499 *
500 * @param element JSON element
501 * @return vector of Rule objects
502 */
503std::vector<std::unique_ptr<Rule>>
504 parseRuleArray(const nlohmann::json& element);
505
506/**
Bob King33e7eaa2020-04-01 18:09:34 +0800507 * Parses the "rule_id" or "actions" property in a JSON element.
508 *
509 * The element must contain one property or the other but not both.
510 *
511 * If the element contains a "rule_id" property, the corresponding C++
512 * RunRuleAction object is returned.
513 *
514 * If the element contains an "actions" property, the corresponding C++ Action
515 * objects are returned.
516 *
517 * Throws an exception if parsing fails.
518 *
519 * @param element JSON element
520 * @return vector of Action objects
521 */
522std::vector<std::unique_ptr<Action>>
523 parseRuleIDOrActionsProperty(const nlohmann::json& element);
524
525/**
Bob King315b0b62020-04-03 21:47:58 +0800526 * Parses a JSON element containing a run_rule action.
527 *
528 * Returns the corresponding C++ RunRuleAction object.
529 *
530 * Throws an exception if parsing fails.
531 *
532 * @param element JSON element
533 * @return RunRuleAction object
534 */
535std::unique_ptr<RunRuleAction> parseRunRule(const nlohmann::json& element);
536
537/**
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800538 * Parses a JSON element containing a sensor monitoring operation.
539 *
540 * Returns the corresponding C++ SensorMonitoring object.
541 *
542 * Throws an exception if parsing fails.
543 *
544 * @param element JSON element
545 * @return SensorMonitoring object
546 */
547std::unique_ptr<SensorMonitoring>
548 parseSensorMonitoring(const nlohmann::json& element);
549
550/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500551 * Parses a JSON element containing a string.
552 *
553 * Returns the corresponding C++ string.
554 *
555 * Throws an exception if parsing fails.
556 *
557 * @param element JSON element
558 * @param isEmptyValid indicates whether an empty string value is valid
559 * @return string value
560 */
561inline std::string parseString(const nlohmann::json& element,
562 bool isEmptyValid = false)
563{
564 if (!element.is_string())
565 {
566 throw std::invalid_argument{"Element is not a string"};
567 }
Bob King6afbf1a2020-04-06 17:19:01 +0800568 std::string value = element.get<std::string>();
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500569 if (value.empty() && !isEmptyValid)
570 {
571 throw std::invalid_argument{"Element contains an empty string"};
572 }
573 return value;
574}
575
576/**
Bob Kingf617f892020-03-30 19:03:35 +0800577 * Parses a JSON element containing an 8-bit unsigned integer.
578 *
579 * Returns the corresponding C++ uint8_t value.
580 *
581 * Throws an exception if parsing fails.
582 *
583 * @param element JSON element
584 * @return uint8_t value
585 */
586inline uint8_t parseUint8(const nlohmann::json& element)
587{
588 // Verify element contains an integer
589 if (!element.is_number_integer())
590 {
591 throw std::invalid_argument{"Element is not an integer"};
592 }
Bob King6afbf1a2020-04-06 17:19:01 +0800593 int value = element.get<int>();
Bob Kingf617f892020-03-30 19:03:35 +0800594 if ((value < 0) || (value > UINT8_MAX))
595 {
596 throw std::invalid_argument{"Element is not an 8-bit unsigned integer"};
597 }
598 return static_cast<uint8_t>(value);
599}
600
601/**
Bob King0e701132020-04-03 21:50:31 +0800602 * Parses a JSON element containing an unsigned integer.
603 *
604 * Returns the corresponding C++ unsigned int value.
605 *
606 * Throws an exception if parsing fails.
607 *
608 * @param element JSON element
609 * @return unsigned int value
610 */
611inline unsigned int parseUnsignedInteger(const nlohmann::json& element)
612{
613 // Verify element contains an unsigned integer
614 if (!element.is_number_unsigned())
615 {
616 throw std::invalid_argument{"Element is not an unsigned integer"};
617 }
618 return element.get<unsigned int>();
619}
620
621/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500622 * Verifies that the specified JSON element is a JSON array.
623 *
624 * Throws an invalid_argument exception if the element is not an array.
625 *
626 * @param element JSON element
627 */
628inline void verifyIsArray(const nlohmann::json& element)
629{
630 if (!element.is_array())
631 {
632 throw std::invalid_argument{"Element is not an array"};
633 }
634}
635
636/**
637 * Verifies that the specified JSON element is a JSON object.
638 *
639 * Throws an invalid_argument exception if the element is not an object.
640 *
641 * @param element JSON element
642 */
643inline void verifyIsObject(const nlohmann::json& element)
644{
645 if (!element.is_object())
646 {
647 throw std::invalid_argument{"Element is not an object"};
648 }
649}
650
651/**
652 * Verifies that the specified JSON element contains the expected number of
653 * properties.
654 *
655 * Throws an invalid_argument exception if the element contains a different
656 * number of properties. This indicates the element contains an invalid
657 * property.
658 *
659 * @param element JSON element
660 * @param expectedCount expected number of properties in element
661 */
662inline void verifyPropertyCount(const nlohmann::json& element,
663 unsigned int expectedCount)
664{
665 if (element.size() != expectedCount)
666 {
667 throw std::invalid_argument{"Element contains an invalid property"};
668 }
669}
670
671} // namespace internal
672
673} // namespace phosphor::power::regulators::config_file_parser