1 /**
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"
20 #include "i2c_interface.hpp"
21 #include "pmbus_utils.hpp"
22
23 #include <exception>
24 #include <fstream>
25 #include <optional>
26 #include <utility>
27
28 using json = nlohmann::json;
29
30 namespace phosphor::power::regulators::config_file_parser
31 {
32
33 std::tuple<std::vector<std::unique_ptr<Rule>>,
34 std::vector<std::unique_ptr<Chassis>>>
parse(const std::filesystem::path & pathName)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
52 namespace internal
53 {
54
parseAction(const json & element)55 std::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 {
70 action = parseAnd(element["and"]);
71 ++propertyCount;
72 }
73 else if (element.contains("compare_presence"))
74 {
75 action = parseComparePresence(element["compare_presence"]);
76 ++propertyCount;
77 }
78 else if (element.contains("compare_vpd"))
79 {
80 action = parseCompareVPD(element["compare_vpd"]);
81 ++propertyCount;
82 }
83 else if (element.contains("i2c_capture_bytes"))
84 {
85 action = parseI2CCaptureBytes(element["i2c_capture_bytes"]);
86 ++propertyCount;
87 }
88 else if (element.contains("i2c_compare_bit"))
89 {
90 action = parseI2CCompareBit(element["i2c_compare_bit"]);
91 ++propertyCount;
92 }
93 else if (element.contains("i2c_compare_byte"))
94 {
95 action = parseI2CCompareByte(element["i2c_compare_byte"]);
96 ++propertyCount;
97 }
98 else if (element.contains("i2c_compare_bytes"))
99 {
100 action = parseI2CCompareBytes(element["i2c_compare_bytes"]);
101 ++propertyCount;
102 }
103 else if (element.contains("i2c_write_bit"))
104 {
105 action = parseI2CWriteBit(element["i2c_write_bit"]);
106 ++propertyCount;
107 }
108 else if (element.contains("i2c_write_byte"))
109 {
110 action = parseI2CWriteByte(element["i2c_write_byte"]);
111 ++propertyCount;
112 }
113 else if (element.contains("i2c_write_bytes"))
114 {
115 action = parseI2CWriteBytes(element["i2c_write_bytes"]);
116 ++propertyCount;
117 }
118 else if (element.contains("if"))
119 {
120 action = parseIf(element["if"]);
121 ++propertyCount;
122 }
123 else if (element.contains("log_phase_fault"))
124 {
125 action = parseLogPhaseFault(element["log_phase_fault"]);
126 ++propertyCount;
127 }
128 else if (element.contains("not"))
129 {
130 action = parseNot(element["not"]);
131 ++propertyCount;
132 }
133 else if (element.contains("or"))
134 {
135 action = parseOr(element["or"]);
136 ++propertyCount;
137 }
138 else if (element.contains("pmbus_read_sensor"))
139 {
140 action = parsePMBusReadSensor(element["pmbus_read_sensor"]);
141 ++propertyCount;
142 }
143 else if (element.contains("pmbus_write_vout_command"))
144 {
145 action =
146 parsePMBusWriteVoutCommand(element["pmbus_write_vout_command"]);
147 ++propertyCount;
148 }
149 else if (element.contains("run_rule"))
150 {
151 action = parseRunRule(element["run_rule"]);
152 ++propertyCount;
153 }
154 else if (element.contains("set_device"))
155 {
156 action = parseSetDevice(element["set_device"]);
157 ++propertyCount;
158 }
159 else
160 {
161 throw std::invalid_argument{"Required action type property missing"};
162 }
163
164 // Verify no invalid properties exist
165 verifyPropertyCount(element, propertyCount);
166
167 return action;
168 }
169
parseActionArray(const json & element)170 std::vector<std::unique_ptr<Action>> parseActionArray(const json& element)
171 {
172 verifyIsArray(element);
173 std::vector<std::unique_ptr<Action>> actions;
174 for (auto& actionElement : element)
175 {
176 actions.emplace_back(parseAction(actionElement));
177 }
178 return actions;
179 }
180
parseAnd(const json & element)181 std::unique_ptr<AndAction> parseAnd(const json& element)
182 {
183 verifyIsArray(element);
184
185 // Verify if array size less than 2
186 if (element.size() < 2)
187 {
188 throw std::invalid_argument{"Array must contain two or more actions"};
189 }
190 // Array of two or more actions
191 std::vector<std::unique_ptr<Action>> actions = parseActionArray(element);
192
193 return std::make_unique<AndAction>(std::move(actions));
194 }
195
parseChassis(const json & element)196 std::unique_ptr<Chassis> parseChassis(const json& element)
197 {
198 verifyIsObject(element);
199 unsigned int propertyCount{0};
200
201 // Optional comments property; value not stored
202 if (element.contains("comments"))
203 {
204 ++propertyCount;
205 }
206
207 // Required number property
208 const json& numberElement = getRequiredProperty(element, "number");
209 unsigned int number = parseUnsignedInteger(numberElement);
210 if (number < 1)
211 {
212 throw std::invalid_argument{"Invalid chassis number: Must be > 0"};
213 }
214 ++propertyCount;
215
216 // Required inventory_path property
217 const json& inventoryPathElement =
218 getRequiredProperty(element, "inventory_path");
219 std::string inventoryPath = parseInventoryPath(inventoryPathElement);
220 ++propertyCount;
221
222 // Optional devices property
223 std::vector<std::unique_ptr<Device>> devices{};
224 auto devicesIt = element.find("devices");
225 if (devicesIt != element.end())
226 {
227 devices = parseDeviceArray(*devicesIt);
228 ++propertyCount;
229 }
230
231 // Verify no invalid properties exist
232 verifyPropertyCount(element, propertyCount);
233
234 return std::make_unique<Chassis>(number, inventoryPath, std::move(devices));
235 }
236
parseChassisArray(const json & element)237 std::vector<std::unique_ptr<Chassis>> parseChassisArray(const json& element)
238 {
239 verifyIsArray(element);
240 std::vector<std::unique_ptr<Chassis>> chassis;
241 for (auto& chassisElement : element)
242 {
243 chassis.emplace_back(parseChassis(chassisElement));
244 }
245 return chassis;
246 }
247
parseComparePresence(const json & element)248 std::unique_ptr<ComparePresenceAction> parseComparePresence(const json& element)
249 {
250 verifyIsObject(element);
251 unsigned int propertyCount{0};
252
253 // Required fru property
254 const json& fruElement = getRequiredProperty(element, "fru");
255 std::string fru = parseInventoryPath(fruElement);
256 ++propertyCount;
257
258 // Required value property
259 const json& valueElement = getRequiredProperty(element, "value");
260 bool value = parseBoolean(valueElement);
261 ++propertyCount;
262
263 // Verify no invalid properties exist
264 verifyPropertyCount(element, propertyCount);
265
266 return std::make_unique<ComparePresenceAction>(fru, value);
267 }
268
parseCompareVPD(const json & element)269 std::unique_ptr<CompareVPDAction> parseCompareVPD(const json& element)
270 {
271 verifyIsObject(element);
272 unsigned int propertyCount{0};
273
274 // Required fru property
275 const json& fruElement = getRequiredProperty(element, "fru");
276 std::string fru = parseInventoryPath(fruElement);
277 ++propertyCount;
278
279 // Required keyword property
280 const json& keywordElement = getRequiredProperty(element, "keyword");
281 std::string keyword = parseString(keywordElement);
282 ++propertyCount;
283
284 // Either value or byte_values required property
285 auto valueIt = element.find("value");
286 std::vector<uint8_t> value{};
287 auto byteValuesIt = element.find("byte_values");
288 if ((valueIt != element.end()) && (byteValuesIt == element.end()))
289 {
290 std::string stringValue = parseString(*valueIt, true);
291 value.insert(value.begin(), stringValue.begin(), stringValue.end());
292 ++propertyCount;
293 }
294 else if ((valueIt == element.end()) && (byteValuesIt != element.end()))
295 {
296 value = parseHexByteArray(*byteValuesIt);
297 ++propertyCount;
298 }
299 else
300 {
301 throw std::invalid_argument{
302 "Invalid property: Must contain either value or byte_values"};
303 }
304
305 // Verify no invalid properties exist
306 verifyPropertyCount(element, propertyCount);
307
308 return std::make_unique<CompareVPDAction>(fru, keyword, value);
309 }
310
parseConfiguration(const json & element)311 std::unique_ptr<Configuration> parseConfiguration(const json& element)
312 {
313 verifyIsObject(element);
314 unsigned int propertyCount{0};
315
316 // Optional comments property; value not stored
317 if (element.contains("comments"))
318 {
319 ++propertyCount;
320 }
321
322 // Optional volts property
323 std::optional<double> volts{};
324 auto voltsIt = element.find("volts");
325 if (voltsIt != element.end())
326 {
327 volts = parseDouble(*voltsIt);
328 ++propertyCount;
329 }
330
331 // Required rule_id or actions property
332 std::vector<std::unique_ptr<Action>> actions{};
333 actions = parseRuleIDOrActionsProperty(element);
334 ++propertyCount;
335
336 // Verify no invalid properties exist
337 verifyPropertyCount(element, propertyCount);
338
339 return std::make_unique<Configuration>(volts, std::move(actions));
340 }
341
parseDevice(const json & element)342 std::unique_ptr<Device> parseDevice(const json& element)
343 {
344 verifyIsObject(element);
345 unsigned int propertyCount{0};
346
347 // Optional comments property; value not stored
348 if (element.contains("comments"))
349 {
350 ++propertyCount;
351 }
352
353 // Required id property
354 const json& idElement = getRequiredProperty(element, "id");
355 std::string id = parseString(idElement);
356 ++propertyCount;
357
358 // Required is_regulator property
359 const json& isRegulatorElement =
360 getRequiredProperty(element, "is_regulator");
361 bool isRegulator = parseBoolean(isRegulatorElement);
362 ++propertyCount;
363
364 // Required fru property
365 const json& fruElement = getRequiredProperty(element, "fru");
366 std::string fru = parseInventoryPath(fruElement);
367 ++propertyCount;
368
369 // Required i2c_interface property
370 const json& i2cInterfaceElement =
371 getRequiredProperty(element, "i2c_interface");
372 std::unique_ptr<i2c::I2CInterface> i2cInterface =
373 parseI2CInterface(i2cInterfaceElement);
374 ++propertyCount;
375
376 // Optional presence_detection property
377 std::unique_ptr<PresenceDetection> presenceDetection{};
378 auto presenceDetectionIt = element.find("presence_detection");
379 if (presenceDetectionIt != element.end())
380 {
381 presenceDetection = parsePresenceDetection(*presenceDetectionIt);
382 ++propertyCount;
383 }
384
385 // Optional configuration property
386 std::unique_ptr<Configuration> configuration{};
387 auto configurationIt = element.find("configuration");
388 if (configurationIt != element.end())
389 {
390 configuration = parseConfiguration(*configurationIt);
391 ++propertyCount;
392 }
393
394 // Optional phase_fault_detection property
395 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
396 auto phaseFaultDetectionIt = element.find("phase_fault_detection");
397 if (phaseFaultDetectionIt != element.end())
398 {
399 if (!isRegulator)
400 {
401 throw std::invalid_argument{"Invalid phase_fault_detection "
402 "property when is_regulator is false"};
403 }
404 phaseFaultDetection = parsePhaseFaultDetection(*phaseFaultDetectionIt);
405 ++propertyCount;
406 }
407
408 // Optional rails property
409 std::vector<std::unique_ptr<Rail>> rails{};
410 auto railsIt = element.find("rails");
411 if (railsIt != element.end())
412 {
413 if (!isRegulator)
414 {
415 throw std::invalid_argument{
416 "Invalid rails property when is_regulator is false"};
417 }
418 rails = parseRailArray(*railsIt);
419 ++propertyCount;
420 }
421
422 // Verify no invalid properties exist
423 verifyPropertyCount(element, propertyCount);
424
425 return std::make_unique<Device>(
426 id, isRegulator, fru, std::move(i2cInterface),
427 std::move(presenceDetection), std::move(configuration),
428 std::move(phaseFaultDetection), std::move(rails));
429 }
430
parseDeviceArray(const json & element)431 std::vector<std::unique_ptr<Device>> parseDeviceArray(const json& element)
432 {
433 verifyIsArray(element);
434 std::vector<std::unique_ptr<Device>> devices;
435 for (auto& deviceElement : element)
436 {
437 devices.emplace_back(parseDevice(deviceElement));
438 }
439 return devices;
440 }
441
parseHexByteArray(const json & element)442 std::vector<uint8_t> parseHexByteArray(const json& element)
443 {
444 verifyIsArray(element);
445 std::vector<uint8_t> values;
446 for (auto& valueElement : element)
447 {
448 values.emplace_back(parseHexByte(valueElement));
449 }
450 return values;
451 }
452
parseI2CCaptureBytes(const json & element)453 std::unique_ptr<I2CCaptureBytesAction> parseI2CCaptureBytes(const json& element)
454 {
455 verifyIsObject(element);
456 unsigned int propertyCount{0};
457
458 // Required register property
459 const json& regElement = getRequiredProperty(element, "register");
460 uint8_t reg = parseHexByte(regElement);
461 ++propertyCount;
462
463 // Required count property
464 const json& countElement = getRequiredProperty(element, "count");
465 uint8_t count = parseUint8(countElement);
466 if (count < 1)
467 {
468 throw std::invalid_argument{"Invalid byte count: Must be > 0"};
469 }
470 ++propertyCount;
471
472 // Verify no invalid properties exist
473 verifyPropertyCount(element, propertyCount);
474
475 return std::make_unique<I2CCaptureBytesAction>(reg, count);
476 }
477
parseI2CCompareBit(const json & element)478 std::unique_ptr<I2CCompareBitAction> parseI2CCompareBit(const json& element)
479 {
480 verifyIsObject(element);
481 unsigned int propertyCount{0};
482
483 // Required register property
484 const json& regElement = getRequiredProperty(element, "register");
485 uint8_t reg = parseHexByte(regElement);
486 ++propertyCount;
487
488 // Required position property
489 const json& positionElement = getRequiredProperty(element, "position");
490 uint8_t position = parseBitPosition(positionElement);
491 ++propertyCount;
492
493 // Required value property
494 const json& valueElement = getRequiredProperty(element, "value");
495 uint8_t value = parseBitValue(valueElement);
496 ++propertyCount;
497
498 // Verify no invalid properties exist
499 verifyPropertyCount(element, propertyCount);
500
501 return std::make_unique<I2CCompareBitAction>(reg, position, value);
502 }
503
parseI2CCompareByte(const json & element)504 std::unique_ptr<I2CCompareByteAction> parseI2CCompareByte(const json& element)
505 {
506 verifyIsObject(element);
507 unsigned int propertyCount{0};
508
509 // Required register property
510 const json& regElement = getRequiredProperty(element, "register");
511 uint8_t reg = parseHexByte(regElement);
512 ++propertyCount;
513
514 // Required value property
515 const json& valueElement = getRequiredProperty(element, "value");
516 uint8_t value = parseHexByte(valueElement);
517 ++propertyCount;
518
519 // Optional mask property
520 uint8_t mask = 0xff;
521 auto maskIt = element.find("mask");
522 if (maskIt != element.end())
523 {
524 mask = parseHexByte(*maskIt);
525 ++propertyCount;
526 }
527
528 // Verify no invalid properties exist
529 verifyPropertyCount(element, propertyCount);
530
531 return std::make_unique<I2CCompareByteAction>(reg, value, mask);
532 }
533
parseI2CCompareBytes(const json & element)534 std::unique_ptr<I2CCompareBytesAction> parseI2CCompareBytes(const json& element)
535 {
536 verifyIsObject(element);
537 unsigned int propertyCount{0};
538
539 // Required register property
540 const json& regElement = getRequiredProperty(element, "register");
541 uint8_t reg = parseHexByte(regElement);
542 ++propertyCount;
543
544 // Required values property
545 const json& valueElement = getRequiredProperty(element, "values");
546 std::vector<uint8_t> values = parseHexByteArray(valueElement);
547 ++propertyCount;
548
549 // Optional masks property
550 std::vector<uint8_t> masks{};
551 auto masksIt = element.find("masks");
552 if (masksIt != element.end())
553 {
554 masks = parseHexByteArray(*masksIt);
555 ++propertyCount;
556 }
557
558 // Verify masks array (if specified) was same size as values array
559 if ((!masks.empty()) && (masks.size() != values.size()))
560 {
561 throw std::invalid_argument{"Invalid number of elements in masks"};
562 }
563
564 // Verify no invalid properties exist
565 verifyPropertyCount(element, propertyCount);
566
567 if (masks.empty())
568 {
569 return std::make_unique<I2CCompareBytesAction>(reg, values);
570 }
571 return std::make_unique<I2CCompareBytesAction>(reg, values, masks);
572 }
573
parseI2CInterface(const json & element)574 std::unique_ptr<i2c::I2CInterface> parseI2CInterface(const json& element)
575 {
576 verifyIsObject(element);
577 unsigned int propertyCount{0};
578
579 // Required bus property
580 const json& busElement = getRequiredProperty(element, "bus");
581 uint8_t bus = parseUint8(busElement);
582 ++propertyCount;
583
584 // Required address property
585 const json& addressElement = getRequiredProperty(element, "address");
586 uint8_t address = parseHexByte(addressElement);
587 ++propertyCount;
588
589 // Verify no invalid properties exist
590 verifyPropertyCount(element, propertyCount);
591
592 // Create I2CInterface object; retry failed I2C operations a max of 3 times.
593 int maxRetries{3};
594 return i2c::create(bus, address, i2c::I2CInterface::InitialState::CLOSED,
595 maxRetries);
596 }
597
parseI2CWriteBit(const json & element)598 std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element)
599 {
600 verifyIsObject(element);
601 unsigned int propertyCount{0};
602
603 // Required register property
604 const json& regElement = getRequiredProperty(element, "register");
605 uint8_t reg = parseHexByte(regElement);
606 ++propertyCount;
607
608 // Required position property
609 const json& positionElement = getRequiredProperty(element, "position");
610 uint8_t position = parseBitPosition(positionElement);
611 ++propertyCount;
612
613 // Required value property
614 const json& valueElement = getRequiredProperty(element, "value");
615 uint8_t value = parseBitValue(valueElement);
616 ++propertyCount;
617
618 // Verify no invalid properties exist
619 verifyPropertyCount(element, propertyCount);
620
621 return std::make_unique<I2CWriteBitAction>(reg, position, value);
622 }
623
parseI2CWriteByte(const json & element)624 std::unique_ptr<I2CWriteByteAction> parseI2CWriteByte(const json& element)
625 {
626 verifyIsObject(element);
627 unsigned int propertyCount{0};
628
629 // Required register property
630 const json& regElement = getRequiredProperty(element, "register");
631 uint8_t reg = parseHexByte(regElement);
632 ++propertyCount;
633
634 // Required value property
635 const json& valueElement = getRequiredProperty(element, "value");
636 uint8_t value = parseHexByte(valueElement);
637 ++propertyCount;
638
639 // Optional mask property
640 uint8_t mask = 0xff;
641 auto maskIt = element.find("mask");
642 if (maskIt != element.end())
643 {
644 mask = parseHexByte(*maskIt);
645 ++propertyCount;
646 }
647
648 // Verify no invalid properties exist
649 verifyPropertyCount(element, propertyCount);
650
651 return std::make_unique<I2CWriteByteAction>(reg, value, mask);
652 }
653
parseI2CWriteBytes(const json & element)654 std::unique_ptr<I2CWriteBytesAction> parseI2CWriteBytes(const json& element)
655 {
656 verifyIsObject(element);
657 unsigned int propertyCount{0};
658
659 // Required register property
660 const json& regElement = getRequiredProperty(element, "register");
661 uint8_t reg = parseHexByte(regElement);
662 ++propertyCount;
663
664 // Required values property
665 const json& valueElement = getRequiredProperty(element, "values");
666 std::vector<uint8_t> values = parseHexByteArray(valueElement);
667 ++propertyCount;
668
669 // Optional masks property
670 std::vector<uint8_t> masks{};
671 auto masksIt = element.find("masks");
672 if (masksIt != element.end())
673 {
674 masks = parseHexByteArray(*masksIt);
675 ++propertyCount;
676 }
677
678 // Verify masks array (if specified) was same size as values array
679 if ((!masks.empty()) && (masks.size() != values.size()))
680 {
681 throw std::invalid_argument{"Invalid number of elements in masks"};
682 }
683
684 // Verify no invalid properties exist
685 verifyPropertyCount(element, propertyCount);
686
687 if (masks.empty())
688 {
689 return std::make_unique<I2CWriteBytesAction>(reg, values);
690 }
691 return std::make_unique<I2CWriteBytesAction>(reg, values, masks);
692 }
693
parseIf(const json & element)694 std::unique_ptr<IfAction> parseIf(const json& element)
695 {
696 verifyIsObject(element);
697 unsigned int propertyCount{0};
698
699 // Required condition property
700 const json& conditionElement = getRequiredProperty(element, "condition");
701 std::unique_ptr<Action> conditionAction = parseAction(conditionElement);
702 ++propertyCount;
703
704 // Required then property
705 const json& thenElement = getRequiredProperty(element, "then");
706 std::vector<std::unique_ptr<Action>> thenActions =
707 parseActionArray(thenElement);
708 ++propertyCount;
709
710 // Optional else property
711 std::vector<std::unique_ptr<Action>> elseActions{};
712 auto elseIt = element.find("else");
713 if (elseIt != element.end())
714 {
715 elseActions = parseActionArray(*elseIt);
716 ++propertyCount;
717 }
718
719 // Verify no invalid properties exist
720 verifyPropertyCount(element, propertyCount);
721
722 return std::make_unique<IfAction>(std::move(conditionAction),
723 std::move(thenActions),
724 std::move(elseActions));
725 }
726
parseInventoryPath(const json & element)727 std::string parseInventoryPath(const json& element)
728 {
729 std::string inventoryPath = parseString(element);
730 std::string absPath = "/xyz/openbmc_project/inventory";
731 if (inventoryPath.front() != '/')
732 {
733 absPath += '/';
734 }
735 absPath += inventoryPath;
736 return absPath;
737 }
738
parseLogPhaseFault(const json & element)739 std::unique_ptr<LogPhaseFaultAction> parseLogPhaseFault(const json& element)
740 {
741 verifyIsObject(element);
742 unsigned int propertyCount{0};
743
744 // Required type property
745 const json& typeElement = getRequiredProperty(element, "type");
746 PhaseFaultType type = parsePhaseFaultType(typeElement);
747 ++propertyCount;
748
749 // Verify no invalid properties exist
750 verifyPropertyCount(element, propertyCount);
751
752 return std::make_unique<LogPhaseFaultAction>(type);
753 }
754
parseNot(const json & element)755 std::unique_ptr<NotAction> parseNot(const json& element)
756 {
757 // Required action to execute
758 std::unique_ptr<Action> action = parseAction(element);
759
760 return std::make_unique<NotAction>(std::move(action));
761 }
762
parseOr(const json & element)763 std::unique_ptr<OrAction> parseOr(const json& element)
764 {
765 verifyIsArray(element);
766
767 // Verify if array size less than 2
768 if (element.size() < 2)
769 {
770 throw std::invalid_argument{"Array must contain two or more actions"};
771 }
772 // Array of two or more actions
773 std::vector<std::unique_ptr<Action>> actions = parseActionArray(element);
774
775 return std::make_unique<OrAction>(std::move(actions));
776 }
777
778 std::unique_ptr<PhaseFaultDetection>
parsePhaseFaultDetection(const json & element)779 parsePhaseFaultDetection(const json& element)
780 {
781 verifyIsObject(element);
782 unsigned int propertyCount{0};
783
784 // Optional comments property; value not stored
785 if (element.contains("comments"))
786 {
787 ++propertyCount;
788 }
789
790 // Optional device_id property
791 std::string deviceID{};
792 auto deviceIDIt = element.find("device_id");
793 if (deviceIDIt != element.end())
794 {
795 deviceID = parseString(*deviceIDIt);
796 ++propertyCount;
797 }
798
799 // Required rule_id or actions property
800 std::vector<std::unique_ptr<Action>> actions{};
801 actions = parseRuleIDOrActionsProperty(element);
802 ++propertyCount;
803
804 // Verify no invalid properties exist
805 verifyPropertyCount(element, propertyCount);
806
807 return std::make_unique<PhaseFaultDetection>(std::move(actions), deviceID);
808 }
809
parsePhaseFaultType(const json & element)810 PhaseFaultType parsePhaseFaultType(const json& element)
811 {
812 std::string value = parseString(element);
813 PhaseFaultType type{};
814
815 if (value == "n")
816 {
817 type = PhaseFaultType::n;
818 }
819 else if (value == "n+1")
820 {
821 type = PhaseFaultType::n_plus_1;
822 }
823 else
824 {
825 throw std::invalid_argument{"Element is not a phase fault type"};
826 }
827
828 return type;
829 }
830
parsePMBusReadSensor(const json & element)831 std::unique_ptr<PMBusReadSensorAction> parsePMBusReadSensor(const json& element)
832 {
833 verifyIsObject(element);
834 unsigned int propertyCount{0};
835
836 // Required type property
837 const json& typeElement = getRequiredProperty(element, "type");
838 SensorType type = parseSensorType(typeElement);
839 ++propertyCount;
840
841 // Required command property
842 const json& commandElement = getRequiredProperty(element, "command");
843 uint8_t command = parseHexByte(commandElement);
844 ++propertyCount;
845
846 // Required format property
847 const json& formatElement = getRequiredProperty(element, "format");
848 pmbus_utils::SensorDataFormat format = parseSensorDataFormat(formatElement);
849 ++propertyCount;
850
851 // Optional exponent property
852 std::optional<int8_t> exponent{};
853 auto exponentIt = element.find("exponent");
854 if (exponentIt != element.end())
855 {
856 exponent = parseInt8(*exponentIt);
857 ++propertyCount;
858 }
859
860 // Verify no invalid properties exist
861 verifyPropertyCount(element, propertyCount);
862
863 return std::make_unique<PMBusReadSensorAction>(type, command, format,
864 exponent);
865 }
866
867 std::unique_ptr<PMBusWriteVoutCommandAction>
parsePMBusWriteVoutCommand(const json & element)868 parsePMBusWriteVoutCommand(const json& element)
869 {
870 verifyIsObject(element);
871 unsigned int propertyCount{0};
872
873 // Optional volts property
874 std::optional<double> volts{};
875 auto voltsIt = element.find("volts");
876 if (voltsIt != element.end())
877 {
878 volts = parseDouble(*voltsIt);
879 ++propertyCount;
880 }
881
882 // Required format property
883 const json& formatElement = getRequiredProperty(element, "format");
884 std::string formatString = parseString(formatElement);
885 if (formatString != "linear")
886 {
887 throw std::invalid_argument{"Invalid format value: " + formatString};
888 }
889 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear;
890 ++propertyCount;
891
892 // Optional exponent property
893 std::optional<int8_t> exponent{};
894 auto exponentIt = element.find("exponent");
895 if (exponentIt != element.end())
896 {
897 exponent = parseInt8(*exponentIt);
898 ++propertyCount;
899 }
900
901 // Optional is_verified property
902 bool isVerified = false;
903 auto isVerifiedIt = element.find("is_verified");
904 if (isVerifiedIt != element.end())
905 {
906 isVerified = parseBoolean(*isVerifiedIt);
907 ++propertyCount;
908 }
909
910 // Verify no invalid properties exist
911 verifyPropertyCount(element, propertyCount);
912
913 return std::make_unique<PMBusWriteVoutCommandAction>(volts, format,
914 exponent, isVerified);
915 }
916
parsePresenceDetection(const json & element)917 std::unique_ptr<PresenceDetection> parsePresenceDetection(const json& element)
918 {
919 verifyIsObject(element);
920 unsigned int propertyCount{0};
921
922 // Optional comments property; value not stored
923 if (element.contains("comments"))
924 {
925 ++propertyCount;
926 }
927
928 // Required rule_id or actions property
929 std::vector<std::unique_ptr<Action>> actions{};
930 actions = parseRuleIDOrActionsProperty(element);
931 ++propertyCount;
932
933 // Verify no invalid properties exist
934 verifyPropertyCount(element, propertyCount);
935
936 return std::make_unique<PresenceDetection>(std::move(actions));
937 }
938
parseRail(const json & element)939 std::unique_ptr<Rail> parseRail(const json& element)
940 {
941 verifyIsObject(element);
942 unsigned int propertyCount{0};
943
944 // Optional comments property; value not stored
945 if (element.contains("comments"))
946 {
947 ++propertyCount;
948 }
949
950 // Required id property
951 const json& idElement = getRequiredProperty(element, "id");
952 std::string id = parseString(idElement);
953 ++propertyCount;
954
955 // Optional configuration property
956 std::unique_ptr<Configuration> configuration{};
957 auto configurationIt = element.find("configuration");
958 if (configurationIt != element.end())
959 {
960 configuration = parseConfiguration(*configurationIt);
961 ++propertyCount;
962 }
963
964 // Optional sensor_monitoring property
965 std::unique_ptr<SensorMonitoring> sensorMonitoring{};
966 auto sensorMonitoringIt = element.find("sensor_monitoring");
967 if (sensorMonitoringIt != element.end())
968 {
969 sensorMonitoring = parseSensorMonitoring(*sensorMonitoringIt);
970 ++propertyCount;
971 }
972
973 // Verify no invalid properties exist
974 verifyPropertyCount(element, propertyCount);
975
976 return std::make_unique<Rail>(id, std::move(configuration),
977 std::move(sensorMonitoring));
978 }
979
parseRailArray(const json & element)980 std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element)
981 {
982 verifyIsArray(element);
983 std::vector<std::unique_ptr<Rail>> rails;
984 for (auto& railElement : element)
985 {
986 rails.emplace_back(parseRail(railElement));
987 }
988 return rails;
989 }
990
991 std::tuple<std::vector<std::unique_ptr<Rule>>,
992 std::vector<std::unique_ptr<Chassis>>>
parseRoot(const json & element)993 parseRoot(const json& element)
994 {
995 verifyIsObject(element);
996 unsigned int propertyCount{0};
997
998 // Optional comments property; value not stored
999 if (element.contains("comments"))
1000 {
1001 ++propertyCount;
1002 }
1003
1004 // Optional rules property
1005 std::vector<std::unique_ptr<Rule>> rules{};
1006 auto rulesIt = element.find("rules");
1007 if (rulesIt != element.end())
1008 {
1009 rules = parseRuleArray(*rulesIt);
1010 ++propertyCount;
1011 }
1012
1013 // Required chassis property
1014 const json& chassisElement = getRequiredProperty(element, "chassis");
1015 std::vector<std::unique_ptr<Chassis>> chassis =
1016 parseChassisArray(chassisElement);
1017 ++propertyCount;
1018
1019 // Verify no invalid properties exist
1020 verifyPropertyCount(element, propertyCount);
1021
1022 return std::make_tuple(std::move(rules), std::move(chassis));
1023 }
1024
parseRule(const json & element)1025 std::unique_ptr<Rule> parseRule(const json& element)
1026 {
1027 verifyIsObject(element);
1028 unsigned int propertyCount{0};
1029
1030 // Optional comments property; value not stored
1031 if (element.contains("comments"))
1032 {
1033 ++propertyCount;
1034 }
1035
1036 // Required id property
1037 const json& idElement = getRequiredProperty(element, "id");
1038 std::string id = parseString(idElement);
1039 ++propertyCount;
1040
1041 // Required actions property
1042 const json& actionsElement = getRequiredProperty(element, "actions");
1043 std::vector<std::unique_ptr<Action>> actions =
1044 parseActionArray(actionsElement);
1045 ++propertyCount;
1046
1047 // Verify no invalid properties exist
1048 verifyPropertyCount(element, propertyCount);
1049
1050 return std::make_unique<Rule>(id, std::move(actions));
1051 }
1052
parseRuleArray(const json & element)1053 std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element)
1054 {
1055 verifyIsArray(element);
1056 std::vector<std::unique_ptr<Rule>> rules;
1057 for (auto& ruleElement : element)
1058 {
1059 rules.emplace_back(parseRule(ruleElement));
1060 }
1061 return rules;
1062 }
1063
1064 std::vector<std::unique_ptr<Action>>
parseRuleIDOrActionsProperty(const json & element)1065 parseRuleIDOrActionsProperty(const json& element)
1066 {
1067 verifyIsObject(element);
1068 // Required rule_id or actions property
1069 std::vector<std::unique_ptr<Action>> actions{};
1070 auto ruleIDIt = element.find("rule_id");
1071 auto actionsIt = element.find("actions");
1072 if ((actionsIt == element.end()) && (ruleIDIt != element.end()))
1073 {
1074 std::string ruleID = parseString(*ruleIDIt);
1075 actions.emplace_back(std::make_unique<RunRuleAction>(ruleID));
1076 }
1077 else if ((actionsIt != element.end()) && (ruleIDIt == element.end()))
1078 {
1079 actions = parseActionArray(*actionsIt);
1080 }
1081 else
1082 {
1083 throw std::invalid_argument{"Invalid property combination: Must "
1084 "contain either rule_id or actions"};
1085 }
1086
1087 return actions;
1088 }
1089
parseRunRule(const json & element)1090 std::unique_ptr<RunRuleAction> parseRunRule(const json& element)
1091 {
1092 // String ruleID
1093 std::string ruleID = parseString(element);
1094
1095 return std::make_unique<RunRuleAction>(ruleID);
1096 }
1097
parseSensorDataFormat(const json & element)1098 pmbus_utils::SensorDataFormat parseSensorDataFormat(const json& element)
1099 {
1100 if (!element.is_string())
1101 {
1102 throw std::invalid_argument{"Element is not a string"};
1103 }
1104 std::string value = element.get<std::string>();
1105 pmbus_utils::SensorDataFormat format{};
1106
1107 if (value == "linear_11")
1108 {
1109 format = pmbus_utils::SensorDataFormat::linear_11;
1110 }
1111 else if (value == "linear_16")
1112 {
1113 format = pmbus_utils::SensorDataFormat::linear_16;
1114 }
1115 else
1116 {
1117 throw std::invalid_argument{"Element is not a sensor data format"};
1118 }
1119
1120 return format;
1121 }
1122
parseSensorMonitoring(const json & element)1123 std::unique_ptr<SensorMonitoring> parseSensorMonitoring(const json& element)
1124 {
1125 verifyIsObject(element);
1126 unsigned int propertyCount{0};
1127
1128 // Optional comments property; value not stored
1129 if (element.contains("comments"))
1130 {
1131 ++propertyCount;
1132 }
1133
1134 // Required rule_id or actions property
1135 std::vector<std::unique_ptr<Action>> actions{};
1136 actions = parseRuleIDOrActionsProperty(element);
1137 ++propertyCount;
1138
1139 // Verify no invalid properties exist
1140 verifyPropertyCount(element, propertyCount);
1141
1142 return std::make_unique<SensorMonitoring>(std::move(actions));
1143 }
1144
parseSensorType(const json & element)1145 SensorType parseSensorType(const json& element)
1146 {
1147 std::string value = parseString(element);
1148 SensorType type{};
1149
1150 if (value == "iout")
1151 {
1152 type = SensorType::iout;
1153 }
1154 else if (value == "iout_peak")
1155 {
1156 type = SensorType::iout_peak;
1157 }
1158 else if (value == "iout_valley")
1159 {
1160 type = SensorType::iout_valley;
1161 }
1162 else if (value == "pout")
1163 {
1164 type = SensorType::pout;
1165 }
1166 else if (value == "temperature")
1167 {
1168 type = SensorType::temperature;
1169 }
1170 else if (value == "temperature_peak")
1171 {
1172 type = SensorType::temperature_peak;
1173 }
1174 else if (value == "vout")
1175 {
1176 type = SensorType::vout;
1177 }
1178 else if (value == "vout_peak")
1179 {
1180 type = SensorType::vout_peak;
1181 }
1182 else if (value == "vout_valley")
1183 {
1184 type = SensorType::vout_valley;
1185 }
1186 else
1187 {
1188 throw std::invalid_argument{"Element is not a sensor type"};
1189 }
1190
1191 return type;
1192 }
1193
parseSetDevice(const json & element)1194 std::unique_ptr<SetDeviceAction> parseSetDevice(const json& element)
1195 {
1196 // String deviceID
1197 std::string deviceID = parseString(element);
1198
1199 return std::make_unique<SetDeviceAction>(deviceID);
1200 }
1201
parseVoutDataFormat(const json & element)1202 pmbus_utils::VoutDataFormat parseVoutDataFormat(const json& element)
1203 {
1204 if (!element.is_string())
1205 {
1206 throw std::invalid_argument{"Element is not a string"};
1207 }
1208 std::string value = element.get<std::string>();
1209 pmbus_utils::VoutDataFormat format{};
1210
1211 if (value == "linear")
1212 {
1213 format = pmbus_utils::VoutDataFormat::linear;
1214 }
1215 else if (value == "vid")
1216 {
1217 format = pmbus_utils::VoutDataFormat::vid;
1218 }
1219 else if (value == "direct")
1220 {
1221 format = pmbus_utils::VoutDataFormat::direct;
1222 }
1223 else if (value == "ieee")
1224 {
1225 format = pmbus_utils::VoutDataFormat::ieee;
1226 }
1227 else
1228 {
1229 throw std::invalid_argument{"Element is not a vout data format"};
1230 }
1231
1232 return format;
1233 }
1234
1235 } // namespace internal
1236
1237 } // namespace phosphor::power::regulators::config_file_parser
1238