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