blob: 9ac60602394ef3dbe3a4c27ad8d3cd392fd7dd7e [file] [log] [blame]
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05001/**
2 * Copyright © 2020 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#include "pmbus_utils.hpp"
21
22#include <exception>
23#include <fstream>
24#include <optional>
25#include <utility>
26
27using json = nlohmann::json;
28
29namespace phosphor::power::regulators::config_file_parser
30{
31
32std::tuple<std::vector<std::unique_ptr<Rule>>,
33 std::vector<std::unique_ptr<Chassis>>>
34 parse(const std::filesystem::path& pathName)
35{
36 try
37 {
38 // Use standard JSON parser to create tree of JSON elements
39 std::ifstream file{pathName};
40 json rootElement = json::parse(file);
41
42 // Parse tree of JSON elements and return corresponding C++ objects
43 return internal::parseRoot(rootElement);
44 }
45 catch (const std::exception& e)
46 {
47 throw ConfigFileParserError{pathName, e.what()};
48 }
49}
50
51namespace internal
52{
53
54std::unique_ptr<Action> parseAction(const json& element)
55{
56 verifyIsObject(element);
57 unsigned int propertyCount{0};
58
59 // Optional comments property; value not stored
60 if (element.contains("comments"))
61 {
62 ++propertyCount;
63 }
64
65 // Required action type property; there must be exactly one specified
66 std::unique_ptr<Action> action{};
67 if (element.contains("and"))
68 {
69 // TODO: Not implemented yet
70 // action = parseAnd(element["and"]);
71 // ++propertyCount;
72 }
73 else if (element.contains("compare_presence"))
74 {
75 // TODO: Not implemented yet
76 // action = parseComparePresence(element["compare_presence"]);
77 // ++propertyCount;
78 }
79 else if (element.contains("compare_vpd"))
80 {
81 // TODO: Not implemented yet
82 // action = parseCompareVPD(element["compare_vpd"]);
83 // ++propertyCount;
84 }
85 else if (element.contains("i2c_compare_bit"))
86 {
87 // TODO: Not implemented yet
88 // action = parseI2CCompareBit(element["i2c_compare_bit"]);
89 // ++propertyCount;
90 }
91 else if (element.contains("i2c_compare_byte"))
92 {
93 // TODO: Not implemented yet
94 // action = parseI2CCompareByte(element["i2c_compare_byte"]);
95 // ++propertyCount;
96 }
97 else if (element.contains("i2c_compare_bytes"))
98 {
99 // TODO: Not implemented yet
100 // action = parseI2CCompareBytes(element["i2c_compare_bytes"]);
101 // ++propertyCount;
102 }
103 else if (element.contains("i2c_write_bit"))
104 {
105 // TODO: Not implemented yet
106 // action = parseI2CWriteBit(element["i2c_write_bit"]);
107 // ++propertyCount;
108 }
109 else if (element.contains("i2c_write_byte"))
110 {
111 // TODO: Not implemented yet
112 // action = parseI2CWriteByte(element["i2c_write_byte"]);
113 // ++propertyCount;
114 }
115 else if (element.contains("i2c_write_bytes"))
116 {
117 // TODO: Not implemented yet
118 // action = parseI2CWriteBytes(element["i2c_write_bytes"]);
119 // ++propertyCount;
120 }
121 else if (element.contains("if"))
122 {
123 // TODO: Not implemented yet
124 // action = parseIf(element["if"]);
125 // ++propertyCount;
126 }
127 else if (element.contains("not"))
128 {
129 // TODO: Not implemented yet
130 // action = parseNot(element["not"]);
131 // ++propertyCount;
132 }
133 else if (element.contains("or"))
134 {
135 // TODO: Not implemented yet
136 // action = parseOr(element["or"]);
137 // ++propertyCount;
138 }
139 else if (element.contains("pmbus_read_sensor"))
140 {
141 // TODO: Not implemented yet
142 // action = parsePMBusReadSensor(element["pmbus_read_sensor"]);
143 // ++propertyCount;
144 }
145 else if (element.contains("pmbus_write_vout_command"))
146 {
147 action =
148 parsePMBusWriteVoutCommand(element["pmbus_write_vout_command"]);
149 ++propertyCount;
150 }
151 else if (element.contains("run_rule"))
152 {
153 // TODO: Not implemented yet
154 // action = parseRunRule(element["run_rule"]);
155 // ++propertyCount;
156 }
157 else if (element.contains("set_device"))
158 {
159 // TODO: Not implemented yet
160 // action = parseSetDevice(element["set_device"]);
161 // ++propertyCount;
162 }
163 else
164 {
165 throw std::invalid_argument{"Required action type property missing"};
166 }
167
168 // Verify no invalid properties exist
169 verifyPropertyCount(element, propertyCount);
170
171 return action;
172}
173
174std::vector<std::unique_ptr<Action>> parseActionArray(const json& element)
175{
176 verifyIsArray(element);
177 std::vector<std::unique_ptr<Action>> actions;
178 for (auto& actionElement : element)
179 {
180 actions.emplace_back(parseAction(actionElement));
181 }
182 return actions;
183}
184
185std::vector<std::unique_ptr<Chassis>> parseChassisArray(const json& element)
186{
187 verifyIsArray(element);
188 std::vector<std::unique_ptr<Chassis>> chassis;
189 // TODO: Not implemented yet
190 // for (auto& chassisElement : element)
191 // {
192 // chassis.emplace_back(parseChassis(chassisElement));
193 // }
194 return chassis;
195}
196
197std::unique_ptr<PMBusWriteVoutCommandAction>
198 parsePMBusWriteVoutCommand(const json& element)
199{
200 verifyIsObject(element);
201 unsigned int propertyCount{0};
202
203 // Optional volts property
204 std::optional<double> volts{};
205 auto voltsIt = element.find("volts");
206 if (voltsIt != element.end())
207 {
208 volts = parseDouble(*voltsIt);
209 ++propertyCount;
210 }
211
212 // Required format property
213 const json& formatElement = getRequiredProperty(element, "format");
214 std::string formatString = parseString(formatElement);
215 if (formatString != "linear")
216 {
217 throw std::invalid_argument{"Invalid format value: " + formatString};
218 }
219 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear;
220 ++propertyCount;
221
222 // Optional exponent property
223 std::optional<int8_t> exponent{};
224 auto exponentIt = element.find("exponent");
225 if (exponentIt != element.end())
226 {
227 exponent = parseInt8(*exponentIt);
228 ++propertyCount;
229 }
230
231 // Optional is_verified property
232 bool isVerified = false;
233 auto isVerifiedIt = element.find("is_verified");
234 if (isVerifiedIt != element.end())
235 {
236 isVerified = parseBoolean(*isVerifiedIt);
237 ++propertyCount;
238 }
239
240 // Verify no invalid properties exist
241 verifyPropertyCount(element, propertyCount);
242
243 return std::make_unique<PMBusWriteVoutCommandAction>(volts, format,
244 exponent, isVerified);
245}
246
247std::tuple<std::vector<std::unique_ptr<Rule>>,
248 std::vector<std::unique_ptr<Chassis>>>
249 parseRoot(const json& element)
250{
251 verifyIsObject(element);
252 unsigned int propertyCount{0};
253
254 // Optional comments property; value not stored
255 if (element.contains("comments"))
256 {
257 ++propertyCount;
258 }
259
260 // Optional rules property
261 std::vector<std::unique_ptr<Rule>> rules{};
262 auto rulesIt = element.find("rules");
263 if (rulesIt != element.end())
264 {
265 rules = parseRuleArray(*rulesIt);
266 ++propertyCount;
267 }
268
269 // Required chassis property
270 const json& chassisElement = getRequiredProperty(element, "chassis");
271 std::vector<std::unique_ptr<Chassis>> chassis =
272 parseChassisArray(chassisElement);
273 ++propertyCount;
274
275 // Verify no invalid properties exist
276 verifyPropertyCount(element, propertyCount);
277
278 return std::make_tuple(std::move(rules), std::move(chassis));
279}
280
281std::unique_ptr<Rule> parseRule(const json& element)
282{
283 verifyIsObject(element);
284 unsigned int propertyCount{0};
285
286 // Optional comments property; value not stored
287 if (element.contains("comments"))
288 {
289 ++propertyCount;
290 }
291
292 // Required id property
293 const json& idElement = getRequiredProperty(element, "id");
294 std::string id = parseString(idElement);
295 ++propertyCount;
296
297 // Required actions property
298 const json& actionsElement = getRequiredProperty(element, "actions");
299 std::vector<std::unique_ptr<Action>> actions =
300 parseActionArray(actionsElement);
301 ++propertyCount;
302
303 // Verify no invalid properties exist
304 verifyPropertyCount(element, propertyCount);
305
306 return std::make_unique<Rule>(id, std::move(actions));
307}
308
309std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element)
310{
311 verifyIsArray(element);
312 std::vector<std::unique_ptr<Rule>> rules;
313 for (auto& ruleElement : element)
314 {
315 rules.emplace_back(parseRule(ruleElement));
316 }
317 return rules;
318}
319
320} // namespace internal
321
322} // namespace phosphor::power::regulators::config_file_parser