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