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 rails property 398 std::vector<std::unique_ptr<Rail>> rails{}; 399 auto railsIt = element.find("rails"); 400 if (railsIt != element.end()) 401 { 402 if (!isRegulator) 403 { 404 throw std::invalid_argument{ 405 "Invalid rails property when is_regulator is false"}; 406 } 407 rails = parseRailArray(*railsIt); 408 ++propertyCount; 409 } 410 411 // Verify no invalid properties exist 412 verifyPropertyCount(element, propertyCount); 413 414 return std::make_unique<Device>(id, isRegulator, fru, 415 std::move(i2cInterface), 416 std::move(presenceDetection), 417 std::move(configuration), std::move(rails)); 418 } 419 420 std::vector<std::unique_ptr<Device>> parseDeviceArray(const json& element) 421 { 422 verifyIsArray(element); 423 std::vector<std::unique_ptr<Device>> devices; 424 for (auto& deviceElement : element) 425 { 426 devices.emplace_back(parseDevice(deviceElement)); 427 } 428 return devices; 429 } 430 431 std::vector<uint8_t> parseHexByteArray(const json& element) 432 { 433 verifyIsArray(element); 434 std::vector<uint8_t> values; 435 for (auto& valueElement : element) 436 { 437 values.emplace_back(parseHexByte(valueElement)); 438 } 439 return values; 440 } 441 442 std::unique_ptr<I2CCaptureBytesAction> parseI2CCaptureBytes(const json& element) 443 { 444 verifyIsObject(element); 445 unsigned int propertyCount{0}; 446 447 // Required register property 448 const json& regElement = getRequiredProperty(element, "register"); 449 uint8_t reg = parseHexByte(regElement); 450 ++propertyCount; 451 452 // Required count property 453 const json& countElement = getRequiredProperty(element, "count"); 454 uint8_t count = parseUint8(countElement); 455 if (count < 1) 456 { 457 throw std::invalid_argument{"Invalid byte count: Must be > 0"}; 458 } 459 ++propertyCount; 460 461 // Verify no invalid properties exist 462 verifyPropertyCount(element, propertyCount); 463 464 return std::make_unique<I2CCaptureBytesAction>(reg, count); 465 } 466 467 std::unique_ptr<I2CCompareBitAction> parseI2CCompareBit(const json& element) 468 { 469 verifyIsObject(element); 470 unsigned int propertyCount{0}; 471 472 // Required register property 473 const json& regElement = getRequiredProperty(element, "register"); 474 uint8_t reg = parseHexByte(regElement); 475 ++propertyCount; 476 477 // Required position property 478 const json& positionElement = getRequiredProperty(element, "position"); 479 uint8_t position = parseBitPosition(positionElement); 480 ++propertyCount; 481 482 // Required value property 483 const json& valueElement = getRequiredProperty(element, "value"); 484 uint8_t value = parseBitValue(valueElement); 485 ++propertyCount; 486 487 // Verify no invalid properties exist 488 verifyPropertyCount(element, propertyCount); 489 490 return std::make_unique<I2CCompareBitAction>(reg, position, value); 491 } 492 493 std::unique_ptr<I2CCompareByteAction> parseI2CCompareByte(const json& element) 494 { 495 verifyIsObject(element); 496 unsigned int propertyCount{0}; 497 498 // Required register property 499 const json& regElement = getRequiredProperty(element, "register"); 500 uint8_t reg = parseHexByte(regElement); 501 ++propertyCount; 502 503 // Required value property 504 const json& valueElement = getRequiredProperty(element, "value"); 505 uint8_t value = parseHexByte(valueElement); 506 ++propertyCount; 507 508 // Optional mask property 509 uint8_t mask = 0xff; 510 auto maskIt = element.find("mask"); 511 if (maskIt != element.end()) 512 { 513 mask = parseHexByte(*maskIt); 514 ++propertyCount; 515 } 516 517 // Verify no invalid properties exist 518 verifyPropertyCount(element, propertyCount); 519 520 return std::make_unique<I2CCompareByteAction>(reg, value, mask); 521 } 522 523 std::unique_ptr<I2CCompareBytesAction> parseI2CCompareBytes(const json& element) 524 { 525 verifyIsObject(element); 526 unsigned int propertyCount{0}; 527 528 // Required register property 529 const json& regElement = getRequiredProperty(element, "register"); 530 uint8_t reg = parseHexByte(regElement); 531 ++propertyCount; 532 533 // Required values property 534 const json& valueElement = getRequiredProperty(element, "values"); 535 std::vector<uint8_t> values = parseHexByteArray(valueElement); 536 ++propertyCount; 537 538 // Optional masks property 539 std::vector<uint8_t> masks{}; 540 auto masksIt = element.find("masks"); 541 if (masksIt != element.end()) 542 { 543 masks = parseHexByteArray(*masksIt); 544 ++propertyCount; 545 } 546 547 // Verify masks array (if specified) was same size as values array 548 if ((!masks.empty()) && (masks.size() != values.size())) 549 { 550 throw std::invalid_argument{"Invalid number of elements in masks"}; 551 } 552 553 // Verify no invalid properties exist 554 verifyPropertyCount(element, propertyCount); 555 556 if (masks.empty()) 557 { 558 return std::make_unique<I2CCompareBytesAction>(reg, values); 559 } 560 return std::make_unique<I2CCompareBytesAction>(reg, values, masks); 561 } 562 563 std::unique_ptr<i2c::I2CInterface> parseI2CInterface(const json& element) 564 { 565 verifyIsObject(element); 566 unsigned int propertyCount{0}; 567 568 // Required bus property 569 const json& busElement = getRequiredProperty(element, "bus"); 570 uint8_t bus = parseUint8(busElement); 571 ++propertyCount; 572 573 // Required address property 574 const json& addressElement = getRequiredProperty(element, "address"); 575 uint8_t address = parseHexByte(addressElement); 576 ++propertyCount; 577 578 verifyPropertyCount(element, propertyCount); 579 return i2c::create(bus, address, i2c::I2CInterface::InitialState::CLOSED); 580 } 581 582 std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element) 583 { 584 verifyIsObject(element); 585 unsigned int propertyCount{0}; 586 587 // Required register property 588 const json& regElement = getRequiredProperty(element, "register"); 589 uint8_t reg = parseHexByte(regElement); 590 ++propertyCount; 591 592 // Required position property 593 const json& positionElement = getRequiredProperty(element, "position"); 594 uint8_t position = parseBitPosition(positionElement); 595 ++propertyCount; 596 597 // Required value property 598 const json& valueElement = getRequiredProperty(element, "value"); 599 uint8_t value = parseBitValue(valueElement); 600 ++propertyCount; 601 602 // Verify no invalid properties exist 603 verifyPropertyCount(element, propertyCount); 604 605 return std::make_unique<I2CWriteBitAction>(reg, position, value); 606 } 607 608 std::unique_ptr<I2CWriteByteAction> parseI2CWriteByte(const json& element) 609 { 610 verifyIsObject(element); 611 unsigned int propertyCount{0}; 612 613 // Required register property 614 const json& regElement = getRequiredProperty(element, "register"); 615 uint8_t reg = parseHexByte(regElement); 616 ++propertyCount; 617 618 // Required value property 619 const json& valueElement = getRequiredProperty(element, "value"); 620 uint8_t value = parseHexByte(valueElement); 621 ++propertyCount; 622 623 // Optional mask property 624 uint8_t mask = 0xff; 625 auto maskIt = element.find("mask"); 626 if (maskIt != element.end()) 627 { 628 mask = parseHexByte(*maskIt); 629 ++propertyCount; 630 } 631 632 // Verify no invalid properties exist 633 verifyPropertyCount(element, propertyCount); 634 635 return std::make_unique<I2CWriteByteAction>(reg, value, mask); 636 } 637 638 std::unique_ptr<I2CWriteBytesAction> parseI2CWriteBytes(const json& element) 639 { 640 verifyIsObject(element); 641 unsigned int propertyCount{0}; 642 643 // Required register property 644 const json& regElement = getRequiredProperty(element, "register"); 645 uint8_t reg = parseHexByte(regElement); 646 ++propertyCount; 647 648 // Required values property 649 const json& valueElement = getRequiredProperty(element, "values"); 650 std::vector<uint8_t> values = parseHexByteArray(valueElement); 651 ++propertyCount; 652 653 // Optional masks property 654 std::vector<uint8_t> masks{}; 655 auto masksIt = element.find("masks"); 656 if (masksIt != element.end()) 657 { 658 masks = parseHexByteArray(*masksIt); 659 ++propertyCount; 660 } 661 662 // Verify masks array (if specified) was same size as values array 663 if ((!masks.empty()) && (masks.size() != values.size())) 664 { 665 throw std::invalid_argument{"Invalid number of elements in masks"}; 666 } 667 668 // Verify no invalid properties exist 669 verifyPropertyCount(element, propertyCount); 670 671 if (masks.empty()) 672 { 673 return std::make_unique<I2CWriteBytesAction>(reg, values); 674 } 675 return std::make_unique<I2CWriteBytesAction>(reg, values, masks); 676 } 677 678 std::unique_ptr<IfAction> parseIf(const json& element) 679 { 680 verifyIsObject(element); 681 unsigned int propertyCount{0}; 682 683 // Required condition property 684 const json& conditionElement = getRequiredProperty(element, "condition"); 685 std::unique_ptr<Action> conditionAction = parseAction(conditionElement); 686 ++propertyCount; 687 688 // Required then property 689 const json& thenElement = getRequiredProperty(element, "then"); 690 std::vector<std::unique_ptr<Action>> thenActions = 691 parseActionArray(thenElement); 692 ++propertyCount; 693 694 // Optional else property 695 std::vector<std::unique_ptr<Action>> elseActions{}; 696 auto elseIt = element.find("else"); 697 if (elseIt != element.end()) 698 { 699 elseActions = parseActionArray(*elseIt); 700 ++propertyCount; 701 } 702 703 // Verify no invalid properties exist 704 verifyPropertyCount(element, propertyCount); 705 706 return std::make_unique<IfAction>(std::move(conditionAction), 707 std::move(thenActions), 708 std::move(elseActions)); 709 } 710 711 std::string parseInventoryPath(const json& element) 712 { 713 std::string inventoryPath = parseString(element); 714 std::string absPath = "/xyz/openbmc_project/inventory"; 715 if (inventoryPath.front() != '/') 716 { 717 absPath += '/'; 718 } 719 absPath += inventoryPath; 720 return absPath; 721 } 722 723 std::unique_ptr<LogPhaseFaultAction> parseLogPhaseFault(const json& element) 724 { 725 verifyIsObject(element); 726 unsigned int propertyCount{0}; 727 728 // Required type property 729 const json& typeElement = getRequiredProperty(element, "type"); 730 PhaseFaultType type = parsePhaseFaultType(typeElement); 731 ++propertyCount; 732 733 // Verify no invalid properties exist 734 verifyPropertyCount(element, propertyCount); 735 736 return std::make_unique<LogPhaseFaultAction>(type); 737 } 738 739 std::unique_ptr<NotAction> parseNot(const json& element) 740 { 741 // Required action to execute 742 std::unique_ptr<Action> action = parseAction(element); 743 744 return std::make_unique<NotAction>(std::move(action)); 745 } 746 747 std::unique_ptr<OrAction> parseOr(const json& element) 748 { 749 verifyIsArray(element); 750 751 // Verify if array size less than 2 752 if (element.size() < 2) 753 { 754 throw std::invalid_argument{"Array must contain two or more actions"}; 755 } 756 // Array of two or more actions 757 std::vector<std::unique_ptr<Action>> actions = parseActionArray(element); 758 759 return std::make_unique<OrAction>(std::move(actions)); 760 } 761 762 std::unique_ptr<PhaseFaultDetection> 763 parsePhaseFaultDetection(const json& element) 764 { 765 verifyIsObject(element); 766 unsigned int propertyCount{0}; 767 768 // Optional comments property; value not stored 769 if (element.contains("comments")) 770 { 771 ++propertyCount; 772 } 773 774 // Optional device_id property 775 std::string deviceID{}; 776 auto deviceIDIt = element.find("device_id"); 777 if (deviceIDIt != element.end()) 778 { 779 deviceID = parseString(*deviceIDIt); 780 ++propertyCount; 781 } 782 783 // Required rule_id or actions property 784 std::vector<std::unique_ptr<Action>> actions{}; 785 actions = parseRuleIDOrActionsProperty(element); 786 ++propertyCount; 787 788 // Verify no invalid properties exist 789 verifyPropertyCount(element, propertyCount); 790 791 return std::make_unique<PhaseFaultDetection>(std::move(actions), deviceID); 792 } 793 794 PhaseFaultType parsePhaseFaultType(const json& element) 795 { 796 std::string value = parseString(element); 797 PhaseFaultType type{}; 798 799 if (value == "n") 800 { 801 type = PhaseFaultType::n; 802 } 803 else if (value == "n+1") 804 { 805 type = PhaseFaultType::n_plus_1; 806 } 807 else 808 { 809 throw std::invalid_argument{"Element is not a phase fault type"}; 810 } 811 812 return type; 813 } 814 815 std::unique_ptr<PMBusReadSensorAction> parsePMBusReadSensor(const json& element) 816 { 817 verifyIsObject(element); 818 unsigned int propertyCount{0}; 819 820 // Required type property 821 const json& typeElement = getRequiredProperty(element, "type"); 822 SensorType type = parseSensorType(typeElement); 823 ++propertyCount; 824 825 // Required command property 826 const json& commandElement = getRequiredProperty(element, "command"); 827 uint8_t command = parseHexByte(commandElement); 828 ++propertyCount; 829 830 // Required format property 831 const json& formatElement = getRequiredProperty(element, "format"); 832 pmbus_utils::SensorDataFormat format = parseSensorDataFormat(formatElement); 833 ++propertyCount; 834 835 // Optional exponent property 836 std::optional<int8_t> exponent{}; 837 auto exponentIt = element.find("exponent"); 838 if (exponentIt != element.end()) 839 { 840 exponent = parseInt8(*exponentIt); 841 ++propertyCount; 842 } 843 844 // Verify no invalid properties exist 845 verifyPropertyCount(element, propertyCount); 846 847 return std::make_unique<PMBusReadSensorAction>(type, command, format, 848 exponent); 849 } 850 851 std::unique_ptr<PMBusWriteVoutCommandAction> 852 parsePMBusWriteVoutCommand(const json& element) 853 { 854 verifyIsObject(element); 855 unsigned int propertyCount{0}; 856 857 // Optional volts property 858 std::optional<double> volts{}; 859 auto voltsIt = element.find("volts"); 860 if (voltsIt != element.end()) 861 { 862 volts = parseDouble(*voltsIt); 863 ++propertyCount; 864 } 865 866 // Required format property 867 const json& formatElement = getRequiredProperty(element, "format"); 868 std::string formatString = parseString(formatElement); 869 if (formatString != "linear") 870 { 871 throw std::invalid_argument{"Invalid format value: " + formatString}; 872 } 873 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear; 874 ++propertyCount; 875 876 // Optional exponent property 877 std::optional<int8_t> exponent{}; 878 auto exponentIt = element.find("exponent"); 879 if (exponentIt != element.end()) 880 { 881 exponent = parseInt8(*exponentIt); 882 ++propertyCount; 883 } 884 885 // Optional is_verified property 886 bool isVerified = false; 887 auto isVerifiedIt = element.find("is_verified"); 888 if (isVerifiedIt != element.end()) 889 { 890 isVerified = parseBoolean(*isVerifiedIt); 891 ++propertyCount; 892 } 893 894 // Verify no invalid properties exist 895 verifyPropertyCount(element, propertyCount); 896 897 return std::make_unique<PMBusWriteVoutCommandAction>(volts, format, 898 exponent, isVerified); 899 } 900 901 std::unique_ptr<PresenceDetection> parsePresenceDetection(const json& element) 902 { 903 verifyIsObject(element); 904 unsigned int propertyCount{0}; 905 906 // Optional comments property; value not stored 907 if (element.contains("comments")) 908 { 909 ++propertyCount; 910 } 911 912 // Required rule_id or actions property 913 std::vector<std::unique_ptr<Action>> actions{}; 914 actions = parseRuleIDOrActionsProperty(element); 915 ++propertyCount; 916 917 // Verify no invalid properties exist 918 verifyPropertyCount(element, propertyCount); 919 920 return std::make_unique<PresenceDetection>(std::move(actions)); 921 } 922 923 std::unique_ptr<Rail> parseRail(const json& element) 924 { 925 verifyIsObject(element); 926 unsigned int propertyCount{0}; 927 928 // Optional comments property; value not stored 929 if (element.contains("comments")) 930 { 931 ++propertyCount; 932 } 933 934 // Required id property 935 const json& idElement = getRequiredProperty(element, "id"); 936 std::string id = parseString(idElement); 937 ++propertyCount; 938 939 // Optional configuration property 940 std::unique_ptr<Configuration> configuration{}; 941 auto configurationIt = element.find("configuration"); 942 if (configurationIt != element.end()) 943 { 944 configuration = parseConfiguration(*configurationIt); 945 ++propertyCount; 946 } 947 948 // Optional sensor_monitoring property 949 std::unique_ptr<SensorMonitoring> sensorMonitoring{}; 950 auto sensorMonitoringIt = element.find("sensor_monitoring"); 951 if (sensorMonitoringIt != element.end()) 952 { 953 sensorMonitoring = parseSensorMonitoring(*sensorMonitoringIt); 954 ++propertyCount; 955 } 956 957 // Verify no invalid properties exist 958 verifyPropertyCount(element, propertyCount); 959 960 return std::make_unique<Rail>(id, std::move(configuration), 961 std::move(sensorMonitoring)); 962 } 963 964 std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element) 965 { 966 verifyIsArray(element); 967 std::vector<std::unique_ptr<Rail>> rails; 968 for (auto& railElement : element) 969 { 970 rails.emplace_back(parseRail(railElement)); 971 } 972 return rails; 973 } 974 975 std::tuple<std::vector<std::unique_ptr<Rule>>, 976 std::vector<std::unique_ptr<Chassis>>> 977 parseRoot(const json& element) 978 { 979 verifyIsObject(element); 980 unsigned int propertyCount{0}; 981 982 // Optional comments property; value not stored 983 if (element.contains("comments")) 984 { 985 ++propertyCount; 986 } 987 988 // Optional rules property 989 std::vector<std::unique_ptr<Rule>> rules{}; 990 auto rulesIt = element.find("rules"); 991 if (rulesIt != element.end()) 992 { 993 rules = parseRuleArray(*rulesIt); 994 ++propertyCount; 995 } 996 997 // Required chassis property 998 const json& chassisElement = getRequiredProperty(element, "chassis"); 999 std::vector<std::unique_ptr<Chassis>> chassis = 1000 parseChassisArray(chassisElement); 1001 ++propertyCount; 1002 1003 // Verify no invalid properties exist 1004 verifyPropertyCount(element, propertyCount); 1005 1006 return std::make_tuple(std::move(rules), std::move(chassis)); 1007 } 1008 1009 std::unique_ptr<Rule> parseRule(const json& element) 1010 { 1011 verifyIsObject(element); 1012 unsigned int propertyCount{0}; 1013 1014 // Optional comments property; value not stored 1015 if (element.contains("comments")) 1016 { 1017 ++propertyCount; 1018 } 1019 1020 // Required id property 1021 const json& idElement = getRequiredProperty(element, "id"); 1022 std::string id = parseString(idElement); 1023 ++propertyCount; 1024 1025 // Required actions property 1026 const json& actionsElement = getRequiredProperty(element, "actions"); 1027 std::vector<std::unique_ptr<Action>> actions = 1028 parseActionArray(actionsElement); 1029 ++propertyCount; 1030 1031 // Verify no invalid properties exist 1032 verifyPropertyCount(element, propertyCount); 1033 1034 return std::make_unique<Rule>(id, std::move(actions)); 1035 } 1036 1037 std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element) 1038 { 1039 verifyIsArray(element); 1040 std::vector<std::unique_ptr<Rule>> rules; 1041 for (auto& ruleElement : element) 1042 { 1043 rules.emplace_back(parseRule(ruleElement)); 1044 } 1045 return rules; 1046 } 1047 1048 std::vector<std::unique_ptr<Action>> 1049 parseRuleIDOrActionsProperty(const json& element) 1050 { 1051 verifyIsObject(element); 1052 // Required rule_id or actions property 1053 std::vector<std::unique_ptr<Action>> actions{}; 1054 auto ruleIDIt = element.find("rule_id"); 1055 auto actionsIt = element.find("actions"); 1056 if ((actionsIt == element.end()) && (ruleIDIt != element.end())) 1057 { 1058 std::string ruleID = parseString(*ruleIDIt); 1059 actions.emplace_back(std::make_unique<RunRuleAction>(ruleID)); 1060 } 1061 else if ((actionsIt != element.end()) && (ruleIDIt == element.end())) 1062 { 1063 actions = parseActionArray(*actionsIt); 1064 } 1065 else 1066 { 1067 throw std::invalid_argument{"Invalid property combination: Must " 1068 "contain either rule_id or actions"}; 1069 } 1070 1071 return actions; 1072 } 1073 1074 std::unique_ptr<RunRuleAction> parseRunRule(const json& element) 1075 { 1076 // String ruleID 1077 std::string ruleID = parseString(element); 1078 1079 return std::make_unique<RunRuleAction>(ruleID); 1080 } 1081 1082 pmbus_utils::SensorDataFormat parseSensorDataFormat(const json& element) 1083 { 1084 if (!element.is_string()) 1085 { 1086 throw std::invalid_argument{"Element is not a string"}; 1087 } 1088 std::string value = element.get<std::string>(); 1089 pmbus_utils::SensorDataFormat format{}; 1090 1091 if (value == "linear_11") 1092 { 1093 format = pmbus_utils::SensorDataFormat::linear_11; 1094 } 1095 else if (value == "linear_16") 1096 { 1097 format = pmbus_utils::SensorDataFormat::linear_16; 1098 } 1099 else 1100 { 1101 throw std::invalid_argument{"Element is not a sensor data format"}; 1102 } 1103 1104 return format; 1105 } 1106 1107 std::unique_ptr<SensorMonitoring> parseSensorMonitoring(const json& element) 1108 { 1109 verifyIsObject(element); 1110 unsigned int propertyCount{0}; 1111 1112 // Optional comments property; value not stored 1113 if (element.contains("comments")) 1114 { 1115 ++propertyCount; 1116 } 1117 1118 // Required rule_id or actions property 1119 std::vector<std::unique_ptr<Action>> actions{}; 1120 actions = parseRuleIDOrActionsProperty(element); 1121 ++propertyCount; 1122 1123 // Verify no invalid properties exist 1124 verifyPropertyCount(element, propertyCount); 1125 1126 return std::make_unique<SensorMonitoring>(std::move(actions)); 1127 } 1128 1129 SensorType parseSensorType(const json& element) 1130 { 1131 std::string value = parseString(element); 1132 SensorType type{}; 1133 1134 if (value == "iout") 1135 { 1136 type = SensorType::iout; 1137 } 1138 else if (value == "iout_peak") 1139 { 1140 type = SensorType::iout_peak; 1141 } 1142 else if (value == "iout_valley") 1143 { 1144 type = SensorType::iout_valley; 1145 } 1146 else if (value == "pout") 1147 { 1148 type = SensorType::pout; 1149 } 1150 else if (value == "temperature") 1151 { 1152 type = SensorType::temperature; 1153 } 1154 else if (value == "temperature_peak") 1155 { 1156 type = SensorType::temperature_peak; 1157 } 1158 else if (value == "vout") 1159 { 1160 type = SensorType::vout; 1161 } 1162 else if (value == "vout_peak") 1163 { 1164 type = SensorType::vout_peak; 1165 } 1166 else if (value == "vout_valley") 1167 { 1168 type = SensorType::vout_valley; 1169 } 1170 else 1171 { 1172 throw std::invalid_argument{"Element is not a sensor type"}; 1173 } 1174 1175 return type; 1176 } 1177 1178 std::unique_ptr<SetDeviceAction> parseSetDevice(const json& element) 1179 { 1180 // String deviceID 1181 std::string deviceID = parseString(element); 1182 1183 return std::make_unique<SetDeviceAction>(deviceID); 1184 } 1185 1186 pmbus_utils::VoutDataFormat parseVoutDataFormat(const json& element) 1187 { 1188 if (!element.is_string()) 1189 { 1190 throw std::invalid_argument{"Element is not a string"}; 1191 } 1192 std::string value = element.get<std::string>(); 1193 pmbus_utils::VoutDataFormat format{}; 1194 1195 if (value == "linear") 1196 { 1197 format = pmbus_utils::VoutDataFormat::linear; 1198 } 1199 else if (value == "vid") 1200 { 1201 format = pmbus_utils::VoutDataFormat::vid; 1202 } 1203 else if (value == "direct") 1204 { 1205 format = pmbus_utils::VoutDataFormat::direct; 1206 } 1207 else if (value == "ieee") 1208 { 1209 format = pmbus_utils::VoutDataFormat::ieee; 1210 } 1211 else 1212 { 1213 throw std::invalid_argument{"Element is not a vout data format"}; 1214 } 1215 1216 return format; 1217 } 1218 1219 } // namespace internal 1220 1221 } // namespace phosphor::power::regulators::config_file_parser 1222