1 /**
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 "i2c_interface.hpp"
21 #include "json_parser_utils.hpp"
22 #include "pmbus_utils.hpp"
23
24 #include <cstdint>
25 #include <exception>
26 #include <fstream>
27 #include <optional>
28 #include <stdexcept>
29 #include <utility>
30
31 using json = nlohmann::json;
32 using ConfigFileParserError = phosphor::power::util::ConfigFileParserError;
33 using namespace phosphor::power::json_parser_utils;
34
35 namespace phosphor::power::regulators::config_file_parser
36 {
37
38 std::tuple<std::vector<std::unique_ptr<Rule>>,
39 std::vector<std::unique_ptr<Chassis>>>
parse(const std::filesystem::path & pathName)40 parse(const std::filesystem::path& pathName)
41 {
42 try
43 {
44 // Use standard JSON parser to create tree of JSON elements
45 std::ifstream file{pathName};
46 json rootElement = json::parse(file);
47
48 // Parse tree of JSON elements and return corresponding C++ objects
49 return internal::parseRoot(rootElement);
50 }
51 catch (const std::exception& e)
52 {
53 throw ConfigFileParserError{pathName, e.what()};
54 }
55 }
56
57 namespace internal
58 {
59
parseAction(const json & element)60 std::unique_ptr<Action> parseAction(const json& element)
61 {
62 verifyIsObject(element);
63 unsigned int propertyCount{0};
64
65 // Optional comments property; value not stored
66 if (element.contains("comments"))
67 {
68 ++propertyCount;
69 }
70
71 // Required action type property; there must be exactly one specified
72 std::unique_ptr<Action> action{};
73 if (element.contains("and"))
74 {
75 action = parseAnd(element["and"]);
76 ++propertyCount;
77 }
78 else if (element.contains("compare_presence"))
79 {
80 action = parseComparePresence(element["compare_presence"]);
81 ++propertyCount;
82 }
83 else if (element.contains("compare_vpd"))
84 {
85 action = parseCompareVPD(element["compare_vpd"]);
86 ++propertyCount;
87 }
88 else if (element.contains("i2c_capture_bytes"))
89 {
90 action = parseI2CCaptureBytes(element["i2c_capture_bytes"]);
91 ++propertyCount;
92 }
93 else if (element.contains("i2c_compare_bit"))
94 {
95 action = parseI2CCompareBit(element["i2c_compare_bit"]);
96 ++propertyCount;
97 }
98 else if (element.contains("i2c_compare_byte"))
99 {
100 action = parseI2CCompareByte(element["i2c_compare_byte"]);
101 ++propertyCount;
102 }
103 else if (element.contains("i2c_compare_bytes"))
104 {
105 action = parseI2CCompareBytes(element["i2c_compare_bytes"]);
106 ++propertyCount;
107 }
108 else if (element.contains("i2c_write_bit"))
109 {
110 action = parseI2CWriteBit(element["i2c_write_bit"]);
111 ++propertyCount;
112 }
113 else if (element.contains("i2c_write_byte"))
114 {
115 action = parseI2CWriteByte(element["i2c_write_byte"]);
116 ++propertyCount;
117 }
118 else if (element.contains("i2c_write_bytes"))
119 {
120 action = parseI2CWriteBytes(element["i2c_write_bytes"]);
121 ++propertyCount;
122 }
123 else if (element.contains("if"))
124 {
125 action = parseIf(element["if"]);
126 ++propertyCount;
127 }
128 else if (element.contains("log_phase_fault"))
129 {
130 action = parseLogPhaseFault(element["log_phase_fault"]);
131 ++propertyCount;
132 }
133 else if (element.contains("not"))
134 {
135 action = parseNot(element["not"]);
136 ++propertyCount;
137 }
138 else if (element.contains("or"))
139 {
140 action = parseOr(element["or"]);
141 ++propertyCount;
142 }
143 else if (element.contains("pmbus_read_sensor"))
144 {
145 action = parsePMBusReadSensor(element["pmbus_read_sensor"]);
146 ++propertyCount;
147 }
148 else if (element.contains("pmbus_write_vout_command"))
149 {
150 action =
151 parsePMBusWriteVoutCommand(element["pmbus_write_vout_command"]);
152 ++propertyCount;
153 }
154 else if (element.contains("run_rule"))
155 {
156 action = parseRunRule(element["run_rule"]);
157 ++propertyCount;
158 }
159 else if (element.contains("set_device"))
160 {
161 action = parseSetDevice(element["set_device"]);
162 ++propertyCount;
163 }
164 else
165 {
166 throw std::invalid_argument{"Required action type property missing"};
167 }
168
169 // Verify no invalid properties exist
170 verifyPropertyCount(element, propertyCount);
171
172 return action;
173 }
174
parseActionArray(const json & element)175 std::vector<std::unique_ptr<Action>> parseActionArray(const json& element)
176 {
177 verifyIsArray(element);
178 std::vector<std::unique_ptr<Action>> actions;
179 for (auto& actionElement : element)
180 {
181 actions.emplace_back(parseAction(actionElement));
182 }
183 return actions;
184 }
185
parseAnd(const json & element)186 std::unique_ptr<AndAction> parseAnd(const json& element)
187 {
188 verifyIsArray(element);
189
190 // Verify if array size less than 2
191 if (element.size() < 2)
192 {
193 throw std::invalid_argument{"Array must contain two or more actions"};
194 }
195 // Array of two or more actions
196 std::vector<std::unique_ptr<Action>> actions = parseActionArray(element);
197
198 return std::make_unique<AndAction>(std::move(actions));
199 }
200
parseChassis(const json & element)201 std::unique_ptr<Chassis> parseChassis(const json& element)
202 {
203 verifyIsObject(element);
204 unsigned int propertyCount{0};
205
206 // Optional comments property; value not stored
207 if (element.contains("comments"))
208 {
209 ++propertyCount;
210 }
211
212 // Required number property
213 const json& numberElement = getRequiredProperty(element, "number");
214 unsigned int number = parseUnsignedInteger(numberElement);
215 if (number < 1)
216 {
217 throw std::invalid_argument{"Invalid chassis number: Must be > 0"};
218 }
219 ++propertyCount;
220
221 // Required inventory_path property
222 const json& inventoryPathElement =
223 getRequiredProperty(element, "inventory_path");
224 std::string inventoryPath = parseInventoryPath(inventoryPathElement);
225 ++propertyCount;
226
227 // Optional devices property
228 std::vector<std::unique_ptr<Device>> devices{};
229 auto devicesIt = element.find("devices");
230 if (devicesIt != element.end())
231 {
232 devices = parseDeviceArray(*devicesIt);
233 ++propertyCount;
234 }
235
236 // Verify no invalid properties exist
237 verifyPropertyCount(element, propertyCount);
238
239 return std::make_unique<Chassis>(number, inventoryPath, std::move(devices));
240 }
241
parseChassisArray(const json & element)242 std::vector<std::unique_ptr<Chassis>> parseChassisArray(const json& element)
243 {
244 verifyIsArray(element);
245 std::vector<std::unique_ptr<Chassis>> chassis;
246 for (auto& chassisElement : element)
247 {
248 chassis.emplace_back(parseChassis(chassisElement));
249 }
250 return chassis;
251 }
252
parseComparePresence(const json & element)253 std::unique_ptr<ComparePresenceAction> parseComparePresence(const json& element)
254 {
255 verifyIsObject(element);
256 unsigned int propertyCount{0};
257
258 // Required fru property
259 const json& fruElement = getRequiredProperty(element, "fru");
260 std::string fru = parseInventoryPath(fruElement);
261 ++propertyCount;
262
263 // Required value property
264 const json& valueElement = getRequiredProperty(element, "value");
265 bool value = parseBoolean(valueElement);
266 ++propertyCount;
267
268 // Verify no invalid properties exist
269 verifyPropertyCount(element, propertyCount);
270
271 return std::make_unique<ComparePresenceAction>(fru, value);
272 }
273
parseCompareVPD(const json & element)274 std::unique_ptr<CompareVPDAction> parseCompareVPD(const json& element)
275 {
276 verifyIsObject(element);
277 unsigned int propertyCount{0};
278
279 // Required fru property
280 const json& fruElement = getRequiredProperty(element, "fru");
281 std::string fru = parseInventoryPath(fruElement);
282 ++propertyCount;
283
284 // Required keyword property
285 const json& keywordElement = getRequiredProperty(element, "keyword");
286 std::string keyword = parseString(keywordElement);
287 ++propertyCount;
288
289 // Either value or byte_values required property
290 auto valueIt = element.find("value");
291 std::vector<uint8_t> value{};
292 auto byteValuesIt = element.find("byte_values");
293 if ((valueIt != element.end()) && (byteValuesIt == element.end()))
294 {
295 std::string stringValue = parseString(*valueIt, true);
296 value.insert(value.begin(), stringValue.begin(), stringValue.end());
297 ++propertyCount;
298 }
299 else if ((valueIt == element.end()) && (byteValuesIt != element.end()))
300 {
301 value = parseHexByteArray(*byteValuesIt);
302 ++propertyCount;
303 }
304 else
305 {
306 throw std::invalid_argument{
307 "Invalid property: Must contain either value or byte_values"};
308 }
309
310 // Verify no invalid properties exist
311 verifyPropertyCount(element, propertyCount);
312
313 return std::make_unique<CompareVPDAction>(fru, keyword, value);
314 }
315
parseConfiguration(const json & element)316 std::unique_ptr<Configuration> parseConfiguration(const json& element)
317 {
318 verifyIsObject(element);
319 unsigned int propertyCount{0};
320
321 // Optional comments property; value not stored
322 if (element.contains("comments"))
323 {
324 ++propertyCount;
325 }
326
327 // Optional volts property
328 std::optional<double> volts{};
329 auto voltsIt = element.find("volts");
330 if (voltsIt != element.end())
331 {
332 volts = parseDouble(*voltsIt);
333 ++propertyCount;
334 }
335
336 // Required rule_id or actions property
337 std::vector<std::unique_ptr<Action>> actions{};
338 actions = parseRuleIDOrActionsProperty(element);
339 ++propertyCount;
340
341 // Verify no invalid properties exist
342 verifyPropertyCount(element, propertyCount);
343
344 return std::make_unique<Configuration>(volts, std::move(actions));
345 }
346
parseDevice(const json & element)347 std::unique_ptr<Device> parseDevice(const json& element)
348 {
349 verifyIsObject(element);
350 unsigned int propertyCount{0};
351
352 // Optional comments property; value not stored
353 if (element.contains("comments"))
354 {
355 ++propertyCount;
356 }
357
358 // Required id property
359 const json& idElement = getRequiredProperty(element, "id");
360 std::string id = parseString(idElement);
361 ++propertyCount;
362
363 // Required is_regulator property
364 const json& isRegulatorElement =
365 getRequiredProperty(element, "is_regulator");
366 bool isRegulator = parseBoolean(isRegulatorElement);
367 ++propertyCount;
368
369 // Required fru property
370 const json& fruElement = getRequiredProperty(element, "fru");
371 std::string fru = parseInventoryPath(fruElement);
372 ++propertyCount;
373
374 // Required i2c_interface property
375 const json& i2cInterfaceElement =
376 getRequiredProperty(element, "i2c_interface");
377 std::unique_ptr<i2c::I2CInterface> i2cInterface =
378 parseI2CInterface(i2cInterfaceElement);
379 ++propertyCount;
380
381 // Optional presence_detection property
382 std::unique_ptr<PresenceDetection> presenceDetection{};
383 auto presenceDetectionIt = element.find("presence_detection");
384 if (presenceDetectionIt != element.end())
385 {
386 presenceDetection = parsePresenceDetection(*presenceDetectionIt);
387 ++propertyCount;
388 }
389
390 // Optional configuration property
391 std::unique_ptr<Configuration> configuration{};
392 auto configurationIt = element.find("configuration");
393 if (configurationIt != element.end())
394 {
395 configuration = parseConfiguration(*configurationIt);
396 ++propertyCount;
397 }
398
399 // Optional phase_fault_detection property
400 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
401 auto phaseFaultDetectionIt = element.find("phase_fault_detection");
402 if (phaseFaultDetectionIt != element.end())
403 {
404 if (!isRegulator)
405 {
406 throw std::invalid_argument{"Invalid phase_fault_detection "
407 "property when is_regulator is false"};
408 }
409 phaseFaultDetection = parsePhaseFaultDetection(*phaseFaultDetectionIt);
410 ++propertyCount;
411 }
412
413 // Optional rails property
414 std::vector<std::unique_ptr<Rail>> rails{};
415 auto railsIt = element.find("rails");
416 if (railsIt != element.end())
417 {
418 if (!isRegulator)
419 {
420 throw std::invalid_argument{
421 "Invalid rails property when is_regulator is false"};
422 }
423 rails = parseRailArray(*railsIt);
424 ++propertyCount;
425 }
426
427 // Verify no invalid properties exist
428 verifyPropertyCount(element, propertyCount);
429
430 return std::make_unique<Device>(
431 id, isRegulator, fru, std::move(i2cInterface),
432 std::move(presenceDetection), std::move(configuration),
433 std::move(phaseFaultDetection), std::move(rails));
434 }
435
parseDeviceArray(const json & element)436 std::vector<std::unique_ptr<Device>> parseDeviceArray(const json& element)
437 {
438 verifyIsArray(element);
439 std::vector<std::unique_ptr<Device>> devices;
440 for (auto& deviceElement : element)
441 {
442 devices.emplace_back(parseDevice(deviceElement));
443 }
444 return devices;
445 }
446
parseI2CCaptureBytes(const json & element)447 std::unique_ptr<I2CCaptureBytesAction> parseI2CCaptureBytes(const json& element)
448 {
449 verifyIsObject(element);
450 unsigned int propertyCount{0};
451
452 // Required register property
453 const json& regElement = getRequiredProperty(element, "register");
454 uint8_t reg = parseHexByte(regElement);
455 ++propertyCount;
456
457 // Required count property
458 const json& countElement = getRequiredProperty(element, "count");
459 uint8_t count = parseUint8(countElement);
460 if (count < 1)
461 {
462 throw std::invalid_argument{"Invalid byte count: Must be > 0"};
463 }
464 ++propertyCount;
465
466 // Verify no invalid properties exist
467 verifyPropertyCount(element, propertyCount);
468
469 return std::make_unique<I2CCaptureBytesAction>(reg, count);
470 }
471
parseI2CCompareBit(const json & element)472 std::unique_ptr<I2CCompareBitAction> parseI2CCompareBit(const json& element)
473 {
474 verifyIsObject(element);
475 unsigned int propertyCount{0};
476
477 // Required register property
478 const json& regElement = getRequiredProperty(element, "register");
479 uint8_t reg = parseHexByte(regElement);
480 ++propertyCount;
481
482 // Required position property
483 const json& positionElement = getRequiredProperty(element, "position");
484 uint8_t position = parseBitPosition(positionElement);
485 ++propertyCount;
486
487 // Required value property
488 const json& valueElement = getRequiredProperty(element, "value");
489 uint8_t value = parseBitValue(valueElement);
490 ++propertyCount;
491
492 // Verify no invalid properties exist
493 verifyPropertyCount(element, propertyCount);
494
495 return std::make_unique<I2CCompareBitAction>(reg, position, value);
496 }
497
parseI2CCompareByte(const json & element)498 std::unique_ptr<I2CCompareByteAction> parseI2CCompareByte(const json& element)
499 {
500 verifyIsObject(element);
501 unsigned int propertyCount{0};
502
503 // Required register property
504 const json& regElement = getRequiredProperty(element, "register");
505 uint8_t reg = parseHexByte(regElement);
506 ++propertyCount;
507
508 // Required value property
509 const json& valueElement = getRequiredProperty(element, "value");
510 uint8_t value = parseHexByte(valueElement);
511 ++propertyCount;
512
513 // Optional mask property
514 uint8_t mask = 0xff;
515 auto maskIt = element.find("mask");
516 if (maskIt != element.end())
517 {
518 mask = parseHexByte(*maskIt);
519 ++propertyCount;
520 }
521
522 // Verify no invalid properties exist
523 verifyPropertyCount(element, propertyCount);
524
525 return std::make_unique<I2CCompareByteAction>(reg, value, mask);
526 }
527
parseI2CCompareBytes(const json & element)528 std::unique_ptr<I2CCompareBytesAction> parseI2CCompareBytes(const json& element)
529 {
530 verifyIsObject(element);
531 unsigned int propertyCount{0};
532
533 // Required register property
534 const json& regElement = getRequiredProperty(element, "register");
535 uint8_t reg = parseHexByte(regElement);
536 ++propertyCount;
537
538 // Required values property
539 const json& valueElement = getRequiredProperty(element, "values");
540 std::vector<uint8_t> values = parseHexByteArray(valueElement);
541 ++propertyCount;
542
543 // Optional masks property
544 std::vector<uint8_t> masks{};
545 auto masksIt = element.find("masks");
546 if (masksIt != element.end())
547 {
548 masks = parseHexByteArray(*masksIt);
549 ++propertyCount;
550 }
551
552 // Verify masks array (if specified) was same size as values array
553 if ((!masks.empty()) && (masks.size() != values.size()))
554 {
555 throw std::invalid_argument{"Invalid number of elements in masks"};
556 }
557
558 // Verify no invalid properties exist
559 verifyPropertyCount(element, propertyCount);
560
561 if (masks.empty())
562 {
563 return std::make_unique<I2CCompareBytesAction>(reg, values);
564 }
565 return std::make_unique<I2CCompareBytesAction>(reg, values, masks);
566 }
567
parseI2CInterface(const json & element)568 std::unique_ptr<i2c::I2CInterface> parseI2CInterface(const json& element)
569 {
570 verifyIsObject(element);
571 unsigned int propertyCount{0};
572
573 // Required bus property
574 const json& busElement = getRequiredProperty(element, "bus");
575 uint8_t bus = parseUint8(busElement);
576 ++propertyCount;
577
578 // Required address property
579 const json& addressElement = getRequiredProperty(element, "address");
580 uint8_t address = parseHexByte(addressElement);
581 ++propertyCount;
582
583 // Verify no invalid properties exist
584 verifyPropertyCount(element, propertyCount);
585
586 // Create I2CInterface object; retry failed I2C operations a max of 3 times.
587 int maxRetries{3};
588 return i2c::create(bus, address, i2c::I2CInterface::InitialState::CLOSED,
589 maxRetries);
590 }
591
parseI2CWriteBit(const json & element)592 std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element)
593 {
594 verifyIsObject(element);
595 unsigned int propertyCount{0};
596
597 // Required register property
598 const json& regElement = getRequiredProperty(element, "register");
599 uint8_t reg = parseHexByte(regElement);
600 ++propertyCount;
601
602 // Required position property
603 const json& positionElement = getRequiredProperty(element, "position");
604 uint8_t position = parseBitPosition(positionElement);
605 ++propertyCount;
606
607 // Required value property
608 const json& valueElement = getRequiredProperty(element, "value");
609 uint8_t value = parseBitValue(valueElement);
610 ++propertyCount;
611
612 // Verify no invalid properties exist
613 verifyPropertyCount(element, propertyCount);
614
615 return std::make_unique<I2CWriteBitAction>(reg, position, value);
616 }
617
parseI2CWriteByte(const json & element)618 std::unique_ptr<I2CWriteByteAction> parseI2CWriteByte(const json& element)
619 {
620 verifyIsObject(element);
621 unsigned int propertyCount{0};
622
623 // Required register property
624 const json& regElement = getRequiredProperty(element, "register");
625 uint8_t reg = parseHexByte(regElement);
626 ++propertyCount;
627
628 // Required value property
629 const json& valueElement = getRequiredProperty(element, "value");
630 uint8_t value = parseHexByte(valueElement);
631 ++propertyCount;
632
633 // Optional mask property
634 uint8_t mask = 0xff;
635 auto maskIt = element.find("mask");
636 if (maskIt != element.end())
637 {
638 mask = parseHexByte(*maskIt);
639 ++propertyCount;
640 }
641
642 // Verify no invalid properties exist
643 verifyPropertyCount(element, propertyCount);
644
645 return std::make_unique<I2CWriteByteAction>(reg, value, mask);
646 }
647
parseI2CWriteBytes(const json & element)648 std::unique_ptr<I2CWriteBytesAction> parseI2CWriteBytes(const json& element)
649 {
650 verifyIsObject(element);
651 unsigned int propertyCount{0};
652
653 // Required register property
654 const json& regElement = getRequiredProperty(element, "register");
655 uint8_t reg = parseHexByte(regElement);
656 ++propertyCount;
657
658 // Required values property
659 const json& valueElement = getRequiredProperty(element, "values");
660 std::vector<uint8_t> values = parseHexByteArray(valueElement);
661 ++propertyCount;
662
663 // Optional masks property
664 std::vector<uint8_t> masks{};
665 auto masksIt = element.find("masks");
666 if (masksIt != element.end())
667 {
668 masks = parseHexByteArray(*masksIt);
669 ++propertyCount;
670 }
671
672 // Verify masks array (if specified) was same size as values array
673 if ((!masks.empty()) && (masks.size() != values.size()))
674 {
675 throw std::invalid_argument{"Invalid number of elements in masks"};
676 }
677
678 // Verify no invalid properties exist
679 verifyPropertyCount(element, propertyCount);
680
681 if (masks.empty())
682 {
683 return std::make_unique<I2CWriteBytesAction>(reg, values);
684 }
685 return std::make_unique<I2CWriteBytesAction>(reg, values, masks);
686 }
687
parseIf(const json & element)688 std::unique_ptr<IfAction> parseIf(const json& element)
689 {
690 verifyIsObject(element);
691 unsigned int propertyCount{0};
692
693 // Required condition property
694 const json& conditionElement = getRequiredProperty(element, "condition");
695 std::unique_ptr<Action> conditionAction = parseAction(conditionElement);
696 ++propertyCount;
697
698 // Required then property
699 const json& thenElement = getRequiredProperty(element, "then");
700 std::vector<std::unique_ptr<Action>> thenActions =
701 parseActionArray(thenElement);
702 ++propertyCount;
703
704 // Optional else property
705 std::vector<std::unique_ptr<Action>> elseActions{};
706 auto elseIt = element.find("else");
707 if (elseIt != element.end())
708 {
709 elseActions = parseActionArray(*elseIt);
710 ++propertyCount;
711 }
712
713 // Verify no invalid properties exist
714 verifyPropertyCount(element, propertyCount);
715
716 return std::make_unique<IfAction>(std::move(conditionAction),
717 std::move(thenActions),
718 std::move(elseActions));
719 }
720
parseInventoryPath(const json & element)721 std::string parseInventoryPath(const json& element)
722 {
723 std::string inventoryPath = parseString(element);
724 std::string absPath = "/xyz/openbmc_project/inventory";
725 if (inventoryPath.front() != '/')
726 {
727 absPath += '/';
728 }
729 absPath += inventoryPath;
730 return absPath;
731 }
732
parseLogPhaseFault(const json & element)733 std::unique_ptr<LogPhaseFaultAction> parseLogPhaseFault(const json& element)
734 {
735 verifyIsObject(element);
736 unsigned int propertyCount{0};
737
738 // Required type property
739 const json& typeElement = getRequiredProperty(element, "type");
740 PhaseFaultType type = parsePhaseFaultType(typeElement);
741 ++propertyCount;
742
743 // Verify no invalid properties exist
744 verifyPropertyCount(element, propertyCount);
745
746 return std::make_unique<LogPhaseFaultAction>(type);
747 }
748
parseNot(const json & element)749 std::unique_ptr<NotAction> parseNot(const json& element)
750 {
751 // Required action to execute
752 std::unique_ptr<Action> action = parseAction(element);
753
754 return std::make_unique<NotAction>(std::move(action));
755 }
756
parseOr(const json & element)757 std::unique_ptr<OrAction> parseOr(const json& element)
758 {
759 verifyIsArray(element);
760
761 // Verify if array size less than 2
762 if (element.size() < 2)
763 {
764 throw std::invalid_argument{"Array must contain two or more actions"};
765 }
766 // Array of two or more actions
767 std::vector<std::unique_ptr<Action>> actions = parseActionArray(element);
768
769 return std::make_unique<OrAction>(std::move(actions));
770 }
771
parsePhaseFaultDetection(const json & element)772 std::unique_ptr<PhaseFaultDetection> parsePhaseFaultDetection(
773 const json& element)
774 {
775 verifyIsObject(element);
776 unsigned int propertyCount{0};
777
778 // Optional comments property; value not stored
779 if (element.contains("comments"))
780 {
781 ++propertyCount;
782 }
783
784 // Optional device_id property
785 std::string deviceID{};
786 auto deviceIDIt = element.find("device_id");
787 if (deviceIDIt != element.end())
788 {
789 deviceID = parseString(*deviceIDIt);
790 ++propertyCount;
791 }
792
793 // Required rule_id or actions property
794 std::vector<std::unique_ptr<Action>> actions{};
795 actions = parseRuleIDOrActionsProperty(element);
796 ++propertyCount;
797
798 // Verify no invalid properties exist
799 verifyPropertyCount(element, propertyCount);
800
801 return std::make_unique<PhaseFaultDetection>(std::move(actions), deviceID);
802 }
803
parsePhaseFaultType(const json & element)804 PhaseFaultType parsePhaseFaultType(const json& element)
805 {
806 std::string value = parseString(element);
807 PhaseFaultType type{};
808
809 if (value == "n")
810 {
811 type = PhaseFaultType::n;
812 }
813 else if (value == "n+1")
814 {
815 type = PhaseFaultType::n_plus_1;
816 }
817 else
818 {
819 throw std::invalid_argument{"Element is not a phase fault type"};
820 }
821
822 return type;
823 }
824
parsePMBusReadSensor(const json & element)825 std::unique_ptr<PMBusReadSensorAction> parsePMBusReadSensor(const json& element)
826 {
827 verifyIsObject(element);
828 unsigned int propertyCount{0};
829
830 // Required type property
831 const json& typeElement = getRequiredProperty(element, "type");
832 SensorType type = parseSensorType(typeElement);
833 ++propertyCount;
834
835 // Required command property
836 const json& commandElement = getRequiredProperty(element, "command");
837 uint8_t command = parseHexByte(commandElement);
838 ++propertyCount;
839
840 // Required format property
841 const json& formatElement = getRequiredProperty(element, "format");
842 pmbus_utils::SensorDataFormat format = parseSensorDataFormat(formatElement);
843 ++propertyCount;
844
845 // Optional exponent property
846 std::optional<int8_t> exponent{};
847 auto exponentIt = element.find("exponent");
848 if (exponentIt != element.end())
849 {
850 exponent = parseInt8(*exponentIt);
851 ++propertyCount;
852 }
853
854 // Verify no invalid properties exist
855 verifyPropertyCount(element, propertyCount);
856
857 return std::make_unique<PMBusReadSensorAction>(type, command, format,
858 exponent);
859 }
860
parsePMBusWriteVoutCommand(const json & element)861 std::unique_ptr<PMBusWriteVoutCommandAction> parsePMBusWriteVoutCommand(
862 const json& element)
863 {
864 verifyIsObject(element);
865 unsigned int propertyCount{0};
866
867 // Optional volts property
868 std::optional<double> volts{};
869 auto voltsIt = element.find("volts");
870 if (voltsIt != element.end())
871 {
872 volts = parseDouble(*voltsIt);
873 ++propertyCount;
874 }
875
876 // Required format property
877 const json& formatElement = getRequiredProperty(element, "format");
878 std::string formatString = parseString(formatElement);
879 if (formatString != "linear")
880 {
881 throw std::invalid_argument{"Invalid format value: " + formatString};
882 }
883 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear;
884 ++propertyCount;
885
886 // Optional exponent property
887 std::optional<int8_t> exponent{};
888 auto exponentIt = element.find("exponent");
889 if (exponentIt != element.end())
890 {
891 exponent = parseInt8(*exponentIt);
892 ++propertyCount;
893 }
894
895 // Optional is_verified property
896 bool isVerified = false;
897 auto isVerifiedIt = element.find("is_verified");
898 if (isVerifiedIt != element.end())
899 {
900 isVerified = parseBoolean(*isVerifiedIt);
901 ++propertyCount;
902 }
903
904 // Verify no invalid properties exist
905 verifyPropertyCount(element, propertyCount);
906
907 return std::make_unique<PMBusWriteVoutCommandAction>(volts, format,
908 exponent, isVerified);
909 }
910
parsePresenceDetection(const json & element)911 std::unique_ptr<PresenceDetection> parsePresenceDetection(const json& element)
912 {
913 verifyIsObject(element);
914 unsigned int propertyCount{0};
915
916 // Optional comments property; value not stored
917 if (element.contains("comments"))
918 {
919 ++propertyCount;
920 }
921
922 // Required rule_id or actions property
923 std::vector<std::unique_ptr<Action>> actions{};
924 actions = parseRuleIDOrActionsProperty(element);
925 ++propertyCount;
926
927 // Verify no invalid properties exist
928 verifyPropertyCount(element, propertyCount);
929
930 return std::make_unique<PresenceDetection>(std::move(actions));
931 }
932
parseRail(const json & element)933 std::unique_ptr<Rail> parseRail(const json& element)
934 {
935 verifyIsObject(element);
936 unsigned int propertyCount{0};
937
938 // Optional comments property; value not stored
939 if (element.contains("comments"))
940 {
941 ++propertyCount;
942 }
943
944 // Required id property
945 const json& idElement = getRequiredProperty(element, "id");
946 std::string id = parseString(idElement);
947 ++propertyCount;
948
949 // Optional configuration property
950 std::unique_ptr<Configuration> configuration{};
951 auto configurationIt = element.find("configuration");
952 if (configurationIt != element.end())
953 {
954 configuration = parseConfiguration(*configurationIt);
955 ++propertyCount;
956 }
957
958 // Optional sensor_monitoring property
959 std::unique_ptr<SensorMonitoring> sensorMonitoring{};
960 auto sensorMonitoringIt = element.find("sensor_monitoring");
961 if (sensorMonitoringIt != element.end())
962 {
963 sensorMonitoring = parseSensorMonitoring(*sensorMonitoringIt);
964 ++propertyCount;
965 }
966
967 // Verify no invalid properties exist
968 verifyPropertyCount(element, propertyCount);
969
970 return std::make_unique<Rail>(id, std::move(configuration),
971 std::move(sensorMonitoring));
972 }
973
parseRailArray(const json & element)974 std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element)
975 {
976 verifyIsArray(element);
977 std::vector<std::unique_ptr<Rail>> rails;
978 for (auto& railElement : element)
979 {
980 rails.emplace_back(parseRail(railElement));
981 }
982 return rails;
983 }
984
985 std::tuple<std::vector<std::unique_ptr<Rule>>,
986 std::vector<std::unique_ptr<Chassis>>>
parseRoot(const json & element)987 parseRoot(const json& element)
988 {
989 verifyIsObject(element);
990 unsigned int propertyCount{0};
991
992 // Optional comments property; value not stored
993 if (element.contains("comments"))
994 {
995 ++propertyCount;
996 }
997
998 // Optional rules property
999 std::vector<std::unique_ptr<Rule>> rules{};
1000 auto rulesIt = element.find("rules");
1001 if (rulesIt != element.end())
1002 {
1003 rules = parseRuleArray(*rulesIt);
1004 ++propertyCount;
1005 }
1006
1007 // Required chassis property
1008 const json& chassisElement = getRequiredProperty(element, "chassis");
1009 std::vector<std::unique_ptr<Chassis>> chassis =
1010 parseChassisArray(chassisElement);
1011 ++propertyCount;
1012
1013 // Verify no invalid properties exist
1014 verifyPropertyCount(element, propertyCount);
1015
1016 return std::make_tuple(std::move(rules), std::move(chassis));
1017 }
1018
parseRule(const json & element)1019 std::unique_ptr<Rule> parseRule(const json& element)
1020 {
1021 verifyIsObject(element);
1022 unsigned int propertyCount{0};
1023
1024 // Optional comments property; value not stored
1025 if (element.contains("comments"))
1026 {
1027 ++propertyCount;
1028 }
1029
1030 // Required id property
1031 const json& idElement = getRequiredProperty(element, "id");
1032 std::string id = parseString(idElement);
1033 ++propertyCount;
1034
1035 // Required actions property
1036 const json& actionsElement = getRequiredProperty(element, "actions");
1037 std::vector<std::unique_ptr<Action>> actions =
1038 parseActionArray(actionsElement);
1039 ++propertyCount;
1040
1041 // Verify no invalid properties exist
1042 verifyPropertyCount(element, propertyCount);
1043
1044 return std::make_unique<Rule>(id, std::move(actions));
1045 }
1046
parseRuleArray(const json & element)1047 std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element)
1048 {
1049 verifyIsArray(element);
1050 std::vector<std::unique_ptr<Rule>> rules;
1051 for (auto& ruleElement : element)
1052 {
1053 rules.emplace_back(parseRule(ruleElement));
1054 }
1055 return rules;
1056 }
1057
parseRuleIDOrActionsProperty(const json & element)1058 std::vector<std::unique_ptr<Action>> parseRuleIDOrActionsProperty(
1059 const json& element)
1060 {
1061 verifyIsObject(element);
1062 // Required rule_id or actions property
1063 std::vector<std::unique_ptr<Action>> actions{};
1064 auto ruleIDIt = element.find("rule_id");
1065 auto actionsIt = element.find("actions");
1066 if ((actionsIt == element.end()) && (ruleIDIt != element.end()))
1067 {
1068 std::string ruleID = parseString(*ruleIDIt);
1069 actions.emplace_back(std::make_unique<RunRuleAction>(ruleID));
1070 }
1071 else if ((actionsIt != element.end()) && (ruleIDIt == element.end()))
1072 {
1073 actions = parseActionArray(*actionsIt);
1074 }
1075 else
1076 {
1077 throw std::invalid_argument{"Invalid property combination: Must "
1078 "contain either rule_id or actions"};
1079 }
1080
1081 return actions;
1082 }
1083
parseRunRule(const json & element)1084 std::unique_ptr<RunRuleAction> parseRunRule(const json& element)
1085 {
1086 // String ruleID
1087 std::string ruleID = parseString(element);
1088
1089 return std::make_unique<RunRuleAction>(ruleID);
1090 }
1091
parseSensorDataFormat(const json & element)1092 pmbus_utils::SensorDataFormat parseSensorDataFormat(const json& element)
1093 {
1094 if (!element.is_string())
1095 {
1096 throw std::invalid_argument{"Element is not a string"};
1097 }
1098 std::string value = element.get<std::string>();
1099 pmbus_utils::SensorDataFormat format{};
1100
1101 if (value == "linear_11")
1102 {
1103 format = pmbus_utils::SensorDataFormat::linear_11;
1104 }
1105 else if (value == "linear_16")
1106 {
1107 format = pmbus_utils::SensorDataFormat::linear_16;
1108 }
1109 else
1110 {
1111 throw std::invalid_argument{"Element is not a sensor data format"};
1112 }
1113
1114 return format;
1115 }
1116
parseSensorMonitoring(const json & element)1117 std::unique_ptr<SensorMonitoring> parseSensorMonitoring(const json& element)
1118 {
1119 verifyIsObject(element);
1120 unsigned int propertyCount{0};
1121
1122 // Optional comments property; value not stored
1123 if (element.contains("comments"))
1124 {
1125 ++propertyCount;
1126 }
1127
1128 // Required rule_id or actions property
1129 std::vector<std::unique_ptr<Action>> actions{};
1130 actions = parseRuleIDOrActionsProperty(element);
1131 ++propertyCount;
1132
1133 // Verify no invalid properties exist
1134 verifyPropertyCount(element, propertyCount);
1135
1136 return std::make_unique<SensorMonitoring>(std::move(actions));
1137 }
1138
parseSensorType(const json & element)1139 SensorType parseSensorType(const json& element)
1140 {
1141 std::string value = parseString(element);
1142 SensorType type{};
1143
1144 if (value == "iout")
1145 {
1146 type = SensorType::iout;
1147 }
1148 else if (value == "iout_peak")
1149 {
1150 type = SensorType::iout_peak;
1151 }
1152 else if (value == "iout_valley")
1153 {
1154 type = SensorType::iout_valley;
1155 }
1156 else if (value == "pout")
1157 {
1158 type = SensorType::pout;
1159 }
1160 else if (value == "temperature")
1161 {
1162 type = SensorType::temperature;
1163 }
1164 else if (value == "temperature_peak")
1165 {
1166 type = SensorType::temperature_peak;
1167 }
1168 else if (value == "vout")
1169 {
1170 type = SensorType::vout;
1171 }
1172 else if (value == "vout_peak")
1173 {
1174 type = SensorType::vout_peak;
1175 }
1176 else if (value == "vout_valley")
1177 {
1178 type = SensorType::vout_valley;
1179 }
1180 else
1181 {
1182 throw std::invalid_argument{"Element is not a sensor type"};
1183 }
1184
1185 return type;
1186 }
1187
parseSetDevice(const json & element)1188 std::unique_ptr<SetDeviceAction> parseSetDevice(const json& element)
1189 {
1190 // String deviceID
1191 std::string deviceID = parseString(element);
1192
1193 return std::make_unique<SetDeviceAction>(deviceID);
1194 }
1195
parseVoutDataFormat(const json & element)1196 pmbus_utils::VoutDataFormat parseVoutDataFormat(const json& element)
1197 {
1198 if (!element.is_string())
1199 {
1200 throw std::invalid_argument{"Element is not a string"};
1201 }
1202 std::string value = element.get<std::string>();
1203 pmbus_utils::VoutDataFormat format{};
1204
1205 if (value == "linear")
1206 {
1207 format = pmbus_utils::VoutDataFormat::linear;
1208 }
1209 else if (value == "vid")
1210 {
1211 format = pmbus_utils::VoutDataFormat::vid;
1212 }
1213 else if (value == "direct")
1214 {
1215 format = pmbus_utils::VoutDataFormat::direct;
1216 }
1217 else if (value == "ieee")
1218 {
1219 format = pmbus_utils::VoutDataFormat::ieee;
1220 }
1221 else
1222 {
1223 throw std::invalid_argument{"Element is not a vout data format"};
1224 }
1225
1226 return format;
1227 }
1228
1229 } // namespace internal
1230
1231 } // namespace phosphor::power::regulators::config_file_parser
1232