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>>> 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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>>> 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 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 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 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 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 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 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 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 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 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