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 // TODO: Not implemented yet 71 // action = parseAnd(element["and"]); 72 // ++propertyCount; 73 } 74 else if (element.contains("compare_presence")) 75 { 76 // TODO: Not implemented yet 77 // action = parseComparePresence(element["compare_presence"]); 78 // ++propertyCount; 79 } 80 else if (element.contains("compare_vpd")) 81 { 82 // TODO: Not implemented yet 83 // action = parseCompareVPD(element["compare_vpd"]); 84 // ++propertyCount; 85 } 86 else if (element.contains("i2c_compare_bit")) 87 { 88 // TODO: Not implemented yet 89 // action = parseI2CCompareBit(element["i2c_compare_bit"]); 90 // ++propertyCount; 91 } 92 else if (element.contains("i2c_compare_byte")) 93 { 94 // TODO: Not implemented yet 95 // action = parseI2CCompareByte(element["i2c_compare_byte"]); 96 // ++propertyCount; 97 } 98 else if (element.contains("i2c_compare_bytes")) 99 { 100 // TODO: Not implemented yet 101 // action = parseI2CCompareBytes(element["i2c_compare_bytes"]); 102 // ++propertyCount; 103 } 104 else if (element.contains("i2c_write_bit")) 105 { 106 action = parseI2CWriteBit(element["i2c_write_bit"]); 107 ++propertyCount; 108 } 109 else if (element.contains("i2c_write_byte")) 110 { 111 action = parseI2CWriteByte(element["i2c_write_byte"]); 112 ++propertyCount; 113 } 114 else if (element.contains("i2c_write_bytes")) 115 { 116 action = parseI2CWriteBytes(element["i2c_write_bytes"]); 117 ++propertyCount; 118 } 119 else if (element.contains("if")) 120 { 121 // TODO: Not implemented yet 122 // action = parseIf(element["if"]); 123 // ++propertyCount; 124 } 125 else if (element.contains("not")) 126 { 127 // TODO: Not implemented yet 128 // action = parseNot(element["not"]); 129 // ++propertyCount; 130 } 131 else if (element.contains("or")) 132 { 133 // TODO: Not implemented yet 134 // action = parseOr(element["or"]); 135 // ++propertyCount; 136 } 137 else if (element.contains("pmbus_read_sensor")) 138 { 139 // TODO: Not implemented yet 140 // action = parsePMBusReadSensor(element["pmbus_read_sensor"]); 141 // ++propertyCount; 142 } 143 else if (element.contains("pmbus_write_vout_command")) 144 { 145 action = 146 parsePMBusWriteVoutCommand(element["pmbus_write_vout_command"]); 147 ++propertyCount; 148 } 149 else if (element.contains("run_rule")) 150 { 151 action = parseRunRule(element["run_rule"]); 152 ++propertyCount; 153 } 154 else if (element.contains("set_device")) 155 { 156 // TODO: Not implemented yet 157 // action = parseSetDevice(element["set_device"]); 158 // ++propertyCount; 159 } 160 else 161 { 162 throw std::invalid_argument{"Required action type property missing"}; 163 } 164 165 // Verify no invalid properties exist 166 verifyPropertyCount(element, propertyCount); 167 168 return action; 169 } 170 171 std::vector<std::unique_ptr<Action>> parseActionArray(const json& element) 172 { 173 verifyIsArray(element); 174 std::vector<std::unique_ptr<Action>> actions; 175 for (auto& actionElement : element) 176 { 177 actions.emplace_back(parseAction(actionElement)); 178 } 179 return actions; 180 } 181 182 std::unique_ptr<Chassis> parseChassis(const json& element) 183 { 184 verifyIsObject(element); 185 unsigned int propertyCount{0}; 186 187 // Optional comments property; value not stored 188 if (element.contains("comments")) 189 { 190 ++propertyCount; 191 } 192 193 // Required number property 194 const json& numberElement = getRequiredProperty(element, "number"); 195 unsigned int number = parseUnsignedInteger(numberElement); 196 if (number < 1) 197 { 198 throw std::invalid_argument{"Invalid chassis number: Must be > 0"}; 199 } 200 ++propertyCount; 201 202 // Optional devices property 203 std::vector<std::unique_ptr<Device>> devices{}; 204 auto devicesIt = element.find("devices"); 205 if (devicesIt != element.end()) 206 { 207 devices = parseDeviceArray(*devicesIt); 208 ++propertyCount; 209 } 210 211 // Verify no invalid properties exist 212 verifyPropertyCount(element, propertyCount); 213 214 return std::make_unique<Chassis>(number, std::move(devices)); 215 } 216 217 std::vector<std::unique_ptr<Chassis>> parseChassisArray(const json& element) 218 { 219 verifyIsArray(element); 220 std::vector<std::unique_ptr<Chassis>> chassis; 221 for (auto& chassisElement : element) 222 { 223 chassis.emplace_back(parseChassis(chassisElement)); 224 } 225 return chassis; 226 } 227 228 std::unique_ptr<Configuration> parseConfiguration(const json& element) 229 { 230 verifyIsObject(element); 231 unsigned int propertyCount{0}; 232 233 // Optional comments property; value not stored 234 if (element.contains("comments")) 235 { 236 ++propertyCount; 237 } 238 239 // Optional volts property 240 std::optional<double> volts{}; 241 auto voltsIt = element.find("volts"); 242 if (voltsIt != element.end()) 243 { 244 volts = parseDouble(*voltsIt); 245 ++propertyCount; 246 } 247 248 // Required rule_id or actions property 249 std::vector<std::unique_ptr<Action>> actions{}; 250 actions = parseRuleIDOrActionsProperty(element); 251 ++propertyCount; 252 253 // Verify no invalid properties exist 254 verifyPropertyCount(element, propertyCount); 255 256 return std::make_unique<Configuration>(volts, std::move(actions)); 257 } 258 259 std::unique_ptr<Device> parseDevice(const json& element) 260 { 261 verifyIsObject(element); 262 unsigned int propertyCount{0}; 263 264 // Optional comments property; value not stored 265 if (element.contains("comments")) 266 { 267 ++propertyCount; 268 } 269 270 // Required id property 271 const json& idElement = getRequiredProperty(element, "id"); 272 std::string id = parseString(idElement); 273 ++propertyCount; 274 275 // Required is_regulator property 276 const json& isRegulatorElement = 277 getRequiredProperty(element, "is_regulator"); 278 bool isRegulator = parseBoolean(isRegulatorElement); 279 ++propertyCount; 280 281 // Required fru property 282 const json& fruElement = getRequiredProperty(element, "fru"); 283 std::string fru = parseString(fruElement); 284 ++propertyCount; 285 286 // Required i2c_interface property 287 const json& i2cInterfaceElement = 288 getRequiredProperty(element, "i2c_interface"); 289 std::unique_ptr<i2c::I2CInterface> i2cInterface = 290 parseI2CInterface(i2cInterfaceElement); 291 ++propertyCount; 292 293 // Optional presence_detection property 294 // TODO: Not implemented yet 295 std::unique_ptr<PresenceDetection> presenceDetection{}; 296 // auto presenceDetectionIt = element.find("presence_detection"); 297 // if (presenceDetectionIt != element.end()) 298 // { 299 // presenceDetection = parsePresenceDetection(*presenceDetectionIt); 300 // ++propertyCount; 301 // } 302 303 // Optional configuration property 304 std::unique_ptr<Configuration> configuration{}; 305 auto configurationIt = element.find("configuration"); 306 if (configurationIt != element.end()) 307 { 308 configuration = parseConfiguration(*configurationIt); 309 ++propertyCount; 310 } 311 312 // Optional rails property 313 std::vector<std::unique_ptr<Rail>> rails{}; 314 auto railsIt = element.find("rails"); 315 if (railsIt != element.end()) 316 { 317 if (!isRegulator) 318 { 319 throw std::invalid_argument{ 320 "Invalid rails property when is_regulator is false"}; 321 } 322 rails = parseRailArray(*railsIt); 323 ++propertyCount; 324 } 325 326 // Verify no invalid properties exist 327 verifyPropertyCount(element, propertyCount); 328 329 return std::make_unique<Device>(id, isRegulator, fru, 330 std::move(i2cInterface), 331 std::move(presenceDetection), 332 std::move(configuration), std::move(rails)); 333 } 334 335 std::vector<std::unique_ptr<Device>> parseDeviceArray(const json& element) 336 { 337 verifyIsArray(element); 338 std::vector<std::unique_ptr<Device>> devices; 339 for (auto& deviceElement : element) 340 { 341 devices.emplace_back(parseDevice(deviceElement)); 342 } 343 return devices; 344 } 345 346 std::vector<uint8_t> parseHexByteArray(const json& element) 347 { 348 verifyIsArray(element); 349 std::vector<uint8_t> values; 350 for (auto& valueElement : element) 351 { 352 values.emplace_back(parseHexByte(valueElement)); 353 } 354 return values; 355 } 356 357 std::unique_ptr<i2c::I2CInterface> parseI2CInterface(const json& element) 358 { 359 verifyIsObject(element); 360 unsigned int propertyCount{0}; 361 362 // Required bus property 363 const json& busElement = getRequiredProperty(element, "bus"); 364 uint8_t bus = parseUint8(busElement); 365 ++propertyCount; 366 367 // Required address property 368 const json& addressElement = getRequiredProperty(element, "address"); 369 uint8_t address = parseHexByte(addressElement); 370 ++propertyCount; 371 372 verifyPropertyCount(element, propertyCount); 373 return i2c::create(bus, address, i2c::I2CInterface::InitialState::CLOSED); 374 } 375 376 std::unique_ptr<I2CWriteBitAction> parseI2CWriteBit(const json& element) 377 { 378 verifyIsObject(element); 379 unsigned int propertyCount{0}; 380 381 // Required register property 382 const json& regElement = getRequiredProperty(element, "register"); 383 uint8_t reg = parseHexByte(regElement); 384 ++propertyCount; 385 386 // Required position property 387 const json& positionElement = getRequiredProperty(element, "position"); 388 uint8_t position = parseBitPosition(positionElement); 389 ++propertyCount; 390 391 // Required value property 392 const json& valueElement = getRequiredProperty(element, "value"); 393 uint8_t value = parseBitValue(valueElement); 394 ++propertyCount; 395 396 // Verify no invalid properties exist 397 verifyPropertyCount(element, propertyCount); 398 399 return std::make_unique<I2CWriteBitAction>(reg, position, value); 400 } 401 402 std::unique_ptr<I2CWriteByteAction> parseI2CWriteByte(const json& element) 403 { 404 verifyIsObject(element); 405 unsigned int propertyCount{0}; 406 407 // Required register property 408 const json& regElement = getRequiredProperty(element, "register"); 409 uint8_t reg = parseHexByte(regElement); 410 ++propertyCount; 411 412 // Required value property 413 const json& valueElement = getRequiredProperty(element, "value"); 414 uint8_t value = parseHexByte(valueElement); 415 ++propertyCount; 416 417 // Optional mask property 418 uint8_t mask = 0xff; 419 auto maskIt = element.find("mask"); 420 if (maskIt != element.end()) 421 { 422 mask = parseHexByte(*maskIt); 423 ++propertyCount; 424 } 425 426 // Verify no invalid properties exist 427 verifyPropertyCount(element, propertyCount); 428 429 return std::make_unique<I2CWriteByteAction>(reg, value, mask); 430 } 431 432 std::unique_ptr<I2CWriteBytesAction> parseI2CWriteBytes(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 values property 443 const json& valueElement = getRequiredProperty(element, "values"); 444 std::vector<uint8_t> values = parseHexByteArray(valueElement); 445 ++propertyCount; 446 447 // Optional masks property 448 std::vector<uint8_t> masks{}; 449 auto masksIt = element.find("masks"); 450 if (masksIt != element.end()) 451 { 452 masks = parseHexByteArray(*masksIt); 453 ++propertyCount; 454 } 455 456 // Verify masks array (if specified) was same size as values array 457 if ((!masks.empty()) && (masks.size() != values.size())) 458 { 459 throw std::invalid_argument{"Invalid number of elements in masks"}; 460 } 461 462 // Verify no invalid properties exist 463 verifyPropertyCount(element, propertyCount); 464 465 if (masks.empty()) 466 { 467 return std::make_unique<I2CWriteBytesAction>(reg, values); 468 } 469 return std::make_unique<I2CWriteBytesAction>(reg, values, masks); 470 } 471 472 std::unique_ptr<PMBusWriteVoutCommandAction> 473 parsePMBusWriteVoutCommand(const json& element) 474 { 475 verifyIsObject(element); 476 unsigned int propertyCount{0}; 477 478 // Optional volts property 479 std::optional<double> volts{}; 480 auto voltsIt = element.find("volts"); 481 if (voltsIt != element.end()) 482 { 483 volts = parseDouble(*voltsIt); 484 ++propertyCount; 485 } 486 487 // Required format property 488 const json& formatElement = getRequiredProperty(element, "format"); 489 std::string formatString = parseString(formatElement); 490 if (formatString != "linear") 491 { 492 throw std::invalid_argument{"Invalid format value: " + formatString}; 493 } 494 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::linear; 495 ++propertyCount; 496 497 // Optional exponent property 498 std::optional<int8_t> exponent{}; 499 auto exponentIt = element.find("exponent"); 500 if (exponentIt != element.end()) 501 { 502 exponent = parseInt8(*exponentIt); 503 ++propertyCount; 504 } 505 506 // Optional is_verified property 507 bool isVerified = false; 508 auto isVerifiedIt = element.find("is_verified"); 509 if (isVerifiedIt != element.end()) 510 { 511 isVerified = parseBoolean(*isVerifiedIt); 512 ++propertyCount; 513 } 514 515 // Verify no invalid properties exist 516 verifyPropertyCount(element, propertyCount); 517 518 return std::make_unique<PMBusWriteVoutCommandAction>(volts, format, 519 exponent, isVerified); 520 } 521 522 std::unique_ptr<Rail> parseRail(const json& element) 523 { 524 verifyIsObject(element); 525 unsigned int propertyCount{0}; 526 527 // Optional comments property; value not stored 528 if (element.contains("comments")) 529 { 530 ++propertyCount; 531 } 532 533 // Required id property 534 const json& idElement = getRequiredProperty(element, "id"); 535 std::string id = parseString(idElement); 536 ++propertyCount; 537 538 // Optional configuration property 539 std::unique_ptr<Configuration> configuration{}; 540 auto configurationIt = element.find("configuration"); 541 if (configurationIt != element.end()) 542 { 543 configuration = parseConfiguration(*configurationIt); 544 ++propertyCount; 545 } 546 547 // Optional sensor_monitoring property 548 std::unique_ptr<SensorMonitoring> sensorMonitoring{}; 549 auto sensorMonitoringIt = element.find("sensor_monitoring"); 550 if (sensorMonitoringIt != element.end()) 551 { 552 sensorMonitoring = parseSensorMonitoring(*sensorMonitoringIt); 553 ++propertyCount; 554 } 555 556 // Verify no invalid properties exist 557 verifyPropertyCount(element, propertyCount); 558 559 return std::make_unique<Rail>(id, std::move(configuration), 560 std::move(sensorMonitoring)); 561 } 562 563 std::vector<std::unique_ptr<Rail>> parseRailArray(const json& element) 564 { 565 verifyIsArray(element); 566 std::vector<std::unique_ptr<Rail>> rails; 567 for (auto& railElement : element) 568 { 569 rails.emplace_back(parseRail(railElement)); 570 } 571 return rails; 572 } 573 574 std::tuple<std::vector<std::unique_ptr<Rule>>, 575 std::vector<std::unique_ptr<Chassis>>> 576 parseRoot(const json& element) 577 { 578 verifyIsObject(element); 579 unsigned int propertyCount{0}; 580 581 // Optional comments property; value not stored 582 if (element.contains("comments")) 583 { 584 ++propertyCount; 585 } 586 587 // Optional rules property 588 std::vector<std::unique_ptr<Rule>> rules{}; 589 auto rulesIt = element.find("rules"); 590 if (rulesIt != element.end()) 591 { 592 rules = parseRuleArray(*rulesIt); 593 ++propertyCount; 594 } 595 596 // Required chassis property 597 const json& chassisElement = getRequiredProperty(element, "chassis"); 598 std::vector<std::unique_ptr<Chassis>> chassis = 599 parseChassisArray(chassisElement); 600 ++propertyCount; 601 602 // Verify no invalid properties exist 603 verifyPropertyCount(element, propertyCount); 604 605 return std::make_tuple(std::move(rules), std::move(chassis)); 606 } 607 608 std::unique_ptr<Rule> parseRule(const json& element) 609 { 610 verifyIsObject(element); 611 unsigned int propertyCount{0}; 612 613 // Optional comments property; value not stored 614 if (element.contains("comments")) 615 { 616 ++propertyCount; 617 } 618 619 // Required id property 620 const json& idElement = getRequiredProperty(element, "id"); 621 std::string id = parseString(idElement); 622 ++propertyCount; 623 624 // Required actions property 625 const json& actionsElement = getRequiredProperty(element, "actions"); 626 std::vector<std::unique_ptr<Action>> actions = 627 parseActionArray(actionsElement); 628 ++propertyCount; 629 630 // Verify no invalid properties exist 631 verifyPropertyCount(element, propertyCount); 632 633 return std::make_unique<Rule>(id, std::move(actions)); 634 } 635 636 std::vector<std::unique_ptr<Rule>> parseRuleArray(const json& element) 637 { 638 verifyIsArray(element); 639 std::vector<std::unique_ptr<Rule>> rules; 640 for (auto& ruleElement : element) 641 { 642 rules.emplace_back(parseRule(ruleElement)); 643 } 644 return rules; 645 } 646 647 std::vector<std::unique_ptr<Action>> 648 parseRuleIDOrActionsProperty(const json& element) 649 { 650 verifyIsObject(element); 651 // Required rule_id or actions property 652 std::vector<std::unique_ptr<Action>> actions{}; 653 auto ruleIDIt = element.find("rule_id"); 654 auto actionsIt = element.find("actions"); 655 if ((actionsIt == element.end()) && (ruleIDIt != element.end())) 656 { 657 std::string ruleID = parseString(*ruleIDIt); 658 actions.emplace_back(std::make_unique<RunRuleAction>(ruleID)); 659 } 660 else if ((actionsIt != element.end()) && (ruleIDIt == element.end())) 661 { 662 actions = parseActionArray(*actionsIt); 663 } 664 else 665 { 666 throw std::invalid_argument{"Invalid property combination: Must " 667 "contain either rule_id or actions"}; 668 } 669 670 return actions; 671 } 672 673 std::unique_ptr<RunRuleAction> parseRunRule(const json& element) 674 { 675 // String ruleID 676 std::string ruleID = parseString(element); 677 678 return std::make_unique<RunRuleAction>(ruleID); 679 } 680 681 std::unique_ptr<SensorMonitoring> parseSensorMonitoring(const json& element) 682 { 683 verifyIsObject(element); 684 unsigned int propertyCount{0}; 685 686 // Optional comments property; value not stored 687 if (element.contains("comments")) 688 { 689 ++propertyCount; 690 } 691 692 // Required rule_id or actions property 693 std::vector<std::unique_ptr<Action>> actions{}; 694 actions = parseRuleIDOrActionsProperty(element); 695 ++propertyCount; 696 697 // Verify no invalid properties exist 698 verifyPropertyCount(element, propertyCount); 699 700 return std::make_unique<SensorMonitoring>(std::move(actions)); 701 } 702 703 } // namespace internal 704 705 } // namespace phosphor::power::regulators::config_file_parser 706