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