blob: 0812744999d652924d249be85ce61d647d67aee6 [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 McCarney6a957f62024-01-10 16:15:19 -060021
Shawn McCarney38f85002025-10-31 17:59:36 -050022#include <cstdint>
Shawn McCarney6a957f62024-01-10 16:15:19 -060023#include <exception>
24#include <fstream>
25#include <optional>
Shawn McCarney38f85002025-10-31 17:59:36 -050026#include <stdexcept>
Shawn McCarney6a957f62024-01-10 16:15:19 -060027
Shawn McCarney38f85002025-10-31 17:59:36 -050028using namespace phosphor::power::json_parser_utils;
29using ConfigFileParserError = phosphor::power::util::ConfigFileParserError;
Shawn McCarney6a957f62024-01-10 16:15:19 -060030using json = nlohmann::json;
Shawn McCarneye9144ab2024-05-22 12:34:18 -050031namespace fs = std::filesystem;
Shawn McCarney6a957f62024-01-10 16:15:19 -060032
33namespace phosphor::power::sequencer::config_file_parser
34{
35
Shawn McCarneye9144ab2024-05-22 12:34:18 -050036const std::filesystem::path standardConfigFileDirectory{
37 "/usr/share/phosphor-power-sequencer"};
38
Patrick Williams92261f82025-02-01 08:22:34 -050039std::filesystem::path find(
40 const std::vector<std::string>& compatibleSystemTypes,
41 const std::filesystem::path& configFileDir)
Shawn McCarneye9144ab2024-05-22 12:34:18 -050042{
43 fs::path pathName, possiblePath;
44 std::string fileName;
45
46 for (const std::string& systemType : compatibleSystemTypes)
47 {
48 // Look for file name that is entire system type + ".json"
49 // Example: com.acme.Hardware.Chassis.Model.MegaServer.json
50 fileName = systemType + ".json";
51 possiblePath = configFileDir / fileName;
52 if (fs::is_regular_file(possiblePath))
53 {
54 pathName = possiblePath;
55 break;
56 }
57
58 // Look for file name that is last node of system type + ".json"
59 // Example: MegaServer.json
60 std::string::size_type pos = systemType.rfind('.');
61 if ((pos != std::string::npos) && ((systemType.size() - pos) > 1))
62 {
63 fileName = systemType.substr(pos + 1) + ".json";
64 possiblePath = configFileDir / fileName;
65 if (fs::is_regular_file(possiblePath))
66 {
67 pathName = possiblePath;
68 break;
69 }
70 }
71 }
72
73 return pathName;
74}
75
Shawn McCarney6a957f62024-01-10 16:15:19 -060076std::vector<std::unique_ptr<Rail>> parse(const std::filesystem::path& pathName)
77{
78 try
79 {
80 // Use standard JSON parser to create tree of JSON elements
81 std::ifstream file{pathName};
82 json rootElement = json::parse(file);
83
84 // Parse tree of JSON elements and return corresponding C++ objects
85 return internal::parseRoot(rootElement);
86 }
87 catch (const std::exception& e)
88 {
89 throw ConfigFileParserError{pathName, e.what()};
90 }
91}
92
93namespace internal
94{
95
Shawn McCarney038f2ba2025-11-06 13:32:16 -060096GPIO parseGPIO(const json& element,
97 const std::map<std::string, std::string>& variables)
Shawn McCarney6a957f62024-01-10 16:15:19 -060098{
99 verifyIsObject(element);
100 unsigned int propertyCount{0};
101
102 // Required line property
103 const json& lineElement = getRequiredProperty(element, "line");
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600104 unsigned int line = parseUnsignedInteger(lineElement, variables);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600105 ++propertyCount;
106
107 // Optional active_low property
108 bool activeLow{false};
109 auto activeLowIt = element.find("active_low");
110 if (activeLowIt != element.end())
111 {
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600112 activeLow = parseBoolean(*activeLowIt, variables);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600113 ++propertyCount;
114 }
115
116 // Verify no invalid properties exist
117 verifyPropertyCount(element, propertyCount);
118
119 return GPIO(line, activeLow);
120}
121
Shawn McCarneye140ed92025-11-06 11:20:38 -0600122std::tuple<uint8_t, uint16_t> parseI2CInterface(
123 const nlohmann::json& element,
124 const std::map<std::string, std::string>& variables)
125{
126 verifyIsObject(element);
127 unsigned int propertyCount{0};
128
129 // Required bus property
130 const json& busElement = getRequiredProperty(element, "bus");
131 uint8_t bus = parseUint8(busElement, variables);
132 ++propertyCount;
133
134 // Required address property
135 const json& addressElement = getRequiredProperty(element, "address");
136 uint16_t address = parseHexByte(addressElement, variables);
137 ++propertyCount;
138
139 // Verify no invalid properties exist
140 verifyPropertyCount(element, propertyCount);
141
142 return {bus, address};
143}
144
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600145std::unique_ptr<Rail> parseRail(
146 const json& element, const std::map<std::string, std::string>& variables)
Shawn McCarney6a957f62024-01-10 16:15:19 -0600147{
148 verifyIsObject(element);
149 unsigned int propertyCount{0};
150
151 // Required name property
152 const json& nameElement = getRequiredProperty(element, "name");
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600153 std::string name = parseString(nameElement, false, variables);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600154 ++propertyCount;
155
156 // Optional presence property
157 std::optional<std::string> presence{};
158 auto presenceIt = element.find("presence");
159 if (presenceIt != element.end())
160 {
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600161 presence = parseString(*presenceIt, false, variables);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600162 ++propertyCount;
163 }
164
165 // Optional page property
166 std::optional<uint8_t> page{};
167 auto pageIt = element.find("page");
168 if (pageIt != element.end())
169 {
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600170 page = parseUint8(*pageIt, variables);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600171 ++propertyCount;
172 }
173
Shawn McCarney16e493a2024-01-29 14:20:32 -0600174 // Optional is_power_supply_rail property
175 bool isPowerSupplyRail{false};
176 auto isPowerSupplyRailIt = element.find("is_power_supply_rail");
177 if (isPowerSupplyRailIt != element.end())
178 {
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600179 isPowerSupplyRail = parseBoolean(*isPowerSupplyRailIt, variables);
Shawn McCarney16e493a2024-01-29 14:20:32 -0600180 ++propertyCount;
181 }
182
Shawn McCarney6a957f62024-01-10 16:15:19 -0600183 // Optional check_status_vout property
184 bool checkStatusVout{false};
185 auto checkStatusVoutIt = element.find("check_status_vout");
186 if (checkStatusVoutIt != element.end())
187 {
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600188 checkStatusVout = parseBoolean(*checkStatusVoutIt, variables);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600189 ++propertyCount;
190 }
191
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600192 // Optional compare_voltage_to_limit property
193 bool compareVoltageToLimit{false};
194 auto compareVoltageToLimitIt = element.find("compare_voltage_to_limit");
195 if (compareVoltageToLimitIt != element.end())
Shawn McCarney6a957f62024-01-10 16:15:19 -0600196 {
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600197 compareVoltageToLimit =
198 parseBoolean(*compareVoltageToLimitIt, variables);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600199 ++propertyCount;
200 }
201
202 // Optional gpio property
203 std::optional<GPIO> gpio{};
204 auto gpioIt = element.find("gpio");
205 if (gpioIt != element.end())
206 {
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600207 gpio = parseGPIO(*gpioIt, variables);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600208 ++propertyCount;
209 }
210
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600211 // If check_status_vout or compare_voltage_to_limit property is true, the
212 // page property is required; verify page was specified
213 if ((checkStatusVout || compareVoltageToLimit) && !page.has_value())
Shawn McCarney6a957f62024-01-10 16:15:19 -0600214 {
215 throw std::invalid_argument{"Required property missing: page"};
216 }
217
218 // Verify no invalid properties exist
219 verifyPropertyCount(element, propertyCount);
220
Shawn McCarney16e493a2024-01-29 14:20:32 -0600221 return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail,
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600222 checkStatusVout, compareVoltageToLimit, gpio);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600223}
224
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600225std::vector<std::unique_ptr<Rail>> parseRailArray(
226 const json& element, const std::map<std::string, std::string>& variables)
Shawn McCarney6a957f62024-01-10 16:15:19 -0600227{
228 verifyIsArray(element);
229 std::vector<std::unique_ptr<Rail>> rails;
230 for (auto& railElement : element)
231 {
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600232 rails.emplace_back(parseRail(railElement, variables));
Shawn McCarney6a957f62024-01-10 16:15:19 -0600233 }
234 return rails;
235}
236
237std::vector<std::unique_ptr<Rail>> parseRoot(const json& element)
238{
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600239 std::map<std::string, std::string> variables{};
240
Shawn McCarney6a957f62024-01-10 16:15:19 -0600241 verifyIsObject(element);
242 unsigned int propertyCount{0};
243
244 // Required rails property
245 const json& railsElement = getRequiredProperty(element, "rails");
Shawn McCarney038f2ba2025-11-06 13:32:16 -0600246 std::vector<std::unique_ptr<Rail>> rails =
247 parseRailArray(railsElement, variables);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600248 ++propertyCount;
249
250 // Verify no invalid properties exist
251 verifyPropertyCount(element, propertyCount);
252
253 return rails;
254}
255
256} // namespace internal
257
258} // namespace phosphor::power::sequencer::config_file_parser