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