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