blob: 4539eb7ac40db62138808b107596ce5f50394283 [file] [log] [blame]
Shawn McCarney6a957f62024-01-10 16:15:19 -06001/**
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"
Shawn McCarney38f85002025-10-31 17:59:36 -050020#include "json_parser_utils.hpp"
Shawn McCarney4840b252025-11-06 16:06:40 -060021#include "ucd90160_device.hpp"
22#include "ucd90320_device.hpp"
Shawn McCarney6a957f62024-01-10 16:15:19 -060023
Shawn McCarney38f85002025-10-31 17:59:36 -050024#include <cstdint>
Shawn McCarney6a957f62024-01-10 16:15:19 -060025#include <exception>
26#include <fstream>
27#include <optional>
Shawn McCarney38f85002025-10-31 17:59:36 -050028#include <stdexcept>
Shawn McCarney6a957f62024-01-10 16:15:19 -060029
Shawn McCarney38f85002025-10-31 17:59:36 -050030using namespace phosphor::power::json_parser_utils;
31using ConfigFileParserError = phosphor::power::util::ConfigFileParserError;
Shawn McCarney6a957f62024-01-10 16:15:19 -060032using json = nlohmann::json;
Shawn McCarneye9144ab2024-05-22 12:34:18 -050033namespace fs = std::filesystem;
Shawn McCarney6a957f62024-01-10 16:15:19 -060034
35namespace phosphor::power::sequencer::config_file_parser
36{
37
Shawn McCarneye9144ab2024-05-22 12:34:18 -050038const std::filesystem::path standardConfigFileDirectory{
39 "/usr/share/phosphor-power-sequencer"};
40
Patrick Williams92261f82025-02-01 08:22:34 -050041std::filesystem::path find(
42 const std::vector<std::string>& compatibleSystemTypes,
43 const std::filesystem::path& configFileDir)
Shawn McCarneye9144ab2024-05-22 12:34:18 -050044{
45 fs::path pathName, possiblePath;
46 std::string fileName;
47
48 for (const std::string& systemType : compatibleSystemTypes)
49 {
50 // Look for file name that is entire system type + ".json"
51 // Example: com.acme.Hardware.Chassis.Model.MegaServer.json
52 fileName = systemType + ".json";
53 possiblePath = configFileDir / fileName;
54 if (fs::is_regular_file(possiblePath))
55 {
56 pathName = possiblePath;
57 break;
58 }
59
60 // Look for file name that is last node of system type + ".json"
61 // Example: MegaServer.json
62 std::string::size_type pos = systemType.rfind('.');
63 if ((pos != std::string::npos) && ((systemType.size() - pos) > 1))
64 {
65 fileName = systemType.substr(pos + 1) + ".json";
66 possiblePath = configFileDir / fileName;
67 if (fs::is_regular_file(possiblePath))
68 {
69 pathName = possiblePath;
70 break;
71 }
72 }
73 }
74
75 return pathName;
76}
77
Shawn McCarney6a957f62024-01-10 16:15:19 -060078std::vector<std::unique_ptr<Rail>> parse(const std::filesystem::path& pathName)
79{
80 try
81 {
82 // Use standard JSON parser to create tree of JSON elements
83 std::ifstream file{pathName};
84 json rootElement = json::parse(file);
85
86 // Parse tree of JSON elements and return corresponding C++ objects
87 return internal::parseRoot(rootElement);
88 }
89 catch (const std::exception& e)
90 {
91 throw ConfigFileParserError{pathName, e.what()};
92 }
93}
94
95namespace internal
96{
97
Shawn McCarney038f2ba2025-11-06 13:32:16 -060098GPIO parseGPIO(const json& element,
99 const std::map<std::string, std::string>& variables)
Shawn McCarney6a957f62024-01-10 16:15:19 -0600100{
101 verifyIsObject(element);
102 unsigned int propertyCount{0};
103
104 // Required line property
105 const json& lineElement = getRequiredProperty(element, "line");
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600106 unsigned int line = parseUnsignedInteger(lineElement, variables);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600107 ++propertyCount;
108
109 // Optional active_low property
110 bool activeLow{false};
111 auto activeLowIt = element.find("active_low");
112 if (activeLowIt != element.end())
113 {
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600114 activeLow = parseBoolean(*activeLowIt, variables);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600115 ++propertyCount;
116 }
117
118 // Verify no invalid properties exist
119 verifyPropertyCount(element, propertyCount);
120
121 return GPIO(line, activeLow);
122}
123
Shawn McCarneye140ed92025-11-06 11:20:38 -0600124std::tuple<uint8_t, uint16_t> parseI2CInterface(
125 const nlohmann::json& element,
126 const std::map<std::string, std::string>& variables)
127{
128 verifyIsObject(element);
129 unsigned int propertyCount{0};
130
131 // Required bus property
132 const json& busElement = getRequiredProperty(element, "bus");
133 uint8_t bus = parseUint8(busElement, variables);
134 ++propertyCount;
135
136 // Required address property
137 const json& addressElement = getRequiredProperty(element, "address");
138 uint16_t address = parseHexByte(addressElement, variables);
139 ++propertyCount;
140
141 // Verify no invalid properties exist
142 verifyPropertyCount(element, propertyCount);
143
144 return {bus, address};
145}
146
Shawn McCarney4840b252025-11-06 16:06:40 -0600147std::unique_ptr<PowerSequencerDevice> parsePowerSequencer(
148 const nlohmann::json& element,
149 const std::map<std::string, std::string>& variables, Services& services)
150{
151 verifyIsObject(element);
152 unsigned int propertyCount{0};
153
154 // Optional comments property; value not stored
155 if (element.contains("comments"))
156 {
157 ++propertyCount;
158 }
159
160 // Required type property
161 const json& typeElement = getRequiredProperty(element, "type");
162 std::string type = parseString(typeElement, false, variables);
163 ++propertyCount;
164
165 // Required i2c_interface property
166 const json& i2cInterfaceElement =
167 getRequiredProperty(element, "i2c_interface");
168 auto [bus, address] = parseI2CInterface(i2cInterfaceElement, variables);
169 ++propertyCount;
170
171 // Required power_control_gpio_name property
172 const json& powerControlGPIONameElement =
173 getRequiredProperty(element, "power_control_gpio_name");
174 std::string powerControlGPIOName =
175 parseString(powerControlGPIONameElement, false, variables);
176 ++propertyCount;
177
178 // Required power_good_gpio_name property
179 const json& powerGoodGPIONameElement =
180 getRequiredProperty(element, "power_good_gpio_name");
181 std::string powerGoodGPIOName =
182 parseString(powerGoodGPIONameElement, false, variables);
183 ++propertyCount;
184
185 // Required rails property
186 const json& railsElement = getRequiredProperty(element, "rails");
187 std::vector<std::unique_ptr<Rail>> rails =
188 parseRailArray(railsElement, variables);
189 ++propertyCount;
190
191 // Verify no invalid properties exist
192 verifyPropertyCount(element, propertyCount);
193
194 if (type == UCD90160Device::deviceName)
195 {
196 return std::make_unique<UCD90160Device>(
197 bus, address, powerControlGPIOName, powerGoodGPIOName,
198 std::move(rails), services);
199 }
200 else if (type == UCD90320Device::deviceName)
201 {
202 return std::make_unique<UCD90320Device>(
203 bus, address, powerControlGPIOName, powerGoodGPIOName,
204 std::move(rails), services);
205 }
206 throw std::invalid_argument{"Invalid power sequencer type: " + type};
207}
208
209std::vector<std::unique_ptr<PowerSequencerDevice>> parsePowerSequencerArray(
210 const nlohmann::json& element,
211 const std::map<std::string, std::string>& variables, Services& services)
212{
213 verifyIsArray(element);
214 std::vector<std::unique_ptr<PowerSequencerDevice>> powerSequencers;
215 for (auto& powerSequencerElement : element)
216 {
217 powerSequencers.emplace_back(
218 parsePowerSequencer(powerSequencerElement, variables, services));
219 }
220 return powerSequencers;
221}
222
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600223std::unique_ptr<Rail> parseRail(
224 const json& element, const std::map<std::string, std::string>& variables)
Shawn McCarney6a957f62024-01-10 16:15:19 -0600225{
226 verifyIsObject(element);
227 unsigned int propertyCount{0};
228
229 // Required name property
230 const json& nameElement = getRequiredProperty(element, "name");
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600231 std::string name = parseString(nameElement, false, variables);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600232 ++propertyCount;
233
234 // Optional presence property
235 std::optional<std::string> presence{};
236 auto presenceIt = element.find("presence");
237 if (presenceIt != element.end())
238 {
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600239 presence = parseString(*presenceIt, false, variables);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600240 ++propertyCount;
241 }
242
243 // Optional page property
244 std::optional<uint8_t> page{};
245 auto pageIt = element.find("page");
246 if (pageIt != element.end())
247 {
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600248 page = parseUint8(*pageIt, variables);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600249 ++propertyCount;
250 }
251
Shawn McCarney16e493a2024-01-29 14:20:32 -0600252 // Optional is_power_supply_rail property
253 bool isPowerSupplyRail{false};
254 auto isPowerSupplyRailIt = element.find("is_power_supply_rail");
255 if (isPowerSupplyRailIt != element.end())
256 {
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600257 isPowerSupplyRail = parseBoolean(*isPowerSupplyRailIt, variables);
Shawn McCarney16e493a2024-01-29 14:20:32 -0600258 ++propertyCount;
259 }
260
Shawn McCarney6a957f62024-01-10 16:15:19 -0600261 // Optional check_status_vout property
262 bool checkStatusVout{false};
263 auto checkStatusVoutIt = element.find("check_status_vout");
264 if (checkStatusVoutIt != element.end())
265 {
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600266 checkStatusVout = parseBoolean(*checkStatusVoutIt, variables);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600267 ++propertyCount;
268 }
269
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600270 // Optional compare_voltage_to_limit property
271 bool compareVoltageToLimit{false};
272 auto compareVoltageToLimitIt = element.find("compare_voltage_to_limit");
273 if (compareVoltageToLimitIt != element.end())
Shawn McCarney6a957f62024-01-10 16:15:19 -0600274 {
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600275 compareVoltageToLimit =
276 parseBoolean(*compareVoltageToLimitIt, variables);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600277 ++propertyCount;
278 }
279
280 // Optional gpio property
281 std::optional<GPIO> gpio{};
282 auto gpioIt = element.find("gpio");
283 if (gpioIt != element.end())
284 {
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600285 gpio = parseGPIO(*gpioIt, variables);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600286 ++propertyCount;
287 }
288
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600289 // If check_status_vout or compare_voltage_to_limit property is true, the
290 // page property is required; verify page was specified
291 if ((checkStatusVout || compareVoltageToLimit) && !page.has_value())
Shawn McCarney6a957f62024-01-10 16:15:19 -0600292 {
293 throw std::invalid_argument{"Required property missing: page"};
294 }
295
296 // Verify no invalid properties exist
297 verifyPropertyCount(element, propertyCount);
298
Shawn McCarney16e493a2024-01-29 14:20:32 -0600299 return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail,
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600300 checkStatusVout, compareVoltageToLimit, gpio);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600301}
302
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600303std::vector<std::unique_ptr<Rail>> parseRailArray(
304 const json& element, const std::map<std::string, std::string>& variables)
Shawn McCarney6a957f62024-01-10 16:15:19 -0600305{
306 verifyIsArray(element);
307 std::vector<std::unique_ptr<Rail>> rails;
308 for (auto& railElement : element)
309 {
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600310 rails.emplace_back(parseRail(railElement, variables));
Shawn McCarney6a957f62024-01-10 16:15:19 -0600311 }
312 return rails;
313}
314
315std::vector<std::unique_ptr<Rail>> parseRoot(const json& element)
316{
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600317 std::map<std::string, std::string> variables{};
318
Shawn McCarney6a957f62024-01-10 16:15:19 -0600319 verifyIsObject(element);
320 unsigned int propertyCount{0};
321
322 // Required rails property
323 const json& railsElement = getRequiredProperty(element, "rails");
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600324 std::vector<std::unique_ptr<Rail>> rails =
325 parseRailArray(railsElement, variables);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600326 ++propertyCount;
327
328 // Verify no invalid properties exist
329 verifyPropertyCount(element, propertyCount);
330
331 return rails;
332}
333
334} // namespace internal
335
336} // namespace phosphor::power::sequencer::config_file_parser