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