1 #include "numeric_sensor.hpp" 2 3 #include "libpldm/platform.h" 4 5 #include "common/utils.hpp" 6 #include "requester/handler.hpp" 7 8 #include <limits> 9 #include <regex> 10 11 PHOSPHOR_LOG2_USING; 12 13 namespace pldm 14 { 15 namespace platform_mc 16 { 17 18 inline bool NumericSensor::createInventoryPath( 19 const std::string& associationPath, const std::string& sensorName, 20 const uint16_t entityType, const uint16_t entityInstanceNum, 21 const uint16_t containerId) 22 { 23 auto& bus = pldm::utils::DBusHandler::getBus(); 24 std::string invPath = associationPath + "/" + sensorName; 25 try 26 { 27 entityIntf = std::make_unique<EntityIntf>(bus, invPath.c_str()); 28 } 29 catch (const sdbusplus::exception_t& e) 30 { 31 lg2::error( 32 "Failed to create Entity interface for compact numeric sensor {PATH} error - {ERROR}", 33 "PATH", invPath, "ERROR", e); 34 return false; 35 } 36 entityIntf->entityType(entityType); 37 entityIntf->entityInstanceNumber(entityInstanceNum); 38 entityIntf->containerID(containerId); 39 40 return true; 41 } 42 43 NumericSensor::NumericSensor( 44 const pldm_tid_t tid, const bool sensorDisabled, 45 std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr, std::string& sensorName, 46 std::string& associationPath) : tid(tid), sensorName(sensorName) 47 { 48 if (!pdr) 49 { 50 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 51 } 52 53 sensorId = pdr->sensor_id; 54 std::string path; 55 SensorUnit sensorUnit = SensorUnit::DegreesC; 56 MetricUnit metricUnit = MetricUnit::Count; 57 useMetricInterface = false; 58 59 switch (pdr->base_unit) 60 { 61 case PLDM_SENSOR_UNIT_DEGRESS_C: 62 sensorNameSpace = "/xyz/openbmc_project/sensors/temperature/"; 63 sensorUnit = SensorUnit::DegreesC; 64 break; 65 case PLDM_SENSOR_UNIT_VOLTS: 66 sensorNameSpace = "/xyz/openbmc_project/sensors/voltage/"; 67 sensorUnit = SensorUnit::Volts; 68 break; 69 case PLDM_SENSOR_UNIT_AMPS: 70 sensorNameSpace = "/xyz/openbmc_project/sensors/current/"; 71 sensorUnit = SensorUnit::Amperes; 72 break; 73 case PLDM_SENSOR_UNIT_RPM: 74 sensorNameSpace = "/xyz/openbmc_project/sensors/fan_pwm/"; 75 sensorUnit = SensorUnit::RPMS; 76 break; 77 case PLDM_SENSOR_UNIT_WATTS: 78 sensorNameSpace = "/xyz/openbmc_project/sensors/power/"; 79 sensorUnit = SensorUnit::Watts; 80 break; 81 case PLDM_SENSOR_UNIT_JOULES: 82 sensorNameSpace = "/xyz/openbmc_project/sensors/energy/"; 83 sensorUnit = SensorUnit::Joules; 84 break; 85 case PLDM_SENSOR_UNIT_PERCENTAGE: 86 sensorNameSpace = "/xyz/openbmc_project/sensors/utilization/"; 87 sensorUnit = SensorUnit::Percent; 88 break; 89 case PLDM_SENSOR_UNIT_COUNTS: 90 case PLDM_SENSOR_UNIT_CORRECTED_ERRORS: 91 case PLDM_SENSOR_UNIT_UNCORRECTABLE_ERRORS: 92 sensorNameSpace = "/xyz/openbmc_project/metric/count/"; 93 useMetricInterface = true; 94 break; 95 case PLDM_SENSOR_UNIT_OEMUNIT: 96 sensorNameSpace = "/xyz/openbmc_project/metric/oem/"; 97 useMetricInterface = true; 98 break; 99 default: 100 lg2::error("Sensor {NAME} has Invalid baseUnit {UNIT}.", "NAME", 101 sensorName, "UNIT", pdr->base_unit); 102 throw sdbusplus::xyz::openbmc_project::Common::Error:: 103 InvalidArgument(); 104 break; 105 } 106 107 path = sensorNameSpace + sensorName; 108 try 109 { 110 std::string tmp{}; 111 std::string interface = SENSOR_VALUE_INTF; 112 if (useMetricInterface) 113 { 114 interface = METRIC_VALUE_INTF; 115 } 116 tmp = pldm::utils::DBusHandler().getService(path.c_str(), 117 interface.c_str()); 118 119 if (!tmp.empty()) 120 { 121 throw sdbusplus::xyz::openbmc_project::Common::Error:: 122 TooManyResources(); 123 } 124 } 125 catch (const std::exception&) 126 { 127 /* The sensor object path is not created */ 128 } 129 130 auto& bus = pldm::utils::DBusHandler::getBus(); 131 try 132 { 133 associationDefinitionsIntf = 134 std::make_unique<AssociationDefinitionsInft>(bus, path.c_str()); 135 } 136 catch (const sdbusplus::exception_t& e) 137 { 138 lg2::error( 139 "Failed to create association interface for numeric sensor {PATH} error - {ERROR}", 140 "PATH", path, "ERROR", e); 141 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 142 } 143 144 associationDefinitionsIntf->associations( 145 {{"chassis", "all_sensors", associationPath}}); 146 147 double maxValue = std::numeric_limits<double>::quiet_NaN(); 148 double minValue = std::numeric_limits<double>::quiet_NaN(); 149 150 switch (pdr->sensor_data_size) 151 { 152 case PLDM_SENSOR_DATA_SIZE_UINT8: 153 maxValue = pdr->max_readable.value_u8; 154 minValue = pdr->min_readable.value_u8; 155 hysteresis = pdr->hysteresis.value_u8; 156 break; 157 case PLDM_SENSOR_DATA_SIZE_SINT8: 158 maxValue = pdr->max_readable.value_s8; 159 minValue = pdr->min_readable.value_s8; 160 hysteresis = pdr->hysteresis.value_s8; 161 break; 162 case PLDM_SENSOR_DATA_SIZE_UINT16: 163 maxValue = pdr->max_readable.value_u16; 164 minValue = pdr->min_readable.value_u16; 165 hysteresis = pdr->hysteresis.value_u16; 166 break; 167 case PLDM_SENSOR_DATA_SIZE_SINT16: 168 maxValue = pdr->max_readable.value_s16; 169 minValue = pdr->min_readable.value_s16; 170 hysteresis = pdr->hysteresis.value_s16; 171 break; 172 case PLDM_SENSOR_DATA_SIZE_UINT32: 173 maxValue = pdr->max_readable.value_u32; 174 minValue = pdr->min_readable.value_u32; 175 hysteresis = pdr->hysteresis.value_u32; 176 break; 177 case PLDM_SENSOR_DATA_SIZE_SINT32: 178 maxValue = pdr->max_readable.value_s32; 179 minValue = pdr->min_readable.value_s32; 180 hysteresis = pdr->hysteresis.value_s32; 181 break; 182 } 183 184 bool hasCriticalThresholds = false; 185 bool hasWarningThresholds = false; 186 double criticalHigh = std::numeric_limits<double>::quiet_NaN(); 187 double criticalLow = std::numeric_limits<double>::quiet_NaN(); 188 double warningHigh = std::numeric_limits<double>::quiet_NaN(); 189 double warningLow = std::numeric_limits<double>::quiet_NaN(); 190 191 if (pdr->supported_thresholds.bits.bit0) 192 { 193 hasWarningThresholds = true; 194 switch (pdr->range_field_format) 195 { 196 case PLDM_RANGE_FIELD_FORMAT_UINT8: 197 warningHigh = pdr->warning_high.value_u8; 198 break; 199 case PLDM_RANGE_FIELD_FORMAT_SINT8: 200 warningHigh = pdr->warning_high.value_s8; 201 break; 202 case PLDM_RANGE_FIELD_FORMAT_UINT16: 203 warningHigh = pdr->warning_high.value_u16; 204 break; 205 case PLDM_RANGE_FIELD_FORMAT_SINT16: 206 warningHigh = pdr->warning_high.value_s16; 207 break; 208 case PLDM_RANGE_FIELD_FORMAT_UINT32: 209 warningHigh = pdr->warning_high.value_u32; 210 break; 211 case PLDM_RANGE_FIELD_FORMAT_SINT32: 212 warningHigh = pdr->warning_high.value_s32; 213 break; 214 case PLDM_RANGE_FIELD_FORMAT_REAL32: 215 warningHigh = pdr->warning_high.value_f32; 216 break; 217 } 218 } 219 220 if (pdr->supported_thresholds.bits.bit3) 221 { 222 hasWarningThresholds = true; 223 switch (pdr->range_field_format) 224 { 225 case PLDM_RANGE_FIELD_FORMAT_UINT8: 226 warningLow = pdr->warning_low.value_u8; 227 break; 228 case PLDM_RANGE_FIELD_FORMAT_SINT8: 229 warningLow = pdr->warning_low.value_s8; 230 break; 231 case PLDM_RANGE_FIELD_FORMAT_UINT16: 232 warningLow = pdr->warning_low.value_u16; 233 break; 234 case PLDM_RANGE_FIELD_FORMAT_SINT16: 235 warningLow = pdr->warning_low.value_s16; 236 break; 237 case PLDM_RANGE_FIELD_FORMAT_UINT32: 238 warningLow = pdr->warning_low.value_u32; 239 break; 240 case PLDM_RANGE_FIELD_FORMAT_SINT32: 241 warningLow = pdr->warning_low.value_s32; 242 break; 243 case PLDM_RANGE_FIELD_FORMAT_REAL32: 244 warningLow = pdr->warning_low.value_f32; 245 break; 246 } 247 } 248 249 if (pdr->supported_thresholds.bits.bit1) 250 { 251 hasCriticalThresholds = true; 252 switch (pdr->range_field_format) 253 { 254 case PLDM_RANGE_FIELD_FORMAT_UINT8: 255 criticalHigh = pdr->critical_high.value_u8; 256 break; 257 case PLDM_RANGE_FIELD_FORMAT_SINT8: 258 criticalHigh = pdr->critical_high.value_s8; 259 break; 260 case PLDM_RANGE_FIELD_FORMAT_UINT16: 261 criticalHigh = pdr->critical_high.value_u16; 262 break; 263 case PLDM_RANGE_FIELD_FORMAT_SINT16: 264 criticalHigh = pdr->critical_high.value_s16; 265 break; 266 case PLDM_RANGE_FIELD_FORMAT_UINT32: 267 criticalHigh = pdr->critical_high.value_u32; 268 break; 269 case PLDM_RANGE_FIELD_FORMAT_SINT32: 270 criticalHigh = pdr->critical_high.value_s32; 271 break; 272 case PLDM_RANGE_FIELD_FORMAT_REAL32: 273 criticalHigh = pdr->critical_high.value_f32; 274 break; 275 } 276 } 277 278 if (pdr->supported_thresholds.bits.bit4) 279 { 280 hasCriticalThresholds = true; 281 switch (pdr->range_field_format) 282 { 283 case PLDM_RANGE_FIELD_FORMAT_UINT8: 284 criticalLow = pdr->critical_low.value_u8; 285 break; 286 case PLDM_RANGE_FIELD_FORMAT_SINT8: 287 criticalLow = pdr->critical_low.value_s8; 288 break; 289 case PLDM_RANGE_FIELD_FORMAT_UINT16: 290 criticalLow = pdr->critical_low.value_u16; 291 break; 292 case PLDM_RANGE_FIELD_FORMAT_SINT16: 293 criticalLow = pdr->critical_low.value_s16; 294 break; 295 case PLDM_RANGE_FIELD_FORMAT_UINT32: 296 criticalLow = pdr->critical_low.value_u32; 297 break; 298 case PLDM_RANGE_FIELD_FORMAT_SINT32: 299 criticalLow = pdr->critical_low.value_s32; 300 break; 301 case PLDM_RANGE_FIELD_FORMAT_REAL32: 302 criticalLow = pdr->critical_low.value_f32; 303 break; 304 } 305 } 306 307 resolution = pdr->resolution; 308 offset = pdr->offset; 309 baseUnitModifier = pdr->unit_modifier; 310 timeStamp = 0; 311 312 /** 313 * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds 314 * updateTime is in microseconds 315 */ 316 updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000); 317 if (!std::isnan(pdr->update_interval)) 318 { 319 updateTime = pdr->update_interval * 1000000; 320 } 321 322 if (!useMetricInterface) 323 { 324 try 325 { 326 valueIntf = std::make_unique<ValueIntf>(bus, path.c_str()); 327 } 328 catch (const sdbusplus::exception_t& e) 329 { 330 lg2::error( 331 "Failed to create Value interface for numeric sensor {PATH} error - {ERROR}", 332 "PATH", path, "ERROR", e); 333 throw sdbusplus::xyz::openbmc_project::Common::Error:: 334 InvalidArgument(); 335 } 336 valueIntf->maxValue(unitModifier(conversionFormula(maxValue))); 337 valueIntf->minValue(unitModifier(conversionFormula(minValue))); 338 valueIntf->unit(sensorUnit); 339 } 340 else 341 { 342 try 343 { 344 metricIntf = std::make_unique<MetricIntf>(bus, path.c_str()); 345 } 346 catch (const sdbusplus::exception_t& e) 347 { 348 lg2::error( 349 "Failed to create Metric interface for numeric sensor {PATH} error - {ERROR}", 350 "PATH", path, "ERROR", e); 351 throw sdbusplus::xyz::openbmc_project::Common::Error:: 352 InvalidArgument(); 353 } 354 metricIntf->maxValue(unitModifier(conversionFormula(maxValue))); 355 metricIntf->minValue(unitModifier(conversionFormula(minValue))); 356 metricIntf->unit(metricUnit); 357 } 358 359 hysteresis = unitModifier(conversionFormula(hysteresis)); 360 361 if (!createInventoryPath(associationPath, sensorName, pdr->entity_type, 362 pdr->entity_instance_num, pdr->container_id)) 363 { 364 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 365 } 366 367 try 368 { 369 availabilityIntf = 370 std::make_unique<AvailabilityIntf>(bus, path.c_str()); 371 } 372 catch (const sdbusplus::exception_t& e) 373 { 374 lg2::error( 375 "Failed to create Availability interface for numeric sensor {PATH} error - {ERROR}", 376 "PATH", path, "ERROR", e); 377 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 378 } 379 availabilityIntf->available(true); 380 381 try 382 { 383 operationalStatusIntf = 384 std::make_unique<OperationalStatusIntf>(bus, path.c_str()); 385 } 386 catch (const sdbusplus::exception_t& e) 387 { 388 lg2::error( 389 "Failed to create Operation status interface for numeric sensor {PATH} error - {ERROR}", 390 "PATH", path, "ERROR", e); 391 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 392 } 393 operationalStatusIntf->functional(!sensorDisabled); 394 395 if (hasWarningThresholds && !useMetricInterface) 396 { 397 try 398 { 399 thresholdWarningIntf = 400 std::make_unique<ThresholdWarningIntf>(bus, path.c_str()); 401 } 402 catch (const sdbusplus::exception_t& e) 403 { 404 lg2::error( 405 "Failed to create Threshold warning interface for numeric sensor {PATH} error - {ERROR}", 406 "PATH", path, "ERROR", e); 407 throw sdbusplus::xyz::openbmc_project::Common::Error:: 408 InvalidArgument(); 409 } 410 thresholdWarningIntf->warningHigh(unitModifier(warningHigh)); 411 thresholdWarningIntf->warningLow(unitModifier(warningLow)); 412 } 413 414 if (hasCriticalThresholds && !useMetricInterface) 415 { 416 try 417 { 418 thresholdCriticalIntf = 419 std::make_unique<ThresholdCriticalIntf>(bus, path.c_str()); 420 } 421 catch (const sdbusplus::exception_t& e) 422 { 423 lg2::error( 424 "Failed to create Threshold critical interface for numeric sensor {PATH} error - {ERROR}", 425 "PATH", path, "ERROR", e); 426 throw sdbusplus::xyz::openbmc_project::Common::Error:: 427 InvalidArgument(); 428 } 429 thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh)); 430 thresholdCriticalIntf->criticalLow(unitModifier(criticalLow)); 431 } 432 } 433 434 NumericSensor::NumericSensor( 435 const pldm_tid_t tid, const bool sensorDisabled, 436 std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr, 437 std::string& sensorName, std::string& associationPath) : 438 tid(tid), sensorName(sensorName) 439 { 440 if (!pdr) 441 { 442 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 443 } 444 445 sensorId = pdr->sensor_id; 446 std::string path; 447 SensorUnit sensorUnit = SensorUnit::DegreesC; 448 MetricUnit metricUnit = MetricUnit::Count; 449 useMetricInterface = false; 450 451 switch (pdr->base_unit) 452 { 453 case PLDM_SENSOR_UNIT_DEGRESS_C: 454 sensorNameSpace = "/xyz/openbmc_project/sensors/temperature/"; 455 sensorUnit = SensorUnit::DegreesC; 456 break; 457 case PLDM_SENSOR_UNIT_VOLTS: 458 sensorNameSpace = "/xyz/openbmc_project/sensors/voltage/"; 459 sensorUnit = SensorUnit::Volts; 460 break; 461 case PLDM_SENSOR_UNIT_AMPS: 462 sensorNameSpace = "/xyz/openbmc_project/sensors/current/"; 463 sensorUnit = SensorUnit::Amperes; 464 break; 465 case PLDM_SENSOR_UNIT_RPM: 466 sensorNameSpace = "/xyz/openbmc_project/sensors/fan_pwm/"; 467 sensorUnit = SensorUnit::RPMS; 468 break; 469 case PLDM_SENSOR_UNIT_WATTS: 470 sensorNameSpace = "/xyz/openbmc_project/sensors/power/"; 471 sensorUnit = SensorUnit::Watts; 472 break; 473 case PLDM_SENSOR_UNIT_JOULES: 474 sensorNameSpace = "/xyz/openbmc_project/sensors/energy/"; 475 sensorUnit = SensorUnit::Joules; 476 break; 477 case PLDM_SENSOR_UNIT_PERCENTAGE: 478 sensorNameSpace = "/xyz/openbmc_project/sensors/utilization/"; 479 sensorUnit = SensorUnit::Percent; 480 break; 481 case PLDM_SENSOR_UNIT_COUNTS: 482 case PLDM_SENSOR_UNIT_CORRECTED_ERRORS: 483 case PLDM_SENSOR_UNIT_UNCORRECTABLE_ERRORS: 484 sensorNameSpace = "/xyz/openbmc_project/metric/count/"; 485 useMetricInterface = true; 486 break; 487 case PLDM_SENSOR_UNIT_OEMUNIT: 488 sensorNameSpace = "/xyz/openbmc_project/metric/oem/"; 489 useMetricInterface = true; 490 break; 491 default: 492 lg2::error("Sensor {NAME} has Invalid baseUnit {UNIT}.", "NAME", 493 sensorName, "UNIT", pdr->base_unit); 494 throw sdbusplus::xyz::openbmc_project::Common::Error:: 495 InvalidArgument(); 496 break; 497 } 498 499 path = sensorNameSpace + sensorName; 500 try 501 { 502 std::string tmp{}; 503 std::string interface = SENSOR_VALUE_INTF; 504 if (useMetricInterface) 505 { 506 interface = METRIC_VALUE_INTF; 507 } 508 tmp = pldm::utils::DBusHandler().getService(path.c_str(), 509 interface.c_str()); 510 511 if (!tmp.empty()) 512 { 513 throw sdbusplus::xyz::openbmc_project::Common::Error:: 514 TooManyResources(); 515 } 516 } 517 catch (const std::exception&) 518 { 519 /* The sensor object path is not created */ 520 } 521 522 auto& bus = pldm::utils::DBusHandler::getBus(); 523 try 524 { 525 associationDefinitionsIntf = 526 std::make_unique<AssociationDefinitionsInft>(bus, path.c_str()); 527 } 528 catch (const sdbusplus::exception_t& e) 529 { 530 lg2::error( 531 "Failed to create Association interface for compact numeric sensor {PATH} error - {ERROR}", 532 "PATH", path, "ERROR", e); 533 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 534 } 535 associationDefinitionsIntf->associations( 536 {{"chassis", "all_sensors", associationPath.c_str()}}); 537 538 double maxValue = std::numeric_limits<double>::quiet_NaN(); 539 double minValue = std::numeric_limits<double>::quiet_NaN(); 540 bool hasWarningThresholds = false; 541 bool hasCriticalThresholds = false; 542 double criticalHigh = std::numeric_limits<double>::quiet_NaN(); 543 double criticalLow = std::numeric_limits<double>::quiet_NaN(); 544 double warningHigh = std::numeric_limits<double>::quiet_NaN(); 545 double warningLow = std::numeric_limits<double>::quiet_NaN(); 546 547 if (pdr->range_field_support.bits.bit0) 548 { 549 hasWarningThresholds = true; 550 warningHigh = pdr->warning_high; 551 } 552 if (pdr->range_field_support.bits.bit1) 553 { 554 hasWarningThresholds = true; 555 warningLow = pdr->warning_low; 556 } 557 558 if (pdr->range_field_support.bits.bit2) 559 { 560 hasCriticalThresholds = true; 561 criticalHigh = pdr->critical_high; 562 } 563 564 if (pdr->range_field_support.bits.bit3) 565 { 566 hasCriticalThresholds = true; 567 criticalLow = pdr->critical_low; 568 } 569 570 resolution = std::numeric_limits<double>::quiet_NaN(); 571 offset = std::numeric_limits<double>::quiet_NaN(); 572 baseUnitModifier = pdr->unit_modifier; 573 timeStamp = 0; 574 hysteresis = 0; 575 576 /** 577 * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds 578 * updateTime is in microseconds 579 */ 580 updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000); 581 582 if (!useMetricInterface) 583 { 584 try 585 { 586 valueIntf = std::make_unique<ValueIntf>(bus, path.c_str()); 587 } 588 catch (const sdbusplus::exception_t& e) 589 { 590 lg2::error( 591 "Failed to create Value interface for compact numeric sensor {PATH} error - {ERROR}", 592 "PATH", path, "ERROR", e); 593 throw sdbusplus::xyz::openbmc_project::Common::Error:: 594 InvalidArgument(); 595 } 596 valueIntf->maxValue(unitModifier(conversionFormula(maxValue))); 597 valueIntf->minValue(unitModifier(conversionFormula(minValue))); 598 valueIntf->unit(sensorUnit); 599 } 600 else 601 { 602 try 603 { 604 metricIntf = std::make_unique<MetricIntf>(bus, path.c_str()); 605 } 606 catch (const sdbusplus::exception_t& e) 607 { 608 lg2::error( 609 "Failed to create Metric interface for compact numeric sensor {PATH} error - {ERROR}", 610 "PATH", path, "ERROR", e); 611 throw sdbusplus::xyz::openbmc_project::Common::Error:: 612 InvalidArgument(); 613 } 614 metricIntf->maxValue(unitModifier(conversionFormula(maxValue))); 615 metricIntf->minValue(unitModifier(conversionFormula(minValue))); 616 metricIntf->unit(metricUnit); 617 } 618 619 hysteresis = unitModifier(conversionFormula(hysteresis)); 620 621 if (!createInventoryPath(associationPath, sensorName, pdr->entity_type, 622 pdr->entity_instance, pdr->container_id)) 623 { 624 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 625 } 626 627 try 628 { 629 availabilityIntf = 630 std::make_unique<AvailabilityIntf>(bus, path.c_str()); 631 } 632 catch (const sdbusplus::exception_t& e) 633 { 634 lg2::error( 635 "Failed to create Availability interface for compact numeric sensor {PATH} error - {ERROR}", 636 "PATH", path, "ERROR", e); 637 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 638 } 639 availabilityIntf->available(true); 640 641 try 642 { 643 operationalStatusIntf = 644 std::make_unique<OperationalStatusIntf>(bus, path.c_str()); 645 } 646 catch (const sdbusplus::exception_t& e) 647 { 648 lg2::error( 649 "Failed to create Operational status interface for compact numeric sensor {PATH} error - {ERROR}", 650 "PATH", path, "ERROR", e); 651 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 652 } 653 operationalStatusIntf->functional(!sensorDisabled); 654 655 if (hasWarningThresholds && !useMetricInterface) 656 { 657 try 658 { 659 thresholdWarningIntf = 660 std::make_unique<ThresholdWarningIntf>(bus, path.c_str()); 661 } 662 catch (const sdbusplus::exception_t& e) 663 { 664 lg2::error( 665 "Failed to create Warning threshold interface for compact numeric sensor {PATH} error - {ERROR}", 666 "PATH", path, "ERROR", e); 667 throw sdbusplus::xyz::openbmc_project::Common::Error:: 668 InvalidArgument(); 669 } 670 thresholdWarningIntf->warningHigh(unitModifier(warningHigh)); 671 thresholdWarningIntf->warningLow(unitModifier(warningLow)); 672 } 673 674 if (hasCriticalThresholds && !useMetricInterface) 675 { 676 try 677 { 678 thresholdCriticalIntf = 679 std::make_unique<ThresholdCriticalIntf>(bus, path.c_str()); 680 } 681 catch (const sdbusplus::exception_t& e) 682 { 683 lg2::error( 684 "Failed to create Critical threshold interface for compact numeric sensor {PATH} error - {ERROR}", 685 "PATH", path, "ERROR", e); 686 throw sdbusplus::xyz::openbmc_project::Common::Error:: 687 InvalidArgument(); 688 } 689 thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh)); 690 thresholdCriticalIntf->criticalLow(unitModifier(criticalLow)); 691 } 692 } 693 694 double NumericSensor::conversionFormula(double value) 695 { 696 double convertedValue = value; 697 convertedValue *= std::isnan(resolution) ? 1 : resolution; 698 convertedValue += std::isnan(offset) ? 0 : offset; 699 return convertedValue; 700 } 701 702 double NumericSensor::unitModifier(double value) 703 { 704 return std::isnan(value) ? value : value * std::pow(10, baseUnitModifier); 705 } 706 707 void NumericSensor::updateReading(bool available, bool functional, double value) 708 { 709 if (!availabilityIntf || !operationalStatusIntf || 710 (!useMetricInterface && !valueIntf) || 711 (useMetricInterface && !metricIntf)) 712 { 713 lg2::error( 714 "Failed to update sensor {NAME} D-Bus interface don't exist.", 715 "NAME", sensorName); 716 return; 717 } 718 availabilityIntf->available(available); 719 operationalStatusIntf->functional(functional); 720 double curValue = 0; 721 if (!useMetricInterface) 722 { 723 curValue = valueIntf->value(); 724 } 725 else 726 { 727 curValue = metricIntf->value(); 728 } 729 730 double newValue = std::numeric_limits<double>::quiet_NaN(); 731 if (functional && available) 732 { 733 newValue = unitModifier(conversionFormula(value)); 734 if (newValue != curValue && 735 (!std::isnan(newValue) || !std::isnan(curValue))) 736 { 737 if (!useMetricInterface) 738 { 739 valueIntf->value(newValue); 740 updateThresholds(); 741 } 742 else 743 { 744 metricIntf->value(newValue); 745 } 746 } 747 } 748 else 749 { 750 if (newValue != curValue && 751 (!std::isnan(newValue) || !std::isnan(curValue))) 752 { 753 if (!useMetricInterface) 754 { 755 valueIntf->value(std::numeric_limits<double>::quiet_NaN()); 756 } 757 else 758 { 759 metricIntf->value(std::numeric_limits<double>::quiet_NaN()); 760 } 761 } 762 } 763 } 764 765 void NumericSensor::handleErrGetSensorReading() 766 { 767 if (!operationalStatusIntf || (!useMetricInterface && !valueIntf) || 768 (useMetricInterface && !metricIntf)) 769 { 770 lg2::error( 771 "Failed to update sensor {NAME} D-Bus interfaces don't exist.", 772 "NAME", sensorName); 773 return; 774 } 775 operationalStatusIntf->functional(false); 776 if (!useMetricInterface) 777 { 778 valueIntf->value(std::numeric_limits<double>::quiet_NaN()); 779 } 780 else 781 { 782 metricIntf->value(std::numeric_limits<double>::quiet_NaN()); 783 } 784 } 785 786 bool NumericSensor::checkThreshold(bool alarm, bool direction, double value, 787 double threshold, double hyst) 788 { 789 if (direction) 790 { 791 if (value >= threshold) 792 { 793 return true; 794 } 795 if (value < (threshold - hyst)) 796 { 797 return false; 798 } 799 } 800 else 801 { 802 if (value <= threshold) 803 { 804 return true; 805 } 806 if (value > (threshold + hyst)) 807 { 808 return false; 809 } 810 } 811 return alarm; 812 } 813 814 void NumericSensor::updateThresholds() 815 { 816 double value = std::numeric_limits<double>::quiet_NaN(); 817 818 if ((!useMetricInterface && !valueIntf) || 819 (useMetricInterface && !metricIntf)) 820 { 821 lg2::error( 822 "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.", 823 "NAME", sensorName); 824 return; 825 } 826 if (!useMetricInterface) 827 { 828 value = valueIntf->value(); 829 } 830 else 831 { 832 value = metricIntf->value(); 833 } 834 if (thresholdWarningIntf && 835 !std::isnan(thresholdWarningIntf->warningHigh())) 836 { 837 auto threshold = thresholdWarningIntf->warningHigh(); 838 auto alarm = thresholdWarningIntf->warningAlarmHigh(); 839 auto newAlarm = 840 checkThreshold(alarm, true, value, threshold, hysteresis); 841 if (alarm != newAlarm) 842 { 843 thresholdWarningIntf->warningAlarmHigh(newAlarm); 844 if (newAlarm) 845 { 846 thresholdWarningIntf->warningHighAlarmAsserted(value); 847 } 848 else 849 { 850 thresholdWarningIntf->warningHighAlarmDeasserted(value); 851 } 852 } 853 } 854 855 if (thresholdWarningIntf && !std::isnan(thresholdWarningIntf->warningLow())) 856 { 857 auto threshold = thresholdWarningIntf->warningLow(); 858 auto alarm = thresholdWarningIntf->warningAlarmLow(); 859 auto newAlarm = 860 checkThreshold(alarm, false, value, threshold, hysteresis); 861 if (alarm != newAlarm) 862 { 863 thresholdWarningIntf->warningAlarmLow(newAlarm); 864 if (newAlarm) 865 { 866 thresholdWarningIntf->warningLowAlarmAsserted(value); 867 } 868 else 869 { 870 thresholdWarningIntf->warningLowAlarmDeasserted(value); 871 } 872 } 873 } 874 875 if (thresholdCriticalIntf && 876 !std::isnan(thresholdCriticalIntf->criticalHigh())) 877 { 878 auto threshold = thresholdCriticalIntf->criticalHigh(); 879 auto alarm = thresholdCriticalIntf->criticalAlarmHigh(); 880 auto newAlarm = 881 checkThreshold(alarm, true, value, threshold, hysteresis); 882 if (alarm != newAlarm) 883 { 884 thresholdCriticalIntf->criticalAlarmHigh(newAlarm); 885 if (newAlarm) 886 { 887 thresholdCriticalIntf->criticalHighAlarmAsserted(value); 888 } 889 else 890 { 891 thresholdCriticalIntf->criticalHighAlarmDeasserted(value); 892 } 893 } 894 } 895 896 if (thresholdCriticalIntf && 897 !std::isnan(thresholdCriticalIntf->criticalLow())) 898 { 899 auto threshold = thresholdCriticalIntf->criticalLow(); 900 auto alarm = thresholdCriticalIntf->criticalAlarmLow(); 901 auto newAlarm = 902 checkThreshold(alarm, false, value, threshold, hysteresis); 903 if (alarm != newAlarm) 904 { 905 thresholdCriticalIntf->criticalAlarmLow(newAlarm); 906 if (newAlarm) 907 { 908 thresholdCriticalIntf->criticalLowAlarmAsserted(value); 909 } 910 else 911 { 912 thresholdCriticalIntf->criticalLowAlarmDeasserted(value); 913 } 914 } 915 } 916 } 917 918 int NumericSensor::triggerThresholdEvent( 919 pldm::utils::Level eventType, pldm::utils::Direction direction, 920 double rawValue, bool newAlarm, bool assert) 921 { 922 if (!valueIntf) 923 { 924 lg2::error( 925 "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.", 926 "NAME", sensorName); 927 return PLDM_ERROR; 928 } 929 930 auto value = unitModifier(conversionFormula(rawValue)); 931 lg2::error( 932 "triggerThresholdEvent eventType {TID}, direction {SID} value {VAL} newAlarm {PSTATE} assert {ESTATE}", 933 "TID", eventType, "SID", direction, "VAL", value, "PSTATE", newAlarm, 934 "ESTATE", assert); 935 936 switch (eventType) 937 { 938 case pldm::utils::Level::WARNING: 939 { 940 if (!thresholdWarningIntf) 941 { 942 lg2::error( 943 "Error:Trigger sensor warning event for non warning threshold sensors {NAME}", 944 "NAME", sensorName); 945 return PLDM_ERROR; 946 } 947 if (direction == pldm::utils::Direction::HIGH && 948 !std::isnan(thresholdWarningIntf->warningHigh())) 949 { 950 auto alarm = thresholdWarningIntf->warningAlarmHigh(); 951 if (alarm == newAlarm) 952 { 953 return PLDM_SUCCESS; 954 } 955 thresholdWarningIntf->warningAlarmHigh(newAlarm); 956 if (assert) 957 { 958 thresholdWarningIntf->warningHighAlarmAsserted(value); 959 } 960 else 961 { 962 thresholdWarningIntf->warningHighAlarmDeasserted(value); 963 } 964 } 965 else if (direction == pldm::utils::Direction::LOW && 966 !std::isnan(thresholdWarningIntf->warningLow())) 967 { 968 auto alarm = thresholdWarningIntf->warningAlarmLow(); 969 if (alarm == newAlarm) 970 { 971 return PLDM_SUCCESS; 972 } 973 thresholdWarningIntf->warningAlarmLow(newAlarm); 974 if (assert) 975 { 976 thresholdWarningIntf->warningLowAlarmAsserted(value); 977 } 978 else 979 { 980 thresholdWarningIntf->warningLowAlarmDeasserted(value); 981 } 982 } 983 break; 984 } 985 case pldm::utils::Level::CRITICAL: 986 { 987 if (!thresholdCriticalIntf) 988 { 989 lg2::error( 990 "Error:Trigger sensor Critical event for non warning threshold sensors {NAME}", 991 "NAME", sensorName); 992 return PLDM_ERROR; 993 } 994 if (direction == pldm::utils::Direction::HIGH && 995 !std::isnan(thresholdCriticalIntf->criticalHigh())) 996 { 997 auto alarm = thresholdCriticalIntf->criticalAlarmHigh(); 998 if (alarm == newAlarm) 999 { 1000 return PLDM_SUCCESS; 1001 } 1002 thresholdCriticalIntf->criticalAlarmHigh(newAlarm); 1003 if (assert) 1004 { 1005 thresholdCriticalIntf->criticalHighAlarmAsserted(value); 1006 } 1007 else 1008 { 1009 thresholdCriticalIntf->criticalHighAlarmDeasserted(value); 1010 } 1011 } 1012 else if (direction == pldm::utils::Direction::LOW && 1013 !std::isnan(thresholdCriticalIntf->criticalLow())) 1014 { 1015 auto alarm = thresholdCriticalIntf->criticalAlarmLow(); 1016 if (alarm == newAlarm) 1017 { 1018 return PLDM_SUCCESS; 1019 } 1020 thresholdCriticalIntf->criticalAlarmLow(newAlarm); 1021 if (assert) 1022 { 1023 thresholdCriticalIntf->criticalLowAlarmAsserted(value); 1024 } 1025 else 1026 { 1027 thresholdCriticalIntf->criticalLowAlarmDeasserted(value); 1028 } 1029 } 1030 break; 1031 } 1032 1033 default: 1034 break; 1035 } 1036 1037 return PLDM_SUCCESS; 1038 } 1039 } // namespace platform_mc 1040 } // namespace pldm 1041