blob: 3163aff8432654f73198d0f67c96adb6fae1d94c [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
96GPIO parseGPIO(const json& element)
97{
98 verifyIsObject(element);
99 unsigned int propertyCount{0};
100
101 // Required line property
102 const json& lineElement = getRequiredProperty(element, "line");
103 unsigned int line = parseUnsignedInteger(lineElement);
104 ++propertyCount;
105
106 // Optional active_low property
107 bool activeLow{false};
108 auto activeLowIt = element.find("active_low");
109 if (activeLowIt != element.end())
110 {
111 activeLow = parseBoolean(*activeLowIt);
112 ++propertyCount;
113 }
114
115 // Verify no invalid properties exist
116 verifyPropertyCount(element, propertyCount);
117
118 return GPIO(line, activeLow);
119}
120
Shawn McCarneye140ed92025-11-06 11:20:38 -0600121std::tuple<uint8_t, uint16_t> parseI2CInterface(
122 const nlohmann::json& element,
123 const std::map<std::string, std::string>& variables)
124{
125 verifyIsObject(element);
126 unsigned int propertyCount{0};
127
128 // Required bus property
129 const json& busElement = getRequiredProperty(element, "bus");
130 uint8_t bus = parseUint8(busElement, variables);
131 ++propertyCount;
132
133 // Required address property
134 const json& addressElement = getRequiredProperty(element, "address");
135 uint16_t address = parseHexByte(addressElement, variables);
136 ++propertyCount;
137
138 // Verify no invalid properties exist
139 verifyPropertyCount(element, propertyCount);
140
141 return {bus, address};
142}
143
Shawn McCarney6a957f62024-01-10 16:15:19 -0600144std::unique_ptr<Rail> parseRail(const json& element)
145{
146 verifyIsObject(element);
147 unsigned int propertyCount{0};
148
149 // Required name property
150 const json& nameElement = getRequiredProperty(element, "name");
151 std::string name = parseString(nameElement);
152 ++propertyCount;
153
154 // Optional presence property
155 std::optional<std::string> presence{};
156 auto presenceIt = element.find("presence");
157 if (presenceIt != element.end())
158 {
159 presence = parseString(*presenceIt);
160 ++propertyCount;
161 }
162
163 // Optional page property
164 std::optional<uint8_t> page{};
165 auto pageIt = element.find("page");
166 if (pageIt != element.end())
167 {
168 page = parseUint8(*pageIt);
169 ++propertyCount;
170 }
171
Shawn McCarney16e493a2024-01-29 14:20:32 -0600172 // Optional is_power_supply_rail property
173 bool isPowerSupplyRail{false};
174 auto isPowerSupplyRailIt = element.find("is_power_supply_rail");
175 if (isPowerSupplyRailIt != element.end())
176 {
177 isPowerSupplyRail = parseBoolean(*isPowerSupplyRailIt);
178 ++propertyCount;
179 }
180
Shawn McCarney6a957f62024-01-10 16:15:19 -0600181 // Optional check_status_vout property
182 bool checkStatusVout{false};
183 auto checkStatusVoutIt = element.find("check_status_vout");
184 if (checkStatusVoutIt != element.end())
185 {
186 checkStatusVout = parseBoolean(*checkStatusVoutIt);
187 ++propertyCount;
188 }
189
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600190 // Optional compare_voltage_to_limit property
191 bool compareVoltageToLimit{false};
192 auto compareVoltageToLimitIt = element.find("compare_voltage_to_limit");
193 if (compareVoltageToLimitIt != element.end())
Shawn McCarney6a957f62024-01-10 16:15:19 -0600194 {
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600195 compareVoltageToLimit = parseBoolean(*compareVoltageToLimitIt);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600196 ++propertyCount;
197 }
198
199 // Optional gpio property
200 std::optional<GPIO> gpio{};
201 auto gpioIt = element.find("gpio");
202 if (gpioIt != element.end())
203 {
204 gpio = parseGPIO(*gpioIt);
205 ++propertyCount;
206 }
207
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600208 // If check_status_vout or compare_voltage_to_limit property is true, the
209 // page property is required; verify page was specified
210 if ((checkStatusVout || compareVoltageToLimit) && !page.has_value())
Shawn McCarney6a957f62024-01-10 16:15:19 -0600211 {
212 throw std::invalid_argument{"Required property missing: page"};
213 }
214
215 // Verify no invalid properties exist
216 verifyPropertyCount(element, propertyCount);
217
Shawn McCarney16e493a2024-01-29 14:20:32 -0600218 return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail,
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600219 checkStatusVout, compareVoltageToLimit, gpio);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600220}
221
222std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element)
223{
224 verifyIsArray(element);
225 std::vector<std::unique_ptr<Rail>> rails;
226 for (auto& railElement : element)
227 {
228 rails.emplace_back(parseRail(railElement));
229 }
230 return rails;
231}
232
233std::vector<std::unique_ptr<Rail>> parseRoot(const json& element)
234{
235 verifyIsObject(element);
236 unsigned int propertyCount{0};
237
238 // Required rails property
239 const json& railsElement = getRequiredProperty(element, "rails");
240 std::vector<std::unique_ptr<Rail>> rails = parseRailArray(railsElement);
241 ++propertyCount;
242
243 // Verify no invalid properties exist
244 verifyPropertyCount(element, propertyCount);
245
246 return rails;
247}
248
249} // namespace internal
250
251} // namespace phosphor::power::sequencer::config_file_parser