blob: 07566aeba2c9b9da7c60221c34e18c68f906f41e [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
121std::unique_ptr<Rail> parseRail(const json& element)
122{
123 verifyIsObject(element);
124 unsigned int propertyCount{0};
125
126 // Required name property
127 const json& nameElement = getRequiredProperty(element, "name");
128 std::string name = parseString(nameElement);
129 ++propertyCount;
130
131 // Optional presence property
132 std::optional<std::string> presence{};
133 auto presenceIt = element.find("presence");
134 if (presenceIt != element.end())
135 {
136 presence = parseString(*presenceIt);
137 ++propertyCount;
138 }
139
140 // Optional page property
141 std::optional<uint8_t> page{};
142 auto pageIt = element.find("page");
143 if (pageIt != element.end())
144 {
145 page = parseUint8(*pageIt);
146 ++propertyCount;
147 }
148
Shawn McCarney16e493a2024-01-29 14:20:32 -0600149 // Optional is_power_supply_rail property
150 bool isPowerSupplyRail{false};
151 auto isPowerSupplyRailIt = element.find("is_power_supply_rail");
152 if (isPowerSupplyRailIt != element.end())
153 {
154 isPowerSupplyRail = parseBoolean(*isPowerSupplyRailIt);
155 ++propertyCount;
156 }
157
Shawn McCarney6a957f62024-01-10 16:15:19 -0600158 // Optional check_status_vout property
159 bool checkStatusVout{false};
160 auto checkStatusVoutIt = element.find("check_status_vout");
161 if (checkStatusVoutIt != element.end())
162 {
163 checkStatusVout = parseBoolean(*checkStatusVoutIt);
164 ++propertyCount;
165 }
166
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600167 // Optional compare_voltage_to_limit property
168 bool compareVoltageToLimit{false};
169 auto compareVoltageToLimitIt = element.find("compare_voltage_to_limit");
170 if (compareVoltageToLimitIt != element.end())
Shawn McCarney6a957f62024-01-10 16:15:19 -0600171 {
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600172 compareVoltageToLimit = parseBoolean(*compareVoltageToLimitIt);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600173 ++propertyCount;
174 }
175
176 // Optional gpio property
177 std::optional<GPIO> gpio{};
178 auto gpioIt = element.find("gpio");
179 if (gpioIt != element.end())
180 {
181 gpio = parseGPIO(*gpioIt);
182 ++propertyCount;
183 }
184
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600185 // If check_status_vout or compare_voltage_to_limit property is true, the
186 // page property is required; verify page was specified
187 if ((checkStatusVout || compareVoltageToLimit) && !page.has_value())
Shawn McCarney6a957f62024-01-10 16:15:19 -0600188 {
189 throw std::invalid_argument{"Required property missing: page"};
190 }
191
192 // Verify no invalid properties exist
193 verifyPropertyCount(element, propertyCount);
194
Shawn McCarney16e493a2024-01-29 14:20:32 -0600195 return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail,
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600196 checkStatusVout, compareVoltageToLimit, gpio);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600197}
198
199std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element)
200{
201 verifyIsArray(element);
202 std::vector<std::unique_ptr<Rail>> rails;
203 for (auto& railElement : element)
204 {
205 rails.emplace_back(parseRail(railElement));
206 }
207 return rails;
208}
209
210std::vector<std::unique_ptr<Rail>> parseRoot(const json& element)
211{
212 verifyIsObject(element);
213 unsigned int propertyCount{0};
214
215 // Required rails property
216 const json& railsElement = getRequiredProperty(element, "rails");
217 std::vector<std::unique_ptr<Rail>> rails = parseRailArray(railsElement);
218 ++propertyCount;
219
220 // Verify no invalid properties exist
221 verifyPropertyCount(element, propertyCount);
222
223 return rails;
224}
225
226} // namespace internal
227
228} // namespace phosphor::power::sequencer::config_file_parser