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