blob: 99a2d1587a126e10e05342dd44bedd9fe20e50a0 [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"
Bob Kingf617f892020-03-30 19:03:35 +080020#include "i2c_interface.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050021#include "pmbus_utils.hpp"
22
23#include <exception>
24#include <fstream>
25#include <optional>
26#include <utility>
27
28using json = nlohmann::json;
29
30namespace phosphor::power::regulators::config_file_parser
31{
32
33std::tuple<std::vector<std::unique_ptr<Rule>>,
34 std::vector<std::unique_ptr<Chassis>>>
35 parse(const std::filesystem::path& pathName)
36{
37 try
38 {
39 // Use standard JSON parser to create tree of JSON elements
40 std::ifstream file{pathName};
41 json rootElement = json::parse(file);
42
43 // Parse tree of JSON elements and return corresponding C++ objects
44 return internal::parseRoot(rootElement);
45 }
46 catch (const std::exception& e)
47 {
48 throw ConfigFileParserError{pathName, e.what()};
49 }
50}
51
52namespace internal
53{
54
55std::unique_ptr<Action> parseAction(const json& element)
56{
57 verifyIsObject(element);
58 unsigned int propertyCount{0};
59
60 // Optional comments property; value not stored
61 if (element.contains("comments"))
62 {
63 ++propertyCount;
64 }
65
66 // Required action type property; there must be exactly one specified
67 std::unique_ptr<Action> action{};
68 if (element.contains("and"))
69 {
70 // TODO: Not implemented yet
71 // action = parseAnd(element["and"]);
72 // ++propertyCount;
73 }
74 else if (element.contains("compare_presence"))
75 {
76 // TODO: Not implemented yet
77 // action = parseComparePresence(element["compare_presence"]);
78 // ++propertyCount;
79 }
80 else if (element.contains("compare_vpd"))
81 {
82 // TODO: Not implemented yet
83 // action = parseCompareVPD(element["compare_vpd"]);
84 // ++propertyCount;
85 }
86 else if (element.contains("i2c_compare_bit"))
87 {
88 // TODO: Not implemented yet
89 // action = parseI2CCompareBit(element["i2c_compare_bit"]);
90 // ++propertyCount;
91 }
92 else if (element.contains("i2c_compare_byte"))
93 {
94 // TODO: Not implemented yet
95 // action = parseI2CCompareByte(element["i2c_compare_byte"]);
96 // ++propertyCount;
97 }
98 else if (element.contains("i2c_compare_bytes"))
99 {
100 // TODO: Not implemented yet
101 // action = parseI2CCompareBytes(element["i2c_compare_bytes"]);
102 // ++propertyCount;
103 }
104 else if (element.contains("i2c_write_bit"))
105 {
Bob Kingf617f892020-03-30 19:03:35 +0800106 action = parseI2CWriteBit(element["i2c_write_bit"]);
107 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500108 }
109 else if (element.contains("i2c_write_byte"))
110 {
Bob King87ff9d72020-03-31 14:02:55 +0800111 action = parseI2CWriteByte(element["i2c_write_byte"]);
112 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500113 }
114 else if (element.contains("i2c_write_bytes"))
115 {
Bob Kingbafcb862020-03-31 16:39:00 +0800116 action = parseI2CWriteBytes(element["i2c_write_bytes"]);
117 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500118 }
119 else if (element.contains("if"))
120 {
121 // TODO: Not implemented yet
122 // action = parseIf(element["if"]);
123 // ++propertyCount;
124 }
125 else if (element.contains("not"))
126 {
127 // TODO: Not implemented yet
128 // action = parseNot(element["not"]);
129 // ++propertyCount;
130 }
131 else if (element.contains("or"))
132 {
133 // TODO: Not implemented yet
134 // action = parseOr(element["or"]);
135 // ++propertyCount;
136 }
137 else if (element.contains("pmbus_read_sensor"))
138 {
139 // TODO: Not implemented yet
140 // action = parsePMBusReadSensor(element["pmbus_read_sensor"]);
141 // ++propertyCount;
142 }
143 else if (element.contains("pmbus_write_vout_command"))
144 {
145 action =
146 parsePMBusWriteVoutCommand(element["pmbus_write_vout_command"]);
147 ++propertyCount;
148 }
149 else if (element.contains("run_rule"))
150 {
Bob King315b0b62020-04-03 21:47:58 +0800151 action = parseRunRule(element["run_rule"]);
152 ++propertyCount;
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500153 }
154 else if (element.contains("set_device"))
155 {
156 // TODO: Not implemented yet
157 // action = parseSetDevice(element["set_device"]);
158 // ++propertyCount;
159 }
160 else
161 {
162 throw std::invalid_argument{"Required action type property missing"};
163 }
164
165 // Verify no invalid properties exist
166 verifyPropertyCount(element, propertyCount);
167
168 return action;
169}
170
171std::vector<std::unique_ptr<Action>> parseActionArray(const json& element)
172{
173 verifyIsArray(element);
174 std::vector<std::unique_ptr<Action>> actions;
175 for (auto& actionElement : element)
176 {
177 actions.emplace_back(parseAction(actionElement));
178 }
179 return actions;
180}
181
Bob King0e701132020-04-03 21:50:31 +0800182std::unique_ptr<Chassis> parseChassis(const json& element)
183{
184 verifyIsObject(element);
185 unsigned int propertyCount{0};
186
187 // Optional comments property; value not stored
188 if (element.contains("comments"))
189 {
190 ++propertyCount;
191 }
192
193 // Required number property
194 const json& numberElement = getRequiredProperty(element, "number");
195 unsigned int number = parseUnsignedInteger(numberElement);
196 if (number < 1)
197 {
198 throw std::invalid_argument{"Invalid chassis number: Must be > 0"};
199 }
200 ++propertyCount;
201
202 // Optional devices property
203 std::vector<std::unique_ptr<Device>> devices{};
204 auto devicesIt = element.find("devices");
205 if (devicesIt != element.end())
206 {
207 devices = parseDeviceArray(*devicesIt);
208 ++propertyCount;
209 }
210
211 // Verify no invalid properties exist
212 verifyPropertyCount(element, propertyCount);
213
214 return std::make_unique<Chassis>(number, std::move(devices));
215}
216
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500217std::vector<std::unique_ptr<Chassis>> parseChassisArray(const json& element)
218{
219 verifyIsArray(element);
220 std::vector<std::unique_ptr<Chassis>> chassis;
Bob King0e701132020-04-03 21:50:31 +0800221 for (auto& chassisElement : element)
222 {
223 chassis.emplace_back(parseChassis(chassisElement));
224 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500225 return chassis;
226}
227
Bob King0e701132020-04-03 21:50:31 +0800228std::vector<std::unique_ptr<Device>> parseDeviceArray(const json& element)
229{
230 verifyIsArray(element);
231 std::vector<std::unique_ptr<Device>> devices;
232 // TODO: Not implemented yet
233 // for (auto& deviceElement : element)
234 // {
235 // devices.emplace_back(parseDevice(deviceElement));
236 // }
237 return devices;
238}
239
Bob Kingbafcb862020-03-31 16:39:00 +0800240std::vector<uint8_t> parseHexByteArray(const json& element)
241{
242 verifyIsArray(element);
243 std::vector<uint8_t> values;
244 for (auto& valueElement : element)
245 {
246 values.emplace_back(parseHexByte(valueElement));
247 }
248 return values;
249}
250
Bob Kingf617f892020-03-30 19:03:35 +0800251std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element)
252{
253 verifyIsObject(element);
254 unsigned int propertyCount{0};
255
256 // Required register property
257 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800258 uint8_t reg = parseHexByte(regElement);
Bob Kingf617f892020-03-30 19:03:35 +0800259 ++propertyCount;
260
261 // Required position property
262 const json& positionElement = getRequiredProperty(element, "position");
263 uint8_t position = parseBitPosition(positionElement);
264 ++propertyCount;
265
266 // Required value property
267 const json& valueElement = getRequiredProperty(element, "value");
268 uint8_t value = parseBitValue(valueElement);
269 ++propertyCount;
270
271 // Verify no invalid properties exist
272 verifyPropertyCount(element, propertyCount);
273
274 return std::make_unique<I2CWriteBitAction>(reg, position, value);
275}
276
Bob King87ff9d72020-03-31 14:02:55 +0800277std::unique_ptr<I2CWriteByteAction> parseI2CWriteByte(const json& element)
278{
279 verifyIsObject(element);
280 unsigned int propertyCount{0};
281
282 // Required register property
283 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800284 uint8_t reg = parseHexByte(regElement);
Bob King87ff9d72020-03-31 14:02:55 +0800285 ++propertyCount;
286
287 // Required value property
288 const json& valueElement = getRequiredProperty(element, "value");
Bob Kingbafcb862020-03-31 16:39:00 +0800289 uint8_t value = parseHexByte(valueElement);
Bob King87ff9d72020-03-31 14:02:55 +0800290 ++propertyCount;
291
292 // Optional mask property
293 uint8_t mask = 0xff;
294 auto maskIt = element.find("mask");
295 if (maskIt != element.end())
296 {
Bob Kingbafcb862020-03-31 16:39:00 +0800297 mask = parseHexByte(*maskIt);
Bob King87ff9d72020-03-31 14:02:55 +0800298 ++propertyCount;
299 }
300
301 // Verify no invalid properties exist
302 verifyPropertyCount(element, propertyCount);
303
304 return std::make_unique<I2CWriteByteAction>(reg, value, mask);
305}
306
Bob Kingbafcb862020-03-31 16:39:00 +0800307std::unique_ptr<I2CWriteBytesAction> parseI2CWriteBytes(const json& element)
308{
309 verifyIsObject(element);
310 unsigned int propertyCount{0};
311
312 // Required register property
313 const json& regElement = getRequiredProperty(element, "register");
314 uint8_t reg = parseHexByte(regElement);
315 ++propertyCount;
316
317 // Required values property
318 const json& valueElement = getRequiredProperty(element, "values");
319 std::vector<uint8_t> values = parseHexByteArray(valueElement);
320 ++propertyCount;
321
322 // Optional masks property
323 std::vector<uint8_t> masks{};
324 auto masksIt = element.find("masks");
325 if (masksIt != element.end())
326 {
327 masks = parseHexByteArray(*masksIt);
328 ++propertyCount;
329 }
330
331 // Verify masks array (if specified) was same size as values array
332 if ((!masks.empty()) && (masks.size() != values.size()))
333 {
334 throw std::invalid_argument{"Invalid number of elements in masks"};
335 }
336
337 // Verify no invalid properties exist
338 verifyPropertyCount(element, propertyCount);
339
340 if (masks.empty())
341 {
342 return std::make_unique<I2CWriteBytesAction>(reg, values);
343 }
344 return std::make_unique<I2CWriteBytesAction>(reg, values, masks);
345}
346
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500347std::unique_ptr<PMBusWriteVoutCommandAction>
348 parsePMBusWriteVoutCommand(const json& element)
349{
350 verifyIsObject(element);
351 unsigned int propertyCount{0};
352
353 // Optional volts property
354 std::optional<double> volts{};
355 auto voltsIt = element.find("volts");
356 if (voltsIt != element.end())
357 {
358 volts = parseDouble(*voltsIt);
359 ++propertyCount;
360 }
361
362 // Required format property
363 const json& formatElement = getRequiredProperty(element, "format");
364 std::string formatString = parseString(formatElement);
365 if (formatString != "linear")
366 {
367 throw std::invalid_argument{"Invalid format value: " + formatString};
368 }
369 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear;
370 ++propertyCount;
371
372 // Optional exponent property
373 std::optional<int8_t> exponent{};
374 auto exponentIt = element.find("exponent");
375 if (exponentIt != element.end())
376 {
377 exponent = parseInt8(*exponentIt);
378 ++propertyCount;
379 }
380
381 // Optional is_verified property
382 bool isVerified = false;
383 auto isVerifiedIt = element.find("is_verified");
384 if (isVerifiedIt != element.end())
385 {
386 isVerified = parseBoolean(*isVerifiedIt);
387 ++propertyCount;
388 }
389
390 // Verify no invalid properties exist
391 verifyPropertyCount(element, propertyCount);
392
393 return std::make_unique<PMBusWriteVoutCommandAction>(volts, format,
394 exponent, isVerified);
395}
396
397std::tuple<std::vector<std::unique_ptr<Rule>>,
398 std::vector<std::unique_ptr<Chassis>>>
399 parseRoot(const json& element)
400{
401 verifyIsObject(element);
402 unsigned int propertyCount{0};
403
404 // Optional comments property; value not stored
405 if (element.contains("comments"))
406 {
407 ++propertyCount;
408 }
409
410 // Optional rules property
411 std::vector<std::unique_ptr<Rule>> rules{};
412 auto rulesIt = element.find("rules");
413 if (rulesIt != element.end())
414 {
415 rules = parseRuleArray(*rulesIt);
416 ++propertyCount;
417 }
418
419 // Required chassis property
420 const json& chassisElement = getRequiredProperty(element, "chassis");
421 std::vector<std::unique_ptr<Chassis>> chassis =
422 parseChassisArray(chassisElement);
423 ++propertyCount;
424
425 // Verify no invalid properties exist
426 verifyPropertyCount(element, propertyCount);
427
428 return std::make_tuple(std::move(rules), std::move(chassis));
429}
430
431std::unique_ptr<Rule> parseRule(const json& element)
432{
433 verifyIsObject(element);
434 unsigned int propertyCount{0};
435
436 // Optional comments property; value not stored
437 if (element.contains("comments"))
438 {
439 ++propertyCount;
440 }
441
442 // Required id property
443 const json& idElement = getRequiredProperty(element, "id");
444 std::string id = parseString(idElement);
445 ++propertyCount;
446
447 // Required actions property
448 const json& actionsElement = getRequiredProperty(element, "actions");
449 std::vector<std::unique_ptr<Action>> actions =
450 parseActionArray(actionsElement);
451 ++propertyCount;
452
453 // Verify no invalid properties exist
454 verifyPropertyCount(element, propertyCount);
455
456 return std::make_unique<Rule>(id, std::move(actions));
457}
458
459std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element)
460{
461 verifyIsArray(element);
462 std::vector<std::unique_ptr<Rule>> rules;
463 for (auto& ruleElement : element)
464 {
465 rules.emplace_back(parseRule(ruleElement));
466 }
467 return rules;
468}
469
Bob King315b0b62020-04-03 21:47:58 +0800470std::unique_ptr<RunRuleAction> parseRunRule(const json& element)
471{
472 // String ruleID
473 std::string ruleID = parseString(element);
474
475 return std::make_unique<RunRuleAction>(ruleID);
476}
477
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500478} // namespace internal
479
480} // namespace phosphor::power::regulators::config_file_parser