blob: 83754b1b5ba105e8aa5ac43d5e598e8efd1c8566 [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"
20
21#include <exception>
22#include <fstream>
23#include <optional>
24
25using json = nlohmann::json;
Shawn McCarneye9144ab2024-05-22 12:34:18 -050026namespace fs = std::filesystem;
Shawn McCarney6a957f62024-01-10 16:15:19 -060027
28namespace phosphor::power::sequencer::config_file_parser
29{
30
Shawn McCarneye9144ab2024-05-22 12:34:18 -050031const std::filesystem::path standardConfigFileDirectory{
32 "/usr/share/phosphor-power-sequencer"};
33
34std::filesystem::path
35 find(const std::vector<std::string>& compatibleSystemTypes,
36 const std::filesystem::path& configFileDir)
37{
38 fs::path pathName, possiblePath;
39 std::string fileName;
40
41 for (const std::string& systemType : compatibleSystemTypes)
42 {
43 // Look for file name that is entire system type + ".json"
44 // Example: com.acme.Hardware.Chassis.Model.MegaServer.json
45 fileName = systemType + ".json";
46 possiblePath = configFileDir / fileName;
47 if (fs::is_regular_file(possiblePath))
48 {
49 pathName = possiblePath;
50 break;
51 }
52
53 // Look for file name that is last node of system type + ".json"
54 // Example: MegaServer.json
55 std::string::size_type pos = systemType.rfind('.');
56 if ((pos != std::string::npos) && ((systemType.size() - pos) > 1))
57 {
58 fileName = systemType.substr(pos + 1) + ".json";
59 possiblePath = configFileDir / fileName;
60 if (fs::is_regular_file(possiblePath))
61 {
62 pathName = possiblePath;
63 break;
64 }
65 }
66 }
67
68 return pathName;
69}
70
Shawn McCarney6a957f62024-01-10 16:15:19 -060071std::vector<std::unique_ptr<Rail>> parse(const std::filesystem::path& pathName)
72{
73 try
74 {
75 // Use standard JSON parser to create tree of JSON elements
76 std::ifstream file{pathName};
77 json rootElement = json::parse(file);
78
79 // Parse tree of JSON elements and return corresponding C++ objects
80 return internal::parseRoot(rootElement);
81 }
82 catch (const std::exception& e)
83 {
84 throw ConfigFileParserError{pathName, e.what()};
85 }
86}
87
88namespace internal
89{
90
91GPIO parseGPIO(const json& element)
92{
93 verifyIsObject(element);
94 unsigned int propertyCount{0};
95
96 // Required line property
97 const json& lineElement = getRequiredProperty(element, "line");
98 unsigned int line = parseUnsignedInteger(lineElement);
99 ++propertyCount;
100
101 // Optional active_low property
102 bool activeLow{false};
103 auto activeLowIt = element.find("active_low");
104 if (activeLowIt != element.end())
105 {
106 activeLow = parseBoolean(*activeLowIt);
107 ++propertyCount;
108 }
109
110 // Verify no invalid properties exist
111 verifyPropertyCount(element, propertyCount);
112
113 return GPIO(line, activeLow);
114}
115
116std::unique_ptr<Rail> parseRail(const json& element)
117{
118 verifyIsObject(element);
119 unsigned int propertyCount{0};
120
121 // Required name property
122 const json& nameElement = getRequiredProperty(element, "name");
123 std::string name = parseString(nameElement);
124 ++propertyCount;
125
126 // Optional presence property
127 std::optional<std::string> presence{};
128 auto presenceIt = element.find("presence");
129 if (presenceIt != element.end())
130 {
131 presence = parseString(*presenceIt);
132 ++propertyCount;
133 }
134
135 // Optional page property
136 std::optional<uint8_t> page{};
137 auto pageIt = element.find("page");
138 if (pageIt != element.end())
139 {
140 page = parseUint8(*pageIt);
141 ++propertyCount;
142 }
143
Shawn McCarney16e493a2024-01-29 14:20:32 -0600144 // Optional is_power_supply_rail property
145 bool isPowerSupplyRail{false};
146 auto isPowerSupplyRailIt = element.find("is_power_supply_rail");
147 if (isPowerSupplyRailIt != element.end())
148 {
149 isPowerSupplyRail = parseBoolean(*isPowerSupplyRailIt);
150 ++propertyCount;
151 }
152
Shawn McCarney6a957f62024-01-10 16:15:19 -0600153 // Optional check_status_vout property
154 bool checkStatusVout{false};
155 auto checkStatusVoutIt = element.find("check_status_vout");
156 if (checkStatusVoutIt != element.end())
157 {
158 checkStatusVout = parseBoolean(*checkStatusVoutIt);
159 ++propertyCount;
160 }
161
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600162 // Optional compare_voltage_to_limit property
163 bool compareVoltageToLimit{false};
164 auto compareVoltageToLimitIt = element.find("compare_voltage_to_limit");
165 if (compareVoltageToLimitIt != element.end())
Shawn McCarney6a957f62024-01-10 16:15:19 -0600166 {
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600167 compareVoltageToLimit = parseBoolean(*compareVoltageToLimitIt);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600168 ++propertyCount;
169 }
170
171 // Optional gpio property
172 std::optional<GPIO> gpio{};
173 auto gpioIt = element.find("gpio");
174 if (gpioIt != element.end())
175 {
176 gpio = parseGPIO(*gpioIt);
177 ++propertyCount;
178 }
179
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600180 // If check_status_vout or compare_voltage_to_limit property is true, the
181 // page property is required; verify page was specified
182 if ((checkStatusVout || compareVoltageToLimit) && !page.has_value())
Shawn McCarney6a957f62024-01-10 16:15:19 -0600183 {
184 throw std::invalid_argument{"Required property missing: page"};
185 }
186
187 // Verify no invalid properties exist
188 verifyPropertyCount(element, propertyCount);
189
Shawn McCarney16e493a2024-01-29 14:20:32 -0600190 return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail,
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600191 checkStatusVout, compareVoltageToLimit, gpio);
Shawn McCarney6a957f62024-01-10 16:15:19 -0600192}
193
194std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element)
195{
196 verifyIsArray(element);
197 std::vector<std::unique_ptr<Rail>> rails;
198 for (auto& railElement : element)
199 {
200 rails.emplace_back(parseRail(railElement));
201 }
202 return rails;
203}
204
205std::vector<std::unique_ptr<Rail>> parseRoot(const json& element)
206{
207 verifyIsObject(element);
208 unsigned int propertyCount{0};
209
210 // Required rails property
211 const json& railsElement = getRequiredProperty(element, "rails");
212 std::vector<std::unique_ptr<Rail>> rails = parseRailArray(railsElement);
213 ++propertyCount;
214
215 // Verify no invalid properties exist
216 verifyPropertyCount(element, propertyCount);
217
218 return rails;
219}
220
221} // namespace internal
222
223} // namespace phosphor::power::sequencer::config_file_parser