blob: 0a931d88f781292b79ad616bc04e1ef200be0727 [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 Kingf617f892020-03-30 19:03:35 +080020#include "i2c_write_bit_action.hpp"
Bob King87ff9d72020-03-31 14:02:55 +080021#include "i2c_write_byte_action.hpp"
Bob Kingbafcb862020-03-31 16:39:00 +080022#include "i2c_write_bytes_action.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050023#include "pmbus_write_vout_command_action.hpp"
24#include "rule.hpp"
Bob King315b0b62020-04-03 21:47:58 +080025#include "run_rule_action.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050026
27#include <nlohmann/json.hpp>
28
29#include <cstdint>
30#include <filesystem>
31#include <memory>
32#include <stdexcept>
33#include <string>
34#include <tuple>
35#include <vector>
36
37namespace phosphor::power::regulators::config_file_parser
38{
39
40/**
41 * Parses the specified JSON configuration file.
42 *
43 * Returns the corresponding C++ Rule and Chassis objects.
44 *
45 * Throws a ConfigFileParserError if an error occurs.
46 *
47 * @param pathName configuration file path name
48 * @return tuple containing vectors of Rule and Chassis objects
49 */
50std::tuple<std::vector<std::unique_ptr<Rule>>,
51 std::vector<std::unique_ptr<Chassis>>>
52 parse(const std::filesystem::path& pathName);
53
54/*
55 * Internal implementation details for parse()
56 */
57namespace internal
58{
59
60/**
61 * Returns the specified property of the specified JSON element.
62 *
63 * Throws an invalid_argument exception if the property does not exist.
64 *
65 * @param element JSON element
66 * @param property property name
67 */
68inline const nlohmann::json& getRequiredProperty(const nlohmann::json& element,
69 const std::string& property)
70{
71 auto it = element.find(property);
72 if (it == element.end())
73 {
74 throw std::invalid_argument{"Required property missing: " + property};
75 }
76 return *it;
77}
78
79/**
80 * Parses a JSON element containing an action.
81 *
82 * Returns the corresponding C++ Action object.
83 *
84 * Throws an exception if parsing fails.
85 *
86 * @param element JSON element
87 * @return Action object
88 */
89std::unique_ptr<Action> parseAction(const nlohmann::json& element);
90
91/**
92 * Parses a JSON element containing an array of actions.
93 *
94 * Returns the corresponding C++ Action objects.
95 *
96 * Throws an exception if parsing fails.
97 *
98 * @param element JSON element
99 * @return vector of Action objects
100 */
101std::vector<std::unique_ptr<Action>>
102 parseActionArray(const nlohmann::json& element);
103
104/**
Bob Kingf617f892020-03-30 19:03:35 +0800105 * Parses a JSON element containing a bit position (from 0-7).
106 *
107 * Returns the corresponding C++ uint8_t value.
108 *
109 * Throws an exception if parsing fails.
110 *
111 * @param element JSON element
112 * @return uint8_t value
113 */
114inline uint8_t parseBitPosition(const nlohmann::json& element)
115{
116 // Verify element contains an integer
117 if (!element.is_number_integer())
118 {
119 throw std::invalid_argument{"Element is not an integer"};
120 }
121 int value = element;
122 if ((value < 0) || (value > 7))
123 {
124 throw std::invalid_argument{"Element is not a bit position"};
125 }
126 return static_cast<uint8_t>(value);
127}
128
129/**
130 * Parses a JSON element containing a bit value (0 or 1).
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 parseBitValue(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 }
146 int value = element;
147 if ((value < 0) || (value > 1))
148 {
149 throw std::invalid_argument{"Element is not a bit value"};
150 }
151 return static_cast<uint8_t>(value);
152}
153
154/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500155 * Parses a JSON element containing a boolean.
156 *
157 * Returns the corresponding C++ boolean value.
158 *
159 * Throws an exception if parsing fails.
160 *
161 * @param element JSON element
162 * @return boolean value
163 */
164inline bool parseBoolean(const nlohmann::json& element)
165{
166 // Verify element contains a boolean
167 if (!element.is_boolean())
168 {
169 throw std::invalid_argument{"Element is not a boolean"};
170 }
171 return element.get<bool>();
172}
173
174/**
175 * Parses a JSON element containing an array of chassis.
176 *
177 * Returns the corresponding C++ Chassis objects.
178 *
179 * Throws an exception if parsing fails.
180 *
181 * @param element JSON element
182 * @return vector of Chassis objects
183 */
184std::vector<std::unique_ptr<Chassis>>
185 parseChassisArray(const nlohmann::json& element);
186
187/**
188 * Parses a JSON element containing a double (floating point number).
189 *
190 * Returns the corresponding C++ double value.
191 *
192 * Throws an exception if parsing fails.
193 *
194 * @param element JSON element
195 * @return double value
196 */
197inline double parseDouble(const nlohmann::json& element)
198{
199 // Verify element contains a number (integer or floating point)
200 if (!element.is_number())
201 {
202 throw std::invalid_argument{"Element is not a number"};
203 }
204 return element.get<double>();
205}
206
207/**
Bob Kingbafcb862020-03-31 16:39:00 +0800208 * Parses a JSON element containing a byte value expressed as a hexadecimal
209 * string.
210 *
211 * The JSON number data type does not support the hexadecimal format. For this
212 * reason, hexadecimal byte values are stored as strings in the configuration
213 * file.
214 *
215 * Returns the corresponding C++ uint8_t value.
216 *
217 * Throws an exception if parsing fails.
218 *
219 * @param element JSON element
220 * @return uint8_t value
221 */
222inline uint8_t parseHexByte(const nlohmann::json& element)
223{
224 if (!element.is_string())
225 {
226 throw std::invalid_argument{"Element is not a string"};
227 }
228 std::string value = element;
229
230 bool isHex = (value.compare(0, 2, "0x") == 0) && (value.size() > 2) &&
231 (value.size() < 5) &&
232 (value.find_first_not_of("0123456789abcdefABCDEF", 2) ==
233 std::string::npos);
234 if (!isHex)
235 {
236 throw std::invalid_argument{"Element is not hexadecimal string"};
237 }
238 return static_cast<uint8_t>(std::stoul(value, 0, 0));
239}
240
241/**
242 * Parses a JSON element containing an array of byte values expressed as a
243 * hexadecimal strings.
244 *
245 * Returns the corresponding C++ uint8_t values.
246 *
247 * Throws an exception if parsing fails.
248 *
249 * @param element JSON element
250 * @return vector of uint8_t
251 */
252std::vector<uint8_t> parseHexByteArray(const nlohmann::json& element);
253
254/**
Bob Kingf617f892020-03-30 19:03:35 +0800255 * Parses a JSON element containing an i2c_write_bit action.
256 *
257 * Returns the corresponding C++ I2CWriteBitAction object.
258 *
259 * Throws an exception if parsing fails.
260 *
261 * @param element JSON element
262 * @return I2CWriteBitAction object
263 */
264std::unique_ptr<I2CWriteBitAction>
265 parseI2CWriteBit(const nlohmann::json& element);
266
267/**
Bob King87ff9d72020-03-31 14:02:55 +0800268 * Parses a JSON element containing an i2c_write_byte action.
269 *
270 * Returns the corresponding C++ I2CWriteByteAction object.
271 *
272 * Throws an exception if parsing fails.
273 *
274 * @param element JSON element
275 * @return I2CWriteByteAction object
276 */
277std::unique_ptr<I2CWriteByteAction>
278 parseI2CWriteByte(const nlohmann::json& element);
279
280/**
Bob Kingbafcb862020-03-31 16:39:00 +0800281 * Parses a JSON element containing an i2c_write_bytes action.
282 *
283 * Returns the corresponding C++ I2CWriteBytesAction object.
284 *
285 * Throws an exception if parsing fails.
286 *
287 * @param element JSON element
288 * @return I2CWriteBytesAction object
289 */
290std::unique_ptr<I2CWriteBytesAction>
291 parseI2CWriteBytes(const nlohmann::json& element);
292
293/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500294 * Parses a JSON element containing an 8-bit signed integer.
295 *
296 * Returns the corresponding C++ int8_t value.
297 *
298 * Throws an exception if parsing fails.
299 *
300 * @param element JSON element
301 * @return int8_t value
302 */
303inline int8_t parseInt8(const nlohmann::json& element)
304{
305 // Verify element contains an integer
306 if (!element.is_number_integer())
307 {
308 throw std::invalid_argument{"Element is not an integer"};
309 }
310 int value = element;
311 if ((value < INT8_MIN) || (value > INT8_MAX))
312 {
313 throw std::invalid_argument{"Element is not an 8-bit signed integer"};
314 }
315 return static_cast<int8_t>(value);
316}
317
318/**
319 * Parses a JSON element containing a pmbus_write_vout_command action.
320 *
321 * Returns the corresponding C++ PMBusWriteVoutCommandAction object.
322 *
323 * Throws an exception if parsing fails.
324 *
325 * @param element JSON element
326 * @return PMBusWriteVoutCommandAction object
327 */
328std::unique_ptr<PMBusWriteVoutCommandAction>
329 parsePMBusWriteVoutCommand(const nlohmann::json& element);
330
331/**
332 * Parses the JSON root element of the entire configuration file.
333 *
334 * Returns the corresponding C++ Rule and Chassis objects.
335 *
336 * Throws an exception if parsing fails.
337 *
338 * @param element JSON element
339 * @return tuple containing vectors of Rule and Chassis objects
340 */
341std::tuple<std::vector<std::unique_ptr<Rule>>,
342 std::vector<std::unique_ptr<Chassis>>>
343 parseRoot(const nlohmann::json& element);
344
345/**
346 * Parses a JSON element containing a rule.
347 *
348 * Returns the corresponding C++ Rule object.
349 *
350 * Throws an exception if parsing fails.
351 *
352 * @param element JSON element
353 * @return Rule object
354 */
355std::unique_ptr<Rule> parseRule(const nlohmann::json& element);
356
357/**
358 * Parses a JSON element containing an array of rules.
359 *
360 * Returns the corresponding C++ Rule objects.
361 *
362 * Throws an exception if parsing fails.
363 *
364 * @param element JSON element
365 * @return vector of Rule objects
366 */
367std::vector<std::unique_ptr<Rule>>
368 parseRuleArray(const nlohmann::json& element);
369
370/**
Bob King315b0b62020-04-03 21:47:58 +0800371 * Parses a JSON element containing a run_rule action.
372 *
373 * Returns the corresponding C++ RunRuleAction object.
374 *
375 * Throws an exception if parsing fails.
376 *
377 * @param element JSON element
378 * @return RunRuleAction object
379 */
380std::unique_ptr<RunRuleAction> parseRunRule(const nlohmann::json& element);
381
382/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500383 * Parses a JSON element containing a string.
384 *
385 * Returns the corresponding C++ string.
386 *
387 * Throws an exception if parsing fails.
388 *
389 * @param element JSON element
390 * @param isEmptyValid indicates whether an empty string value is valid
391 * @return string value
392 */
393inline std::string parseString(const nlohmann::json& element,
394 bool isEmptyValid = false)
395{
396 if (!element.is_string())
397 {
398 throw std::invalid_argument{"Element is not a string"};
399 }
400 std::string value = element;
401 if (value.empty() && !isEmptyValid)
402 {
403 throw std::invalid_argument{"Element contains an empty string"};
404 }
405 return value;
406}
407
408/**
Bob Kingf617f892020-03-30 19:03:35 +0800409 * Parses a JSON element containing an 8-bit unsigned integer.
410 *
411 * Returns the corresponding C++ uint8_t value.
412 *
413 * Throws an exception if parsing fails.
414 *
415 * @param element JSON element
416 * @return uint8_t value
417 */
418inline uint8_t parseUint8(const nlohmann::json& element)
419{
420 // Verify element contains an integer
421 if (!element.is_number_integer())
422 {
423 throw std::invalid_argument{"Element is not an integer"};
424 }
425 int value = element;
426 if ((value < 0) || (value > UINT8_MAX))
427 {
428 throw std::invalid_argument{"Element is not an 8-bit unsigned integer"};
429 }
430 return static_cast<uint8_t>(value);
431}
432
433/**
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500434 * Verifies that the specified JSON element is a JSON array.
435 *
436 * Throws an invalid_argument exception if the element is not an array.
437 *
438 * @param element JSON element
439 */
440inline void verifyIsArray(const nlohmann::json& element)
441{
442 if (!element.is_array())
443 {
444 throw std::invalid_argument{"Element is not an array"};
445 }
446}
447
448/**
449 * Verifies that the specified JSON element is a JSON object.
450 *
451 * Throws an invalid_argument exception if the element is not an object.
452 *
453 * @param element JSON element
454 */
455inline void verifyIsObject(const nlohmann::json& element)
456{
457 if (!element.is_object())
458 {
459 throw std::invalid_argument{"Element is not an object"};
460 }
461}
462
463/**
464 * Verifies that the specified JSON element contains the expected number of
465 * properties.
466 *
467 * Throws an invalid_argument exception if the element contains a different
468 * number of properties. This indicates the element contains an invalid
469 * property.
470 *
471 * @param element JSON element
472 * @param expectedCount expected number of properties in element
473 */
474inline void verifyPropertyCount(const nlohmann::json& element,
475 unsigned int expectedCount)
476{
477 if (element.size() != expectedCount)
478 {
479 throw std::invalid_argument{"Element contains an invalid property"};
480 }
481}
482
483} // namespace internal
484
485} // namespace phosphor::power::regulators::config_file_parser