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