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 // Either value or byte_values required property 278 auto valueIt = element.find("value"); 279 std::vector<uint8_t> value{}; 280 auto byteValuesIt = element.find("byte_values"); 281 if ((valueIt != element.end()) && (byteValuesIt == element.end())) 282 { 283 std::string stringValue = parseString(*valueIt); 284 value.insert(value.begin(), stringValue.begin(), stringValue.end()); 285 ++propertyCount; 286 } 287 else if ((valueIt == element.end()) && (byteValuesIt != element.end())) 288 { 289 value = parseHexByteArray(*byteValuesIt); 290 ++propertyCount; 291 } 292 else 293 { 294 throw std::invalid_argument{ 295 "Invalid property: Must contain either value or byte_values"}; 296 } 297 298 // Verify no invalid properties exist 299 verifyPropertyCount(element, propertyCount); 300 301 return std::make_unique<CompareVPDAction>(fru, keyword, value); 302 } 303 304 std::unique_ptr<Configuration> parseConfiguration(const json& element) 305 { 306 verifyIsObject(element); 307 unsigned int propertyCount{0}; 308 309 // Optional comments property; value not stored 310 if (element.contains("comments")) 311 { 312 ++propertyCount; 313 } 314 315 // Optional volts property 316 std::optional<double> volts{}; 317 auto voltsIt = element.find("volts"); 318 if (voltsIt != element.end()) 319 { 320 volts = parseDouble(*voltsIt); 321 ++propertyCount; 322 } 323 324 // Required rule_id or actions property 325 std::vector<std::unique_ptr<Action>> actions{}; 326 actions = parseRuleIDOrActionsProperty(element); 327 ++propertyCount; 328 329 // Verify no invalid properties exist 330 verifyPropertyCount(element, propertyCount); 331 332 return std::make_unique<Configuration>(volts, std::move(actions)); 333 } 334 335 std::unique_ptr<Device> parseDevice(const json& element) 336 { 337 verifyIsObject(element); 338 unsigned int propertyCount{0}; 339 340 // Optional comments property; value not stored 341 if (element.contains("comments")) 342 { 343 ++propertyCount; 344 } 345 346 // Required id property 347 const json& idElement = getRequiredProperty(element, "id"); 348 std::string id = parseString(idElement); 349 ++propertyCount; 350 351 // Required is_regulator property 352 const json& isRegulatorElement = 353 getRequiredProperty(element, "is_regulator"); 354 bool isRegulator = parseBoolean(isRegulatorElement); 355 ++propertyCount; 356 357 // Required fru property 358 const json& fruElement = getRequiredProperty(element, "fru"); 359 std::string fru = parseInventoryPath(fruElement); 360 ++propertyCount; 361 362 // Required i2c_interface property 363 const json& i2cInterfaceElement = 364 getRequiredProperty(element, "i2c_interface"); 365 std::unique_ptr<i2c::I2CInterface> i2cInterface = 366 parseI2CInterface(i2cInterfaceElement); 367 ++propertyCount; 368 369 // Optional presence_detection property 370 std::unique_ptr<PresenceDetection> presenceDetection{}; 371 auto presenceDetectionIt = element.find("presence_detection"); 372 if (presenceDetectionIt != element.end()) 373 { 374 presenceDetection = parsePresenceDetection(*presenceDetectionIt); 375 ++propertyCount; 376 } 377 378 // Optional configuration property 379 std::unique_ptr<Configuration> configuration{}; 380 auto configurationIt = element.find("configuration"); 381 if (configurationIt != element.end()) 382 { 383 configuration = parseConfiguration(*configurationIt); 384 ++propertyCount; 385 } 386 387 // Optional rails property 388 std::vector<std::unique_ptr<Rail>> rails{}; 389 auto railsIt = element.find("rails"); 390 if (railsIt != element.end()) 391 { 392 if (!isRegulator) 393 { 394 throw std::invalid_argument{ 395 "Invalid rails property when is_regulator is false"}; 396 } 397 rails = parseRailArray(*railsIt); 398 ++propertyCount; 399 } 400 401 // Verify no invalid properties exist 402 verifyPropertyCount(element, propertyCount); 403 404 return std::make_unique<Device>(id, isRegulator, fru, 405 std::move(i2cInterface), 406 std::move(presenceDetection), 407 std::move(configuration), std::move(rails)); 408 } 409 410 std::vector<std::unique_ptr<Device>> parseDeviceArray(const json& element) 411 { 412 verifyIsArray(element); 413 std::vector<std::unique_ptr<Device>> devices; 414 for (auto& deviceElement : element) 415 { 416 devices.emplace_back(parseDevice(deviceElement)); 417 } 418 return devices; 419 } 420 421 std::vector<uint8_t> parseHexByteArray(const json& element) 422 { 423 verifyIsArray(element); 424 std::vector<uint8_t> values; 425 for (auto& valueElement : element) 426 { 427 values.emplace_back(parseHexByte(valueElement)); 428 } 429 return values; 430 } 431 432 std::unique_ptr<I2CCompareBitAction> parseI2CCompareBit(const json& element) 433 { 434 verifyIsObject(element); 435 unsigned int propertyCount{0}; 436 437 // Required register property 438 const json& regElement = getRequiredProperty(element, "register"); 439 uint8_t reg = parseHexByte(regElement); 440 ++propertyCount; 441 442 // Required position property 443 const json& positionElement = getRequiredProperty(element, "position"); 444 uint8_t position = parseBitPosition(positionElement); 445 ++propertyCount; 446 447 // Required value property 448 const json& valueElement = getRequiredProperty(element, "value"); 449 uint8_t value = parseBitValue(valueElement); 450 ++propertyCount; 451 452 // Verify no invalid properties exist 453 verifyPropertyCount(element, propertyCount); 454 455 return std::make_unique<I2CCompareBitAction>(reg, position, value); 456 } 457 458 std::unique_ptr<I2CCompareByteAction> parseI2CCompareByte(const json& element) 459 { 460 verifyIsObject(element); 461 unsigned int propertyCount{0}; 462 463 // Required register property 464 const json& regElement = getRequiredProperty(element, "register"); 465 uint8_t reg = parseHexByte(regElement); 466 ++propertyCount; 467 468 // Required value property 469 const json& valueElement = getRequiredProperty(element, "value"); 470 uint8_t value = parseHexByte(valueElement); 471 ++propertyCount; 472 473 // Optional mask property 474 uint8_t mask = 0xff; 475 auto maskIt = element.find("mask"); 476 if (maskIt != element.end()) 477 { 478 mask = parseHexByte(*maskIt); 479 ++propertyCount; 480 } 481 482 // Verify no invalid properties exist 483 verifyPropertyCount(element, propertyCount); 484 485 return std::make_unique<I2CCompareByteAction>(reg, value, mask); 486 } 487 488 std::unique_ptr<I2CCompareBytesAction> parseI2CCompareBytes(const json& element) 489 { 490 verifyIsObject(element); 491 unsigned int propertyCount{0}; 492 493 // Required register property 494 const json& regElement = getRequiredProperty(element, "register"); 495 uint8_t reg = parseHexByte(regElement); 496 ++propertyCount; 497 498 // Required values property 499 const json& valueElement = getRequiredProperty(element, "values"); 500 std::vector<uint8_t> values = parseHexByteArray(valueElement); 501 ++propertyCount; 502 503 // Optional masks property 504 std::vector<uint8_t> masks{}; 505 auto masksIt = element.find("masks"); 506 if (masksIt != element.end()) 507 { 508 masks = parseHexByteArray(*masksIt); 509 ++propertyCount; 510 } 511 512 // Verify masks array (if specified) was same size as values array 513 if ((!masks.empty()) && (masks.size() != values.size())) 514 { 515 throw std::invalid_argument{"Invalid number of elements in masks"}; 516 } 517 518 // Verify no invalid properties exist 519 verifyPropertyCount(element, propertyCount); 520 521 if (masks.empty()) 522 { 523 return std::make_unique<I2CCompareBytesAction>(reg, values); 524 } 525 return std::make_unique<I2CCompareBytesAction>(reg, values, masks); 526 } 527 528 std::unique_ptr<i2c::I2CInterface> parseI2CInterface(const json& element) 529 { 530 verifyIsObject(element); 531 unsigned int propertyCount{0}; 532 533 // Required bus property 534 const json& busElement = getRequiredProperty(element, "bus"); 535 uint8_t bus = parseUint8(busElement); 536 ++propertyCount; 537 538 // Required address property 539 const json& addressElement = getRequiredProperty(element, "address"); 540 uint8_t address = parseHexByte(addressElement); 541 ++propertyCount; 542 543 verifyPropertyCount(element, propertyCount); 544 return i2c::create(bus, address, i2c::I2CInterface::InitialState::CLOSED); 545 } 546 547 std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element) 548 { 549 verifyIsObject(element); 550 unsigned int propertyCount{0}; 551 552 // Required register property 553 const json& regElement = getRequiredProperty(element, "register"); 554 uint8_t reg = parseHexByte(regElement); 555 ++propertyCount; 556 557 // Required position property 558 const json& positionElement = getRequiredProperty(element, "position"); 559 uint8_t position = parseBitPosition(positionElement); 560 ++propertyCount; 561 562 // Required value property 563 const json& valueElement = getRequiredProperty(element, "value"); 564 uint8_t value = parseBitValue(valueElement); 565 ++propertyCount; 566 567 // Verify no invalid properties exist 568 verifyPropertyCount(element, propertyCount); 569 570 return std::make_unique<I2CWriteBitAction>(reg, position, value); 571 } 572 573 std::unique_ptr<I2CWriteByteAction> parseI2CWriteByte(const json& element) 574 { 575 verifyIsObject(element); 576 unsigned int propertyCount{0}; 577 578 // Required register property 579 const json& regElement = getRequiredProperty(element, "register"); 580 uint8_t reg = parseHexByte(regElement); 581 ++propertyCount; 582 583 // Required value property 584 const json& valueElement = getRequiredProperty(element, "value"); 585 uint8_t value = parseHexByte(valueElement); 586 ++propertyCount; 587 588 // Optional mask property 589 uint8_t mask = 0xff; 590 auto maskIt = element.find("mask"); 591 if (maskIt != element.end()) 592 { 593 mask = parseHexByte(*maskIt); 594 ++propertyCount; 595 } 596 597 // Verify no invalid properties exist 598 verifyPropertyCount(element, propertyCount); 599 600 return std::make_unique<I2CWriteByteAction>(reg, value, mask); 601 } 602 603 std::unique_ptr<I2CWriteBytesAction> parseI2CWriteBytes(const json& element) 604 { 605 verifyIsObject(element); 606 unsigned int propertyCount{0}; 607 608 // Required register property 609 const json& regElement = getRequiredProperty(element, "register"); 610 uint8_t reg = parseHexByte(regElement); 611 ++propertyCount; 612 613 // Required values property 614 const json& valueElement = getRequiredProperty(element, "values"); 615 std::vector<uint8_t> values = parseHexByteArray(valueElement); 616 ++propertyCount; 617 618 // Optional masks property 619 std::vector<uint8_t> masks{}; 620 auto masksIt = element.find("masks"); 621 if (masksIt != element.end()) 622 { 623 masks = parseHexByteArray(*masksIt); 624 ++propertyCount; 625 } 626 627 // Verify masks array (if specified) was same size as values array 628 if ((!masks.empty()) && (masks.size() != values.size())) 629 { 630 throw std::invalid_argument{"Invalid number of elements in masks"}; 631 } 632 633 // Verify no invalid properties exist 634 verifyPropertyCount(element, propertyCount); 635 636 if (masks.empty()) 637 { 638 return std::make_unique<I2CWriteBytesAction>(reg, values); 639 } 640 return std::make_unique<I2CWriteBytesAction>(reg, values, masks); 641 } 642 643 std::unique_ptr<IfAction> parseIf(const json& element) 644 { 645 verifyIsObject(element); 646 unsigned int propertyCount{0}; 647 648 // Required condition property 649 const json& conditionElement = getRequiredProperty(element, "condition"); 650 std::unique_ptr<Action> conditionAction = parseAction(conditionElement); 651 ++propertyCount; 652 653 // Required then property 654 const json& thenElement = getRequiredProperty(element, "then"); 655 std::vector<std::unique_ptr<Action>> thenActions = 656 parseActionArray(thenElement); 657 ++propertyCount; 658 659 // Optional else property 660 std::vector<std::unique_ptr<Action>> elseActions{}; 661 auto elseIt = element.find("else"); 662 if (elseIt != element.end()) 663 { 664 elseActions = parseActionArray(*elseIt); 665 ++propertyCount; 666 } 667 668 // Verify no invalid properties exist 669 verifyPropertyCount(element, propertyCount); 670 671 return std::make_unique<IfAction>(std::move(conditionAction), 672 std::move(thenActions), 673 std::move(elseActions)); 674 } 675 676 std::string parseInventoryPath(const json& element) 677 { 678 std::string inventoryPath = parseString(element); 679 std::string absPath = "/xyz/openbmc_project/inventory"; 680 if (inventoryPath.front() != '/') 681 { 682 absPath += '/'; 683 } 684 absPath += inventoryPath; 685 return absPath; 686 } 687 688 std::unique_ptr<NotAction> parseNot(const json& element) 689 { 690 // Required action to execute 691 std::unique_ptr<Action> action = parseAction(element); 692 693 return std::make_unique<NotAction>(std::move(action)); 694 } 695 696 std::unique_ptr<OrAction> parseOr(const json& element) 697 { 698 verifyIsArray(element); 699 700 // Verify if array size less than 2 701 if (element.size() < 2) 702 { 703 throw std::invalid_argument{"Array must contain two or more actions"}; 704 } 705 // Array of two or more actions 706 std::vector<std::unique_ptr<Action>> actions = parseActionArray(element); 707 708 return std::make_unique<OrAction>(std::move(actions)); 709 } 710 711 std::unique_ptr<PMBusReadSensorAction> parsePMBusReadSensor(const json& element) 712 { 713 verifyIsObject(element); 714 unsigned int propertyCount{0}; 715 716 // Required type property 717 const json& typeElement = getRequiredProperty(element, "type"); 718 SensorType type = parseSensorType(typeElement); 719 ++propertyCount; 720 721 // Required command property 722 const json& commandElement = getRequiredProperty(element, "command"); 723 uint8_t command = parseHexByte(commandElement); 724 ++propertyCount; 725 726 // Required format property 727 const json& formatElement = getRequiredProperty(element, "format"); 728 pmbus_utils::SensorDataFormat format = parseSensorDataFormat(formatElement); 729 ++propertyCount; 730 731 // Optional exponent property 732 std::optional<int8_t> exponent{}; 733 auto exponentIt = element.find("exponent"); 734 if (exponentIt != element.end()) 735 { 736 exponent = parseInt8(*exponentIt); 737 ++propertyCount; 738 } 739 740 // Verify no invalid properties exist 741 verifyPropertyCount(element, propertyCount); 742 743 return std::make_unique<PMBusReadSensorAction>(type, command, format, 744 exponent); 745 } 746 747 std::unique_ptr<PMBusWriteVoutCommandAction> 748 parsePMBusWriteVoutCommand(const json& element) 749 { 750 verifyIsObject(element); 751 unsigned int propertyCount{0}; 752 753 // Optional volts property 754 std::optional<double> volts{}; 755 auto voltsIt = element.find("volts"); 756 if (voltsIt != element.end()) 757 { 758 volts = parseDouble(*voltsIt); 759 ++propertyCount; 760 } 761 762 // Required format property 763 const json& formatElement = getRequiredProperty(element, "format"); 764 std::string formatString = parseString(formatElement); 765 if (formatString != "linear") 766 { 767 throw std::invalid_argument{"Invalid format value: " + formatString}; 768 } 769 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear; 770 ++propertyCount; 771 772 // Optional exponent property 773 std::optional<int8_t> exponent{}; 774 auto exponentIt = element.find("exponent"); 775 if (exponentIt != element.end()) 776 { 777 exponent = parseInt8(*exponentIt); 778 ++propertyCount; 779 } 780 781 // Optional is_verified property 782 bool isVerified = false; 783 auto isVerifiedIt = element.find("is_verified"); 784 if (isVerifiedIt != element.end()) 785 { 786 isVerified = parseBoolean(*isVerifiedIt); 787 ++propertyCount; 788 } 789 790 // Verify no invalid properties exist 791 verifyPropertyCount(element, propertyCount); 792 793 return std::make_unique<PMBusWriteVoutCommandAction>(volts, format, 794 exponent, isVerified); 795 } 796 797 std::unique_ptr<PresenceDetection> parsePresenceDetection(const json& element) 798 { 799 verifyIsObject(element); 800 unsigned int propertyCount{0}; 801 802 // Optional comments property; value not stored 803 if (element.contains("comments")) 804 { 805 ++propertyCount; 806 } 807 808 // Required rule_id or actions property 809 std::vector<std::unique_ptr<Action>> actions{}; 810 actions = parseRuleIDOrActionsProperty(element); 811 ++propertyCount; 812 813 // Verify no invalid properties exist 814 verifyPropertyCount(element, propertyCount); 815 816 return std::make_unique<PresenceDetection>(std::move(actions)); 817 } 818 819 std::unique_ptr<Rail> parseRail(const json& element) 820 { 821 verifyIsObject(element); 822 unsigned int propertyCount{0}; 823 824 // Optional comments property; value not stored 825 if (element.contains("comments")) 826 { 827 ++propertyCount; 828 } 829 830 // Required id property 831 const json& idElement = getRequiredProperty(element, "id"); 832 std::string id = parseString(idElement); 833 ++propertyCount; 834 835 // Optional configuration property 836 std::unique_ptr<Configuration> configuration{}; 837 auto configurationIt = element.find("configuration"); 838 if (configurationIt != element.end()) 839 { 840 configuration = parseConfiguration(*configurationIt); 841 ++propertyCount; 842 } 843 844 // Optional sensor_monitoring property 845 std::unique_ptr<SensorMonitoring> sensorMonitoring{}; 846 auto sensorMonitoringIt = element.find("sensor_monitoring"); 847 if (sensorMonitoringIt != element.end()) 848 { 849 sensorMonitoring = parseSensorMonitoring(*sensorMonitoringIt); 850 ++propertyCount; 851 } 852 853 // Verify no invalid properties exist 854 verifyPropertyCount(element, propertyCount); 855 856 return std::make_unique<Rail>(id, std::move(configuration), 857 std::move(sensorMonitoring)); 858 } 859 860 std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element) 861 { 862 verifyIsArray(element); 863 std::vector<std::unique_ptr<Rail>> rails; 864 for (auto& railElement : element) 865 { 866 rails.emplace_back(parseRail(railElement)); 867 } 868 return rails; 869 } 870 871 std::tuple<std::vector<std::unique_ptr<Rule>>, 872 std::vector<std::unique_ptr<Chassis>>> 873 parseRoot(const json& element) 874 { 875 verifyIsObject(element); 876 unsigned int propertyCount{0}; 877 878 // Optional comments property; value not stored 879 if (element.contains("comments")) 880 { 881 ++propertyCount; 882 } 883 884 // Optional rules property 885 std::vector<std::unique_ptr<Rule>> rules{}; 886 auto rulesIt = element.find("rules"); 887 if (rulesIt != element.end()) 888 { 889 rules = parseRuleArray(*rulesIt); 890 ++propertyCount; 891 } 892 893 // Required chassis property 894 const json& chassisElement = getRequiredProperty(element, "chassis"); 895 std::vector<std::unique_ptr<Chassis>> chassis = 896 parseChassisArray(chassisElement); 897 ++propertyCount; 898 899 // Verify no invalid properties exist 900 verifyPropertyCount(element, propertyCount); 901 902 return std::make_tuple(std::move(rules), std::move(chassis)); 903 } 904 905 std::unique_ptr<Rule> parseRule(const json& element) 906 { 907 verifyIsObject(element); 908 unsigned int propertyCount{0}; 909 910 // Optional comments property; value not stored 911 if (element.contains("comments")) 912 { 913 ++propertyCount; 914 } 915 916 // Required id property 917 const json& idElement = getRequiredProperty(element, "id"); 918 std::string id = parseString(idElement); 919 ++propertyCount; 920 921 // Required actions property 922 const json& actionsElement = getRequiredProperty(element, "actions"); 923 std::vector<std::unique_ptr<Action>> actions = 924 parseActionArray(actionsElement); 925 ++propertyCount; 926 927 // Verify no invalid properties exist 928 verifyPropertyCount(element, propertyCount); 929 930 return std::make_unique<Rule>(id, std::move(actions)); 931 } 932 933 std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element) 934 { 935 verifyIsArray(element); 936 std::vector<std::unique_ptr<Rule>> rules; 937 for (auto& ruleElement : element) 938 { 939 rules.emplace_back(parseRule(ruleElement)); 940 } 941 return rules; 942 } 943 944 std::vector<std::unique_ptr<Action>> 945 parseRuleIDOrActionsProperty(const json& element) 946 { 947 verifyIsObject(element); 948 // Required rule_id or actions property 949 std::vector<std::unique_ptr<Action>> actions{}; 950 auto ruleIDIt = element.find("rule_id"); 951 auto actionsIt = element.find("actions"); 952 if ((actionsIt == element.end()) && (ruleIDIt != element.end())) 953 { 954 std::string ruleID = parseString(*ruleIDIt); 955 actions.emplace_back(std::make_unique<RunRuleAction>(ruleID)); 956 } 957 else if ((actionsIt != element.end()) && (ruleIDIt == element.end())) 958 { 959 actions = parseActionArray(*actionsIt); 960 } 961 else 962 { 963 throw std::invalid_argument{"Invalid property combination: Must " 964 "contain either rule_id or actions"}; 965 } 966 967 return actions; 968 } 969 970 std::unique_ptr<RunRuleAction> parseRunRule(const json& element) 971 { 972 // String ruleID 973 std::string ruleID = parseString(element); 974 975 return std::make_unique<RunRuleAction>(ruleID); 976 } 977 978 pmbus_utils::SensorDataFormat parseSensorDataFormat(const json& element) 979 { 980 if (!element.is_string()) 981 { 982 throw std::invalid_argument{"Element is not a string"}; 983 } 984 std::string value = element.get<std::string>(); 985 pmbus_utils::SensorDataFormat format{}; 986 987 if (value == "linear_11") 988 { 989 format = pmbus_utils::SensorDataFormat::linear_11; 990 } 991 else if (value == "linear_16") 992 { 993 format = pmbus_utils::SensorDataFormat::linear_16; 994 } 995 else 996 { 997 throw std::invalid_argument{"Element is not a sensor data format"}; 998 } 999 1000 return format; 1001 } 1002 1003 std::unique_ptr<SensorMonitoring> parseSensorMonitoring(const json& element) 1004 { 1005 verifyIsObject(element); 1006 unsigned int propertyCount{0}; 1007 1008 // Optional comments property; value not stored 1009 if (element.contains("comments")) 1010 { 1011 ++propertyCount; 1012 } 1013 1014 // Required rule_id or actions property 1015 std::vector<std::unique_ptr<Action>> actions{}; 1016 actions = parseRuleIDOrActionsProperty(element); 1017 ++propertyCount; 1018 1019 // Verify no invalid properties exist 1020 verifyPropertyCount(element, propertyCount); 1021 1022 return std::make_unique<SensorMonitoring>(std::move(actions)); 1023 } 1024 1025 SensorType parseSensorType(const json& element) 1026 { 1027 if (!element.is_string()) 1028 { 1029 throw std::invalid_argument{"Element is not a string"}; 1030 } 1031 std::string value = element.get<std::string>(); 1032 SensorType type{}; 1033 1034 if (value == "iout") 1035 { 1036 type = SensorType::iout; 1037 } 1038 else if (value == "iout_peak") 1039 { 1040 type = SensorType::iout_peak; 1041 } 1042 else if (value == "iout_valley") 1043 { 1044 type = SensorType::iout_valley; 1045 } 1046 else if (value == "pout") 1047 { 1048 type = SensorType::pout; 1049 } 1050 else if (value == "temperature") 1051 { 1052 type = SensorType::temperature; 1053 } 1054 else if (value == "temperature_peak") 1055 { 1056 type = SensorType::temperature_peak; 1057 } 1058 else if (value == "vout") 1059 { 1060 type = SensorType::vout; 1061 } 1062 else if (value == "vout_peak") 1063 { 1064 type = SensorType::vout_peak; 1065 } 1066 else if (value == "vout_valley") 1067 { 1068 type = SensorType::vout_valley; 1069 } 1070 else 1071 { 1072 throw std::invalid_argument{"Element is not a sensor type"}; 1073 } 1074 1075 return type; 1076 } 1077 1078 std::unique_ptr<SetDeviceAction> parseSetDevice(const json& element) 1079 { 1080 // String deviceID 1081 std::string deviceID = parseString(element); 1082 1083 return std::make_unique<SetDeviceAction>(deviceID); 1084 } 1085 1086 pmbus_utils::VoutDataFormat parseVoutDataFormat(const json& element) 1087 { 1088 if (!element.is_string()) 1089 { 1090 throw std::invalid_argument{"Element is not a string"}; 1091 } 1092 std::string value = element.get<std::string>(); 1093 pmbus_utils::VoutDataFormat format{}; 1094 1095 if (value == "linear") 1096 { 1097 format = pmbus_utils::VoutDataFormat::linear; 1098 } 1099 else if (value == "vid") 1100 { 1101 format = pmbus_utils::VoutDataFormat::vid; 1102 } 1103 else if (value == "direct") 1104 { 1105 format = pmbus_utils::VoutDataFormat::direct; 1106 } 1107 else if (value == "ieee") 1108 { 1109 format = pmbus_utils::VoutDataFormat::ieee; 1110 } 1111 else 1112 { 1113 throw std::invalid_argument{"Element is not a vout data format"}; 1114 } 1115 1116 return format; 1117 } 1118 1119 } // namespace internal 1120 1121 } // namespace phosphor::power::regulators::config_file_parser 1122