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