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