blob: 3d56629b6ed840b9f1ee0178a87371cfbf63c6cf [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 King9c36c5f2020-04-06 11:34:09 +0800228std::unique_ptr<Device> parseDevice(const json& element)
229{
230 verifyIsObject(element);
231 unsigned int propertyCount{0};
232
233 // Optional comments property; value not stored
234 if (element.contains("comments"))
235 {
236 ++propertyCount;
237 }
238
239 // Required id property
240 const json& idElement = getRequiredProperty(element, "id");
241 std::string id = parseString(idElement);
242 ++propertyCount;
243
244 // Required is_regulator property
245 const json& isRegulatorElement =
246 getRequiredProperty(element, "is_regulator");
247 bool isRegulator = parseBoolean(isRegulatorElement);
248 ++propertyCount;
249
250 // Required fru property
251 const json& fruElement = getRequiredProperty(element, "fru");
252 std::string fru = parseString(fruElement);
253 ++propertyCount;
254
255 // Required i2c_interface property
256 const json& i2cInterfaceElement =
257 getRequiredProperty(element, "i2c_interface");
258 std::unique_ptr<i2c::I2CInterface> i2cInterface =
259 parseI2CInterface(i2cInterfaceElement);
260 ++propertyCount;
261
262 // Optional presence_detection property
263 // TODO: Not implemented yet
264 std::unique_ptr<PresenceDetection> presenceDetection{};
265 // auto presenceDetectionIt = element.find("presence_detection");
266 // if (presenceDetectionIt != element.end())
267 // {
268 // presenceDetection = parsePresenceDetection(*presenceDetectionIt);
269 // ++propertyCount;
270 // }
271
272 // Optional configuration property
273 // TODO: Not implemented yet
274 std::unique_ptr<Configuration> configuration{};
275 // auto configurationIt = element.find("configuration");
276 // if (configurationIt != element.end())
277 // {
278 // configuration = parseConfiguration(*configurationIt);
279 // ++propertyCount;
280 // }
281
282 // Optional rails property
283 std::vector<std::unique_ptr<Rail>> rails{};
284 auto railsIt = element.find("rails");
285 if (railsIt != element.end())
286 {
287 if (!isRegulator)
288 {
289 throw std::invalid_argument{
290 "Invalid rails property when is_regulator is false"};
291 }
292 rails = parseRailArray(*railsIt);
293 ++propertyCount;
294 }
295
296 // Verify no invalid properties exist
297 verifyPropertyCount(element, propertyCount);
298
299 return std::make_unique<Device>(id, isRegulator, fru,
300 std::move(i2cInterface),
301 std::move(presenceDetection),
302 std::move(configuration), std::move(rails));
303}
304
Bob King0e701132020-04-03 21:50:31 +0800305std::vector<std::unique_ptr<Device>> parseDeviceArray(const json& element)
306{
307 verifyIsArray(element);
308 std::vector<std::unique_ptr<Device>> devices;
Bob King9c36c5f2020-04-06 11:34:09 +0800309 for (auto& deviceElement : element)
310 {
311 devices.emplace_back(parseDevice(deviceElement));
312 }
Bob King0e701132020-04-03 21:50:31 +0800313 return devices;
314}
315
Bob Kingbafcb862020-03-31 16:39:00 +0800316std::vector<uint8_t> parseHexByteArray(const json& element)
317{
318 verifyIsArray(element);
319 std::vector<uint8_t> values;
320 for (auto& valueElement : element)
321 {
322 values.emplace_back(parseHexByte(valueElement));
323 }
324 return values;
325}
326
Bob King9c36c5f2020-04-06 11:34:09 +0800327std::unique_ptr<i2c::I2CInterface> parseI2CInterface(const json& element)
328{
329 verifyIsObject(element);
330 unsigned int propertyCount{0};
331
332 // Required bus property
333 const json& busElement = getRequiredProperty(element, "bus");
334 uint8_t bus = parseUint8(busElement);
335 ++propertyCount;
336
337 // Required address property
338 const json& addressElement = getRequiredProperty(element, "address");
339 uint8_t address = parseHexByte(addressElement);
340 ++propertyCount;
341
342 verifyPropertyCount(element, propertyCount);
343 return i2c::create(bus, address, i2c::I2CInterface::InitialState::CLOSED);
344}
345
Bob Kingf617f892020-03-30 19:03:35 +0800346std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element)
347{
348 verifyIsObject(element);
349 unsigned int propertyCount{0};
350
351 // Required register property
352 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800353 uint8_t reg = parseHexByte(regElement);
Bob Kingf617f892020-03-30 19:03:35 +0800354 ++propertyCount;
355
356 // Required position property
357 const json& positionElement = getRequiredProperty(element, "position");
358 uint8_t position = parseBitPosition(positionElement);
359 ++propertyCount;
360
361 // Required value property
362 const json& valueElement = getRequiredProperty(element, "value");
363 uint8_t value = parseBitValue(valueElement);
364 ++propertyCount;
365
366 // Verify no invalid properties exist
367 verifyPropertyCount(element, propertyCount);
368
369 return std::make_unique<I2CWriteBitAction>(reg, position, value);
370}
371
Bob King87ff9d72020-03-31 14:02:55 +0800372std::unique_ptr<I2CWriteByteAction> parseI2CWriteByte(const json& element)
373{
374 verifyIsObject(element);
375 unsigned int propertyCount{0};
376
377 // Required register property
378 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800379 uint8_t reg = parseHexByte(regElement);
Bob King87ff9d72020-03-31 14:02:55 +0800380 ++propertyCount;
381
382 // Required value property
383 const json& valueElement = getRequiredProperty(element, "value");
Bob Kingbafcb862020-03-31 16:39:00 +0800384 uint8_t value = parseHexByte(valueElement);
Bob King87ff9d72020-03-31 14:02:55 +0800385 ++propertyCount;
386
387 // Optional mask property
388 uint8_t mask = 0xff;
389 auto maskIt = element.find("mask");
390 if (maskIt != element.end())
391 {
Bob Kingbafcb862020-03-31 16:39:00 +0800392 mask = parseHexByte(*maskIt);
Bob King87ff9d72020-03-31 14:02:55 +0800393 ++propertyCount;
394 }
395
396 // Verify no invalid properties exist
397 verifyPropertyCount(element, propertyCount);
398
399 return std::make_unique<I2CWriteByteAction>(reg, value, mask);
400}
401
Bob Kingbafcb862020-03-31 16:39:00 +0800402std::unique_ptr<I2CWriteBytesAction> parseI2CWriteBytes(const json& element)
403{
404 verifyIsObject(element);
405 unsigned int propertyCount{0};
406
407 // Required register property
408 const json& regElement = getRequiredProperty(element, "register");
409 uint8_t reg = parseHexByte(regElement);
410 ++propertyCount;
411
412 // Required values property
413 const json& valueElement = getRequiredProperty(element, "values");
414 std::vector<uint8_t> values = parseHexByteArray(valueElement);
415 ++propertyCount;
416
417 // Optional masks property
418 std::vector<uint8_t> masks{};
419 auto masksIt = element.find("masks");
420 if (masksIt != element.end())
421 {
422 masks = parseHexByteArray(*masksIt);
423 ++propertyCount;
424 }
425
426 // Verify masks array (if specified) was same size as values array
427 if ((!masks.empty()) && (masks.size() != values.size()))
428 {
429 throw std::invalid_argument{"Invalid number of elements in masks"};
430 }
431
432 // Verify no invalid properties exist
433 verifyPropertyCount(element, propertyCount);
434
435 if (masks.empty())
436 {
437 return std::make_unique<I2CWriteBytesAction>(reg, values);
438 }
439 return std::make_unique<I2CWriteBytesAction>(reg, values, masks);
440}
441
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500442std::unique_ptr<PMBusWriteVoutCommandAction>
443 parsePMBusWriteVoutCommand(const json& element)
444{
445 verifyIsObject(element);
446 unsigned int propertyCount{0};
447
448 // Optional volts property
449 std::optional<double> volts{};
450 auto voltsIt = element.find("volts");
451 if (voltsIt != element.end())
452 {
453 volts = parseDouble(*voltsIt);
454 ++propertyCount;
455 }
456
457 // Required format property
458 const json& formatElement = getRequiredProperty(element, "format");
459 std::string formatString = parseString(formatElement);
460 if (formatString != "linear")
461 {
462 throw std::invalid_argument{"Invalid format value: " + formatString};
463 }
464 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear;
465 ++propertyCount;
466
467 // Optional exponent property
468 std::optional<int8_t> exponent{};
469 auto exponentIt = element.find("exponent");
470 if (exponentIt != element.end())
471 {
472 exponent = parseInt8(*exponentIt);
473 ++propertyCount;
474 }
475
476 // Optional is_verified property
477 bool isVerified = false;
478 auto isVerifiedIt = element.find("is_verified");
479 if (isVerifiedIt != element.end())
480 {
481 isVerified = parseBoolean(*isVerifiedIt);
482 ++propertyCount;
483 }
484
485 // Verify no invalid properties exist
486 verifyPropertyCount(element, propertyCount);
487
488 return std::make_unique<PMBusWriteVoutCommandAction>(volts, format,
489 exponent, isVerified);
490}
491
Bob King9c36c5f2020-04-06 11:34:09 +0800492std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element)
493{
494 verifyIsArray(element);
495 std::vector<std::unique_ptr<Rail>> rails;
496 // TODO: Not implemented yet
497 // for (auto& railElement : element)
498 // {
499 // rails.emplace_back(parseRail(railElement));
500 // }
501 return rails;
502}
503
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500504std::tuple<std::vector<std::unique_ptr<Rule>>,
505 std::vector<std::unique_ptr<Chassis>>>
506 parseRoot(const json& element)
507{
508 verifyIsObject(element);
509 unsigned int propertyCount{0};
510
511 // Optional comments property; value not stored
512 if (element.contains("comments"))
513 {
514 ++propertyCount;
515 }
516
517 // Optional rules property
518 std::vector<std::unique_ptr<Rule>> rules{};
519 auto rulesIt = element.find("rules");
520 if (rulesIt != element.end())
521 {
522 rules = parseRuleArray(*rulesIt);
523 ++propertyCount;
524 }
525
526 // Required chassis property
527 const json& chassisElement = getRequiredProperty(element, "chassis");
528 std::vector<std::unique_ptr<Chassis>> chassis =
529 parseChassisArray(chassisElement);
530 ++propertyCount;
531
532 // Verify no invalid properties exist
533 verifyPropertyCount(element, propertyCount);
534
535 return std::make_tuple(std::move(rules), std::move(chassis));
536}
537
538std::unique_ptr<Rule> parseRule(const json& element)
539{
540 verifyIsObject(element);
541 unsigned int propertyCount{0};
542
543 // Optional comments property; value not stored
544 if (element.contains("comments"))
545 {
546 ++propertyCount;
547 }
548
549 // Required id property
550 const json& idElement = getRequiredProperty(element, "id");
551 std::string id = parseString(idElement);
552 ++propertyCount;
553
554 // Required actions property
555 const json& actionsElement = getRequiredProperty(element, "actions");
556 std::vector<std::unique_ptr<Action>> actions =
557 parseActionArray(actionsElement);
558 ++propertyCount;
559
560 // Verify no invalid properties exist
561 verifyPropertyCount(element, propertyCount);
562
563 return std::make_unique<Rule>(id, std::move(actions));
564}
565
566std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element)
567{
568 verifyIsArray(element);
569 std::vector<std::unique_ptr<Rule>> rules;
570 for (auto& ruleElement : element)
571 {
572 rules.emplace_back(parseRule(ruleElement));
573 }
574 return rules;
575}
576
Bob King315b0b62020-04-03 21:47:58 +0800577std::unique_ptr<RunRuleAction> parseRunRule(const json& element)
578{
579 // String ruleID
580 std::string ruleID = parseString(element);
581
582 return std::make_unique<RunRuleAction>(ruleID);
583}
584
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500585} // namespace internal
586
587} // namespace phosphor::power::regulators::config_file_parser