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