1 /** 2 * Copyright © 2024 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 21 #include <exception> 22 #include <fstream> 23 #include <optional> 24 25 using json = nlohmann::json; 26 27 namespace phosphor::power::sequencer::config_file_parser 28 { 29 30 std::vector<std::unique_ptr<Rail>> parse(const std::filesystem::path& pathName) 31 { 32 try 33 { 34 // Use standard JSON parser to create tree of JSON elements 35 std::ifstream file{pathName}; 36 json rootElement = json::parse(file); 37 38 // Parse tree of JSON elements and return corresponding C++ objects 39 return internal::parseRoot(rootElement); 40 } 41 catch (const std::exception& e) 42 { 43 throw ConfigFileParserError{pathName, e.what()}; 44 } 45 } 46 47 namespace internal 48 { 49 50 GPIO parseGPIO(const json& element) 51 { 52 verifyIsObject(element); 53 unsigned int propertyCount{0}; 54 55 // Required line property 56 const json& lineElement = getRequiredProperty(element, "line"); 57 unsigned int line = parseUnsignedInteger(lineElement); 58 ++propertyCount; 59 60 // Optional active_low property 61 bool activeLow{false}; 62 auto activeLowIt = element.find("active_low"); 63 if (activeLowIt != element.end()) 64 { 65 activeLow = parseBoolean(*activeLowIt); 66 ++propertyCount; 67 } 68 69 // Verify no invalid properties exist 70 verifyPropertyCount(element, propertyCount); 71 72 return GPIO(line, activeLow); 73 } 74 75 std::unique_ptr<Rail> parseRail(const json& element) 76 { 77 verifyIsObject(element); 78 unsigned int propertyCount{0}; 79 80 // Required name property 81 const json& nameElement = getRequiredProperty(element, "name"); 82 std::string name = parseString(nameElement); 83 ++propertyCount; 84 85 // Optional presence property 86 std::optional<std::string> presence{}; 87 auto presenceIt = element.find("presence"); 88 if (presenceIt != element.end()) 89 { 90 presence = parseString(*presenceIt); 91 ++propertyCount; 92 } 93 94 // Optional page property 95 std::optional<uint8_t> page{}; 96 auto pageIt = element.find("page"); 97 if (pageIt != element.end()) 98 { 99 page = parseUint8(*pageIt); 100 ++propertyCount; 101 } 102 103 // Optional is_power_supply_rail property 104 bool isPowerSupplyRail{false}; 105 auto isPowerSupplyRailIt = element.find("is_power_supply_rail"); 106 if (isPowerSupplyRailIt != element.end()) 107 { 108 isPowerSupplyRail = parseBoolean(*isPowerSupplyRailIt); 109 ++propertyCount; 110 } 111 112 // Optional check_status_vout property 113 bool checkStatusVout{false}; 114 auto checkStatusVoutIt = element.find("check_status_vout"); 115 if (checkStatusVoutIt != element.end()) 116 { 117 checkStatusVout = parseBoolean(*checkStatusVoutIt); 118 ++propertyCount; 119 } 120 121 // Optional compare_voltage_to_limits property 122 bool compareVoltageToLimits{false}; 123 auto compareVoltageToLimitsIt = element.find("compare_voltage_to_limits"); 124 if (compareVoltageToLimitsIt != element.end()) 125 { 126 compareVoltageToLimits = parseBoolean(*compareVoltageToLimitsIt); 127 ++propertyCount; 128 } 129 130 // Optional gpio property 131 std::optional<GPIO> gpio{}; 132 auto gpioIt = element.find("gpio"); 133 if (gpioIt != element.end()) 134 { 135 gpio = parseGPIO(*gpioIt); 136 ++propertyCount; 137 } 138 139 // If check_status_vout or compare_voltage_to_limits property is true, 140 // the page property is required; verify page was specified 141 if ((checkStatusVout || compareVoltageToLimits) && !page.has_value()) 142 { 143 throw std::invalid_argument{"Required property missing: page"}; 144 } 145 146 // Verify no invalid properties exist 147 verifyPropertyCount(element, propertyCount); 148 149 return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail, 150 checkStatusVout, compareVoltageToLimits, 151 gpio); 152 } 153 154 std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element) 155 { 156 verifyIsArray(element); 157 std::vector<std::unique_ptr<Rail>> rails; 158 for (auto& railElement : element) 159 { 160 rails.emplace_back(parseRail(railElement)); 161 } 162 return rails; 163 } 164 165 std::vector<std::unique_ptr<Rail>> parseRoot(const json& element) 166 { 167 verifyIsObject(element); 168 unsigned int propertyCount{0}; 169 170 // Required rails property 171 const json& railsElement = getRequiredProperty(element, "rails"); 172 std::vector<std::unique_ptr<Rail>> rails = parseRailArray(railsElement); 173 ++propertyCount; 174 175 // Verify no invalid properties exist 176 verifyPropertyCount(element, propertyCount); 177 178 return rails; 179 } 180 181 } // namespace internal 182 183 } // namespace phosphor::power::sequencer::config_file_parser 184