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 check_status_vout property 104 bool checkStatusVout{false}; 105 auto checkStatusVoutIt = element.find("check_status_vout"); 106 if (checkStatusVoutIt != element.end()) 107 { 108 checkStatusVout = parseBoolean(*checkStatusVoutIt); 109 ++propertyCount; 110 } 111 112 // Optional compare_voltage_to_limits property 113 bool compareVoltageToLimits{false}; 114 auto compareVoltageToLimitsIt = element.find("compare_voltage_to_limits"); 115 if (compareVoltageToLimitsIt != element.end()) 116 { 117 compareVoltageToLimits = parseBoolean(*compareVoltageToLimitsIt); 118 ++propertyCount; 119 } 120 121 // Optional gpio property 122 std::optional<GPIO> gpio{}; 123 auto gpioIt = element.find("gpio"); 124 if (gpioIt != element.end()) 125 { 126 gpio = parseGPIO(*gpioIt); 127 ++propertyCount; 128 } 129 130 // If check_status_vout or compare_voltage_to_limits property is true, 131 // the page property is required; verify page was specified 132 if ((checkStatusVout || compareVoltageToLimits) && !page.has_value()) 133 { 134 throw std::invalid_argument{"Required property missing: page"}; 135 } 136 137 // Verify no invalid properties exist 138 verifyPropertyCount(element, propertyCount); 139 140 return std::make_unique<Rail>(name, presence, page, checkStatusVout, 141 compareVoltageToLimits, gpio); 142 } 143 144 std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element) 145 { 146 verifyIsArray(element); 147 std::vector<std::unique_ptr<Rail>> rails; 148 for (auto& railElement : element) 149 { 150 rails.emplace_back(parseRail(railElement)); 151 } 152 return rails; 153 } 154 155 std::vector<std::unique_ptr<Rail>> parseRoot(const json& element) 156 { 157 verifyIsObject(element); 158 unsigned int propertyCount{0}; 159 160 // Required rails property 161 const json& railsElement = getRequiredProperty(element, "rails"); 162 std::vector<std::unique_ptr<Rail>> rails = parseRailArray(railsElement); 163 ++propertyCount; 164 165 // Verify no invalid properties exist 166 verifyPropertyCount(element, propertyCount); 167 168 return rails; 169 } 170 171 } // namespace internal 172 173 } // namespace phosphor::power::sequencer::config_file_parser 174