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