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     // 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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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     verifyPropertyCount(element, propertyCount);
590     return i2c::create(bus, address, i2c::I2CInterface::InitialState::CLOSED);
591 }
592 
593 std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element)
594 {
595     verifyIsObject(element);
596     unsigned int propertyCount{0};
597 
598     // Required register property
599     const json& regElement = getRequiredProperty(element, "register");
600     uint8_t reg = parseHexByte(regElement);
601     ++propertyCount;
602 
603     // Required position property
604     const json& positionElement = getRequiredProperty(element, "position");
605     uint8_t position = parseBitPosition(positionElement);
606     ++propertyCount;
607 
608     // Required value property
609     const json& valueElement = getRequiredProperty(element, "value");
610     uint8_t value = parseBitValue(valueElement);
611     ++propertyCount;
612 
613     // Verify no invalid properties exist
614     verifyPropertyCount(element, propertyCount);
615 
616     return std::make_unique<I2CWriteBitAction>(reg, position, value);
617 }
618 
619 std::unique_ptr<I2CWriteByteAction> parseI2CWriteByte(const json& element)
620 {
621     verifyIsObject(element);
622     unsigned int propertyCount{0};
623 
624     // Required register property
625     const json& regElement = getRequiredProperty(element, "register");
626     uint8_t reg = parseHexByte(regElement);
627     ++propertyCount;
628 
629     // Required value property
630     const json& valueElement = getRequiredProperty(element, "value");
631     uint8_t value = parseHexByte(valueElement);
632     ++propertyCount;
633 
634     // Optional mask property
635     uint8_t mask = 0xff;
636     auto maskIt = element.find("mask");
637     if (maskIt != element.end())
638     {
639         mask = parseHexByte(*maskIt);
640         ++propertyCount;
641     }
642 
643     // Verify no invalid properties exist
644     verifyPropertyCount(element, propertyCount);
645 
646     return std::make_unique<I2CWriteByteAction>(reg, value, mask);
647 }
648 
649 std::unique_ptr<I2CWriteBytesAction> parseI2CWriteBytes(const json& element)
650 {
651     verifyIsObject(element);
652     unsigned int propertyCount{0};
653 
654     // Required register property
655     const json& regElement = getRequiredProperty(element, "register");
656     uint8_t reg = parseHexByte(regElement);
657     ++propertyCount;
658 
659     // Required values property
660     const json& valueElement = getRequiredProperty(element, "values");
661     std::vector<uint8_t> values = parseHexByteArray(valueElement);
662     ++propertyCount;
663 
664     // Optional masks property
665     std::vector<uint8_t> masks{};
666     auto masksIt = element.find("masks");
667     if (masksIt != element.end())
668     {
669         masks = parseHexByteArray(*masksIt);
670         ++propertyCount;
671     }
672 
673     // Verify masks array (if specified) was same size as values array
674     if ((!masks.empty()) && (masks.size() != values.size()))
675     {
676         throw std::invalid_argument{"Invalid number of elements in masks"};
677     }
678 
679     // Verify no invalid properties exist
680     verifyPropertyCount(element, propertyCount);
681 
682     if (masks.empty())
683     {
684         return std::make_unique<I2CWriteBytesAction>(reg, values);
685     }
686     return std::make_unique<I2CWriteBytesAction>(reg, values, masks);
687 }
688 
689 std::unique_ptr<IfAction> parseIf(const json& element)
690 {
691     verifyIsObject(element);
692     unsigned int propertyCount{0};
693 
694     // Required condition property
695     const json& conditionElement = getRequiredProperty(element, "condition");
696     std::unique_ptr<Action> conditionAction = parseAction(conditionElement);
697     ++propertyCount;
698 
699     // Required then property
700     const json& thenElement = getRequiredProperty(element, "then");
701     std::vector<std::unique_ptr<Action>> thenActions =
702         parseActionArray(thenElement);
703     ++propertyCount;
704 
705     // Optional else property
706     std::vector<std::unique_ptr<Action>> elseActions{};
707     auto elseIt = element.find("else");
708     if (elseIt != element.end())
709     {
710         elseActions = parseActionArray(*elseIt);
711         ++propertyCount;
712     }
713 
714     // Verify no invalid properties exist
715     verifyPropertyCount(element, propertyCount);
716 
717     return std::make_unique<IfAction>(std::move(conditionAction),
718                                       std::move(thenActions),
719                                       std::move(elseActions));
720 }
721 
722 std::string parseInventoryPath(const json& element)
723 {
724     std::string inventoryPath = parseString(element);
725     std::string absPath = "/xyz/openbmc_project/inventory";
726     if (inventoryPath.front() != '/')
727     {
728         absPath += '/';
729     }
730     absPath += inventoryPath;
731     return absPath;
732 }
733 
734 std::unique_ptr<LogPhaseFaultAction> parseLogPhaseFault(const json& element)
735 {
736     verifyIsObject(element);
737     unsigned int propertyCount{0};
738 
739     // Required type property
740     const json& typeElement = getRequiredProperty(element, "type");
741     PhaseFaultType type = parsePhaseFaultType(typeElement);
742     ++propertyCount;
743 
744     // Verify no invalid properties exist
745     verifyPropertyCount(element, propertyCount);
746 
747     return std::make_unique<LogPhaseFaultAction>(type);
748 }
749 
750 std::unique_ptr<NotAction> parseNot(const json& element)
751 {
752     // Required action to execute
753     std::unique_ptr<Action> action = parseAction(element);
754 
755     return std::make_unique<NotAction>(std::move(action));
756 }
757 
758 std::unique_ptr<OrAction> parseOr(const json& element)
759 {
760     verifyIsArray(element);
761 
762     // Verify if array size less than 2
763     if (element.size() < 2)
764     {
765         throw std::invalid_argument{"Array must contain two or more actions"};
766     }
767     // Array of two or more actions
768     std::vector<std::unique_ptr<Action>> actions = parseActionArray(element);
769 
770     return std::make_unique<OrAction>(std::move(actions));
771 }
772 
773 std::unique_ptr<PhaseFaultDetection>
774     parsePhaseFaultDetection(const json& element)
775 {
776     verifyIsObject(element);
777     unsigned int propertyCount{0};
778 
779     // Optional comments property; value not stored
780     if (element.contains("comments"))
781     {
782         ++propertyCount;
783     }
784 
785     // Optional device_id property
786     std::string deviceID{};
787     auto deviceIDIt = element.find("device_id");
788     if (deviceIDIt != element.end())
789     {
790         deviceID = parseString(*deviceIDIt);
791         ++propertyCount;
792     }
793 
794     // Required rule_id or actions property
795     std::vector<std::unique_ptr<Action>> actions{};
796     actions = parseRuleIDOrActionsProperty(element);
797     ++propertyCount;
798 
799     // Verify no invalid properties exist
800     verifyPropertyCount(element, propertyCount);
801 
802     return std::make_unique<PhaseFaultDetection>(std::move(actions), deviceID);
803 }
804 
805 PhaseFaultType parsePhaseFaultType(const json& element)
806 {
807     std::string value = parseString(element);
808     PhaseFaultType type{};
809 
810     if (value == "n")
811     {
812         type = PhaseFaultType::n;
813     }
814     else if (value == "n+1")
815     {
816         type = PhaseFaultType::n_plus_1;
817     }
818     else
819     {
820         throw std::invalid_argument{"Element is not a phase fault type"};
821     }
822 
823     return type;
824 }
825 
826 std::unique_ptr<PMBusReadSensorAction> parsePMBusReadSensor(const json& element)
827 {
828     verifyIsObject(element);
829     unsigned int propertyCount{0};
830 
831     // Required type property
832     const json& typeElement = getRequiredProperty(element, "type");
833     SensorType type = parseSensorType(typeElement);
834     ++propertyCount;
835 
836     // Required command property
837     const json& commandElement = getRequiredProperty(element, "command");
838     uint8_t command = parseHexByte(commandElement);
839     ++propertyCount;
840 
841     // Required format property
842     const json& formatElement = getRequiredProperty(element, "format");
843     pmbus_utils::SensorDataFormat format = parseSensorDataFormat(formatElement);
844     ++propertyCount;
845 
846     // Optional exponent property
847     std::optional<int8_t> exponent{};
848     auto exponentIt = element.find("exponent");
849     if (exponentIt != element.end())
850     {
851         exponent = parseInt8(*exponentIt);
852         ++propertyCount;
853     }
854 
855     // Verify no invalid properties exist
856     verifyPropertyCount(element, propertyCount);
857 
858     return std::make_unique<PMBusReadSensorAction>(type, command, format,
859                                                    exponent);
860 }
861 
862 std::unique_ptr<PMBusWriteVoutCommandAction>
863     parsePMBusWriteVoutCommand(const json& element)
864 {
865     verifyIsObject(element);
866     unsigned int propertyCount{0};
867 
868     // Optional volts property
869     std::optional<double> volts{};
870     auto voltsIt = element.find("volts");
871     if (voltsIt != element.end())
872     {
873         volts = parseDouble(*voltsIt);
874         ++propertyCount;
875     }
876 
877     // Required format property
878     const json& formatElement = getRequiredProperty(element, "format");
879     std::string formatString = parseString(formatElement);
880     if (formatString != "linear")
881     {
882         throw std::invalid_argument{"Invalid format value: " + formatString};
883     }
884     pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear;
885     ++propertyCount;
886 
887     // Optional exponent property
888     std::optional<int8_t> exponent{};
889     auto exponentIt = element.find("exponent");
890     if (exponentIt != element.end())
891     {
892         exponent = parseInt8(*exponentIt);
893         ++propertyCount;
894     }
895 
896     // Optional is_verified property
897     bool isVerified = false;
898     auto isVerifiedIt = element.find("is_verified");
899     if (isVerifiedIt != element.end())
900     {
901         isVerified = parseBoolean(*isVerifiedIt);
902         ++propertyCount;
903     }
904 
905     // Verify no invalid properties exist
906     verifyPropertyCount(element, propertyCount);
907 
908     return std::make_unique<PMBusWriteVoutCommandAction>(volts, format,
909                                                          exponent, isVerified);
910 }
911 
912 std::unique_ptr<PresenceDetection> parsePresenceDetection(const json& element)
913 {
914     verifyIsObject(element);
915     unsigned int propertyCount{0};
916 
917     // Optional comments property; value not stored
918     if (element.contains("comments"))
919     {
920         ++propertyCount;
921     }
922 
923     // Required rule_id or actions property
924     std::vector<std::unique_ptr<Action>> actions{};
925     actions = parseRuleIDOrActionsProperty(element);
926     ++propertyCount;
927 
928     // Verify no invalid properties exist
929     verifyPropertyCount(element, propertyCount);
930 
931     return std::make_unique<PresenceDetection>(std::move(actions));
932 }
933 
934 std::unique_ptr<Rail> parseRail(const json& element)
935 {
936     verifyIsObject(element);
937     unsigned int propertyCount{0};
938 
939     // Optional comments property; value not stored
940     if (element.contains("comments"))
941     {
942         ++propertyCount;
943     }
944 
945     // Required id property
946     const json& idElement = getRequiredProperty(element, "id");
947     std::string id = parseString(idElement);
948     ++propertyCount;
949 
950     // Optional configuration property
951     std::unique_ptr<Configuration> configuration{};
952     auto configurationIt = element.find("configuration");
953     if (configurationIt != element.end())
954     {
955         configuration = parseConfiguration(*configurationIt);
956         ++propertyCount;
957     }
958 
959     // Optional sensor_monitoring property
960     std::unique_ptr<SensorMonitoring> sensorMonitoring{};
961     auto sensorMonitoringIt = element.find("sensor_monitoring");
962     if (sensorMonitoringIt != element.end())
963     {
964         sensorMonitoring = parseSensorMonitoring(*sensorMonitoringIt);
965         ++propertyCount;
966     }
967 
968     // Verify no invalid properties exist
969     verifyPropertyCount(element, propertyCount);
970 
971     return std::make_unique<Rail>(id, std::move(configuration),
972                                   std::move(sensorMonitoring));
973 }
974 
975 std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element)
976 {
977     verifyIsArray(element);
978     std::vector<std::unique_ptr<Rail>> rails;
979     for (auto& railElement : element)
980     {
981         rails.emplace_back(parseRail(railElement));
982     }
983     return rails;
984 }
985 
986 std::tuple<std::vector<std::unique_ptr<Rule>>,
987            std::vector<std::unique_ptr<Chassis>>>
988     parseRoot(const json& element)
989 {
990     verifyIsObject(element);
991     unsigned int propertyCount{0};
992 
993     // Optional comments property; value not stored
994     if (element.contains("comments"))
995     {
996         ++propertyCount;
997     }
998 
999     // Optional rules property
1000     std::vector<std::unique_ptr<Rule>> rules{};
1001     auto rulesIt = element.find("rules");
1002     if (rulesIt != element.end())
1003     {
1004         rules = parseRuleArray(*rulesIt);
1005         ++propertyCount;
1006     }
1007 
1008     // Required chassis property
1009     const json& chassisElement = getRequiredProperty(element, "chassis");
1010     std::vector<std::unique_ptr<Chassis>> chassis =
1011         parseChassisArray(chassisElement);
1012     ++propertyCount;
1013 
1014     // Verify no invalid properties exist
1015     verifyPropertyCount(element, propertyCount);
1016 
1017     return std::make_tuple(std::move(rules), std::move(chassis));
1018 }
1019 
1020 std::unique_ptr<Rule> parseRule(const json& element)
1021 {
1022     verifyIsObject(element);
1023     unsigned int propertyCount{0};
1024 
1025     // Optional comments property; value not stored
1026     if (element.contains("comments"))
1027     {
1028         ++propertyCount;
1029     }
1030 
1031     // Required id property
1032     const json& idElement = getRequiredProperty(element, "id");
1033     std::string id = parseString(idElement);
1034     ++propertyCount;
1035 
1036     // Required actions property
1037     const json& actionsElement = getRequiredProperty(element, "actions");
1038     std::vector<std::unique_ptr<Action>> actions =
1039         parseActionArray(actionsElement);
1040     ++propertyCount;
1041 
1042     // Verify no invalid properties exist
1043     verifyPropertyCount(element, propertyCount);
1044 
1045     return std::make_unique<Rule>(id, std::move(actions));
1046 }
1047 
1048 std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element)
1049 {
1050     verifyIsArray(element);
1051     std::vector<std::unique_ptr<Rule>> rules;
1052     for (auto& ruleElement : element)
1053     {
1054         rules.emplace_back(parseRule(ruleElement));
1055     }
1056     return rules;
1057 }
1058 
1059 std::vector<std::unique_ptr<Action>>
1060     parseRuleIDOrActionsProperty(const json& element)
1061 {
1062     verifyIsObject(element);
1063     // Required rule_id or actions property
1064     std::vector<std::unique_ptr<Action>> actions{};
1065     auto ruleIDIt = element.find("rule_id");
1066     auto actionsIt = element.find("actions");
1067     if ((actionsIt == element.end()) && (ruleIDIt != element.end()))
1068     {
1069         std::string ruleID = parseString(*ruleIDIt);
1070         actions.emplace_back(std::make_unique<RunRuleAction>(ruleID));
1071     }
1072     else if ((actionsIt != element.end()) && (ruleIDIt == element.end()))
1073     {
1074         actions = parseActionArray(*actionsIt);
1075     }
1076     else
1077     {
1078         throw std::invalid_argument{"Invalid property combination: Must "
1079                                     "contain either rule_id or actions"};
1080     }
1081 
1082     return actions;
1083 }
1084 
1085 std::unique_ptr<RunRuleAction> parseRunRule(const json& element)
1086 {
1087     // String ruleID
1088     std::string ruleID = parseString(element);
1089 
1090     return std::make_unique<RunRuleAction>(ruleID);
1091 }
1092 
1093 pmbus_utils::SensorDataFormat parseSensorDataFormat(const json& element)
1094 {
1095     if (!element.is_string())
1096     {
1097         throw std::invalid_argument{"Element is not a string"};
1098     }
1099     std::string value = element.get<std::string>();
1100     pmbus_utils::SensorDataFormat format{};
1101 
1102     if (value == "linear_11")
1103     {
1104         format = pmbus_utils::SensorDataFormat::linear_11;
1105     }
1106     else if (value == "linear_16")
1107     {
1108         format = pmbus_utils::SensorDataFormat::linear_16;
1109     }
1110     else
1111     {
1112         throw std::invalid_argument{"Element is not a sensor data format"};
1113     }
1114 
1115     return format;
1116 }
1117 
1118 std::unique_ptr<SensorMonitoring> parseSensorMonitoring(const json& element)
1119 {
1120     verifyIsObject(element);
1121     unsigned int propertyCount{0};
1122 
1123     // Optional comments property; value not stored
1124     if (element.contains("comments"))
1125     {
1126         ++propertyCount;
1127     }
1128 
1129     // Required rule_id or actions property
1130     std::vector<std::unique_ptr<Action>> actions{};
1131     actions = parseRuleIDOrActionsProperty(element);
1132     ++propertyCount;
1133 
1134     // Verify no invalid properties exist
1135     verifyPropertyCount(element, propertyCount);
1136 
1137     return std::make_unique<SensorMonitoring>(std::move(actions));
1138 }
1139 
1140 SensorType parseSensorType(const json& element)
1141 {
1142     std::string value = parseString(element);
1143     SensorType type{};
1144 
1145     if (value == "iout")
1146     {
1147         type = SensorType::iout;
1148     }
1149     else if (value == "iout_peak")
1150     {
1151         type = SensorType::iout_peak;
1152     }
1153     else if (value == "iout_valley")
1154     {
1155         type = SensorType::iout_valley;
1156     }
1157     else if (value == "pout")
1158     {
1159         type = SensorType::pout;
1160     }
1161     else if (value == "temperature")
1162     {
1163         type = SensorType::temperature;
1164     }
1165     else if (value == "temperature_peak")
1166     {
1167         type = SensorType::temperature_peak;
1168     }
1169     else if (value == "vout")
1170     {
1171         type = SensorType::vout;
1172     }
1173     else if (value == "vout_peak")
1174     {
1175         type = SensorType::vout_peak;
1176     }
1177     else if (value == "vout_valley")
1178     {
1179         type = SensorType::vout_valley;
1180     }
1181     else
1182     {
1183         throw std::invalid_argument{"Element is not a sensor type"};
1184     }
1185 
1186     return type;
1187 }
1188 
1189 std::unique_ptr<SetDeviceAction> parseSetDevice(const json& element)
1190 {
1191     // String deviceID
1192     std::string deviceID = parseString(element);
1193 
1194     return std::make_unique<SetDeviceAction>(deviceID);
1195 }
1196 
1197 pmbus_utils::VoutDataFormat parseVoutDataFormat(const json& element)
1198 {
1199     if (!element.is_string())
1200     {
1201         throw std::invalid_argument{"Element is not a string"};
1202     }
1203     std::string value = element.get<std::string>();
1204     pmbus_utils::VoutDataFormat format{};
1205 
1206     if (value == "linear")
1207     {
1208         format = pmbus_utils::VoutDataFormat::linear;
1209     }
1210     else if (value == "vid")
1211     {
1212         format = pmbus_utils::VoutDataFormat::vid;
1213     }
1214     else if (value == "direct")
1215     {
1216         format = pmbus_utils::VoutDataFormat::direct;
1217     }
1218     else if (value == "ieee")
1219     {
1220         format = pmbus_utils::VoutDataFormat::ieee;
1221     }
1222     else
1223     {
1224         throw std::invalid_argument{"Element is not a vout data format"};
1225     }
1226 
1227     return format;
1228 }
1229 
1230 } // namespace internal
1231 
1232 } // namespace phosphor::power::regulators::config_file_parser
1233