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