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