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 #pragma once 17 18 #include "action.hpp" 19 #include "and_action.hpp" 20 #include "chassis.hpp" 21 #include "compare_presence_action.hpp" 22 #include "compare_vpd_action.hpp" 23 #include "configuration.hpp" 24 #include "device.hpp" 25 #include "i2c_compare_bit_action.hpp" 26 #include "i2c_compare_byte_action.hpp" 27 #include "i2c_compare_bytes_action.hpp" 28 #include "i2c_interface.hpp" 29 #include "i2c_write_bit_action.hpp" 30 #include "i2c_write_byte_action.hpp" 31 #include "i2c_write_bytes_action.hpp" 32 #include "if_action.hpp" 33 #include "not_action.hpp" 34 #include "or_action.hpp" 35 #include "pmbus_read_sensor_action.hpp" 36 #include "pmbus_write_vout_command_action.hpp" 37 #include "presence_detection.hpp" 38 #include "rail.hpp" 39 #include "rule.hpp" 40 #include "run_rule_action.hpp" 41 #include "sensor_monitoring.hpp" 42 #include "set_device_action.hpp" 43 44 #include <nlohmann/json.hpp> 45 46 #include <cstdint> 47 #include <filesystem> 48 #include <memory> 49 #include <stdexcept> 50 #include <string> 51 #include <tuple> 52 #include <vector> 53 54 namespace phosphor::power::regulators::config_file_parser 55 { 56 57 /** 58 * Parses the specified JSON configuration file. 59 * 60 * Returns the corresponding C++ Rule and Chassis objects. 61 * 62 * Throws a ConfigFileParserError if an error occurs. 63 * 64 * @param pathName configuration file path name 65 * @return tuple containing vectors of Rule and Chassis objects 66 */ 67 std::tuple<std::vector<std::unique_ptr<Rule>>, 68 std::vector<std::unique_ptr<Chassis>>> 69 parse(const std::filesystem::path& pathName); 70 71 /* 72 * Internal implementation details for parse() 73 */ 74 namespace internal 75 { 76 77 /** 78 * Returns the specified property of the specified JSON element. 79 * 80 * Throws an invalid_argument exception if the property does not exist. 81 * 82 * @param element JSON element 83 * @param property property name 84 */ 85 inline const nlohmann::json& getRequiredProperty(const nlohmann::json& element, 86 const std::string& property) 87 { 88 auto it = element.find(property); 89 if (it == element.end()) 90 { 91 throw std::invalid_argument{"Required property missing: " + property}; 92 } 93 return *it; 94 } 95 96 /** 97 * Parses a JSON element containing an action. 98 * 99 * Returns the corresponding C++ Action object. 100 * 101 * Throws an exception if parsing fails. 102 * 103 * @param element JSON element 104 * @return Action object 105 */ 106 std::unique_ptr<Action> parseAction(const nlohmann::json& element); 107 108 /** 109 * Parses a JSON element containing an array of actions. 110 * 111 * Returns the corresponding C++ Action objects. 112 * 113 * Throws an exception if parsing fails. 114 * 115 * @param element JSON element 116 * @return vector of Action objects 117 */ 118 std::vector<std::unique_ptr<Action>> 119 parseActionArray(const nlohmann::json& element); 120 121 /** 122 * Parses a JSON element containing an and action. 123 * 124 * Returns the corresponding C++ AndAction object. 125 * 126 * Throws an exception if parsing fails. 127 * 128 * @param element JSON element 129 * @return AndAction object 130 */ 131 std::unique_ptr<AndAction> parseAnd(const nlohmann::json& element); 132 133 /** 134 * Parses a JSON element containing a bit position (from 0-7). 135 * 136 * Returns the corresponding C++ uint8_t value. 137 * 138 * Throws an exception if parsing fails. 139 * 140 * @param element JSON element 141 * @return uint8_t value 142 */ 143 inline uint8_t parseBitPosition(const nlohmann::json& element) 144 { 145 // Verify element contains an integer 146 if (!element.is_number_integer()) 147 { 148 throw std::invalid_argument{"Element is not an integer"}; 149 } 150 int value = element.get<int>(); 151 if ((value < 0) || (value > 7)) 152 { 153 throw std::invalid_argument{"Element is not a bit position"}; 154 } 155 return static_cast<uint8_t>(value); 156 } 157 158 /** 159 * Parses a JSON element containing a bit value (0 or 1). 160 * 161 * Returns the corresponding C++ uint8_t value. 162 * 163 * Throws an exception if parsing fails. 164 * 165 * @param element JSON element 166 * @return uint8_t value 167 */ 168 inline uint8_t parseBitValue(const nlohmann::json& element) 169 { 170 // Verify element contains an integer 171 if (!element.is_number_integer()) 172 { 173 throw std::invalid_argument{"Element is not an integer"}; 174 } 175 int value = element.get<int>(); 176 if ((value < 0) || (value > 1)) 177 { 178 throw std::invalid_argument{"Element is not a bit value"}; 179 } 180 return static_cast<uint8_t>(value); 181 } 182 183 /** 184 * Parses a JSON element containing a boolean. 185 * 186 * Returns the corresponding C++ boolean value. 187 * 188 * Throws an exception if parsing fails. 189 * 190 * @param element JSON element 191 * @return boolean value 192 */ 193 inline bool parseBoolean(const nlohmann::json& element) 194 { 195 // Verify element contains a boolean 196 if (!element.is_boolean()) 197 { 198 throw std::invalid_argument{"Element is not a boolean"}; 199 } 200 return element.get<bool>(); 201 } 202 203 /** 204 * Parses a JSON element containing a chassis. 205 * 206 * Returns the corresponding C++ Chassis object. 207 * 208 * Throws an exception if parsing fails. 209 * 210 * @param element JSON element 211 * @return Chassis object 212 */ 213 std::unique_ptr<Chassis> parseChassis(const nlohmann::json& element); 214 215 /** 216 * Parses a JSON element containing an array of chassis. 217 * 218 * Returns the corresponding C++ Chassis objects. 219 * 220 * Throws an exception if parsing fails. 221 * 222 * @param element JSON element 223 * @return vector of Chassis objects 224 */ 225 std::vector<std::unique_ptr<Chassis>> 226 parseChassisArray(const nlohmann::json& element); 227 228 /** 229 * Parses a JSON element containing a compare_presence action. 230 * 231 * Returns the corresponding C++ ComparePresenceAction object. 232 * 233 * Throws an exception if parsing fails. 234 * 235 * @param element JSON element 236 * @return ComparePresenceAction object 237 */ 238 std::unique_ptr<ComparePresenceAction> 239 parseComparePresence(const nlohmann::json& element); 240 241 /** 242 * Parses a JSON element containing a compare_vpd action. 243 * 244 * Returns the corresponding C++ CompareVPDAction object. 245 * 246 * Throws an exception if parsing fails. 247 * 248 * @param element JSON element 249 * @return CompareVPDAction object 250 */ 251 std::unique_ptr<CompareVPDAction> 252 parseCompareVPD(const nlohmann::json& element); 253 254 /** 255 * Parses a JSON element containing a configuration. 256 * 257 * Returns the corresponding C++ Configuration object. 258 * 259 * Throws an exception if parsing fails. 260 * 261 * @param element JSON element 262 * @return Configuration object 263 */ 264 std::unique_ptr<Configuration> 265 parseConfiguration(const nlohmann::json& element); 266 267 /** 268 * Parses a JSON element containing a device. 269 * 270 * Returns the corresponding C++ Device object. 271 * 272 * Throws an exception if parsing fails. 273 * 274 * @param element JSON element 275 * @return Device object 276 */ 277 std::unique_ptr<Device> parseDevice(const nlohmann::json& element); 278 279 /** 280 * Parses a JSON element containing an array of devices. 281 * 282 * Returns the corresponding C++ Device objects. 283 * 284 * Throws an exception if parsing fails. 285 * 286 * @param element JSON element 287 * @return vector of Device objects 288 */ 289 std::vector<std::unique_ptr<Device>> 290 parseDeviceArray(const nlohmann::json& element); 291 292 /** 293 * Parses a JSON element containing a double (floating point number). 294 * 295 * Returns the corresponding C++ double value. 296 * 297 * Throws an exception if parsing fails. 298 * 299 * @param element JSON element 300 * @return double value 301 */ 302 inline double parseDouble(const nlohmann::json& element) 303 { 304 // Verify element contains a number (integer or floating point) 305 if (!element.is_number()) 306 { 307 throw std::invalid_argument{"Element is not a number"}; 308 } 309 return element.get<double>(); 310 } 311 312 /** 313 * Parses a JSON element containing a byte value expressed as a hexadecimal 314 * string. 315 * 316 * The JSON number data type does not support the hexadecimal format. For this 317 * reason, hexadecimal byte values are stored as strings in the configuration 318 * file. 319 * 320 * Returns the corresponding C++ uint8_t value. 321 * 322 * Throws an exception if parsing fails. 323 * 324 * @param element JSON element 325 * @return uint8_t value 326 */ 327 inline uint8_t parseHexByte(const nlohmann::json& element) 328 { 329 if (!element.is_string()) 330 { 331 throw std::invalid_argument{"Element is not a string"}; 332 } 333 std::string value = element.get<std::string>(); 334 335 bool isHex = (value.compare(0, 2, "0x") == 0) && (value.size() > 2) && 336 (value.size() < 5) && 337 (value.find_first_not_of("0123456789abcdefABCDEF", 2) == 338 std::string::npos); 339 if (!isHex) 340 { 341 throw std::invalid_argument{"Element is not hexadecimal string"}; 342 } 343 return static_cast<uint8_t>(std::stoul(value, 0, 0)); 344 } 345 346 /** 347 * Parses a JSON element containing an array of byte values expressed as a 348 * hexadecimal strings. 349 * 350 * Returns the corresponding C++ uint8_t values. 351 * 352 * Throws an exception if parsing fails. 353 * 354 * @param element JSON element 355 * @return vector of uint8_t 356 */ 357 std::vector<uint8_t> parseHexByteArray(const nlohmann::json& element); 358 359 /** 360 * Parses a JSON element containing an i2c_compare_bit action. 361 * 362 * Returns the corresponding C++ I2CCompareBitAction object. 363 * 364 * Throws an exception if parsing fails. 365 * 366 * @param element JSON element 367 * @return I2CCompareBitAction object 368 */ 369 std::unique_ptr<I2CCompareBitAction> 370 parseI2CCompareBit(const nlohmann::json& element); 371 372 /** 373 * Parses a JSON element containing an i2c_compare_byte action. 374 * 375 * Returns the corresponding C++ I2CCompareByteAction object. 376 * 377 * Throws an exception if parsing fails. 378 * 379 * @param element JSON element 380 * @return I2CCompareByteAction object 381 */ 382 std::unique_ptr<I2CCompareByteAction> 383 parseI2CCompareByte(const nlohmann::json& element); 384 385 /** 386 * Parses a JSON element containing an i2c_compare_bytes action. 387 * 388 * Returns the corresponding C++ I2CCompareBytesAction object. 389 * 390 * Throws an exception if parsing fails. 391 * 392 * @param element JSON element 393 * @return I2CCompareBytesAction object 394 */ 395 std::unique_ptr<I2CCompareBytesAction> 396 parseI2CCompareBytes(const nlohmann::json& element); 397 398 /** 399 * Parses a JSON element containing an i2c_interface. 400 * 401 * Returns the corresponding C++ i2c::I2CInterface object. 402 * 403 * Throws an exception if parsing fails. 404 * 405 * @param element JSON element 406 * @return i2c::I2CInterface object 407 */ 408 std::unique_ptr<i2c::I2CInterface> 409 parseI2CInterface(const nlohmann::json& element); 410 411 /** 412 * Parses a JSON element containing an i2c_write_bit action. 413 * 414 * Returns the corresponding C++ I2CWriteBitAction object. 415 * 416 * Throws an exception if parsing fails. 417 * 418 * @param element JSON element 419 * @return I2CWriteBitAction object 420 */ 421 std::unique_ptr<I2CWriteBitAction> 422 parseI2CWriteBit(const nlohmann::json& element); 423 424 /** 425 * Parses a JSON element containing an i2c_write_byte action. 426 * 427 * Returns the corresponding C++ I2CWriteByteAction object. 428 * 429 * Throws an exception if parsing fails. 430 * 431 * @param element JSON element 432 * @return I2CWriteByteAction object 433 */ 434 std::unique_ptr<I2CWriteByteAction> 435 parseI2CWriteByte(const nlohmann::json& element); 436 437 /** 438 * Parses a JSON element containing an i2c_write_bytes action. 439 * 440 * Returns the corresponding C++ I2CWriteBytesAction object. 441 * 442 * Throws an exception if parsing fails. 443 * 444 * @param element JSON element 445 * @return I2CWriteBytesAction object 446 */ 447 std::unique_ptr<I2CWriteBytesAction> 448 parseI2CWriteBytes(const nlohmann::json& element); 449 450 /** 451 * Parses a JSON element containing an if action. 452 * 453 * Returns the corresponding C++ IfAction object. 454 * 455 * Throws an exception if parsing fails. 456 * 457 * @param element JSON element 458 * @return IfAction object 459 */ 460 std::unique_ptr<IfAction> parseIf(const nlohmann::json& element); 461 462 /** 463 * Parses a JSON element containing an 8-bit signed integer. 464 * 465 * Returns the corresponding C++ int8_t value. 466 * 467 * Throws an exception if parsing fails. 468 * 469 * @param element JSON element 470 * @return int8_t value 471 */ 472 inline int8_t parseInt8(const nlohmann::json& element) 473 { 474 // Verify element contains an integer 475 if (!element.is_number_integer()) 476 { 477 throw std::invalid_argument{"Element is not an integer"}; 478 } 479 int value = element.get<int>(); 480 if ((value < INT8_MIN) || (value > INT8_MAX)) 481 { 482 throw std::invalid_argument{"Element is not an 8-bit signed integer"}; 483 } 484 return static_cast<int8_t>(value); 485 } 486 487 /** 488 * Parses a JSON element containing a not action. 489 * 490 * Returns the corresponding C++ NotAction object. 491 * 492 * Throws an exception if parsing fails. 493 * 494 * @param element JSON element 495 * @return NotAction object 496 */ 497 std::unique_ptr<NotAction> parseNot(const nlohmann::json& element); 498 499 /** 500 * Parses a JSON element containing an or action. 501 * 502 * Returns the corresponding C++ OrAction object. 503 * 504 * Throws an exception if parsing fails. 505 * 506 * @param element JSON element 507 * @return OrAction object 508 */ 509 std::unique_ptr<OrAction> parseOr(const nlohmann::json& element); 510 511 /** 512 * Parses a JSON element containing a pmbus_read_sensor action. 513 * 514 * Returns the corresponding C++ PMBusReadSensorAction object. 515 * 516 * Throws an exception if parsing fails. 517 * 518 * @param element JSON element 519 * @return PMBusReadSensorAction object 520 */ 521 std::unique_ptr<PMBusReadSensorAction> 522 parsePMBusReadSensor(const nlohmann::json& element); 523 524 /** 525 * Parses a JSON element containing a pmbus_write_vout_command action. 526 * 527 * Returns the corresponding C++ PMBusWriteVoutCommandAction object. 528 * 529 * Throws an exception if parsing fails. 530 * 531 * @param element JSON element 532 * @return PMBusWriteVoutCommandAction object 533 */ 534 std::unique_ptr<PMBusWriteVoutCommandAction> 535 parsePMBusWriteVoutCommand(const nlohmann::json& element); 536 537 /** 538 * Parses a JSON element containing a presence detection operation. 539 * 540 * Returns the corresponding C++ PresenceDetection object. 541 * 542 * Throws an exception if parsing fails. 543 * 544 * @param element JSON element 545 * @return PresenceDetection object 546 */ 547 std::unique_ptr<PresenceDetection> 548 parsePresenceDetection(const nlohmann::json& element); 549 550 /** 551 * Parses a JSON element containing a rail. 552 * 553 * Returns the corresponding C++ Rail object. 554 * 555 * Throws an exception if parsing fails. 556 * 557 * @param element JSON element 558 * @return Rail object 559 */ 560 std::unique_ptr<Rail> parseRail(const nlohmann::json& element); 561 562 /** 563 * Parses a JSON element containing an array of rails. 564 * 565 * Returns the corresponding C++ Rail objects. 566 * 567 * Throws an exception if parsing fails. 568 * 569 * @param element JSON element 570 * @return vector of Rail objects 571 */ 572 std::vector<std::unique_ptr<Rail>> 573 parseRailArray(const nlohmann::json& element); 574 575 /** 576 * Parses the JSON root element of the entire configuration file. 577 * 578 * Returns the corresponding C++ Rule and Chassis objects. 579 * 580 * Throws an exception if parsing fails. 581 * 582 * @param element JSON element 583 * @return tuple containing vectors of Rule and Chassis objects 584 */ 585 std::tuple<std::vector<std::unique_ptr<Rule>>, 586 std::vector<std::unique_ptr<Chassis>>> 587 parseRoot(const nlohmann::json& element); 588 589 /** 590 * Parses a JSON element containing a rule. 591 * 592 * Returns the corresponding C++ Rule object. 593 * 594 * Throws an exception if parsing fails. 595 * 596 * @param element JSON element 597 * @return Rule object 598 */ 599 std::unique_ptr<Rule> parseRule(const nlohmann::json& element); 600 601 /** 602 * Parses a JSON element containing an array of rules. 603 * 604 * Returns the corresponding C++ Rule objects. 605 * 606 * Throws an exception if parsing fails. 607 * 608 * @param element JSON element 609 * @return vector of Rule objects 610 */ 611 std::vector<std::unique_ptr<Rule>> 612 parseRuleArray(const nlohmann::json& element); 613 614 /** 615 * Parses the "rule_id" or "actions" property in a JSON element. 616 * 617 * The element must contain one property or the other but not both. 618 * 619 * If the element contains a "rule_id" property, the corresponding C++ 620 * RunRuleAction object is returned. 621 * 622 * If the element contains an "actions" property, the corresponding C++ Action 623 * objects are returned. 624 * 625 * Throws an exception if parsing fails. 626 * 627 * @param element JSON element 628 * @return vector of Action objects 629 */ 630 std::vector<std::unique_ptr<Action>> 631 parseRuleIDOrActionsProperty(const nlohmann::json& element); 632 633 /** 634 * Parses a JSON element containing a run_rule action. 635 * 636 * Returns the corresponding C++ RunRuleAction object. 637 * 638 * Throws an exception if parsing fails. 639 * 640 * @param element JSON element 641 * @return RunRuleAction object 642 */ 643 std::unique_ptr<RunRuleAction> parseRunRule(const nlohmann::json& element); 644 645 /** 646 * Parses a JSON element containing a SensorDataFormat expressed as a string. 647 * 648 * Returns the corresponding SensorDataFormat enum value. 649 * 650 * Throws an exception if parsing fails. 651 * 652 * @param element JSON element 653 * @return SensorDataFormat enum value 654 */ 655 pmbus_utils::SensorDataFormat 656 parseSensorDataFormat(const nlohmann::json& element); 657 658 /** 659 * Parses a JSON element containing a sensor monitoring operation. 660 * 661 * Returns the corresponding C++ SensorMonitoring object. 662 * 663 * Throws an exception if parsing fails. 664 * 665 * @param element JSON element 666 * @return SensorMonitoring object 667 */ 668 std::unique_ptr<SensorMonitoring> 669 parseSensorMonitoring(const nlohmann::json& element); 670 671 /** 672 * Parses a JSON element containing a SensorValueType expressed as a string. 673 * 674 * Returns the corresponding SensorValueType enum value. 675 * 676 * Throws an exception if parsing fails. 677 * 678 * @param element JSON element 679 * @return SensorValueType enum value 680 */ 681 pmbus_utils::SensorValueType 682 parseSensorValueType(const nlohmann::json& element); 683 684 /** 685 * Parses a JSON element containing a set_device action. 686 * 687 * Returns the corresponding C++ SetDeviceAction object. 688 * 689 * Throws an exception if parsing fails. 690 * 691 * @param element JSON element 692 * @return SetDeviceAction object 693 */ 694 std::unique_ptr<SetDeviceAction> parseSetDevice(const nlohmann::json& element); 695 696 /** 697 * Parses a JSON element containing a string. 698 * 699 * Returns the corresponding C++ string. 700 * 701 * Throws an exception if parsing fails. 702 * 703 * @param element JSON element 704 * @param isEmptyValid indicates whether an empty string value is valid 705 * @return string value 706 */ 707 inline std::string parseString(const nlohmann::json& element, 708 bool isEmptyValid = false) 709 { 710 if (!element.is_string()) 711 { 712 throw std::invalid_argument{"Element is not a string"}; 713 } 714 std::string value = element.get<std::string>(); 715 if (value.empty() && !isEmptyValid) 716 { 717 throw std::invalid_argument{"Element contains an empty string"}; 718 } 719 return value; 720 } 721 722 /** 723 * Parses a JSON element containing an 8-bit unsigned integer. 724 * 725 * Returns the corresponding C++ uint8_t value. 726 * 727 * Throws an exception if parsing fails. 728 * 729 * @param element JSON element 730 * @return uint8_t value 731 */ 732 inline uint8_t parseUint8(const nlohmann::json& element) 733 { 734 // Verify element contains an integer 735 if (!element.is_number_integer()) 736 { 737 throw std::invalid_argument{"Element is not an integer"}; 738 } 739 int value = element.get<int>(); 740 if ((value < 0) || (value > UINT8_MAX)) 741 { 742 throw std::invalid_argument{"Element is not an 8-bit unsigned integer"}; 743 } 744 return static_cast<uint8_t>(value); 745 } 746 747 /** 748 * Parses a JSON element containing an unsigned integer. 749 * 750 * Returns the corresponding C++ unsigned int value. 751 * 752 * Throws an exception if parsing fails. 753 * 754 * @param element JSON element 755 * @return unsigned int value 756 */ 757 inline unsigned int parseUnsignedInteger(const nlohmann::json& element) 758 { 759 // Verify element contains an unsigned integer 760 if (!element.is_number_unsigned()) 761 { 762 throw std::invalid_argument{"Element is not an unsigned integer"}; 763 } 764 return element.get<unsigned int>(); 765 } 766 767 /** 768 * Parses a JSON element containing a VoutDataFormat expressed as a string. 769 * 770 * Returns the corresponding VoutDataFormat enum value. 771 * 772 * Throws an exception if parsing fails. 773 * 774 * @param element JSON element 775 * @return VoutDataFormat enum value 776 */ 777 pmbus_utils::VoutDataFormat parseVoutDataFormat(const nlohmann::json& element); 778 779 /** 780 * Verifies that the specified JSON element is a JSON array. 781 * 782 * Throws an invalid_argument exception if the element is not an array. 783 * 784 * @param element JSON element 785 */ 786 inline void verifyIsArray(const nlohmann::json& element) 787 { 788 if (!element.is_array()) 789 { 790 throw std::invalid_argument{"Element is not an array"}; 791 } 792 } 793 794 /** 795 * Verifies that the specified JSON element is a JSON object. 796 * 797 * Throws an invalid_argument exception if the element is not an object. 798 * 799 * @param element JSON element 800 */ 801 inline void verifyIsObject(const nlohmann::json& element) 802 { 803 if (!element.is_object()) 804 { 805 throw std::invalid_argument{"Element is not an object"}; 806 } 807 } 808 809 /** 810 * Verifies that the specified JSON element contains the expected number of 811 * properties. 812 * 813 * Throws an invalid_argument exception if the element contains a different 814 * number of properties. This indicates the element contains an invalid 815 * property. 816 * 817 * @param element JSON element 818 * @param expectedCount expected number of properties in element 819 */ 820 inline void verifyPropertyCount(const nlohmann::json& element, 821 unsigned int expectedCount) 822 { 823 if (element.size() != expectedCount) 824 { 825 throw std::invalid_argument{"Element contains an invalid property"}; 826 } 827 } 828 829 } // namespace internal 830 831 } // namespace phosphor::power::regulators::config_file_parser 832