blob: 0b4673d0ed97e9d1b311847c7bc6b95ce9029ba6 [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
17#include "config_file_parser.hpp"
18
19#include "config_file_parser_error.hpp"
Bob Kingf617f892020-03-30 19:03:35 +080020#include "i2c_interface.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050021#include "pmbus_utils.hpp"
22
23#include <exception>
24#include <fstream>
25#include <optional>
26#include <utility>
27
28using json = nlohmann::json;
29
30namespace phosphor::power::regulators::config_file_parser
31{
32
33std::tuple<std::vector<std::unique_ptr<Rule>>,
34 std::vector<std::unique_ptr<Chassis>>>
35 parse(const std::filesystem::path& pathName)
36{
37 try
38 {
39 // Use standard JSON parser to create tree of JSON elements
40 std::ifstream file{pathName};
41 json rootElement = json::parse(file);
42
43 // Parse tree of JSON elements and return corresponding C++ objects
44 return internal::parseRoot(rootElement);
45 }
46 catch (const std::exception& e)
47 {
48 throw ConfigFileParserError{pathName, e.what()};
49 }
50}
51
52namespace internal
53{
54
55std::unique_ptr<Action> parseAction(const json& element)
56{
57 verifyIsObject(element);
58 unsigned int propertyCount{0};
59
60 // Optional comments property; value not stored
61 if (element.contains("comments"))
62 {
63 ++propertyCount;
64 }
65
66 // Required action type property; there must be exactly one specified
67 std::unique_ptr<Action> action{};
68 if (element.contains("and"))
69 {
Bob King3a787542020-04-14 13:45:01 +080070 action = parseAnd(element["and"]);
71 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050072 }
73 else if (element.contains("compare_presence"))
74 {
Bob Kingb267b7e2020-04-22 14:42:39 +080075 action = parseComparePresence(element["compare_presence"]);
76 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050077 }
78 else if (element.contains("compare_vpd"))
79 {
Bob Kingf2134322020-04-27 14:14:56 +080080 action = parseCompareVPD(element["compare_vpd"]);
81 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050082 }
83 else if (element.contains("i2c_compare_bit"))
84 {
Bob Kingf09bfe02020-04-13 17:21:15 +080085 action = parseI2CCompareBit(element["i2c_compare_bit"]);
86 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050087 }
88 else if (element.contains("i2c_compare_byte"))
89 {
Bob Kingf09bfe02020-04-13 17:21:15 +080090 action = parseI2CCompareByte(element["i2c_compare_byte"]);
91 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050092 }
93 else if (element.contains("i2c_compare_bytes"))
94 {
Bob Kingf09bfe02020-04-13 17:21:15 +080095 action = parseI2CCompareBytes(element["i2c_compare_bytes"]);
96 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050097 }
98 else if (element.contains("i2c_write_bit"))
99 {
Bob Kingf617f892020-03-30 19:03:35 +0800100 action = parseI2CWriteBit(element["i2c_write_bit"]);
101 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500102 }
103 else if (element.contains("i2c_write_byte"))
104 {
Bob King87ff9d72020-03-31 14:02:55 +0800105 action = parseI2CWriteByte(element["i2c_write_byte"]);
106 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500107 }
108 else if (element.contains("i2c_write_bytes"))
109 {
Bob Kingbafcb862020-03-31 16:39:00 +0800110 action = parseI2CWriteBytes(element["i2c_write_bytes"]);
111 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500112 }
113 else if (element.contains("if"))
114 {
Bob King93a89d72020-04-15 15:11:11 +0800115 action = parseIf(element["if"]);
116 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500117 }
118 else if (element.contains("not"))
119 {
Bob Kingf1b58dc2020-04-14 14:53:10 +0800120 action = parseNot(element["not"]);
121 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500122 }
123 else if (element.contains("or"))
124 {
Bob King0b51a9b2020-04-15 13:24:18 +0800125 action = parseOr(element["or"]);
126 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500127 }
128 else if (element.contains("pmbus_read_sensor"))
129 {
Bob King84614882020-04-30 13:13:48 +0800130 action = parsePMBusReadSensor(element["pmbus_read_sensor"]);
131 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500132 }
133 else if (element.contains("pmbus_write_vout_command"))
134 {
135 action =
136 parsePMBusWriteVoutCommand(element["pmbus_write_vout_command"]);
137 ++propertyCount;
138 }
139 else if (element.contains("run_rule"))
140 {
Bob King315b0b62020-04-03 21:47:58 +0800141 action = parseRunRule(element["run_rule"]);
142 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500143 }
144 else if (element.contains("set_device"))
145 {
Bob King18a68502020-04-17 14:19:56 +0800146 action = parseSetDevice(element["set_device"]);
147 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500148 }
149 else
150 {
151 throw std::invalid_argument{"Required action type property missing"};
152 }
153
154 // Verify no invalid properties exist
155 verifyPropertyCount(element, propertyCount);
156
157 return action;
158}
159
160std::vector<std::unique_ptr<Action>> parseActionArray(const json& element)
161{
162 verifyIsArray(element);
163 std::vector<std::unique_ptr<Action>> actions;
164 for (auto& actionElement : element)
165 {
166 actions.emplace_back(parseAction(actionElement));
167 }
168 return actions;
169}
170
Bob King3a787542020-04-14 13:45:01 +0800171std::unique_ptr<AndAction> parseAnd(const json& element)
172{
173 verifyIsArray(element);
174
175 // Verify if array size less than 2
176 if (element.size() < 2)
177 {
178 throw std::invalid_argument{"Array must contain two or more actions"};
179 }
180 // Array of two or more actions
181 std::vector<std::unique_ptr<Action>> actions = parseActionArray(element);
182
183 return std::make_unique<AndAction>(std::move(actions));
184}
185
Bob King0e701132020-04-03 21:50:31 +0800186std::unique_ptr<Chassis> parseChassis(const json& element)
187{
188 verifyIsObject(element);
189 unsigned int propertyCount{0};
190
191 // Optional comments property; value not stored
192 if (element.contains("comments"))
193 {
194 ++propertyCount;
195 }
196
197 // Required number property
198 const json& numberElement = getRequiredProperty(element, "number");
199 unsigned int number = parseUnsignedInteger(numberElement);
200 if (number < 1)
201 {
202 throw std::invalid_argument{"Invalid chassis number: Must be > 0"};
203 }
204 ++propertyCount;
205
Shawn McCarneycb3f6a62021-04-30 10:54:30 -0500206 // Optional inventory_path property. Will be required in future.
207 std::string inventoryPath{"/xyz/openbmc_project/inventory/system/chassis"};
208 auto inventoryPathIt = element.find("inventory_path");
209 if (inventoryPathIt != element.end())
210 {
211 inventoryPath = parseInventoryPath(*inventoryPathIt);
212 ++propertyCount;
213 }
214
Bob King0e701132020-04-03 21:50:31 +0800215 // Optional devices property
216 std::vector<std::unique_ptr<Device>> devices{};
217 auto devicesIt = element.find("devices");
218 if (devicesIt != element.end())
219 {
220 devices = parseDeviceArray(*devicesIt);
221 ++propertyCount;
222 }
223
224 // Verify no invalid properties exist
225 verifyPropertyCount(element, propertyCount);
226
Shawn McCarneycb3f6a62021-04-30 10:54:30 -0500227 return std::make_unique<Chassis>(number, inventoryPath, std::move(devices));
Bob King0e701132020-04-03 21:50:31 +0800228}
229
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500230std::vector<std::unique_ptr<Chassis>> parseChassisArray(const json& element)
231{
232 verifyIsArray(element);
233 std::vector<std::unique_ptr<Chassis>> chassis;
Bob King0e701132020-04-03 21:50:31 +0800234 for (auto& chassisElement : element)
235 {
236 chassis.emplace_back(parseChassis(chassisElement));
237 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500238 return chassis;
239}
240
Bob Kingb267b7e2020-04-22 14:42:39 +0800241std::unique_ptr<ComparePresenceAction> parseComparePresence(const json& element)
242{
243 verifyIsObject(element);
244 unsigned int propertyCount{0};
245
246 // Required fru property
247 const json& fruElement = getRequiredProperty(element, "fru");
Bob Kinga76898f2020-10-13 15:08:33 +0800248 std::string fru = parseInventoryPath(fruElement);
Bob Kingb267b7e2020-04-22 14:42:39 +0800249 ++propertyCount;
250
251 // Required value property
252 const json& valueElement = getRequiredProperty(element, "value");
253 bool value = parseBoolean(valueElement);
254 ++propertyCount;
255
256 // Verify no invalid properties exist
257 verifyPropertyCount(element, propertyCount);
258
259 return std::make_unique<ComparePresenceAction>(fru, value);
260}
261
Bob Kingf2134322020-04-27 14:14:56 +0800262std::unique_ptr<CompareVPDAction> parseCompareVPD(const json& element)
263{
264 verifyIsObject(element);
265 unsigned int propertyCount{0};
266
267 // Required fru property
268 const json& fruElement = getRequiredProperty(element, "fru");
Bob Kinga76898f2020-10-13 15:08:33 +0800269 std::string fru = parseInventoryPath(fruElement);
Bob Kingf2134322020-04-27 14:14:56 +0800270 ++propertyCount;
271
272 // Required keyword property
273 const json& keywordElement = getRequiredProperty(element, "keyword");
274 std::string keyword = parseString(keywordElement);
275 ++propertyCount;
276
Matt Spinleraacc2aa2021-05-25 09:31:35 -0600277 // Either value or byte_values required property
278 auto valueIt = element.find("value");
279 std::vector<uint8_t> value{};
280 auto byteValuesIt = element.find("byte_values");
281 if ((valueIt != element.end()) && (byteValuesIt == element.end()))
282 {
283 std::string stringValue = parseString(*valueIt);
284 value.insert(value.begin(), stringValue.begin(), stringValue.end());
285 ++propertyCount;
286 }
287 else if ((valueIt == element.end()) && (byteValuesIt != element.end()))
288 {
289 value = parseHexByteArray(*byteValuesIt);
290 ++propertyCount;
291 }
292 else
293 {
294 throw std::invalid_argument{
295 "Invalid property: Must contain either value or byte_values"};
296 }
Bob Kingf2134322020-04-27 14:14:56 +0800297
298 // Verify no invalid properties exist
299 verifyPropertyCount(element, propertyCount);
300
301 return std::make_unique<CompareVPDAction>(fru, keyword, value);
302}
303
Bob King33e7eaa2020-04-01 18:09:34 +0800304std::unique_ptr<Configuration> parseConfiguration(const json& element)
305{
306 verifyIsObject(element);
307 unsigned int propertyCount{0};
308
309 // Optional comments property; value not stored
310 if (element.contains("comments"))
311 {
312 ++propertyCount;
313 }
314
315 // Optional volts property
316 std::optional<double> volts{};
317 auto voltsIt = element.find("volts");
318 if (voltsIt != element.end())
319 {
320 volts = parseDouble(*voltsIt);
321 ++propertyCount;
322 }
323
324 // Required rule_id or actions property
325 std::vector<std::unique_ptr<Action>> actions{};
326 actions = parseRuleIDOrActionsProperty(element);
327 ++propertyCount;
328
329 // Verify no invalid properties exist
330 verifyPropertyCount(element, propertyCount);
331
332 return std::make_unique<Configuration>(volts, std::move(actions));
333}
334
Bob King9c36c5f2020-04-06 11:34:09 +0800335std::unique_ptr<Device> parseDevice(const json& element)
336{
337 verifyIsObject(element);
338 unsigned int propertyCount{0};
339
340 // Optional comments property; value not stored
341 if (element.contains("comments"))
342 {
343 ++propertyCount;
344 }
345
346 // Required id property
347 const json& idElement = getRequiredProperty(element, "id");
348 std::string id = parseString(idElement);
349 ++propertyCount;
350
351 // Required is_regulator property
352 const json& isRegulatorElement =
353 getRequiredProperty(element, "is_regulator");
354 bool isRegulator = parseBoolean(isRegulatorElement);
355 ++propertyCount;
356
357 // Required fru property
358 const json& fruElement = getRequiredProperty(element, "fru");
Bob Kinga76898f2020-10-13 15:08:33 +0800359 std::string fru = parseInventoryPath(fruElement);
Bob King9c36c5f2020-04-06 11:34:09 +0800360 ++propertyCount;
361
362 // Required i2c_interface property
363 const json& i2cInterfaceElement =
364 getRequiredProperty(element, "i2c_interface");
365 std::unique_ptr<i2c::I2CInterface> i2cInterface =
366 parseI2CInterface(i2cInterfaceElement);
367 ++propertyCount;
368
369 // Optional presence_detection property
Bob King9c36c5f2020-04-06 11:34:09 +0800370 std::unique_ptr<PresenceDetection> presenceDetection{};
Bob King2aafb1c2020-04-16 15:24:32 +0800371 auto presenceDetectionIt = element.find("presence_detection");
372 if (presenceDetectionIt != element.end())
373 {
374 presenceDetection = parsePresenceDetection(*presenceDetectionIt);
375 ++propertyCount;
376 }
Bob King9c36c5f2020-04-06 11:34:09 +0800377
378 // Optional configuration property
Bob King9c36c5f2020-04-06 11:34:09 +0800379 std::unique_ptr<Configuration> configuration{};
Bob King33e7eaa2020-04-01 18:09:34 +0800380 auto configurationIt = element.find("configuration");
381 if (configurationIt != element.end())
382 {
383 configuration = parseConfiguration(*configurationIt);
384 ++propertyCount;
385 }
Bob King9c36c5f2020-04-06 11:34:09 +0800386
387 // Optional rails property
388 std::vector<std::unique_ptr<Rail>> rails{};
389 auto railsIt = element.find("rails");
390 if (railsIt != element.end())
391 {
392 if (!isRegulator)
393 {
394 throw std::invalid_argument{
395 "Invalid rails property when is_regulator is false"};
396 }
397 rails = parseRailArray(*railsIt);
398 ++propertyCount;
399 }
400
401 // Verify no invalid properties exist
402 verifyPropertyCount(element, propertyCount);
403
404 return std::make_unique<Device>(id, isRegulator, fru,
405 std::move(i2cInterface),
406 std::move(presenceDetection),
407 std::move(configuration), std::move(rails));
408}
409
Bob King0e701132020-04-03 21:50:31 +0800410std::vector<std::unique_ptr<Device>> parseDeviceArray(const json& element)
411{
412 verifyIsArray(element);
413 std::vector<std::unique_ptr<Device>> devices;
Bob King9c36c5f2020-04-06 11:34:09 +0800414 for (auto& deviceElement : element)
415 {
416 devices.emplace_back(parseDevice(deviceElement));
417 }
Bob King0e701132020-04-03 21:50:31 +0800418 return devices;
419}
420
Bob Kingbafcb862020-03-31 16:39:00 +0800421std::vector<uint8_t> parseHexByteArray(const json& element)
422{
423 verifyIsArray(element);
424 std::vector<uint8_t> values;
425 for (auto& valueElement : element)
426 {
427 values.emplace_back(parseHexByte(valueElement));
428 }
429 return values;
430}
431
Bob Kingf09bfe02020-04-13 17:21:15 +0800432std::unique_ptr<I2CCompareBitAction> parseI2CCompareBit(const json& element)
433{
434 verifyIsObject(element);
435 unsigned int propertyCount{0};
436
437 // Required register property
438 const json& regElement = getRequiredProperty(element, "register");
439 uint8_t reg = parseHexByte(regElement);
440 ++propertyCount;
441
442 // Required position property
443 const json& positionElement = getRequiredProperty(element, "position");
444 uint8_t position = parseBitPosition(positionElement);
445 ++propertyCount;
446
447 // Required value property
448 const json& valueElement = getRequiredProperty(element, "value");
449 uint8_t value = parseBitValue(valueElement);
450 ++propertyCount;
451
452 // Verify no invalid properties exist
453 verifyPropertyCount(element, propertyCount);
454
455 return std::make_unique<I2CCompareBitAction>(reg, position, value);
456}
457
458std::unique_ptr<I2CCompareByteAction> parseI2CCompareByte(const json& element)
459{
460 verifyIsObject(element);
461 unsigned int propertyCount{0};
462
463 // Required register property
464 const json& regElement = getRequiredProperty(element, "register");
465 uint8_t reg = parseHexByte(regElement);
466 ++propertyCount;
467
468 // Required value property
469 const json& valueElement = getRequiredProperty(element, "value");
470 uint8_t value = parseHexByte(valueElement);
471 ++propertyCount;
472
473 // Optional mask property
474 uint8_t mask = 0xff;
475 auto maskIt = element.find("mask");
476 if (maskIt != element.end())
477 {
478 mask = parseHexByte(*maskIt);
479 ++propertyCount;
480 }
481
482 // Verify no invalid properties exist
483 verifyPropertyCount(element, propertyCount);
484
485 return std::make_unique<I2CCompareByteAction>(reg, value, mask);
486}
487
488std::unique_ptr<I2CCompareBytesAction> parseI2CCompareBytes(const json& element)
489{
490 verifyIsObject(element);
491 unsigned int propertyCount{0};
492
493 // Required register property
494 const json& regElement = getRequiredProperty(element, "register");
495 uint8_t reg = parseHexByte(regElement);
496 ++propertyCount;
497
498 // Required values property
499 const json& valueElement = getRequiredProperty(element, "values");
500 std::vector<uint8_t> values = parseHexByteArray(valueElement);
501 ++propertyCount;
502
503 // Optional masks property
504 std::vector<uint8_t> masks{};
505 auto masksIt = element.find("masks");
506 if (masksIt != element.end())
507 {
508 masks = parseHexByteArray(*masksIt);
509 ++propertyCount;
510 }
511
512 // Verify masks array (if specified) was same size as values array
513 if ((!masks.empty()) && (masks.size() != values.size()))
514 {
515 throw std::invalid_argument{"Invalid number of elements in masks"};
516 }
517
518 // Verify no invalid properties exist
519 verifyPropertyCount(element, propertyCount);
520
521 if (masks.empty())
522 {
523 return std::make_unique<I2CCompareBytesAction>(reg, values);
524 }
525 return std::make_unique<I2CCompareBytesAction>(reg, values, masks);
526}
527
Bob King9c36c5f2020-04-06 11:34:09 +0800528std::unique_ptr<i2c::I2CInterface> parseI2CInterface(const json& element)
529{
530 verifyIsObject(element);
531 unsigned int propertyCount{0};
532
533 // Required bus property
534 const json& busElement = getRequiredProperty(element, "bus");
535 uint8_t bus = parseUint8(busElement);
536 ++propertyCount;
537
538 // Required address property
539 const json& addressElement = getRequiredProperty(element, "address");
540 uint8_t address = parseHexByte(addressElement);
541 ++propertyCount;
542
543 verifyPropertyCount(element, propertyCount);
544 return i2c::create(bus, address, i2c::I2CInterface::InitialState::CLOSED);
545}
546
Bob Kingf617f892020-03-30 19:03:35 +0800547std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element)
548{
549 verifyIsObject(element);
550 unsigned int propertyCount{0};
551
552 // Required register property
553 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800554 uint8_t reg = parseHexByte(regElement);
Bob Kingf617f892020-03-30 19:03:35 +0800555 ++propertyCount;
556
557 // Required position property
558 const json& positionElement = getRequiredProperty(element, "position");
559 uint8_t position = parseBitPosition(positionElement);
560 ++propertyCount;
561
562 // Required value property
563 const json& valueElement = getRequiredProperty(element, "value");
564 uint8_t value = parseBitValue(valueElement);
565 ++propertyCount;
566
567 // Verify no invalid properties exist
568 verifyPropertyCount(element, propertyCount);
569
570 return std::make_unique<I2CWriteBitAction>(reg, position, value);
571}
572
Bob King87ff9d72020-03-31 14:02:55 +0800573std::unique_ptr<I2CWriteByteAction> parseI2CWriteByte(const json& element)
574{
575 verifyIsObject(element);
576 unsigned int propertyCount{0};
577
578 // Required register property
579 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800580 uint8_t reg = parseHexByte(regElement);
Bob King87ff9d72020-03-31 14:02:55 +0800581 ++propertyCount;
582
583 // Required value property
584 const json& valueElement = getRequiredProperty(element, "value");
Bob Kingbafcb862020-03-31 16:39:00 +0800585 uint8_t value = parseHexByte(valueElement);
Bob King87ff9d72020-03-31 14:02:55 +0800586 ++propertyCount;
587
588 // Optional mask property
589 uint8_t mask = 0xff;
590 auto maskIt = element.find("mask");
591 if (maskIt != element.end())
592 {
Bob Kingbafcb862020-03-31 16:39:00 +0800593 mask = parseHexByte(*maskIt);
Bob King87ff9d72020-03-31 14:02:55 +0800594 ++propertyCount;
595 }
596
597 // Verify no invalid properties exist
598 verifyPropertyCount(element, propertyCount);
599
600 return std::make_unique<I2CWriteByteAction>(reg, value, mask);
601}
602
Bob Kingbafcb862020-03-31 16:39:00 +0800603std::unique_ptr<I2CWriteBytesAction> parseI2CWriteBytes(const json& element)
604{
605 verifyIsObject(element);
606 unsigned int propertyCount{0};
607
608 // Required register property
609 const json& regElement = getRequiredProperty(element, "register");
610 uint8_t reg = parseHexByte(regElement);
611 ++propertyCount;
612
613 // Required values property
614 const json& valueElement = getRequiredProperty(element, "values");
615 std::vector<uint8_t> values = parseHexByteArray(valueElement);
616 ++propertyCount;
617
618 // Optional masks property
619 std::vector<uint8_t> masks{};
620 auto masksIt = element.find("masks");
621 if (masksIt != element.end())
622 {
623 masks = parseHexByteArray(*masksIt);
624 ++propertyCount;
625 }
626
627 // Verify masks array (if specified) was same size as values array
628 if ((!masks.empty()) && (masks.size() != values.size()))
629 {
630 throw std::invalid_argument{"Invalid number of elements in masks"};
631 }
632
633 // Verify no invalid properties exist
634 verifyPropertyCount(element, propertyCount);
635
636 if (masks.empty())
637 {
638 return std::make_unique<I2CWriteBytesAction>(reg, values);
639 }
640 return std::make_unique<I2CWriteBytesAction>(reg, values, masks);
641}
642
Bob King93a89d72020-04-15 15:11:11 +0800643std::unique_ptr<IfAction> parseIf(const json& element)
644{
645 verifyIsObject(element);
646 unsigned int propertyCount{0};
647
648 // Required condition property
649 const json& conditionElement = getRequiredProperty(element, "condition");
650 std::unique_ptr<Action> conditionAction = parseAction(conditionElement);
651 ++propertyCount;
652
653 // Required then property
654 const json& thenElement = getRequiredProperty(element, "then");
655 std::vector<std::unique_ptr<Action>> thenActions =
656 parseActionArray(thenElement);
657 ++propertyCount;
658
659 // Optional else property
660 std::vector<std::unique_ptr<Action>> elseActions{};
661 auto elseIt = element.find("else");
662 if (elseIt != element.end())
663 {
664 elseActions = parseActionArray(*elseIt);
665 ++propertyCount;
666 }
667
668 // Verify no invalid properties exist
669 verifyPropertyCount(element, propertyCount);
670
671 return std::make_unique<IfAction>(std::move(conditionAction),
672 std::move(thenActions),
673 std::move(elseActions));
674}
675
Bob Kinga76898f2020-10-13 15:08:33 +0800676std::string parseInventoryPath(const json& element)
677{
678 std::string inventoryPath = parseString(element);
679 std::string absPath = "/xyz/openbmc_project/inventory";
680 if (inventoryPath.front() != '/')
681 {
682 absPath += '/';
683 }
684 absPath += inventoryPath;
685 return absPath;
686}
687
Bob Kingf1b58dc2020-04-14 14:53:10 +0800688std::unique_ptr<NotAction> parseNot(const json& element)
689{
690 // Required action to execute
691 std::unique_ptr<Action> action = parseAction(element);
692
693 return std::make_unique<NotAction>(std::move(action));
694}
695
Bob King0b51a9b2020-04-15 13:24:18 +0800696std::unique_ptr<OrAction> parseOr(const json& element)
697{
698 verifyIsArray(element);
699
700 // Verify if array size less than 2
701 if (element.size() < 2)
702 {
703 throw std::invalid_argument{"Array must contain two or more actions"};
704 }
705 // Array of two or more actions
706 std::vector<std::unique_ptr<Action>> actions = parseActionArray(element);
707
708 return std::make_unique<OrAction>(std::move(actions));
709}
710
Bob King84614882020-04-30 13:13:48 +0800711std::unique_ptr<PMBusReadSensorAction> parsePMBusReadSensor(const json& element)
712{
713 verifyIsObject(element);
714 unsigned int propertyCount{0};
715
716 // Required type property
717 const json& typeElement = getRequiredProperty(element, "type");
Shawn McCarney2f9e14f2021-04-29 02:45:18 -0500718 SensorType type = parseSensorType(typeElement);
Bob King84614882020-04-30 13:13:48 +0800719 ++propertyCount;
720
721 // Required command property
722 const json& commandElement = getRequiredProperty(element, "command");
723 uint8_t command = parseHexByte(commandElement);
724 ++propertyCount;
725
726 // Required format property
727 const json& formatElement = getRequiredProperty(element, "format");
728 pmbus_utils::SensorDataFormat format = parseSensorDataFormat(formatElement);
729 ++propertyCount;
730
731 // Optional exponent property
732 std::optional<int8_t> exponent{};
733 auto exponentIt = element.find("exponent");
734 if (exponentIt != element.end())
735 {
736 exponent = parseInt8(*exponentIt);
737 ++propertyCount;
738 }
739
740 // Verify no invalid properties exist
741 verifyPropertyCount(element, propertyCount);
742
743 return std::make_unique<PMBusReadSensorAction>(type, command, format,
744 exponent);
745}
746
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500747std::unique_ptr<PMBusWriteVoutCommandAction>
748 parsePMBusWriteVoutCommand(const json& element)
749{
750 verifyIsObject(element);
751 unsigned int propertyCount{0};
752
753 // Optional volts property
754 std::optional<double> volts{};
755 auto voltsIt = element.find("volts");
756 if (voltsIt != element.end())
757 {
758 volts = parseDouble(*voltsIt);
759 ++propertyCount;
760 }
761
762 // Required format property
763 const json& formatElement = getRequiredProperty(element, "format");
764 std::string formatString = parseString(formatElement);
765 if (formatString != "linear")
766 {
767 throw std::invalid_argument{"Invalid format value: " + formatString};
768 }
769 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear;
770 ++propertyCount;
771
772 // Optional exponent property
773 std::optional<int8_t> exponent{};
774 auto exponentIt = element.find("exponent");
775 if (exponentIt != element.end())
776 {
777 exponent = parseInt8(*exponentIt);
778 ++propertyCount;
779 }
780
781 // Optional is_verified property
782 bool isVerified = false;
783 auto isVerifiedIt = element.find("is_verified");
784 if (isVerifiedIt != element.end())
785 {
786 isVerified = parseBoolean(*isVerifiedIt);
787 ++propertyCount;
788 }
789
790 // Verify no invalid properties exist
791 verifyPropertyCount(element, propertyCount);
792
793 return std::make_unique<PMBusWriteVoutCommandAction>(volts, format,
794 exponent, isVerified);
795}
796
Bob King2aafb1c2020-04-16 15:24:32 +0800797std::unique_ptr<PresenceDetection> parsePresenceDetection(const json& element)
798{
799 verifyIsObject(element);
800 unsigned int propertyCount{0};
801
802 // Optional comments property; value not stored
803 if (element.contains("comments"))
804 {
805 ++propertyCount;
806 }
807
808 // Required rule_id or actions property
809 std::vector<std::unique_ptr<Action>> actions{};
810 actions = parseRuleIDOrActionsProperty(element);
811 ++propertyCount;
812
813 // Verify no invalid properties exist
814 verifyPropertyCount(element, propertyCount);
815
816 return std::make_unique<PresenceDetection>(std::move(actions));
817}
818
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800819std::unique_ptr<Rail> parseRail(const json& element)
820{
821 verifyIsObject(element);
822 unsigned int propertyCount{0};
823
824 // Optional comments property; value not stored
825 if (element.contains("comments"))
826 {
827 ++propertyCount;
828 }
829
830 // Required id property
831 const json& idElement = getRequiredProperty(element, "id");
832 std::string id = parseString(idElement);
833 ++propertyCount;
834
835 // Optional configuration property
836 std::unique_ptr<Configuration> configuration{};
837 auto configurationIt = element.find("configuration");
838 if (configurationIt != element.end())
839 {
840 configuration = parseConfiguration(*configurationIt);
841 ++propertyCount;
842 }
843
844 // Optional sensor_monitoring property
845 std::unique_ptr<SensorMonitoring> sensorMonitoring{};
846 auto sensorMonitoringIt = element.find("sensor_monitoring");
847 if (sensorMonitoringIt != element.end())
848 {
849 sensorMonitoring = parseSensorMonitoring(*sensorMonitoringIt);
850 ++propertyCount;
851 }
852
853 // Verify no invalid properties exist
854 verifyPropertyCount(element, propertyCount);
855
856 return std::make_unique<Rail>(id, std::move(configuration),
857 std::move(sensorMonitoring));
858}
859
Bob King9c36c5f2020-04-06 11:34:09 +0800860std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element)
861{
862 verifyIsArray(element);
863 std::vector<std::unique_ptr<Rail>> rails;
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800864 for (auto& railElement : element)
865 {
866 rails.emplace_back(parseRail(railElement));
867 }
Bob King9c36c5f2020-04-06 11:34:09 +0800868 return rails;
869}
870
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500871std::tuple<std::vector<std::unique_ptr<Rule>>,
872 std::vector<std::unique_ptr<Chassis>>>
873 parseRoot(const json& element)
874{
875 verifyIsObject(element);
876 unsigned int propertyCount{0};
877
878 // Optional comments property; value not stored
879 if (element.contains("comments"))
880 {
881 ++propertyCount;
882 }
883
884 // Optional rules property
885 std::vector<std::unique_ptr<Rule>> rules{};
886 auto rulesIt = element.find("rules");
887 if (rulesIt != element.end())
888 {
889 rules = parseRuleArray(*rulesIt);
890 ++propertyCount;
891 }
892
893 // Required chassis property
894 const json& chassisElement = getRequiredProperty(element, "chassis");
895 std::vector<std::unique_ptr<Chassis>> chassis =
896 parseChassisArray(chassisElement);
897 ++propertyCount;
898
899 // Verify no invalid properties exist
900 verifyPropertyCount(element, propertyCount);
901
902 return std::make_tuple(std::move(rules), std::move(chassis));
903}
904
905std::unique_ptr<Rule> parseRule(const json& element)
906{
907 verifyIsObject(element);
908 unsigned int propertyCount{0};
909
910 // Optional comments property; value not stored
911 if (element.contains("comments"))
912 {
913 ++propertyCount;
914 }
915
916 // Required id property
917 const json& idElement = getRequiredProperty(element, "id");
918 std::string id = parseString(idElement);
919 ++propertyCount;
920
921 // Required actions property
922 const json& actionsElement = getRequiredProperty(element, "actions");
923 std::vector<std::unique_ptr<Action>> actions =
924 parseActionArray(actionsElement);
925 ++propertyCount;
926
927 // Verify no invalid properties exist
928 verifyPropertyCount(element, propertyCount);
929
930 return std::make_unique<Rule>(id, std::move(actions));
931}
932
933std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element)
934{
935 verifyIsArray(element);
936 std::vector<std::unique_ptr<Rule>> rules;
937 for (auto& ruleElement : element)
938 {
939 rules.emplace_back(parseRule(ruleElement));
940 }
941 return rules;
942}
943
Bob King33e7eaa2020-04-01 18:09:34 +0800944std::vector<std::unique_ptr<Action>>
945 parseRuleIDOrActionsProperty(const json& element)
946{
947 verifyIsObject(element);
948 // Required rule_id or actions property
949 std::vector<std::unique_ptr<Action>> actions{};
950 auto ruleIDIt = element.find("rule_id");
951 auto actionsIt = element.find("actions");
952 if ((actionsIt == element.end()) && (ruleIDIt != element.end()))
953 {
954 std::string ruleID = parseString(*ruleIDIt);
955 actions.emplace_back(std::make_unique<RunRuleAction>(ruleID));
956 }
957 else if ((actionsIt != element.end()) && (ruleIDIt == element.end()))
958 {
959 actions = parseActionArray(*actionsIt);
960 }
961 else
962 {
963 throw std::invalid_argument{"Invalid property combination: Must "
964 "contain either rule_id or actions"};
965 }
966
967 return actions;
968}
969
Bob King315b0b62020-04-03 21:47:58 +0800970std::unique_ptr<RunRuleAction> parseRunRule(const json& element)
971{
972 // String ruleID
973 std::string ruleID = parseString(element);
974
975 return std::make_unique<RunRuleAction>(ruleID);
976}
977
Bob King84614882020-04-30 13:13:48 +0800978pmbus_utils::SensorDataFormat parseSensorDataFormat(const json& element)
979{
980 if (!element.is_string())
981 {
982 throw std::invalid_argument{"Element is not a string"};
983 }
984 std::string value = element.get<std::string>();
985 pmbus_utils::SensorDataFormat format{};
986
987 if (value == "linear_11")
988 {
989 format = pmbus_utils::SensorDataFormat::linear_11;
990 }
991 else if (value == "linear_16")
992 {
993 format = pmbus_utils::SensorDataFormat::linear_16;
994 }
995 else
996 {
997 throw std::invalid_argument{"Element is not a sensor data format"};
998 }
999
1000 return format;
1001}
1002
Bob Kinga2f2a0d2020-04-09 13:32:14 +08001003std::unique_ptr<SensorMonitoring> parseSensorMonitoring(const json& element)
1004{
1005 verifyIsObject(element);
1006 unsigned int propertyCount{0};
1007
1008 // Optional comments property; value not stored
1009 if (element.contains("comments"))
1010 {
1011 ++propertyCount;
1012 }
1013
1014 // Required rule_id or actions property
1015 std::vector<std::unique_ptr<Action>> actions{};
1016 actions = parseRuleIDOrActionsProperty(element);
1017 ++propertyCount;
1018
1019 // Verify no invalid properties exist
1020 verifyPropertyCount(element, propertyCount);
1021
1022 return std::make_unique<SensorMonitoring>(std::move(actions));
1023}
1024
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001025SensorType parseSensorType(const json& element)
Bob King84614882020-04-30 13:13:48 +08001026{
1027 if (!element.is_string())
1028 {
1029 throw std::invalid_argument{"Element is not a string"};
1030 }
1031 std::string value = element.get<std::string>();
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001032 SensorType type{};
Bob King84614882020-04-30 13:13:48 +08001033
1034 if (value == "iout")
1035 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001036 type = SensorType::iout;
Bob King84614882020-04-30 13:13:48 +08001037 }
1038 else if (value == "iout_peak")
1039 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001040 type = SensorType::iout_peak;
Bob King84614882020-04-30 13:13:48 +08001041 }
1042 else if (value == "iout_valley")
1043 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001044 type = SensorType::iout_valley;
Bob King84614882020-04-30 13:13:48 +08001045 }
1046 else if (value == "pout")
1047 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001048 type = SensorType::pout;
Bob King84614882020-04-30 13:13:48 +08001049 }
1050 else if (value == "temperature")
1051 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001052 type = SensorType::temperature;
Bob King84614882020-04-30 13:13:48 +08001053 }
1054 else if (value == "temperature_peak")
1055 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001056 type = SensorType::temperature_peak;
Bob King84614882020-04-30 13:13:48 +08001057 }
1058 else if (value == "vout")
1059 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001060 type = SensorType::vout;
Bob King84614882020-04-30 13:13:48 +08001061 }
1062 else if (value == "vout_peak")
1063 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001064 type = SensorType::vout_peak;
Bob King84614882020-04-30 13:13:48 +08001065 }
1066 else if (value == "vout_valley")
1067 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001068 type = SensorType::vout_valley;
Bob King84614882020-04-30 13:13:48 +08001069 }
1070 else
1071 {
Shawn McCarney2f9e14f2021-04-29 02:45:18 -05001072 throw std::invalid_argument{"Element is not a sensor type"};
Bob King84614882020-04-30 13:13:48 +08001073 }
1074
1075 return type;
1076}
1077
Bob King18a68502020-04-17 14:19:56 +08001078std::unique_ptr<SetDeviceAction> parseSetDevice(const json& element)
1079{
1080 // String deviceID
1081 std::string deviceID = parseString(element);
1082
1083 return std::make_unique<SetDeviceAction>(deviceID);
1084}
1085
Bob King84614882020-04-30 13:13:48 +08001086pmbus_utils::VoutDataFormat parseVoutDataFormat(const json& element)
1087{
1088 if (!element.is_string())
1089 {
1090 throw std::invalid_argument{"Element is not a string"};
1091 }
1092 std::string value = element.get<std::string>();
1093 pmbus_utils::VoutDataFormat format{};
1094
1095 if (value == "linear")
1096 {
1097 format = pmbus_utils::VoutDataFormat::linear;
1098 }
1099 else if (value == "vid")
1100 {
1101 format = pmbus_utils::VoutDataFormat::vid;
1102 }
1103 else if (value == "direct")
1104 {
1105 format = pmbus_utils::VoutDataFormat::direct;
1106 }
1107 else if (value == "ieee")
1108 {
1109 format = pmbus_utils::VoutDataFormat::ieee;
1110 }
1111 else
1112 {
1113 throw std::invalid_argument{"Element is not a vout data format"};
1114 }
1115
1116 return format;
1117}
1118
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05001119} // namespace internal
1120
1121} // namespace phosphor::power::regulators::config_file_parser