blob: 7104356c8d115487eff0651595d73e0963c27ff6 [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"
Bob King3a787542020-04-14 13:45:01 +080019#include "and_action.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050020#include "chassis.hpp"
Bob King9c36c5f2020-04-06 11:34:09 +080021#include "configuration.hpp"
Bob King0e701132020-04-03 21:50:31 +080022#include "device.hpp"
Bob Kingf09bfe02020-04-13 17:21:15 +080023#include "i2c_compare_bit_action.hpp"
24#include "i2c_compare_byte_action.hpp"
25#include "i2c_compare_bytes_action.hpp"
Bob King9c36c5f2020-04-06 11:34:09 +080026#include "i2c_interface.hpp"
Bob Kingf617f892020-03-30 19:03:35 +080027#include "i2c_write_bit_action.hpp"
Bob King87ff9d72020-03-31 14:02:55 +080028#include "i2c_write_byte_action.hpp"
Bob Kingbafcb862020-03-31 16:39:00 +080029#include "i2c_write_bytes_action.hpp"
Bob Kingf1b58dc2020-04-14 14:53:10 +080030#include "not_action.hpp"
Bob King0b51a9b2020-04-15 13:24:18 +080031#include "or_action.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050032#include "pmbus_write_vout_command_action.hpp"
Bob King9c36c5f2020-04-06 11:34:09 +080033#include "presence_detection.hpp"
34#include "rail.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050035#include "rule.hpp"
Bob King315b0b62020-04-03 21:47:58 +080036#include "run_rule_action.hpp"
Bob Kinga2f2a0d2020-04-09 13:32:14 +080037#include "sensor_monitoring.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050038
39#include <nlohmann/json.hpp>
40
41#include <cstdint>
42#include <filesystem>
43#include <memory>
44#include <stdexcept>
45#include <string>
46#include <tuple>
47#include <vector>
48
49namespace phosphor::power::regulators::config_file_parser
50{
51
52/**
53 * Parses the specified JSON configuration file.
54 *
55 * Returns the corresponding C++ Rule and Chassis objects.
56 *
57 * Throws a ConfigFileParserError if an error occurs.
58 *
59 * @param pathName configuration file path name
60 * @return tuple containing vectors of Rule and Chassis objects
61 */
62std::tuple<std::vector<std::unique_ptr<Rule>>,
63 std::vector<std::unique_ptr<Chassis>>>
64 parse(const std::filesystem::path& pathName);
65
66/*
67 * Internal implementation details for parse()
68 */
69namespace internal
70{
71
72/**
73 * Returns the specified property of the specified JSON element.
74 *
75 * Throws an invalid_argument exception if the property does not exist.
76 *
77 * @param element JSON element
78 * @param property property name
79 */
80inline const nlohmann::json& getRequiredProperty(const nlohmann::json& element,
81 const std::string& property)
82{
83 auto it = element.find(property);
84 if (it == element.end())
85 {
86 throw std::invalid_argument{"Required property missing: " + property};
87 }
88 return *it;
89}
90
91/**
92 * Parses a JSON element containing an action.
93 *
94 * Returns the corresponding C++ Action object.
95 *
96 * Throws an exception if parsing fails.
97 *
98 * @param element JSON element
99 * @return Action object
100 */
101std::unique_ptr<Action> parseAction(const nlohmann::json& element);
102
103/**
104 * Parses a JSON element containing an array of actions.
105 *
106 * Returns the corresponding C++ Action objects.
107 *
108 * Throws an exception if parsing fails.
109 *
110 * @param element JSON element
111 * @return vector of Action objects
112 */
113std::vector<std::unique_ptr<Action>>
114 parseActionArray(const nlohmann::json& element);
115
116/**
Bob King3a787542020-04-14 13:45:01 +0800117 * Parses a JSON element containing an and action.
118 *
119 * Returns the corresponding C++ AndAction object.
120 *
121 * Throws an exception if parsing fails.
122 *
123 * @param element JSON element
124 * @return AndAction object
125 */
126std::unique_ptr<AndAction> parseAnd(const nlohmann::json& element);
127
128/**
Bob Kingf617f892020-03-30 19:03:35 +0800129 * Parses a JSON element containing a bit position (from 0-7).
130 *
131 * Returns the corresponding C++ uint8_t value.
132 *
133 * Throws an exception if parsing fails.
134 *
135 * @param element JSON element
136 * @return uint8_t value
137 */
138inline uint8_t parseBitPosition(const nlohmann::json& element)
139{
140 // Verify element contains an integer
141 if (!element.is_number_integer())
142 {
143 throw std::invalid_argument{"Element is not an integer"};
144 }
Bob King6afbf1a2020-04-06 17:19:01 +0800145 int value = element.get<int>();
Bob Kingf617f892020-03-30 19:03:35 +0800146 if ((value < 0) || (value > 7))
147 {
148 throw std::invalid_argument{"Element is not a bit position"};
149 }
150 return static_cast<uint8_t>(value);
151}
152
153/**
154 * Parses a JSON element containing a bit value (0 or 1).
155 *
156 * Returns the corresponding C++ uint8_t value.
157 *
158 * Throws an exception if parsing fails.
159 *
160 * @param element JSON element
161 * @return uint8_t value
162 */
163inline uint8_t parseBitValue(const nlohmann::json& element)
164{
165 // Verify element contains an integer
166 if (!element.is_number_integer())
167 {
168 throw std::invalid_argument{"Element is not an integer"};
169 }
Bob King6afbf1a2020-04-06 17:19:01 +0800170 int value = element.get<int>();
Bob Kingf617f892020-03-30 19:03:35 +0800171 if ((value < 0) || (value > 1))
172 {
173 throw std::invalid_argument{"Element is not a bit value"};
174 }
175 return static_cast<uint8_t>(value);
176}
177
178/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500179 * Parses a JSON element containing a boolean.
180 *
181 * Returns the corresponding C++ boolean value.
182 *
183 * Throws an exception if parsing fails.
184 *
185 * @param element JSON element
186 * @return boolean value
187 */
188inline bool parseBoolean(const nlohmann::json& element)
189{
190 // Verify element contains a boolean
191 if (!element.is_boolean())
192 {
193 throw std::invalid_argument{"Element is not a boolean"};
194 }
195 return element.get<bool>();
196}
197
198/**
Bob King0e701132020-04-03 21:50:31 +0800199 * Parses a JSON element containing a chassis.
200 *
201 * Returns the corresponding C++ Chassis object.
202 *
203 * Throws an exception if parsing fails.
204 *
205 * @param element JSON element
206 * @return Chassis object
207 */
208std::unique_ptr<Chassis> parseChassis(const nlohmann::json& element);
209
210/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500211 * Parses a JSON element containing an array of chassis.
212 *
213 * Returns the corresponding C++ Chassis objects.
214 *
215 * Throws an exception if parsing fails.
216 *
217 * @param element JSON element
218 * @return vector of Chassis objects
219 */
220std::vector<std::unique_ptr<Chassis>>
221 parseChassisArray(const nlohmann::json& element);
222
223/**
Bob King33e7eaa2020-04-01 18:09:34 +0800224 * Parses a JSON element containing a configuration.
225 *
226 * Returns the corresponding C++ Configuration object.
227 *
228 * Throws an exception if parsing fails.
229 *
230 * @param element JSON element
231 * @return Configuration object
232 */
233std::unique_ptr<Configuration>
234 parseConfiguration(const nlohmann::json& element);
235
236/**
Bob King9c36c5f2020-04-06 11:34:09 +0800237 * Parses a JSON element containing a device.
238 *
239 * Returns the corresponding C++ Device object.
240 *
241 * Throws an exception if parsing fails.
242 *
243 * @param element JSON element
244 * @return Device object
245 */
246std::unique_ptr<Device> parseDevice(const nlohmann::json& element);
247
248/**
Bob King0e701132020-04-03 21:50:31 +0800249 * Parses a JSON element containing an array of devices.
250 *
251 * Returns the corresponding C++ Device objects.
252 *
253 * Throws an exception if parsing fails.
254 *
255 * @param element JSON element
256 * @return vector of Device objects
257 */
258std::vector<std::unique_ptr<Device>>
259 parseDeviceArray(const nlohmann::json& element);
260
261/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500262 * Parses a JSON element containing a double (floating point number).
263 *
264 * Returns the corresponding C++ double value.
265 *
266 * Throws an exception if parsing fails.
267 *
268 * @param element JSON element
269 * @return double value
270 */
271inline double parseDouble(const nlohmann::json& element)
272{
273 // Verify element contains a number (integer or floating point)
274 if (!element.is_number())
275 {
276 throw std::invalid_argument{"Element is not a number"};
277 }
278 return element.get<double>();
279}
280
281/**
Bob Kingbafcb862020-03-31 16:39:00 +0800282 * Parses a JSON element containing a byte value expressed as a hexadecimal
283 * string.
284 *
285 * The JSON number data type does not support the hexadecimal format. For this
286 * reason, hexadecimal byte values are stored as strings in the configuration
287 * file.
288 *
289 * Returns the corresponding C++ uint8_t value.
290 *
291 * Throws an exception if parsing fails.
292 *
293 * @param element JSON element
294 * @return uint8_t value
295 */
296inline uint8_t parseHexByte(const nlohmann::json& element)
297{
298 if (!element.is_string())
299 {
300 throw std::invalid_argument{"Element is not a string"};
301 }
Bob King6afbf1a2020-04-06 17:19:01 +0800302 std::string value = element.get<std::string>();
Bob Kingbafcb862020-03-31 16:39:00 +0800303
304 bool isHex = (value.compare(0, 2, "0x") == 0) && (value.size() > 2) &&
305 (value.size() < 5) &&
306 (value.find_first_not_of("0123456789abcdefABCDEF", 2) ==
307 std::string::npos);
308 if (!isHex)
309 {
310 throw std::invalid_argument{"Element is not hexadecimal string"};
311 }
312 return static_cast<uint8_t>(std::stoul(value, 0, 0));
313}
314
315/**
316 * Parses a JSON element containing an array of byte values expressed as a
317 * hexadecimal strings.
318 *
319 * Returns the corresponding C++ uint8_t values.
320 *
321 * Throws an exception if parsing fails.
322 *
323 * @param element JSON element
324 * @return vector of uint8_t
325 */
326std::vector<uint8_t> parseHexByteArray(const nlohmann::json& element);
327
328/**
Bob Kingf09bfe02020-04-13 17:21:15 +0800329 * Parses a JSON element containing an i2c_compare_bit action.
330 *
331 * Returns the corresponding C++ I2CCompareBitAction object.
332 *
333 * Throws an exception if parsing fails.
334 *
335 * @param element JSON element
336 * @return I2CCompareBitAction object
337 */
338std::unique_ptr<I2CCompareBitAction>
339 parseI2CCompareBit(const nlohmann::json& element);
340
341/**
342 * Parses a JSON element containing an i2c_compare_byte action.
343 *
344 * Returns the corresponding C++ I2CCompareByteAction object.
345 *
346 * Throws an exception if parsing fails.
347 *
348 * @param element JSON element
349 * @return I2CCompareByteAction object
350 */
351std::unique_ptr<I2CCompareByteAction>
352 parseI2CCompareByte(const nlohmann::json& element);
353
354/**
355 * Parses a JSON element containing an i2c_compare_bytes action.
356 *
357 * Returns the corresponding C++ I2CCompareBytesAction object.
358 *
359 * Throws an exception if parsing fails.
360 *
361 * @param element JSON element
362 * @return I2CCompareBytesAction object
363 */
364std::unique_ptr<I2CCompareBytesAction>
365 parseI2CCompareBytes(const nlohmann::json& element);
366
367/**
Bob King9c36c5f2020-04-06 11:34:09 +0800368 * Parses a JSON element containing an i2c_interface.
369 *
370 * Returns the corresponding C++ i2c::I2CInterface object.
371 *
372 * Throws an exception if parsing fails.
373 *
374 * @param element JSON element
375 * @return i2c::I2CInterface object
376 */
377std::unique_ptr<i2c::I2CInterface>
378 parseI2CInterface(const nlohmann::json& element);
379
380/**
Bob Kingf617f892020-03-30 19:03:35 +0800381 * Parses a JSON element containing an i2c_write_bit action.
382 *
383 * Returns the corresponding C++ I2CWriteBitAction object.
384 *
385 * Throws an exception if parsing fails.
386 *
387 * @param element JSON element
388 * @return I2CWriteBitAction object
389 */
390std::unique_ptr<I2CWriteBitAction>
391 parseI2CWriteBit(const nlohmann::json& element);
392
393/**
Bob King87ff9d72020-03-31 14:02:55 +0800394 * Parses a JSON element containing an i2c_write_byte action.
395 *
396 * Returns the corresponding C++ I2CWriteByteAction object.
397 *
398 * Throws an exception if parsing fails.
399 *
400 * @param element JSON element
401 * @return I2CWriteByteAction object
402 */
403std::unique_ptr<I2CWriteByteAction>
404 parseI2CWriteByte(const nlohmann::json& element);
405
406/**
Bob Kingbafcb862020-03-31 16:39:00 +0800407 * Parses a JSON element containing an i2c_write_bytes action.
408 *
409 * Returns the corresponding C++ I2CWriteBytesAction object.
410 *
411 * Throws an exception if parsing fails.
412 *
413 * @param element JSON element
414 * @return I2CWriteBytesAction object
415 */
416std::unique_ptr<I2CWriteBytesAction>
417 parseI2CWriteBytes(const nlohmann::json& element);
418
419/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500420 * Parses a JSON element containing an 8-bit signed integer.
421 *
422 * Returns the corresponding C++ int8_t value.
423 *
424 * Throws an exception if parsing fails.
425 *
426 * @param element JSON element
427 * @return int8_t value
428 */
429inline int8_t parseInt8(const nlohmann::json& element)
430{
431 // Verify element contains an integer
432 if (!element.is_number_integer())
433 {
434 throw std::invalid_argument{"Element is not an integer"};
435 }
Bob King6afbf1a2020-04-06 17:19:01 +0800436 int value = element.get<int>();
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500437 if ((value < INT8_MIN) || (value > INT8_MAX))
438 {
439 throw std::invalid_argument{"Element is not an 8-bit signed integer"};
440 }
441 return static_cast<int8_t>(value);
442}
443
444/**
Bob Kingf1b58dc2020-04-14 14:53:10 +0800445 * Parses a JSON element containing a not action.
446 *
447 * Returns the corresponding C++ NotAction object.
448 *
449 * Throws an exception if parsing fails.
450 *
451 * @param element JSON element
452 * @return NotAction object
453 */
454std::unique_ptr<NotAction> parseNot(const nlohmann::json& element);
455
456/**
Bob King0b51a9b2020-04-15 13:24:18 +0800457 * Parses a JSON element containing an or action.
458 *
459 * Returns the corresponding C++ OrAction object.
460 *
461 * Throws an exception if parsing fails.
462 *
463 * @param element JSON element
464 * @return OrAction object
465 */
466std::unique_ptr<OrAction> parseOr(const nlohmann::json& element);
467
468/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500469 * Parses a JSON element containing a pmbus_write_vout_command action.
470 *
471 * Returns the corresponding C++ PMBusWriteVoutCommandAction object.
472 *
473 * Throws an exception if parsing fails.
474 *
475 * @param element JSON element
476 * @return PMBusWriteVoutCommandAction object
477 */
478std::unique_ptr<PMBusWriteVoutCommandAction>
479 parsePMBusWriteVoutCommand(const nlohmann::json& element);
480
481/**
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800482 * Parses a JSON element containing a rail.
483 *
484 * Returns the corresponding C++ Rail object.
485 *
486 * Throws an exception if parsing fails.
487 *
488 * @param element JSON element
489 * @return Rail object
490 */
491std::unique_ptr<Rail> parseRail(const nlohmann::json& element);
492
493/**
Bob King9c36c5f2020-04-06 11:34:09 +0800494 * Parses a JSON element containing an array of rails.
495 *
496 * Returns the corresponding C++ Rail objects.
497 *
498 * Throws an exception if parsing fails.
499 *
500 * @param element JSON element
501 * @return vector of Rail objects
502 */
503std::vector<std::unique_ptr<Rail>>
504 parseRailArray(const nlohmann::json& element);
505
506/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500507 * Parses the JSON root element of the entire configuration file.
508 *
509 * Returns the corresponding C++ Rule and Chassis objects.
510 *
511 * Throws an exception if parsing fails.
512 *
513 * @param element JSON element
514 * @return tuple containing vectors of Rule and Chassis objects
515 */
516std::tuple<std::vector<std::unique_ptr<Rule>>,
517 std::vector<std::unique_ptr<Chassis>>>
518 parseRoot(const nlohmann::json& element);
519
520/**
521 * Parses a JSON element containing a rule.
522 *
523 * Returns the corresponding C++ Rule object.
524 *
525 * Throws an exception if parsing fails.
526 *
527 * @param element JSON element
528 * @return Rule object
529 */
530std::unique_ptr<Rule> parseRule(const nlohmann::json& element);
531
532/**
533 * Parses a JSON element containing an array of rules.
534 *
535 * Returns the corresponding C++ Rule objects.
536 *
537 * Throws an exception if parsing fails.
538 *
539 * @param element JSON element
540 * @return vector of Rule objects
541 */
542std::vector<std::unique_ptr<Rule>>
543 parseRuleArray(const nlohmann::json& element);
544
545/**
Bob King33e7eaa2020-04-01 18:09:34 +0800546 * Parses the "rule_id" or "actions" property in a JSON element.
547 *
548 * The element must contain one property or the other but not both.
549 *
550 * If the element contains a "rule_id" property, the corresponding C++
551 * RunRuleAction object is returned.
552 *
553 * If the element contains an "actions" property, the corresponding C++ Action
554 * objects are returned.
555 *
556 * Throws an exception if parsing fails.
557 *
558 * @param element JSON element
559 * @return vector of Action objects
560 */
561std::vector<std::unique_ptr<Action>>
562 parseRuleIDOrActionsProperty(const nlohmann::json& element);
563
564/**
Bob King315b0b62020-04-03 21:47:58 +0800565 * Parses a JSON element containing a run_rule action.
566 *
567 * Returns the corresponding C++ RunRuleAction object.
568 *
569 * Throws an exception if parsing fails.
570 *
571 * @param element JSON element
572 * @return RunRuleAction object
573 */
574std::unique_ptr<RunRuleAction> parseRunRule(const nlohmann::json& element);
575
576/**
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800577 * Parses a JSON element containing a sensor monitoring operation.
578 *
579 * Returns the corresponding C++ SensorMonitoring object.
580 *
581 * Throws an exception if parsing fails.
582 *
583 * @param element JSON element
584 * @return SensorMonitoring object
585 */
586std::unique_ptr<SensorMonitoring>
587 parseSensorMonitoring(const nlohmann::json& element);
588
589/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500590 * Parses a JSON element containing a string.
591 *
592 * Returns the corresponding C++ string.
593 *
594 * Throws an exception if parsing fails.
595 *
596 * @param element JSON element
597 * @param isEmptyValid indicates whether an empty string value is valid
598 * @return string value
599 */
600inline std::string parseString(const nlohmann::json& element,
601 bool isEmptyValid = false)
602{
603 if (!element.is_string())
604 {
605 throw std::invalid_argument{"Element is not a string"};
606 }
Bob King6afbf1a2020-04-06 17:19:01 +0800607 std::string value = element.get<std::string>();
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500608 if (value.empty() && !isEmptyValid)
609 {
610 throw std::invalid_argument{"Element contains an empty string"};
611 }
612 return value;
613}
614
615/**
Bob Kingf617f892020-03-30 19:03:35 +0800616 * Parses a JSON element containing an 8-bit unsigned integer.
617 *
618 * Returns the corresponding C++ uint8_t value.
619 *
620 * Throws an exception if parsing fails.
621 *
622 * @param element JSON element
623 * @return uint8_t value
624 */
625inline uint8_t parseUint8(const nlohmann::json& element)
626{
627 // Verify element contains an integer
628 if (!element.is_number_integer())
629 {
630 throw std::invalid_argument{"Element is not an integer"};
631 }
Bob King6afbf1a2020-04-06 17:19:01 +0800632 int value = element.get<int>();
Bob Kingf617f892020-03-30 19:03:35 +0800633 if ((value < 0) || (value > UINT8_MAX))
634 {
635 throw std::invalid_argument{"Element is not an 8-bit unsigned integer"};
636 }
637 return static_cast<uint8_t>(value);
638}
639
640/**
Bob King0e701132020-04-03 21:50:31 +0800641 * Parses a JSON element containing an unsigned integer.
642 *
643 * Returns the corresponding C++ unsigned int value.
644 *
645 * Throws an exception if parsing fails.
646 *
647 * @param element JSON element
648 * @return unsigned int value
649 */
650inline unsigned int parseUnsignedInteger(const nlohmann::json& element)
651{
652 // Verify element contains an unsigned integer
653 if (!element.is_number_unsigned())
654 {
655 throw std::invalid_argument{"Element is not an unsigned integer"};
656 }
657 return element.get<unsigned int>();
658}
659
660/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500661 * Verifies that the specified JSON element is a JSON array.
662 *
663 * Throws an invalid_argument exception if the element is not an array.
664 *
665 * @param element JSON element
666 */
667inline void verifyIsArray(const nlohmann::json& element)
668{
669 if (!element.is_array())
670 {
671 throw std::invalid_argument{"Element is not an array"};
672 }
673}
674
675/**
676 * Verifies that the specified JSON element is a JSON object.
677 *
678 * Throws an invalid_argument exception if the element is not an object.
679 *
680 * @param element JSON element
681 */
682inline void verifyIsObject(const nlohmann::json& element)
683{
684 if (!element.is_object())
685 {
686 throw std::invalid_argument{"Element is not an object"};
687 }
688}
689
690/**
691 * Verifies that the specified JSON element contains the expected number of
692 * properties.
693 *
694 * Throws an invalid_argument exception if the element contains a different
695 * number of properties. This indicates the element contains an invalid
696 * property.
697 *
698 * @param element JSON element
699 * @param expectedCount expected number of properties in element
700 */
701inline void verifyPropertyCount(const nlohmann::json& element,
702 unsigned int expectedCount)
703{
704 if (element.size() != expectedCount)
705 {
706 throw std::invalid_argument{"Element contains an invalid property"};
707 }
708}
709
710} // namespace internal
711
712} // namespace phosphor::power::regulators::config_file_parser