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