xref: /openbmc/phosphor-power/phosphor-regulators/src/config_file_parser.cpp (revision 92261f88729b618b1c31d20f28328a8aff73b83b)
10e8c68abSShawn McCarney /**
20e8c68abSShawn McCarney  * Copyright © 2020 IBM Corporation
30e8c68abSShawn McCarney  *
40e8c68abSShawn McCarney  * Licensed under the Apache License, Version 2.0 (the "License");
50e8c68abSShawn McCarney  * you may not use this file except in compliance with the License.
60e8c68abSShawn McCarney  * You may obtain a copy of the License at
70e8c68abSShawn McCarney  *
80e8c68abSShawn McCarney  *     http://www.apache.org/licenses/LICENSE-2.0
90e8c68abSShawn McCarney  *
100e8c68abSShawn McCarney  * Unless required by applicable law or agreed to in writing, software
110e8c68abSShawn McCarney  * distributed under the License is distributed on an "AS IS" BASIS,
120e8c68abSShawn McCarney  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130e8c68abSShawn McCarney  * See the License for the specific language governing permissions and
140e8c68abSShawn McCarney  * limitations under the License.
150e8c68abSShawn McCarney  */
160e8c68abSShawn McCarney 
170e8c68abSShawn McCarney #include "config_file_parser.hpp"
180e8c68abSShawn McCarney 
190e8c68abSShawn McCarney #include "config_file_parser_error.hpp"
20f617f893SBob King #include "i2c_interface.hpp"
210e8c68abSShawn McCarney #include "pmbus_utils.hpp"
220e8c68abSShawn McCarney 
230e8c68abSShawn McCarney #include <exception>
240e8c68abSShawn McCarney #include <fstream>
250e8c68abSShawn McCarney #include <optional>
260e8c68abSShawn McCarney #include <utility>
270e8c68abSShawn McCarney 
280e8c68abSShawn McCarney using json = nlohmann::json;
290e8c68abSShawn McCarney 
300e8c68abSShawn McCarney namespace phosphor::power::regulators::config_file_parser
310e8c68abSShawn McCarney {
320e8c68abSShawn McCarney 
330e8c68abSShawn McCarney std::tuple<std::vector<std::unique_ptr<Rule>>,
340e8c68abSShawn McCarney            std::vector<std::unique_ptr<Chassis>>>
parse(const std::filesystem::path & pathName)350e8c68abSShawn McCarney     parse(const std::filesystem::path& pathName)
360e8c68abSShawn McCarney {
370e8c68abSShawn McCarney     try
380e8c68abSShawn McCarney     {
390e8c68abSShawn McCarney         // Use standard JSON parser to create tree of JSON elements
400e8c68abSShawn McCarney         std::ifstream file{pathName};
410e8c68abSShawn McCarney         json rootElement = json::parse(file);
420e8c68abSShawn McCarney 
430e8c68abSShawn McCarney         // Parse tree of JSON elements and return corresponding C++ objects
440e8c68abSShawn McCarney         return internal::parseRoot(rootElement);
450e8c68abSShawn McCarney     }
460e8c68abSShawn McCarney     catch (const std::exception& e)
470e8c68abSShawn McCarney     {
480e8c68abSShawn McCarney         throw ConfigFileParserError{pathName, e.what()};
490e8c68abSShawn McCarney     }
500e8c68abSShawn McCarney }
510e8c68abSShawn McCarney 
520e8c68abSShawn McCarney namespace internal
530e8c68abSShawn McCarney {
540e8c68abSShawn McCarney 
parseAction(const json & element)550e8c68abSShawn McCarney std::unique_ptr<Action> parseAction(const json& element)
560e8c68abSShawn McCarney {
570e8c68abSShawn McCarney     verifyIsObject(element);
580e8c68abSShawn McCarney     unsigned int propertyCount{0};
590e8c68abSShawn McCarney 
600e8c68abSShawn McCarney     // Optional comments property; value not stored
610e8c68abSShawn McCarney     if (element.contains("comments"))
620e8c68abSShawn McCarney     {
630e8c68abSShawn McCarney         ++propertyCount;
640e8c68abSShawn McCarney     }
650e8c68abSShawn McCarney 
660e8c68abSShawn McCarney     // Required action type property; there must be exactly one specified
670e8c68abSShawn McCarney     std::unique_ptr<Action> action{};
680e8c68abSShawn McCarney     if (element.contains("and"))
690e8c68abSShawn McCarney     {
703a787540SBob King         action = parseAnd(element["and"]);
713a787540SBob King         ++propertyCount;
720e8c68abSShawn McCarney     }
730e8c68abSShawn McCarney     else if (element.contains("compare_presence"))
740e8c68abSShawn McCarney     {
75b267b7ebSBob King         action = parseComparePresence(element["compare_presence"]);
76b267b7ebSBob King         ++propertyCount;
770e8c68abSShawn McCarney     }
780e8c68abSShawn McCarney     else if (element.contains("compare_vpd"))
790e8c68abSShawn McCarney     {
80f2134320SBob King         action = parseCompareVPD(element["compare_vpd"]);
81f2134320SBob King         ++propertyCount;
820e8c68abSShawn McCarney     }
8391f87a56SShawn McCarney     else if (element.contains("i2c_capture_bytes"))
8491f87a56SShawn McCarney     {
8591f87a56SShawn McCarney         action = parseI2CCaptureBytes(element["i2c_capture_bytes"]);
8691f87a56SShawn McCarney         ++propertyCount;
8791f87a56SShawn McCarney     }
880e8c68abSShawn McCarney     else if (element.contains("i2c_compare_bit"))
890e8c68abSShawn McCarney     {
90f09bfe07SBob King         action = parseI2CCompareBit(element["i2c_compare_bit"]);
91f09bfe07SBob King         ++propertyCount;
920e8c68abSShawn McCarney     }
930e8c68abSShawn McCarney     else if (element.contains("i2c_compare_byte"))
940e8c68abSShawn McCarney     {
95f09bfe07SBob King         action = parseI2CCompareByte(element["i2c_compare_byte"]);
96f09bfe07SBob King         ++propertyCount;
970e8c68abSShawn McCarney     }
980e8c68abSShawn McCarney     else if (element.contains("i2c_compare_bytes"))
990e8c68abSShawn McCarney     {
100f09bfe07SBob King         action = parseI2CCompareBytes(element["i2c_compare_bytes"]);
101f09bfe07SBob King         ++propertyCount;
1020e8c68abSShawn McCarney     }
1030e8c68abSShawn McCarney     else if (element.contains("i2c_write_bit"))
1040e8c68abSShawn McCarney     {
105f617f893SBob King         action = parseI2CWriteBit(element["i2c_write_bit"]);
106f617f893SBob King         ++propertyCount;
1070e8c68abSShawn McCarney     }
1080e8c68abSShawn McCarney     else if (element.contains("i2c_write_byte"))
1090e8c68abSShawn McCarney     {
11087ff9d7dSBob King         action = parseI2CWriteByte(element["i2c_write_byte"]);
11187ff9d7dSBob King         ++propertyCount;
1120e8c68abSShawn McCarney     }
1130e8c68abSShawn McCarney     else if (element.contains("i2c_write_bytes"))
1140e8c68abSShawn McCarney     {
115bafcb86cSBob King         action = parseI2CWriteBytes(element["i2c_write_bytes"]);
116bafcb86cSBob King         ++propertyCount;
1170e8c68abSShawn McCarney     }
1180e8c68abSShawn McCarney     else if (element.contains("if"))
1190e8c68abSShawn McCarney     {
12093a89d72SBob King         action = parseIf(element["if"]);
12193a89d72SBob King         ++propertyCount;
1220e8c68abSShawn McCarney     }
1231115785fSShawn McCarney     else if (element.contains("log_phase_fault"))
1241115785fSShawn McCarney     {
1251115785fSShawn McCarney         action = parseLogPhaseFault(element["log_phase_fault"]);
1261115785fSShawn McCarney         ++propertyCount;
1271115785fSShawn McCarney     }
1280e8c68abSShawn McCarney     else if (element.contains("not"))
1290e8c68abSShawn McCarney     {
130f1b58dc4SBob King         action = parseNot(element["not"]);
131f1b58dc4SBob King         ++propertyCount;
1320e8c68abSShawn McCarney     }
1330e8c68abSShawn McCarney     else if (element.contains("or"))
1340e8c68abSShawn McCarney     {
1350b51a9b2SBob King         action = parseOr(element["or"]);
1360b51a9b2SBob King         ++propertyCount;
1370e8c68abSShawn McCarney     }
1380e8c68abSShawn McCarney     else if (element.contains("pmbus_read_sensor"))
1390e8c68abSShawn McCarney     {
14084614882SBob King         action = parsePMBusReadSensor(element["pmbus_read_sensor"]);
14184614882SBob King         ++propertyCount;
1420e8c68abSShawn McCarney     }
1430e8c68abSShawn McCarney     else if (element.contains("pmbus_write_vout_command"))
1440e8c68abSShawn McCarney     {
1450e8c68abSShawn McCarney         action =
1460e8c68abSShawn McCarney             parsePMBusWriteVoutCommand(element["pmbus_write_vout_command"]);
1470e8c68abSShawn McCarney         ++propertyCount;
1480e8c68abSShawn McCarney     }
1490e8c68abSShawn McCarney     else if (element.contains("run_rule"))
1500e8c68abSShawn McCarney     {
151315b0b62SBob King         action = parseRunRule(element["run_rule"]);
152315b0b62SBob King         ++propertyCount;
1530e8c68abSShawn McCarney     }
1540e8c68abSShawn McCarney     else if (element.contains("set_device"))
1550e8c68abSShawn McCarney     {
15618a68505SBob King         action = parseSetDevice(element["set_device"]);
15718a68505SBob King         ++propertyCount;
1580e8c68abSShawn McCarney     }
1590e8c68abSShawn McCarney     else
1600e8c68abSShawn McCarney     {
1610e8c68abSShawn McCarney         throw std::invalid_argument{"Required action type property missing"};
1620e8c68abSShawn McCarney     }
1630e8c68abSShawn McCarney 
1640e8c68abSShawn McCarney     // Verify no invalid properties exist
1650e8c68abSShawn McCarney     verifyPropertyCount(element, propertyCount);
1660e8c68abSShawn McCarney 
1670e8c68abSShawn McCarney     return action;
1680e8c68abSShawn McCarney }
1690e8c68abSShawn McCarney 
parseActionArray(const json & element)1700e8c68abSShawn McCarney std::vector<std::unique_ptr<Action>> parseActionArray(const json& element)
1710e8c68abSShawn McCarney {
1720e8c68abSShawn McCarney     verifyIsArray(element);
1730e8c68abSShawn McCarney     std::vector<std::unique_ptr<Action>> actions;
1740e8c68abSShawn McCarney     for (auto& actionElement : element)
1750e8c68abSShawn McCarney     {
1760e8c68abSShawn McCarney         actions.emplace_back(parseAction(actionElement));
1770e8c68abSShawn McCarney     }
1780e8c68abSShawn McCarney     return actions;
1790e8c68abSShawn McCarney }
1800e8c68abSShawn McCarney 
parseAnd(const json & element)1813a787540SBob King std::unique_ptr<AndAction> parseAnd(const json& element)
1823a787540SBob King {
1833a787540SBob King     verifyIsArray(element);
1843a787540SBob King 
1853a787540SBob King     // Verify if array size less than 2
1863a787540SBob King     if (element.size() < 2)
1873a787540SBob King     {
1883a787540SBob King         throw std::invalid_argument{"Array must contain two or more actions"};
1893a787540SBob King     }
1903a787540SBob King     // Array of two or more actions
1913a787540SBob King     std::vector<std::unique_ptr<Action>> actions = parseActionArray(element);
1923a787540SBob King 
1933a787540SBob King     return std::make_unique<AndAction>(std::move(actions));
1943a787540SBob King }
1953a787540SBob King 
parseChassis(const json & element)1960e70113dSBob King std::unique_ptr<Chassis> parseChassis(const json& element)
1970e70113dSBob King {
1980e70113dSBob King     verifyIsObject(element);
1990e70113dSBob King     unsigned int propertyCount{0};
2000e70113dSBob King 
2010e70113dSBob King     // Optional comments property; value not stored
2020e70113dSBob King     if (element.contains("comments"))
2030e70113dSBob King     {
2040e70113dSBob King         ++propertyCount;
2050e70113dSBob King     }
2060e70113dSBob King 
2070e70113dSBob King     // Required number property
2080e70113dSBob King     const json& numberElement = getRequiredProperty(element, "number");
2090e70113dSBob King     unsigned int number = parseUnsignedInteger(numberElement);
2100e70113dSBob King     if (number < 1)
2110e70113dSBob King     {
2120e70113dSBob King         throw std::invalid_argument{"Invalid chassis number: Must be > 0"};
2130e70113dSBob King     }
2140e70113dSBob King     ++propertyCount;
2150e70113dSBob King 
2164c88a4c2SShawn McCarney     // Required inventory_path property
217f5402197SPatrick Williams     const json& inventoryPathElement =
218f5402197SPatrick Williams         getRequiredProperty(element, "inventory_path");
2194c88a4c2SShawn McCarney     std::string inventoryPath = parseInventoryPath(inventoryPathElement);
220cb3f6a63SShawn McCarney     ++propertyCount;
221cb3f6a63SShawn McCarney 
2220e70113dSBob King     // Optional devices property
2230e70113dSBob King     std::vector<std::unique_ptr<Device>> devices{};
2240e70113dSBob King     auto devicesIt = element.find("devices");
2250e70113dSBob King     if (devicesIt != element.end())
2260e70113dSBob King     {
2270e70113dSBob King         devices = parseDeviceArray(*devicesIt);
2280e70113dSBob King         ++propertyCount;
2290e70113dSBob King     }
2300e70113dSBob King 
2310e70113dSBob King     // Verify no invalid properties exist
2320e70113dSBob King     verifyPropertyCount(element, propertyCount);
2330e70113dSBob King 
234cb3f6a63SShawn McCarney     return std::make_unique<Chassis>(number, inventoryPath, std::move(devices));
2350e70113dSBob King }
2360e70113dSBob King 
parseChassisArray(const json & element)2370e8c68abSShawn McCarney std::vector<std::unique_ptr<Chassis>> parseChassisArray(const json& element)
2380e8c68abSShawn McCarney {
2390e8c68abSShawn McCarney     verifyIsArray(element);
2400e8c68abSShawn McCarney     std::vector<std::unique_ptr<Chassis>> chassis;
2410e70113dSBob King     for (auto& chassisElement : element)
2420e70113dSBob King     {
2430e70113dSBob King         chassis.emplace_back(parseChassis(chassisElement));
2440e70113dSBob King     }
2450e8c68abSShawn McCarney     return chassis;
2460e8c68abSShawn McCarney }
2470e8c68abSShawn McCarney 
parseComparePresence(const json & element)248b267b7ebSBob King std::unique_ptr<ComparePresenceAction> parseComparePresence(const json& element)
249b267b7ebSBob King {
250b267b7ebSBob King     verifyIsObject(element);
251b267b7ebSBob King     unsigned int propertyCount{0};
252b267b7ebSBob King 
253b267b7ebSBob King     // Required fru property
254b267b7ebSBob King     const json& fruElement = getRequiredProperty(element, "fru");
255a76898f1SBob King     std::string fru = parseInventoryPath(fruElement);
256b267b7ebSBob King     ++propertyCount;
257b267b7ebSBob King 
258b267b7ebSBob King     // Required value property
259b267b7ebSBob King     const json& valueElement = getRequiredProperty(element, "value");
260b267b7ebSBob King     bool value = parseBoolean(valueElement);
261b267b7ebSBob King     ++propertyCount;
262b267b7ebSBob King 
263b267b7ebSBob King     // Verify no invalid properties exist
264b267b7ebSBob King     verifyPropertyCount(element, propertyCount);
265b267b7ebSBob King 
266b267b7ebSBob King     return std::make_unique<ComparePresenceAction>(fru, value);
267b267b7ebSBob King }
268b267b7ebSBob King 
parseCompareVPD(const json & element)269f2134320SBob King std::unique_ptr<CompareVPDAction> parseCompareVPD(const json& element)
270f2134320SBob King {
271f2134320SBob King     verifyIsObject(element);
272f2134320SBob King     unsigned int propertyCount{0};
273f2134320SBob King 
274f2134320SBob King     // Required fru property
275f2134320SBob King     const json& fruElement = getRequiredProperty(element, "fru");
276a76898f1SBob King     std::string fru = parseInventoryPath(fruElement);
277f2134320SBob King     ++propertyCount;
278f2134320SBob King 
279f2134320SBob King     // Required keyword property
280f2134320SBob King     const json& keywordElement = getRequiredProperty(element, "keyword");
281f2134320SBob King     std::string keyword = parseString(keywordElement);
282f2134320SBob King     ++propertyCount;
283f2134320SBob King 
284aacc2aafSMatt Spinler     // Either value or byte_values required property
285aacc2aafSMatt Spinler     auto valueIt = element.find("value");
286aacc2aafSMatt Spinler     std::vector<uint8_t> value{};
287aacc2aafSMatt Spinler     auto byteValuesIt = element.find("byte_values");
288aacc2aafSMatt Spinler     if ((valueIt != element.end()) && (byteValuesIt == element.end()))
289aacc2aafSMatt Spinler     {
290a2a830b1SShawn McCarney         std::string stringValue = parseString(*valueIt, true);
291aacc2aafSMatt Spinler         value.insert(value.begin(), stringValue.begin(), stringValue.end());
292f2134320SBob King         ++propertyCount;
293aacc2aafSMatt Spinler     }
294aacc2aafSMatt Spinler     else if ((valueIt == element.end()) && (byteValuesIt != element.end()))
295aacc2aafSMatt Spinler     {
296aacc2aafSMatt Spinler         value = parseHexByteArray(*byteValuesIt);
297aacc2aafSMatt Spinler         ++propertyCount;
298aacc2aafSMatt Spinler     }
299aacc2aafSMatt Spinler     else
300aacc2aafSMatt Spinler     {
301aacc2aafSMatt Spinler         throw std::invalid_argument{
302aacc2aafSMatt Spinler             "Invalid property: Must contain either value or byte_values"};
303aacc2aafSMatt Spinler     }
304f2134320SBob King 
305f2134320SBob King     // Verify no invalid properties exist
306f2134320SBob King     verifyPropertyCount(element, propertyCount);
307f2134320SBob King 
308f2134320SBob King     return std::make_unique<CompareVPDAction>(fru, keyword, value);
309f2134320SBob King }
310f2134320SBob King 
parseConfiguration(const json & element)31133e7eaa5SBob King std::unique_ptr<Configuration> parseConfiguration(const json& element)
31233e7eaa5SBob King {
31333e7eaa5SBob King     verifyIsObject(element);
31433e7eaa5SBob King     unsigned int propertyCount{0};
31533e7eaa5SBob King 
31633e7eaa5SBob King     // Optional comments property; value not stored
31733e7eaa5SBob King     if (element.contains("comments"))
31833e7eaa5SBob King     {
31933e7eaa5SBob King         ++propertyCount;
32033e7eaa5SBob King     }
32133e7eaa5SBob King 
32233e7eaa5SBob King     // Optional volts property
32333e7eaa5SBob King     std::optional<double> volts{};
32433e7eaa5SBob King     auto voltsIt = element.find("volts");
32533e7eaa5SBob King     if (voltsIt != element.end())
32633e7eaa5SBob King     {
32733e7eaa5SBob King         volts = parseDouble(*voltsIt);
32833e7eaa5SBob King         ++propertyCount;
32933e7eaa5SBob King     }
33033e7eaa5SBob King 
33133e7eaa5SBob King     // Required rule_id or actions property
33233e7eaa5SBob King     std::vector<std::unique_ptr<Action>> actions{};
33333e7eaa5SBob King     actions = parseRuleIDOrActionsProperty(element);
33433e7eaa5SBob King     ++propertyCount;
33533e7eaa5SBob King 
33633e7eaa5SBob King     // Verify no invalid properties exist
33733e7eaa5SBob King     verifyPropertyCount(element, propertyCount);
33833e7eaa5SBob King 
33933e7eaa5SBob King     return std::make_unique<Configuration>(volts, std::move(actions));
34033e7eaa5SBob King }
34133e7eaa5SBob King 
parseDevice(const json & element)3429c36c5fbSBob King std::unique_ptr<Device> parseDevice(const json& element)
3439c36c5fbSBob King {
3449c36c5fbSBob King     verifyIsObject(element);
3459c36c5fbSBob King     unsigned int propertyCount{0};
3469c36c5fbSBob King 
3479c36c5fbSBob King     // Optional comments property; value not stored
3489c36c5fbSBob King     if (element.contains("comments"))
3499c36c5fbSBob King     {
3509c36c5fbSBob King         ++propertyCount;
3519c36c5fbSBob King     }
3529c36c5fbSBob King 
3539c36c5fbSBob King     // Required id property
3549c36c5fbSBob King     const json& idElement = getRequiredProperty(element, "id");
3559c36c5fbSBob King     std::string id = parseString(idElement);
3569c36c5fbSBob King     ++propertyCount;
3579c36c5fbSBob King 
3589c36c5fbSBob King     // Required is_regulator property
359f5402197SPatrick Williams     const json& isRegulatorElement =
360f5402197SPatrick Williams         getRequiredProperty(element, "is_regulator");
3619c36c5fbSBob King     bool isRegulator = parseBoolean(isRegulatorElement);
3629c36c5fbSBob King     ++propertyCount;
3639c36c5fbSBob King 
3649c36c5fbSBob King     // Required fru property
3659c36c5fbSBob King     const json& fruElement = getRequiredProperty(element, "fru");
366a76898f1SBob King     std::string fru = parseInventoryPath(fruElement);
3679c36c5fbSBob King     ++propertyCount;
3689c36c5fbSBob King 
3699c36c5fbSBob King     // Required i2c_interface property
370f5402197SPatrick Williams     const json& i2cInterfaceElement =
371f5402197SPatrick Williams         getRequiredProperty(element, "i2c_interface");
3729c36c5fbSBob King     std::unique_ptr<i2c::I2CInterface> i2cInterface =
3739c36c5fbSBob King         parseI2CInterface(i2cInterfaceElement);
3749c36c5fbSBob King     ++propertyCount;
3759c36c5fbSBob King 
3769c36c5fbSBob King     // Optional presence_detection property
3779c36c5fbSBob King     std::unique_ptr<PresenceDetection> presenceDetection{};
3782aafb1c7SBob King     auto presenceDetectionIt = element.find("presence_detection");
3792aafb1c7SBob King     if (presenceDetectionIt != element.end())
3802aafb1c7SBob King     {
3812aafb1c7SBob King         presenceDetection = parsePresenceDetection(*presenceDetectionIt);
3822aafb1c7SBob King         ++propertyCount;
3832aafb1c7SBob King     }
3849c36c5fbSBob King 
3859c36c5fbSBob King     // Optional configuration property
3869c36c5fbSBob King     std::unique_ptr<Configuration> configuration{};
38733e7eaa5SBob King     auto configurationIt = element.find("configuration");
38833e7eaa5SBob King     if (configurationIt != element.end())
38933e7eaa5SBob King     {
39033e7eaa5SBob King         configuration = parseConfiguration(*configurationIt);
39133e7eaa5SBob King         ++propertyCount;
39233e7eaa5SBob King     }
3939c36c5fbSBob King 
39432252599SShawn McCarney     // Optional phase_fault_detection property
39532252599SShawn McCarney     std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
39632252599SShawn McCarney     auto phaseFaultDetectionIt = element.find("phase_fault_detection");
39732252599SShawn McCarney     if (phaseFaultDetectionIt != element.end())
39832252599SShawn McCarney     {
39932252599SShawn McCarney         if (!isRegulator)
40032252599SShawn McCarney         {
40132252599SShawn McCarney             throw std::invalid_argument{"Invalid phase_fault_detection "
40232252599SShawn McCarney                                         "property when is_regulator is false"};
40332252599SShawn McCarney         }
40432252599SShawn McCarney         phaseFaultDetection = parsePhaseFaultDetection(*phaseFaultDetectionIt);
40532252599SShawn McCarney         ++propertyCount;
40632252599SShawn McCarney     }
40732252599SShawn McCarney 
4089c36c5fbSBob King     // Optional rails property
4099c36c5fbSBob King     std::vector<std::unique_ptr<Rail>> rails{};
4109c36c5fbSBob King     auto railsIt = element.find("rails");
4119c36c5fbSBob King     if (railsIt != element.end())
4129c36c5fbSBob King     {
4139c36c5fbSBob King         if (!isRegulator)
4149c36c5fbSBob King         {
4159c36c5fbSBob King             throw std::invalid_argument{
4169c36c5fbSBob King                 "Invalid rails property when is_regulator is false"};
4179c36c5fbSBob King         }
4189c36c5fbSBob King         rails = parseRailArray(*railsIt);
4199c36c5fbSBob King         ++propertyCount;
4209c36c5fbSBob King     }
4219c36c5fbSBob King 
4229c36c5fbSBob King     // Verify no invalid properties exist
4239c36c5fbSBob King     verifyPropertyCount(element, propertyCount);
4249c36c5fbSBob King 
42532252599SShawn McCarney     return std::make_unique<Device>(
42632252599SShawn McCarney         id, isRegulator, fru, std::move(i2cInterface),
42732252599SShawn McCarney         std::move(presenceDetection), std::move(configuration),
42832252599SShawn McCarney         std::move(phaseFaultDetection), std::move(rails));
4299c36c5fbSBob King }
4309c36c5fbSBob King 
parseDeviceArray(const json & element)4310e70113dSBob King std::vector<std::unique_ptr<Device>> parseDeviceArray(const json& element)
4320e70113dSBob King {
4330e70113dSBob King     verifyIsArray(element);
4340e70113dSBob King     std::vector<std::unique_ptr<Device>> devices;
4359c36c5fbSBob King     for (auto& deviceElement : element)
4369c36c5fbSBob King     {
4379c36c5fbSBob King         devices.emplace_back(parseDevice(deviceElement));
4389c36c5fbSBob King     }
4390e70113dSBob King     return devices;
4400e70113dSBob King }
4410e70113dSBob King 
parseHexByteArray(const json & element)442bafcb86cSBob King std::vector<uint8_t> parseHexByteArray(const json& element)
443bafcb86cSBob King {
444bafcb86cSBob King     verifyIsArray(element);
445bafcb86cSBob King     std::vector<uint8_t> values;
446bafcb86cSBob King     for (auto& valueElement : element)
447bafcb86cSBob King     {
448bafcb86cSBob King         values.emplace_back(parseHexByte(valueElement));
449bafcb86cSBob King     }
450bafcb86cSBob King     return values;
451bafcb86cSBob King }
452bafcb86cSBob King 
parseI2CCaptureBytes(const json & element)45391f87a56SShawn McCarney std::unique_ptr<I2CCaptureBytesAction> parseI2CCaptureBytes(const json& element)
45491f87a56SShawn McCarney {
45591f87a56SShawn McCarney     verifyIsObject(element);
45691f87a56SShawn McCarney     unsigned int propertyCount{0};
45791f87a56SShawn McCarney 
45891f87a56SShawn McCarney     // Required register property
45991f87a56SShawn McCarney     const json& regElement = getRequiredProperty(element, "register");
46091f87a56SShawn McCarney     uint8_t reg = parseHexByte(regElement);
46191f87a56SShawn McCarney     ++propertyCount;
46291f87a56SShawn McCarney 
46391f87a56SShawn McCarney     // Required count property
46491f87a56SShawn McCarney     const json& countElement = getRequiredProperty(element, "count");
46591f87a56SShawn McCarney     uint8_t count = parseUint8(countElement);
46691f87a56SShawn McCarney     if (count < 1)
46791f87a56SShawn McCarney     {
46891f87a56SShawn McCarney         throw std::invalid_argument{"Invalid byte count: Must be > 0"};
46991f87a56SShawn McCarney     }
47091f87a56SShawn McCarney     ++propertyCount;
47191f87a56SShawn McCarney 
47291f87a56SShawn McCarney     // Verify no invalid properties exist
47391f87a56SShawn McCarney     verifyPropertyCount(element, propertyCount);
47491f87a56SShawn McCarney 
47591f87a56SShawn McCarney     return std::make_unique<I2CCaptureBytesAction>(reg, count);
47691f87a56SShawn McCarney }
47791f87a56SShawn McCarney 
parseI2CCompareBit(const json & element)478f09bfe07SBob King std::unique_ptr<I2CCompareBitAction> parseI2CCompareBit(const json& element)
479f09bfe07SBob King {
480f09bfe07SBob King     verifyIsObject(element);
481f09bfe07SBob King     unsigned int propertyCount{0};
482f09bfe07SBob King 
483f09bfe07SBob King     // Required register property
484f09bfe07SBob King     const json& regElement = getRequiredProperty(element, "register");
485f09bfe07SBob King     uint8_t reg = parseHexByte(regElement);
486f09bfe07SBob King     ++propertyCount;
487f09bfe07SBob King 
488f09bfe07SBob King     // Required position property
489f09bfe07SBob King     const json& positionElement = getRequiredProperty(element, "position");
490f09bfe07SBob King     uint8_t position = parseBitPosition(positionElement);
491f09bfe07SBob King     ++propertyCount;
492f09bfe07SBob King 
493f09bfe07SBob King     // Required value property
494f09bfe07SBob King     const json& valueElement = getRequiredProperty(element, "value");
495f09bfe07SBob King     uint8_t value = parseBitValue(valueElement);
496f09bfe07SBob King     ++propertyCount;
497f09bfe07SBob King 
498f09bfe07SBob King     // Verify no invalid properties exist
499f09bfe07SBob King     verifyPropertyCount(element, propertyCount);
500f09bfe07SBob King 
501f09bfe07SBob King     return std::make_unique<I2CCompareBitAction>(reg, position, value);
502f09bfe07SBob King }
503f09bfe07SBob King 
parseI2CCompareByte(const json & element)504f09bfe07SBob King std::unique_ptr<I2CCompareByteAction> parseI2CCompareByte(const json& element)
505f09bfe07SBob King {
506f09bfe07SBob King     verifyIsObject(element);
507f09bfe07SBob King     unsigned int propertyCount{0};
508f09bfe07SBob King 
509f09bfe07SBob King     // Required register property
510f09bfe07SBob King     const json& regElement = getRequiredProperty(element, "register");
511f09bfe07SBob King     uint8_t reg = parseHexByte(regElement);
512f09bfe07SBob King     ++propertyCount;
513f09bfe07SBob King 
514f09bfe07SBob King     // Required value property
515f09bfe07SBob King     const json& valueElement = getRequiredProperty(element, "value");
516f09bfe07SBob King     uint8_t value = parseHexByte(valueElement);
517f09bfe07SBob King     ++propertyCount;
518f09bfe07SBob King 
519f09bfe07SBob King     // Optional mask property
520f09bfe07SBob King     uint8_t mask = 0xff;
521f09bfe07SBob King     auto maskIt = element.find("mask");
522f09bfe07SBob King     if (maskIt != element.end())
523f09bfe07SBob King     {
524f09bfe07SBob King         mask = parseHexByte(*maskIt);
525f09bfe07SBob King         ++propertyCount;
526f09bfe07SBob King     }
527f09bfe07SBob King 
528f09bfe07SBob King     // Verify no invalid properties exist
529f09bfe07SBob King     verifyPropertyCount(element, propertyCount);
530f09bfe07SBob King 
531f09bfe07SBob King     return std::make_unique<I2CCompareByteAction>(reg, value, mask);
532f09bfe07SBob King }
533f09bfe07SBob King 
parseI2CCompareBytes(const json & element)534f09bfe07SBob King std::unique_ptr<I2CCompareBytesAction> parseI2CCompareBytes(const json& element)
535f09bfe07SBob King {
536f09bfe07SBob King     verifyIsObject(element);
537f09bfe07SBob King     unsigned int propertyCount{0};
538f09bfe07SBob King 
539f09bfe07SBob King     // Required register property
540f09bfe07SBob King     const json& regElement = getRequiredProperty(element, "register");
541f09bfe07SBob King     uint8_t reg = parseHexByte(regElement);
542f09bfe07SBob King     ++propertyCount;
543f09bfe07SBob King 
544f09bfe07SBob King     // Required values property
545f09bfe07SBob King     const json& valueElement = getRequiredProperty(element, "values");
546f09bfe07SBob King     std::vector<uint8_t> values = parseHexByteArray(valueElement);
547f09bfe07SBob King     ++propertyCount;
548f09bfe07SBob King 
549f09bfe07SBob King     // Optional masks property
550f09bfe07SBob King     std::vector<uint8_t> masks{};
551f09bfe07SBob King     auto masksIt = element.find("masks");
552f09bfe07SBob King     if (masksIt != element.end())
553f09bfe07SBob King     {
554f09bfe07SBob King         masks = parseHexByteArray(*masksIt);
555f09bfe07SBob King         ++propertyCount;
556f09bfe07SBob King     }
557f09bfe07SBob King 
558f09bfe07SBob King     // Verify masks array (if specified) was same size as values array
559f09bfe07SBob King     if ((!masks.empty()) && (masks.size() != values.size()))
560f09bfe07SBob King     {
561f09bfe07SBob King         throw std::invalid_argument{"Invalid number of elements in masks"};
562f09bfe07SBob King     }
563f09bfe07SBob King 
564f09bfe07SBob King     // Verify no invalid properties exist
565f09bfe07SBob King     verifyPropertyCount(element, propertyCount);
566f09bfe07SBob King 
567f09bfe07SBob King     if (masks.empty())
568f09bfe07SBob King     {
569f09bfe07SBob King         return std::make_unique<I2CCompareBytesAction>(reg, values);
570f09bfe07SBob King     }
571f09bfe07SBob King     return std::make_unique<I2CCompareBytesAction>(reg, values, masks);
572f09bfe07SBob King }
573f09bfe07SBob King 
parseI2CInterface(const json & element)5749c36c5fbSBob King std::unique_ptr<i2c::I2CInterface> parseI2CInterface(const json& element)
5759c36c5fbSBob King {
5769c36c5fbSBob King     verifyIsObject(element);
5779c36c5fbSBob King     unsigned int propertyCount{0};
5789c36c5fbSBob King 
5799c36c5fbSBob King     // Required bus property
5809c36c5fbSBob King     const json& busElement = getRequiredProperty(element, "bus");
5819c36c5fbSBob King     uint8_t bus = parseUint8(busElement);
5829c36c5fbSBob King     ++propertyCount;
5839c36c5fbSBob King 
5849c36c5fbSBob King     // Required address property
5859c36c5fbSBob King     const json& addressElement = getRequiredProperty(element, "address");
5869c36c5fbSBob King     uint8_t address = parseHexByte(addressElement);
5879c36c5fbSBob King     ++propertyCount;
5889c36c5fbSBob King 
5895d23d9d6SShawn McCarney     // Verify no invalid properties exist
5909c36c5fbSBob King     verifyPropertyCount(element, propertyCount);
5915d23d9d6SShawn McCarney 
5925d23d9d6SShawn McCarney     // Create I2CInterface object; retry failed I2C operations a max of 3 times.
5935d23d9d6SShawn McCarney     int maxRetries{3};
5945d23d9d6SShawn McCarney     return i2c::create(bus, address, i2c::I2CInterface::InitialState::CLOSED,
5955d23d9d6SShawn McCarney                        maxRetries);
5969c36c5fbSBob King }
5979c36c5fbSBob King 
parseI2CWriteBit(const json & element)598f617f893SBob King std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element)
599f617f893SBob King {
600f617f893SBob King     verifyIsObject(element);
601f617f893SBob King     unsigned int propertyCount{0};
602f617f893SBob King 
603f617f893SBob King     // Required register property
604f617f893SBob King     const json& regElement = getRequiredProperty(element, "register");
605bafcb86cSBob King     uint8_t reg = parseHexByte(regElement);
606f617f893SBob King     ++propertyCount;
607f617f893SBob King 
608f617f893SBob King     // Required position property
609f617f893SBob King     const json& positionElement = getRequiredProperty(element, "position");
610f617f893SBob King     uint8_t position = parseBitPosition(positionElement);
611f617f893SBob King     ++propertyCount;
612f617f893SBob King 
613f617f893SBob King     // Required value property
614f617f893SBob King     const json& valueElement = getRequiredProperty(element, "value");
615f617f893SBob King     uint8_t value = parseBitValue(valueElement);
616f617f893SBob King     ++propertyCount;
617f617f893SBob King 
618f617f893SBob King     // Verify no invalid properties exist
619f617f893SBob King     verifyPropertyCount(element, propertyCount);
620f617f893SBob King 
621f617f893SBob King     return std::make_unique<I2CWriteBitAction>(reg, position, value);
622f617f893SBob King }
623f617f893SBob King 
parseI2CWriteByte(const json & element)62487ff9d7dSBob King std::unique_ptr<I2CWriteByteAction> parseI2CWriteByte(const json& element)
62587ff9d7dSBob King {
62687ff9d7dSBob King     verifyIsObject(element);
62787ff9d7dSBob King     unsigned int propertyCount{0};
62887ff9d7dSBob King 
62987ff9d7dSBob King     // Required register property
63087ff9d7dSBob King     const json& regElement = getRequiredProperty(element, "register");
631bafcb86cSBob King     uint8_t reg = parseHexByte(regElement);
63287ff9d7dSBob King     ++propertyCount;
63387ff9d7dSBob King 
63487ff9d7dSBob King     // Required value property
63587ff9d7dSBob King     const json& valueElement = getRequiredProperty(element, "value");
636bafcb86cSBob King     uint8_t value = parseHexByte(valueElement);
63787ff9d7dSBob King     ++propertyCount;
63887ff9d7dSBob King 
63987ff9d7dSBob King     // Optional mask property
64087ff9d7dSBob King     uint8_t mask = 0xff;
64187ff9d7dSBob King     auto maskIt = element.find("mask");
64287ff9d7dSBob King     if (maskIt != element.end())
64387ff9d7dSBob King     {
644bafcb86cSBob King         mask = parseHexByte(*maskIt);
64587ff9d7dSBob King         ++propertyCount;
64687ff9d7dSBob King     }
64787ff9d7dSBob King 
64887ff9d7dSBob King     // Verify no invalid properties exist
64987ff9d7dSBob King     verifyPropertyCount(element, propertyCount);
65087ff9d7dSBob King 
65187ff9d7dSBob King     return std::make_unique<I2CWriteByteAction>(reg, value, mask);
65287ff9d7dSBob King }
65387ff9d7dSBob King 
parseI2CWriteBytes(const json & element)654bafcb86cSBob King std::unique_ptr<I2CWriteBytesAction> parseI2CWriteBytes(const json& element)
655bafcb86cSBob King {
656bafcb86cSBob King     verifyIsObject(element);
657bafcb86cSBob King     unsigned int propertyCount{0};
658bafcb86cSBob King 
659bafcb86cSBob King     // Required register property
660bafcb86cSBob King     const json& regElement = getRequiredProperty(element, "register");
661bafcb86cSBob King     uint8_t reg = parseHexByte(regElement);
662bafcb86cSBob King     ++propertyCount;
663bafcb86cSBob King 
664bafcb86cSBob King     // Required values property
665bafcb86cSBob King     const json& valueElement = getRequiredProperty(element, "values");
666bafcb86cSBob King     std::vector<uint8_t> values = parseHexByteArray(valueElement);
667bafcb86cSBob King     ++propertyCount;
668bafcb86cSBob King 
669bafcb86cSBob King     // Optional masks property
670bafcb86cSBob King     std::vector<uint8_t> masks{};
671bafcb86cSBob King     auto masksIt = element.find("masks");
672bafcb86cSBob King     if (masksIt != element.end())
673bafcb86cSBob King     {
674bafcb86cSBob King         masks = parseHexByteArray(*masksIt);
675bafcb86cSBob King         ++propertyCount;
676bafcb86cSBob King     }
677bafcb86cSBob King 
678bafcb86cSBob King     // Verify masks array (if specified) was same size as values array
679bafcb86cSBob King     if ((!masks.empty()) && (masks.size() != values.size()))
680bafcb86cSBob King     {
681bafcb86cSBob King         throw std::invalid_argument{"Invalid number of elements in masks"};
682bafcb86cSBob King     }
683bafcb86cSBob King 
684bafcb86cSBob King     // Verify no invalid properties exist
685bafcb86cSBob King     verifyPropertyCount(element, propertyCount);
686bafcb86cSBob King 
687bafcb86cSBob King     if (masks.empty())
688bafcb86cSBob King     {
689bafcb86cSBob King         return std::make_unique<I2CWriteBytesAction>(reg, values);
690bafcb86cSBob King     }
691bafcb86cSBob King     return std::make_unique<I2CWriteBytesAction>(reg, values, masks);
692bafcb86cSBob King }
693bafcb86cSBob King 
parseIf(const json & element)69493a89d72SBob King std::unique_ptr<IfAction> parseIf(const json& element)
69593a89d72SBob King {
69693a89d72SBob King     verifyIsObject(element);
69793a89d72SBob King     unsigned int propertyCount{0};
69893a89d72SBob King 
69993a89d72SBob King     // Required condition property
70093a89d72SBob King     const json& conditionElement = getRequiredProperty(element, "condition");
70193a89d72SBob King     std::unique_ptr<Action> conditionAction = parseAction(conditionElement);
70293a89d72SBob King     ++propertyCount;
70393a89d72SBob King 
70493a89d72SBob King     // Required then property
70593a89d72SBob King     const json& thenElement = getRequiredProperty(element, "then");
70693a89d72SBob King     std::vector<std::unique_ptr<Action>> thenActions =
70793a89d72SBob King         parseActionArray(thenElement);
70893a89d72SBob King     ++propertyCount;
70993a89d72SBob King 
71093a89d72SBob King     // Optional else property
71193a89d72SBob King     std::vector<std::unique_ptr<Action>> elseActions{};
71293a89d72SBob King     auto elseIt = element.find("else");
71393a89d72SBob King     if (elseIt != element.end())
71493a89d72SBob King     {
71593a89d72SBob King         elseActions = parseActionArray(*elseIt);
71693a89d72SBob King         ++propertyCount;
71793a89d72SBob King     }
71893a89d72SBob King 
71993a89d72SBob King     // Verify no invalid properties exist
72093a89d72SBob King     verifyPropertyCount(element, propertyCount);
72193a89d72SBob King 
72293a89d72SBob King     return std::make_unique<IfAction>(std::move(conditionAction),
72393a89d72SBob King                                       std::move(thenActions),
72493a89d72SBob King                                       std::move(elseActions));
72593a89d72SBob King }
72693a89d72SBob King 
parseInventoryPath(const json & element)727a76898f1SBob King std::string parseInventoryPath(const json& element)
728a76898f1SBob King {
729a76898f1SBob King     std::string inventoryPath = parseString(element);
730a76898f1SBob King     std::string absPath = "/xyz/openbmc_project/inventory";
731a76898f1SBob King     if (inventoryPath.front() != '/')
732a76898f1SBob King     {
733a76898f1SBob King         absPath += '/';
734a76898f1SBob King     }
735a76898f1SBob King     absPath += inventoryPath;
736a76898f1SBob King     return absPath;
737a76898f1SBob King }
738a76898f1SBob King 
parseLogPhaseFault(const json & element)7391115785fSShawn McCarney std::unique_ptr<LogPhaseFaultAction> parseLogPhaseFault(const json& element)
7401115785fSShawn McCarney {
7411115785fSShawn McCarney     verifyIsObject(element);
7421115785fSShawn McCarney     unsigned int propertyCount{0};
7431115785fSShawn McCarney 
7441115785fSShawn McCarney     // Required type property
7451115785fSShawn McCarney     const json& typeElement = getRequiredProperty(element, "type");
7461115785fSShawn McCarney     PhaseFaultType type = parsePhaseFaultType(typeElement);
7471115785fSShawn McCarney     ++propertyCount;
7481115785fSShawn McCarney 
7491115785fSShawn McCarney     // Verify no invalid properties exist
7501115785fSShawn McCarney     verifyPropertyCount(element, propertyCount);
7511115785fSShawn McCarney 
7521115785fSShawn McCarney     return std::make_unique<LogPhaseFaultAction>(type);
7531115785fSShawn McCarney }
7541115785fSShawn McCarney 
parseNot(const json & element)755f1b58dc4SBob King std::unique_ptr<NotAction> parseNot(const json& element)
756f1b58dc4SBob King {
757f1b58dc4SBob King     // Required action to execute
758f1b58dc4SBob King     std::unique_ptr<Action> action = parseAction(element);
759f1b58dc4SBob King 
760f1b58dc4SBob King     return std::make_unique<NotAction>(std::move(action));
761f1b58dc4SBob King }
762f1b58dc4SBob King 
parseOr(const json & element)7630b51a9b2SBob King std::unique_ptr<OrAction> parseOr(const json& element)
7640b51a9b2SBob King {
7650b51a9b2SBob King     verifyIsArray(element);
7660b51a9b2SBob King 
7670b51a9b2SBob King     // Verify if array size less than 2
7680b51a9b2SBob King     if (element.size() < 2)
7690b51a9b2SBob King     {
7700b51a9b2SBob King         throw std::invalid_argument{"Array must contain two or more actions"};
7710b51a9b2SBob King     }
7720b51a9b2SBob King     // Array of two or more actions
7730b51a9b2SBob King     std::vector<std::unique_ptr<Action>> actions = parseActionArray(element);
7740b51a9b2SBob King 
7750b51a9b2SBob King     return std::make_unique<OrAction>(std::move(actions));
7760b51a9b2SBob King }
7770b51a9b2SBob King 
parsePhaseFaultDetection(const json & element)778*92261f88SPatrick Williams std::unique_ptr<PhaseFaultDetection> parsePhaseFaultDetection(
779*92261f88SPatrick Williams     const json& element)
78039eb08a9SShawn McCarney {
78139eb08a9SShawn McCarney     verifyIsObject(element);
78239eb08a9SShawn McCarney     unsigned int propertyCount{0};
78339eb08a9SShawn McCarney 
78439eb08a9SShawn McCarney     // Optional comments property; value not stored
78539eb08a9SShawn McCarney     if (element.contains("comments"))
78639eb08a9SShawn McCarney     {
78739eb08a9SShawn McCarney         ++propertyCount;
78839eb08a9SShawn McCarney     }
78939eb08a9SShawn McCarney 
79039eb08a9SShawn McCarney     // Optional device_id property
79139eb08a9SShawn McCarney     std::string deviceID{};
79239eb08a9SShawn McCarney     auto deviceIDIt = element.find("device_id");
79339eb08a9SShawn McCarney     if (deviceIDIt != element.end())
79439eb08a9SShawn McCarney     {
79539eb08a9SShawn McCarney         deviceID = parseString(*deviceIDIt);
79639eb08a9SShawn McCarney         ++propertyCount;
79739eb08a9SShawn McCarney     }
79839eb08a9SShawn McCarney 
79939eb08a9SShawn McCarney     // Required rule_id or actions property
80039eb08a9SShawn McCarney     std::vector<std::unique_ptr<Action>> actions{};
80139eb08a9SShawn McCarney     actions = parseRuleIDOrActionsProperty(element);
80239eb08a9SShawn McCarney     ++propertyCount;
80339eb08a9SShawn McCarney 
80439eb08a9SShawn McCarney     // Verify no invalid properties exist
80539eb08a9SShawn McCarney     verifyPropertyCount(element, propertyCount);
80639eb08a9SShawn McCarney 
80739eb08a9SShawn McCarney     return std::make_unique<PhaseFaultDetection>(std::move(actions), deviceID);
80839eb08a9SShawn McCarney }
80939eb08a9SShawn McCarney 
parsePhaseFaultType(const json & element)810b70370b7SShawn McCarney PhaseFaultType parsePhaseFaultType(const json& element)
811b70370b7SShawn McCarney {
812b70370b7SShawn McCarney     std::string value = parseString(element);
813b70370b7SShawn McCarney     PhaseFaultType type{};
814b70370b7SShawn McCarney 
815b70370b7SShawn McCarney     if (value == "n")
816b70370b7SShawn McCarney     {
817b70370b7SShawn McCarney         type = PhaseFaultType::n;
818b70370b7SShawn McCarney     }
819b70370b7SShawn McCarney     else if (value == "n+1")
820b70370b7SShawn McCarney     {
821b70370b7SShawn McCarney         type = PhaseFaultType::n_plus_1;
822b70370b7SShawn McCarney     }
823b70370b7SShawn McCarney     else
824b70370b7SShawn McCarney     {
825b70370b7SShawn McCarney         throw std::invalid_argument{"Element is not a phase fault type"};
826b70370b7SShawn McCarney     }
827b70370b7SShawn McCarney 
828b70370b7SShawn McCarney     return type;
829b70370b7SShawn McCarney }
830b70370b7SShawn McCarney 
parsePMBusReadSensor(const json & element)83184614882SBob King std::unique_ptr<PMBusReadSensorAction> parsePMBusReadSensor(const json& element)
83284614882SBob King {
83384614882SBob King     verifyIsObject(element);
83484614882SBob King     unsigned int propertyCount{0};
83584614882SBob King 
83684614882SBob King     // Required type property
83784614882SBob King     const json& typeElement = getRequiredProperty(element, "type");
8382f9e14f6SShawn McCarney     SensorType type = parseSensorType(typeElement);
83984614882SBob King     ++propertyCount;
84084614882SBob King 
84184614882SBob King     // Required command property
84284614882SBob King     const json& commandElement = getRequiredProperty(element, "command");
84384614882SBob King     uint8_t command = parseHexByte(commandElement);
84484614882SBob King     ++propertyCount;
84584614882SBob King 
84684614882SBob King     // Required format property
84784614882SBob King     const json& formatElement = getRequiredProperty(element, "format");
84884614882SBob King     pmbus_utils::SensorDataFormat format = parseSensorDataFormat(formatElement);
84984614882SBob King     ++propertyCount;
85084614882SBob King 
85184614882SBob King     // Optional exponent property
85284614882SBob King     std::optional<int8_t> exponent{};
85384614882SBob King     auto exponentIt = element.find("exponent");
85484614882SBob King     if (exponentIt != element.end())
85584614882SBob King     {
85684614882SBob King         exponent = parseInt8(*exponentIt);
85784614882SBob King         ++propertyCount;
85884614882SBob King     }
85984614882SBob King 
86084614882SBob King     // Verify no invalid properties exist
86184614882SBob King     verifyPropertyCount(element, propertyCount);
86284614882SBob King 
86384614882SBob King     return std::make_unique<PMBusReadSensorAction>(type, command, format,
86484614882SBob King                                                    exponent);
86584614882SBob King }
86684614882SBob King 
parsePMBusWriteVoutCommand(const json & element)867*92261f88SPatrick Williams std::unique_ptr<PMBusWriteVoutCommandAction> parsePMBusWriteVoutCommand(
868*92261f88SPatrick Williams     const json& element)
8690e8c68abSShawn McCarney {
8700e8c68abSShawn McCarney     verifyIsObject(element);
8710e8c68abSShawn McCarney     unsigned int propertyCount{0};
8720e8c68abSShawn McCarney 
8730e8c68abSShawn McCarney     // Optional volts property
8740e8c68abSShawn McCarney     std::optional<double> volts{};
8750e8c68abSShawn McCarney     auto voltsIt = element.find("volts");
8760e8c68abSShawn McCarney     if (voltsIt != element.end())
8770e8c68abSShawn McCarney     {
8780e8c68abSShawn McCarney         volts = parseDouble(*voltsIt);
8790e8c68abSShawn McCarney         ++propertyCount;
8800e8c68abSShawn McCarney     }
8810e8c68abSShawn McCarney 
8820e8c68abSShawn McCarney     // Required format property
8830e8c68abSShawn McCarney     const json& formatElement = getRequiredProperty(element, "format");
8840e8c68abSShawn McCarney     std::string formatString = parseString(formatElement);
8850e8c68abSShawn McCarney     if (formatString != "linear")
8860e8c68abSShawn McCarney     {
8870e8c68abSShawn McCarney         throw std::invalid_argument{"Invalid format value: " + formatString};
8880e8c68abSShawn McCarney     }
8890e8c68abSShawn McCarney     pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear;
8900e8c68abSShawn McCarney     ++propertyCount;
8910e8c68abSShawn McCarney 
8920e8c68abSShawn McCarney     // Optional exponent property
8930e8c68abSShawn McCarney     std::optional<int8_t> exponent{};
8940e8c68abSShawn McCarney     auto exponentIt = element.find("exponent");
8950e8c68abSShawn McCarney     if (exponentIt != element.end())
8960e8c68abSShawn McCarney     {
8970e8c68abSShawn McCarney         exponent = parseInt8(*exponentIt);
8980e8c68abSShawn McCarney         ++propertyCount;
8990e8c68abSShawn McCarney     }
9000e8c68abSShawn McCarney 
9010e8c68abSShawn McCarney     // Optional is_verified property
9020e8c68abSShawn McCarney     bool isVerified = false;
9030e8c68abSShawn McCarney     auto isVerifiedIt = element.find("is_verified");
9040e8c68abSShawn McCarney     if (isVerifiedIt != element.end())
9050e8c68abSShawn McCarney     {
9060e8c68abSShawn McCarney         isVerified = parseBoolean(*isVerifiedIt);
9070e8c68abSShawn McCarney         ++propertyCount;
9080e8c68abSShawn McCarney     }
9090e8c68abSShawn McCarney 
9100e8c68abSShawn McCarney     // Verify no invalid properties exist
9110e8c68abSShawn McCarney     verifyPropertyCount(element, propertyCount);
9120e8c68abSShawn McCarney 
9130e8c68abSShawn McCarney     return std::make_unique<PMBusWriteVoutCommandAction>(volts, format,
9140e8c68abSShawn McCarney                                                          exponent, isVerified);
9150e8c68abSShawn McCarney }
9160e8c68abSShawn McCarney 
parsePresenceDetection(const json & element)9172aafb1c7SBob King std::unique_ptr<PresenceDetection> parsePresenceDetection(const json& element)
9182aafb1c7SBob King {
9192aafb1c7SBob King     verifyIsObject(element);
9202aafb1c7SBob King     unsigned int propertyCount{0};
9212aafb1c7SBob King 
9222aafb1c7SBob King     // Optional comments property; value not stored
9232aafb1c7SBob King     if (element.contains("comments"))
9242aafb1c7SBob King     {
9252aafb1c7SBob King         ++propertyCount;
9262aafb1c7SBob King     }
9272aafb1c7SBob King 
9282aafb1c7SBob King     // Required rule_id or actions property
9292aafb1c7SBob King     std::vector<std::unique_ptr<Action>> actions{};
9302aafb1c7SBob King     actions = parseRuleIDOrActionsProperty(element);
9312aafb1c7SBob King     ++propertyCount;
9322aafb1c7SBob King 
9332aafb1c7SBob King     // Verify no invalid properties exist
9342aafb1c7SBob King     verifyPropertyCount(element, propertyCount);
9352aafb1c7SBob King 
9362aafb1c7SBob King     return std::make_unique<PresenceDetection>(std::move(actions));
9372aafb1c7SBob King }
9382aafb1c7SBob King 
parseRail(const json & element)939a2f2a0dcSBob King std::unique_ptr<Rail> parseRail(const json& element)
940a2f2a0dcSBob King {
941a2f2a0dcSBob King     verifyIsObject(element);
942a2f2a0dcSBob King     unsigned int propertyCount{0};
943a2f2a0dcSBob King 
944a2f2a0dcSBob King     // Optional comments property; value not stored
945a2f2a0dcSBob King     if (element.contains("comments"))
946a2f2a0dcSBob King     {
947a2f2a0dcSBob King         ++propertyCount;
948a2f2a0dcSBob King     }
949a2f2a0dcSBob King 
950a2f2a0dcSBob King     // Required id property
951a2f2a0dcSBob King     const json& idElement = getRequiredProperty(element, "id");
952a2f2a0dcSBob King     std::string id = parseString(idElement);
953a2f2a0dcSBob King     ++propertyCount;
954a2f2a0dcSBob King 
955a2f2a0dcSBob King     // Optional configuration property
956a2f2a0dcSBob King     std::unique_ptr<Configuration> configuration{};
957a2f2a0dcSBob King     auto configurationIt = element.find("configuration");
958a2f2a0dcSBob King     if (configurationIt != element.end())
959a2f2a0dcSBob King     {
960a2f2a0dcSBob King         configuration = parseConfiguration(*configurationIt);
961a2f2a0dcSBob King         ++propertyCount;
962a2f2a0dcSBob King     }
963a2f2a0dcSBob King 
964a2f2a0dcSBob King     // Optional sensor_monitoring property
965a2f2a0dcSBob King     std::unique_ptr<SensorMonitoring> sensorMonitoring{};
966a2f2a0dcSBob King     auto sensorMonitoringIt = element.find("sensor_monitoring");
967a2f2a0dcSBob King     if (sensorMonitoringIt != element.end())
968a2f2a0dcSBob King     {
969a2f2a0dcSBob King         sensorMonitoring = parseSensorMonitoring(*sensorMonitoringIt);
970a2f2a0dcSBob King         ++propertyCount;
971a2f2a0dcSBob King     }
972a2f2a0dcSBob King 
973a2f2a0dcSBob King     // Verify no invalid properties exist
974a2f2a0dcSBob King     verifyPropertyCount(element, propertyCount);
975a2f2a0dcSBob King 
976a2f2a0dcSBob King     return std::make_unique<Rail>(id, std::move(configuration),
977a2f2a0dcSBob King                                   std::move(sensorMonitoring));
978a2f2a0dcSBob King }
979a2f2a0dcSBob King 
parseRailArray(const json & element)9809c36c5fbSBob King std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element)
9819c36c5fbSBob King {
9829c36c5fbSBob King     verifyIsArray(element);
9839c36c5fbSBob King     std::vector<std::unique_ptr<Rail>> rails;
984a2f2a0dcSBob King     for (auto& railElement : element)
985a2f2a0dcSBob King     {
986a2f2a0dcSBob King         rails.emplace_back(parseRail(railElement));
987a2f2a0dcSBob King     }
9889c36c5fbSBob King     return rails;
9899c36c5fbSBob King }
9909c36c5fbSBob King 
9910e8c68abSShawn McCarney std::tuple<std::vector<std::unique_ptr<Rule>>,
9920e8c68abSShawn McCarney            std::vector<std::unique_ptr<Chassis>>>
parseRoot(const json & element)9930e8c68abSShawn McCarney     parseRoot(const json& element)
9940e8c68abSShawn McCarney {
9950e8c68abSShawn McCarney     verifyIsObject(element);
9960e8c68abSShawn McCarney     unsigned int propertyCount{0};
9970e8c68abSShawn McCarney 
9980e8c68abSShawn McCarney     // Optional comments property; value not stored
9990e8c68abSShawn McCarney     if (element.contains("comments"))
10000e8c68abSShawn McCarney     {
10010e8c68abSShawn McCarney         ++propertyCount;
10020e8c68abSShawn McCarney     }
10030e8c68abSShawn McCarney 
10040e8c68abSShawn McCarney     // Optional rules property
10050e8c68abSShawn McCarney     std::vector<std::unique_ptr<Rule>> rules{};
10060e8c68abSShawn McCarney     auto rulesIt = element.find("rules");
10070e8c68abSShawn McCarney     if (rulesIt != element.end())
10080e8c68abSShawn McCarney     {
10090e8c68abSShawn McCarney         rules = parseRuleArray(*rulesIt);
10100e8c68abSShawn McCarney         ++propertyCount;
10110e8c68abSShawn McCarney     }
10120e8c68abSShawn McCarney 
10130e8c68abSShawn McCarney     // Required chassis property
10140e8c68abSShawn McCarney     const json& chassisElement = getRequiredProperty(element, "chassis");
10150e8c68abSShawn McCarney     std::vector<std::unique_ptr<Chassis>> chassis =
10160e8c68abSShawn McCarney         parseChassisArray(chassisElement);
10170e8c68abSShawn McCarney     ++propertyCount;
10180e8c68abSShawn McCarney 
10190e8c68abSShawn McCarney     // Verify no invalid properties exist
10200e8c68abSShawn McCarney     verifyPropertyCount(element, propertyCount);
10210e8c68abSShawn McCarney 
10220e8c68abSShawn McCarney     return std::make_tuple(std::move(rules), std::move(chassis));
10230e8c68abSShawn McCarney }
10240e8c68abSShawn McCarney 
parseRule(const json & element)10250e8c68abSShawn McCarney std::unique_ptr<Rule> parseRule(const json& element)
10260e8c68abSShawn McCarney {
10270e8c68abSShawn McCarney     verifyIsObject(element);
10280e8c68abSShawn McCarney     unsigned int propertyCount{0};
10290e8c68abSShawn McCarney 
10300e8c68abSShawn McCarney     // Optional comments property; value not stored
10310e8c68abSShawn McCarney     if (element.contains("comments"))
10320e8c68abSShawn McCarney     {
10330e8c68abSShawn McCarney         ++propertyCount;
10340e8c68abSShawn McCarney     }
10350e8c68abSShawn McCarney 
10360e8c68abSShawn McCarney     // Required id property
10370e8c68abSShawn McCarney     const json& idElement = getRequiredProperty(element, "id");
10380e8c68abSShawn McCarney     std::string id = parseString(idElement);
10390e8c68abSShawn McCarney     ++propertyCount;
10400e8c68abSShawn McCarney 
10410e8c68abSShawn McCarney     // Required actions property
10420e8c68abSShawn McCarney     const json& actionsElement = getRequiredProperty(element, "actions");
10430e8c68abSShawn McCarney     std::vector<std::unique_ptr<Action>> actions =
10440e8c68abSShawn McCarney         parseActionArray(actionsElement);
10450e8c68abSShawn McCarney     ++propertyCount;
10460e8c68abSShawn McCarney 
10470e8c68abSShawn McCarney     // Verify no invalid properties exist
10480e8c68abSShawn McCarney     verifyPropertyCount(element, propertyCount);
10490e8c68abSShawn McCarney 
10500e8c68abSShawn McCarney     return std::make_unique<Rule>(id, std::move(actions));
10510e8c68abSShawn McCarney }
10520e8c68abSShawn McCarney 
parseRuleArray(const json & element)10530e8c68abSShawn McCarney std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element)
10540e8c68abSShawn McCarney {
10550e8c68abSShawn McCarney     verifyIsArray(element);
10560e8c68abSShawn McCarney     std::vector<std::unique_ptr<Rule>> rules;
10570e8c68abSShawn McCarney     for (auto& ruleElement : element)
10580e8c68abSShawn McCarney     {
10590e8c68abSShawn McCarney         rules.emplace_back(parseRule(ruleElement));
10600e8c68abSShawn McCarney     }
10610e8c68abSShawn McCarney     return rules;
10620e8c68abSShawn McCarney }
10630e8c68abSShawn McCarney 
parseRuleIDOrActionsProperty(const json & element)1064*92261f88SPatrick Williams std::vector<std::unique_ptr<Action>> parseRuleIDOrActionsProperty(
1065*92261f88SPatrick Williams     const json& element)
106633e7eaa5SBob King {
106733e7eaa5SBob King     verifyIsObject(element);
106833e7eaa5SBob King     // Required rule_id or actions property
106933e7eaa5SBob King     std::vector<std::unique_ptr<Action>> actions{};
107033e7eaa5SBob King     auto ruleIDIt = element.find("rule_id");
107133e7eaa5SBob King     auto actionsIt = element.find("actions");
107233e7eaa5SBob King     if ((actionsIt == element.end()) && (ruleIDIt != element.end()))
107333e7eaa5SBob King     {
107433e7eaa5SBob King         std::string ruleID = parseString(*ruleIDIt);
107533e7eaa5SBob King         actions.emplace_back(std::make_unique<RunRuleAction>(ruleID));
107633e7eaa5SBob King     }
107733e7eaa5SBob King     else if ((actionsIt != element.end()) && (ruleIDIt == element.end()))
107833e7eaa5SBob King     {
107933e7eaa5SBob King         actions = parseActionArray(*actionsIt);
108033e7eaa5SBob King     }
108133e7eaa5SBob King     else
108233e7eaa5SBob King     {
108333e7eaa5SBob King         throw std::invalid_argument{"Invalid property combination: Must "
108433e7eaa5SBob King                                     "contain either rule_id or actions"};
108533e7eaa5SBob King     }
108633e7eaa5SBob King 
108733e7eaa5SBob King     return actions;
108833e7eaa5SBob King }
108933e7eaa5SBob King 
parseRunRule(const json & element)1090315b0b62SBob King std::unique_ptr<RunRuleAction> parseRunRule(const json& element)
1091315b0b62SBob King {
1092315b0b62SBob King     // String ruleID
1093315b0b62SBob King     std::string ruleID = parseString(element);
1094315b0b62SBob King 
1095315b0b62SBob King     return std::make_unique<RunRuleAction>(ruleID);
1096315b0b62SBob King }
1097315b0b62SBob King 
parseSensorDataFormat(const json & element)109884614882SBob King pmbus_utils::SensorDataFormat parseSensorDataFormat(const json& element)
109984614882SBob King {
110084614882SBob King     if (!element.is_string())
110184614882SBob King     {
110284614882SBob King         throw std::invalid_argument{"Element is not a string"};
110384614882SBob King     }
110484614882SBob King     std::string value = element.get<std::string>();
110584614882SBob King     pmbus_utils::SensorDataFormat format{};
110684614882SBob King 
110784614882SBob King     if (value == "linear_11")
110884614882SBob King     {
110984614882SBob King         format = pmbus_utils::SensorDataFormat::linear_11;
111084614882SBob King     }
111184614882SBob King     else if (value == "linear_16")
111284614882SBob King     {
111384614882SBob King         format = pmbus_utils::SensorDataFormat::linear_16;
111484614882SBob King     }
111584614882SBob King     else
111684614882SBob King     {
111784614882SBob King         throw std::invalid_argument{"Element is not a sensor data format"};
111884614882SBob King     }
111984614882SBob King 
112084614882SBob King     return format;
112184614882SBob King }
112284614882SBob King 
parseSensorMonitoring(const json & element)1123a2f2a0dcSBob King std::unique_ptr<SensorMonitoring> parseSensorMonitoring(const json& element)
1124a2f2a0dcSBob King {
1125a2f2a0dcSBob King     verifyIsObject(element);
1126a2f2a0dcSBob King     unsigned int propertyCount{0};
1127a2f2a0dcSBob King 
1128a2f2a0dcSBob King     // Optional comments property; value not stored
1129a2f2a0dcSBob King     if (element.contains("comments"))
1130a2f2a0dcSBob King     {
1131a2f2a0dcSBob King         ++propertyCount;
1132a2f2a0dcSBob King     }
1133a2f2a0dcSBob King 
1134a2f2a0dcSBob King     // Required rule_id or actions property
1135a2f2a0dcSBob King     std::vector<std::unique_ptr<Action>> actions{};
1136a2f2a0dcSBob King     actions = parseRuleIDOrActionsProperty(element);
1137a2f2a0dcSBob King     ++propertyCount;
1138a2f2a0dcSBob King 
1139a2f2a0dcSBob King     // Verify no invalid properties exist
1140a2f2a0dcSBob King     verifyPropertyCount(element, propertyCount);
1141a2f2a0dcSBob King 
1142a2f2a0dcSBob King     return std::make_unique<SensorMonitoring>(std::move(actions));
1143a2f2a0dcSBob King }
1144a2f2a0dcSBob King 
parseSensorType(const json & element)11452f9e14f6SShawn McCarney SensorType parseSensorType(const json& element)
114684614882SBob King {
1147b70370b7SShawn McCarney     std::string value = parseString(element);
11482f9e14f6SShawn McCarney     SensorType type{};
114984614882SBob King 
115084614882SBob King     if (value == "iout")
115184614882SBob King     {
11522f9e14f6SShawn McCarney         type = SensorType::iout;
115384614882SBob King     }
115484614882SBob King     else if (value == "iout_peak")
115584614882SBob King     {
11562f9e14f6SShawn McCarney         type = SensorType::iout_peak;
115784614882SBob King     }
115884614882SBob King     else if (value == "iout_valley")
115984614882SBob King     {
11602f9e14f6SShawn McCarney         type = SensorType::iout_valley;
116184614882SBob King     }
116284614882SBob King     else if (value == "pout")
116384614882SBob King     {
11642f9e14f6SShawn McCarney         type = SensorType::pout;
116584614882SBob King     }
116684614882SBob King     else if (value == "temperature")
116784614882SBob King     {
11682f9e14f6SShawn McCarney         type = SensorType::temperature;
116984614882SBob King     }
117084614882SBob King     else if (value == "temperature_peak")
117184614882SBob King     {
11722f9e14f6SShawn McCarney         type = SensorType::temperature_peak;
117384614882SBob King     }
117484614882SBob King     else if (value == "vout")
117584614882SBob King     {
11762f9e14f6SShawn McCarney         type = SensorType::vout;
117784614882SBob King     }
117884614882SBob King     else if (value == "vout_peak")
117984614882SBob King     {
11802f9e14f6SShawn McCarney         type = SensorType::vout_peak;
118184614882SBob King     }
118284614882SBob King     else if (value == "vout_valley")
118384614882SBob King     {
11842f9e14f6SShawn McCarney         type = SensorType::vout_valley;
118584614882SBob King     }
118684614882SBob King     else
118784614882SBob King     {
11882f9e14f6SShawn McCarney         throw std::invalid_argument{"Element is not a sensor type"};
118984614882SBob King     }
119084614882SBob King 
119184614882SBob King     return type;
119284614882SBob King }
119384614882SBob King 
parseSetDevice(const json & element)119418a68505SBob King std::unique_ptr<SetDeviceAction> parseSetDevice(const json& element)
119518a68505SBob King {
119618a68505SBob King     // String deviceID
119718a68505SBob King     std::string deviceID = parseString(element);
119818a68505SBob King 
119918a68505SBob King     return std::make_unique<SetDeviceAction>(deviceID);
120018a68505SBob King }
120118a68505SBob King 
parseVoutDataFormat(const json & element)120284614882SBob King pmbus_utils::VoutDataFormat parseVoutDataFormat(const json& element)
120384614882SBob King {
120484614882SBob King     if (!element.is_string())
120584614882SBob King     {
120684614882SBob King         throw std::invalid_argument{"Element is not a string"};
120784614882SBob King     }
120884614882SBob King     std::string value = element.get<std::string>();
120984614882SBob King     pmbus_utils::VoutDataFormat format{};
121084614882SBob King 
121184614882SBob King     if (value == "linear")
121284614882SBob King     {
121384614882SBob King         format = pmbus_utils::VoutDataFormat::linear;
121484614882SBob King     }
121584614882SBob King     else if (value == "vid")
121684614882SBob King     {
121784614882SBob King         format = pmbus_utils::VoutDataFormat::vid;
121884614882SBob King     }
121984614882SBob King     else if (value == "direct")
122084614882SBob King     {
122184614882SBob King         format = pmbus_utils::VoutDataFormat::direct;
122284614882SBob King     }
122384614882SBob King     else if (value == "ieee")
122484614882SBob King     {
122584614882SBob King         format = pmbus_utils::VoutDataFormat::ieee;
122684614882SBob King     }
122784614882SBob King     else
122884614882SBob King     {
122984614882SBob King         throw std::invalid_argument{"Element is not a vout data format"};
123084614882SBob King     }
123184614882SBob King 
123284614882SBob King     return format;
123384614882SBob King }
123484614882SBob King 
12350e8c68abSShawn McCarney } // namespace internal
12360e8c68abSShawn McCarney 
12370e8c68abSShawn McCarney } // namespace phosphor::power::regulators::config_file_parser
1238