blob: cc9654568ef8d48a5bc234c761e9165cc573ba55 [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 King33e7eaa2020-04-01 18:09:34 +0800228std::unique_ptr<Configuration> parseConfiguration(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 // Optional volts property
240 std::optional<double> volts{};
241 auto voltsIt = element.find("volts");
242 if (voltsIt != element.end())
243 {
244 volts = parseDouble(*voltsIt);
245 ++propertyCount;
246 }
247
248 // Required rule_id or actions property
249 std::vector<std::unique_ptr<Action>> actions{};
250 actions = parseRuleIDOrActionsProperty(element);
251 ++propertyCount;
252
253 // Verify no invalid properties exist
254 verifyPropertyCount(element, propertyCount);
255
256 return std::make_unique<Configuration>(volts, std::move(actions));
257}
258
Bob King9c36c5f2020-04-06 11:34:09 +0800259std::unique_ptr<Device> parseDevice(const json& element)
260{
261 verifyIsObject(element);
262 unsigned int propertyCount{0};
263
264 // Optional comments property; value not stored
265 if (element.contains("comments"))
266 {
267 ++propertyCount;
268 }
269
270 // Required id property
271 const json& idElement = getRequiredProperty(element, "id");
272 std::string id = parseString(idElement);
273 ++propertyCount;
274
275 // Required is_regulator property
276 const json& isRegulatorElement =
277 getRequiredProperty(element, "is_regulator");
278 bool isRegulator = parseBoolean(isRegulatorElement);
279 ++propertyCount;
280
281 // Required fru property
282 const json& fruElement = getRequiredProperty(element, "fru");
283 std::string fru = parseString(fruElement);
284 ++propertyCount;
285
286 // Required i2c_interface property
287 const json& i2cInterfaceElement =
288 getRequiredProperty(element, "i2c_interface");
289 std::unique_ptr<i2c::I2CInterface> i2cInterface =
290 parseI2CInterface(i2cInterfaceElement);
291 ++propertyCount;
292
293 // Optional presence_detection property
294 // TODO: Not implemented yet
295 std::unique_ptr<PresenceDetection> presenceDetection{};
296 // auto presenceDetectionIt = element.find("presence_detection");
297 // if (presenceDetectionIt != element.end())
298 // {
299 // presenceDetection = parsePresenceDetection(*presenceDetectionIt);
300 // ++propertyCount;
301 // }
302
303 // Optional configuration property
Bob King9c36c5f2020-04-06 11:34:09 +0800304 std::unique_ptr<Configuration> configuration{};
Bob King33e7eaa2020-04-01 18:09:34 +0800305 auto configurationIt = element.find("configuration");
306 if (configurationIt != element.end())
307 {
308 configuration = parseConfiguration(*configurationIt);
309 ++propertyCount;
310 }
Bob King9c36c5f2020-04-06 11:34:09 +0800311
312 // Optional rails property
313 std::vector<std::unique_ptr<Rail>> rails{};
314 auto railsIt = element.find("rails");
315 if (railsIt != element.end())
316 {
317 if (!isRegulator)
318 {
319 throw std::invalid_argument{
320 "Invalid rails property when is_regulator is false"};
321 }
322 rails = parseRailArray(*railsIt);
323 ++propertyCount;
324 }
325
326 // Verify no invalid properties exist
327 verifyPropertyCount(element, propertyCount);
328
329 return std::make_unique<Device>(id, isRegulator, fru,
330 std::move(i2cInterface),
331 std::move(presenceDetection),
332 std::move(configuration), std::move(rails));
333}
334
Bob King0e701132020-04-03 21:50:31 +0800335std::vector<std::unique_ptr<Device>> parseDeviceArray(const json& element)
336{
337 verifyIsArray(element);
338 std::vector<std::unique_ptr<Device>> devices;
Bob King9c36c5f2020-04-06 11:34:09 +0800339 for (auto& deviceElement : element)
340 {
341 devices.emplace_back(parseDevice(deviceElement));
342 }
Bob King0e701132020-04-03 21:50:31 +0800343 return devices;
344}
345
Bob Kingbafcb862020-03-31 16:39:00 +0800346std::vector<uint8_t> parseHexByteArray(const json& element)
347{
348 verifyIsArray(element);
349 std::vector<uint8_t> values;
350 for (auto& valueElement : element)
351 {
352 values.emplace_back(parseHexByte(valueElement));
353 }
354 return values;
355}
356
Bob King9c36c5f2020-04-06 11:34:09 +0800357std::unique_ptr<i2c::I2CInterface> parseI2CInterface(const json& element)
358{
359 verifyIsObject(element);
360 unsigned int propertyCount{0};
361
362 // Required bus property
363 const json& busElement = getRequiredProperty(element, "bus");
364 uint8_t bus = parseUint8(busElement);
365 ++propertyCount;
366
367 // Required address property
368 const json& addressElement = getRequiredProperty(element, "address");
369 uint8_t address = parseHexByte(addressElement);
370 ++propertyCount;
371
372 verifyPropertyCount(element, propertyCount);
373 return i2c::create(bus, address, i2c::I2CInterface::InitialState::CLOSED);
374}
375
Bob Kingf617f892020-03-30 19:03:35 +0800376std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element)
377{
378 verifyIsObject(element);
379 unsigned int propertyCount{0};
380
381 // Required register property
382 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800383 uint8_t reg = parseHexByte(regElement);
Bob Kingf617f892020-03-30 19:03:35 +0800384 ++propertyCount;
385
386 // Required position property
387 const json& positionElement = getRequiredProperty(element, "position");
388 uint8_t position = parseBitPosition(positionElement);
389 ++propertyCount;
390
391 // Required value property
392 const json& valueElement = getRequiredProperty(element, "value");
393 uint8_t value = parseBitValue(valueElement);
394 ++propertyCount;
395
396 // Verify no invalid properties exist
397 verifyPropertyCount(element, propertyCount);
398
399 return std::make_unique<I2CWriteBitAction>(reg, position, value);
400}
401
Bob King87ff9d72020-03-31 14:02:55 +0800402std::unique_ptr<I2CWriteByteAction> parseI2CWriteByte(const json& element)
403{
404 verifyIsObject(element);
405 unsigned int propertyCount{0};
406
407 // Required register property
408 const json& regElement = getRequiredProperty(element, "register");
Bob Kingbafcb862020-03-31 16:39:00 +0800409 uint8_t reg = parseHexByte(regElement);
Bob King87ff9d72020-03-31 14:02:55 +0800410 ++propertyCount;
411
412 // Required value property
413 const json& valueElement = getRequiredProperty(element, "value");
Bob Kingbafcb862020-03-31 16:39:00 +0800414 uint8_t value = parseHexByte(valueElement);
Bob King87ff9d72020-03-31 14:02:55 +0800415 ++propertyCount;
416
417 // Optional mask property
418 uint8_t mask = 0xff;
419 auto maskIt = element.find("mask");
420 if (maskIt != element.end())
421 {
Bob Kingbafcb862020-03-31 16:39:00 +0800422 mask = parseHexByte(*maskIt);
Bob King87ff9d72020-03-31 14:02:55 +0800423 ++propertyCount;
424 }
425
426 // Verify no invalid properties exist
427 verifyPropertyCount(element, propertyCount);
428
429 return std::make_unique<I2CWriteByteAction>(reg, value, mask);
430}
431
Bob Kingbafcb862020-03-31 16:39:00 +0800432std::unique_ptr<I2CWriteBytesAction> parseI2CWriteBytes(const json& element)
433{
434 verifyIsObject(element);
435 unsigned int propertyCount{0};
436
437 // Required register property
438 const json& regElement = getRequiredProperty(element, "register");
439 uint8_t reg = parseHexByte(regElement);
440 ++propertyCount;
441
442 // Required values property
443 const json& valueElement = getRequiredProperty(element, "values");
444 std::vector<uint8_t> values = parseHexByteArray(valueElement);
445 ++propertyCount;
446
447 // Optional masks property
448 std::vector<uint8_t> masks{};
449 auto masksIt = element.find("masks");
450 if (masksIt != element.end())
451 {
452 masks = parseHexByteArray(*masksIt);
453 ++propertyCount;
454 }
455
456 // Verify masks array (if specified) was same size as values array
457 if ((!masks.empty()) && (masks.size() != values.size()))
458 {
459 throw std::invalid_argument{"Invalid number of elements in masks"};
460 }
461
462 // Verify no invalid properties exist
463 verifyPropertyCount(element, propertyCount);
464
465 if (masks.empty())
466 {
467 return std::make_unique<I2CWriteBytesAction>(reg, values);
468 }
469 return std::make_unique<I2CWriteBytesAction>(reg, values, masks);
470}
471
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500472std::unique_ptr<PMBusWriteVoutCommandAction>
473 parsePMBusWriteVoutCommand(const json& element)
474{
475 verifyIsObject(element);
476 unsigned int propertyCount{0};
477
478 // Optional volts property
479 std::optional<double> volts{};
480 auto voltsIt = element.find("volts");
481 if (voltsIt != element.end())
482 {
483 volts = parseDouble(*voltsIt);
484 ++propertyCount;
485 }
486
487 // Required format property
488 const json& formatElement = getRequiredProperty(element, "format");
489 std::string formatString = parseString(formatElement);
490 if (formatString != "linear")
491 {
492 throw std::invalid_argument{"Invalid format value: " + formatString};
493 }
494 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear;
495 ++propertyCount;
496
497 // Optional exponent property
498 std::optional<int8_t> exponent{};
499 auto exponentIt = element.find("exponent");
500 if (exponentIt != element.end())
501 {
502 exponent = parseInt8(*exponentIt);
503 ++propertyCount;
504 }
505
506 // Optional is_verified property
507 bool isVerified = false;
508 auto isVerifiedIt = element.find("is_verified");
509 if (isVerifiedIt != element.end())
510 {
511 isVerified = parseBoolean(*isVerifiedIt);
512 ++propertyCount;
513 }
514
515 // Verify no invalid properties exist
516 verifyPropertyCount(element, propertyCount);
517
518 return std::make_unique<PMBusWriteVoutCommandAction>(volts, format,
519 exponent, isVerified);
520}
521
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800522std::unique_ptr<Rail> parseRail(const json& element)
523{
524 verifyIsObject(element);
525 unsigned int propertyCount{0};
526
527 // Optional comments property; value not stored
528 if (element.contains("comments"))
529 {
530 ++propertyCount;
531 }
532
533 // Required id property
534 const json& idElement = getRequiredProperty(element, "id");
535 std::string id = parseString(idElement);
536 ++propertyCount;
537
538 // Optional configuration property
539 std::unique_ptr<Configuration> configuration{};
540 auto configurationIt = element.find("configuration");
541 if (configurationIt != element.end())
542 {
543 configuration = parseConfiguration(*configurationIt);
544 ++propertyCount;
545 }
546
547 // Optional sensor_monitoring property
548 std::unique_ptr<SensorMonitoring> sensorMonitoring{};
549 auto sensorMonitoringIt = element.find("sensor_monitoring");
550 if (sensorMonitoringIt != element.end())
551 {
552 sensorMonitoring = parseSensorMonitoring(*sensorMonitoringIt);
553 ++propertyCount;
554 }
555
556 // Verify no invalid properties exist
557 verifyPropertyCount(element, propertyCount);
558
559 return std::make_unique<Rail>(id, std::move(configuration),
560 std::move(sensorMonitoring));
561}
562
Bob King9c36c5f2020-04-06 11:34:09 +0800563std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element)
564{
565 verifyIsArray(element);
566 std::vector<std::unique_ptr<Rail>> rails;
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800567 for (auto& railElement : element)
568 {
569 rails.emplace_back(parseRail(railElement));
570 }
Bob King9c36c5f2020-04-06 11:34:09 +0800571 return rails;
572}
573
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500574std::tuple<std::vector<std::unique_ptr<Rule>>,
575 std::vector<std::unique_ptr<Chassis>>>
576 parseRoot(const json& element)
577{
578 verifyIsObject(element);
579 unsigned int propertyCount{0};
580
581 // Optional comments property; value not stored
582 if (element.contains("comments"))
583 {
584 ++propertyCount;
585 }
586
587 // Optional rules property
588 std::vector<std::unique_ptr<Rule>> rules{};
589 auto rulesIt = element.find("rules");
590 if (rulesIt != element.end())
591 {
592 rules = parseRuleArray(*rulesIt);
593 ++propertyCount;
594 }
595
596 // Required chassis property
597 const json& chassisElement = getRequiredProperty(element, "chassis");
598 std::vector<std::unique_ptr<Chassis>> chassis =
599 parseChassisArray(chassisElement);
600 ++propertyCount;
601
602 // Verify no invalid properties exist
603 verifyPropertyCount(element, propertyCount);
604
605 return std::make_tuple(std::move(rules), std::move(chassis));
606}
607
608std::unique_ptr<Rule> parseRule(const json& element)
609{
610 verifyIsObject(element);
611 unsigned int propertyCount{0};
612
613 // Optional comments property; value not stored
614 if (element.contains("comments"))
615 {
616 ++propertyCount;
617 }
618
619 // Required id property
620 const json& idElement = getRequiredProperty(element, "id");
621 std::string id = parseString(idElement);
622 ++propertyCount;
623
624 // Required actions property
625 const json& actionsElement = getRequiredProperty(element, "actions");
626 std::vector<std::unique_ptr<Action>> actions =
627 parseActionArray(actionsElement);
628 ++propertyCount;
629
630 // Verify no invalid properties exist
631 verifyPropertyCount(element, propertyCount);
632
633 return std::make_unique<Rule>(id, std::move(actions));
634}
635
636std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element)
637{
638 verifyIsArray(element);
639 std::vector<std::unique_ptr<Rule>> rules;
640 for (auto& ruleElement : element)
641 {
642 rules.emplace_back(parseRule(ruleElement));
643 }
644 return rules;
645}
646
Bob King33e7eaa2020-04-01 18:09:34 +0800647std::vector<std::unique_ptr<Action>>
648 parseRuleIDOrActionsProperty(const json& element)
649{
650 verifyIsObject(element);
651 // Required rule_id or actions property
652 std::vector<std::unique_ptr<Action>> actions{};
653 auto ruleIDIt = element.find("rule_id");
654 auto actionsIt = element.find("actions");
655 if ((actionsIt == element.end()) && (ruleIDIt != element.end()))
656 {
657 std::string ruleID = parseString(*ruleIDIt);
658 actions.emplace_back(std::make_unique<RunRuleAction>(ruleID));
659 }
660 else if ((actionsIt != element.end()) && (ruleIDIt == element.end()))
661 {
662 actions = parseActionArray(*actionsIt);
663 }
664 else
665 {
666 throw std::invalid_argument{"Invalid property combination: Must "
667 "contain either rule_id or actions"};
668 }
669
670 return actions;
671}
672
Bob King315b0b62020-04-03 21:47:58 +0800673std::unique_ptr<RunRuleAction> parseRunRule(const json& element)
674{
675 // String ruleID
676 std::string ruleID = parseString(element);
677
678 return std::make_unique<RunRuleAction>(ruleID);
679}
680
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800681std::unique_ptr<SensorMonitoring> parseSensorMonitoring(const json& element)
682{
683 verifyIsObject(element);
684 unsigned int propertyCount{0};
685
686 // Optional comments property; value not stored
687 if (element.contains("comments"))
688 {
689 ++propertyCount;
690 }
691
692 // Required rule_id or actions property
693 std::vector<std::unique_ptr<Action>> actions{};
694 actions = parseRuleIDOrActionsProperty(element);
695 ++propertyCount;
696
697 // Verify no invalid properties exist
698 verifyPropertyCount(element, propertyCount);
699
700 return std::make_unique<SensorMonitoring>(std::move(actions));
701}
702
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500703} // namespace internal
704
705} // namespace phosphor::power::regulators::config_file_parser