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 544 /** 545 * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds 546 * updateTime is in microseconds 547 */ 548 updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000); 549 550 if (!useMetricInterface) 551 { 552 try 553 { 554 valueIntf = std::make_unique<ValueIntf>(bus, path.c_str()); 555 } 556 catch (const sdbusplus::exception_t& e) 557 { 558 lg2::error( 559 "Failed to create Value interface for compact numeric sensor {PATH} error - {ERROR}", 560 "PATH", path, "ERROR", e); 561 throw sdbusplus::xyz::openbmc_project::Common::Error:: 562 InvalidArgument(); 563 } 564 valueIntf->maxValue(unitModifier(conversionFormula(maxValue))); 565 valueIntf->minValue(unitModifier(conversionFormula(minValue))); 566 valueIntf->unit(sensorUnit); 567 } 568 else 569 { 570 try 571 { 572 metricIntf = std::make_unique<MetricIntf>(bus, path.c_str()); 573 } 574 catch (const sdbusplus::exception_t& e) 575 { 576 lg2::error( 577 "Failed to create Metric interface for compact numeric sensor {PATH} error - {ERROR}", 578 "PATH", path, "ERROR", e); 579 throw sdbusplus::xyz::openbmc_project::Common::Error:: 580 InvalidArgument(); 581 } 582 metricIntf->maxValue(unitModifier(conversionFormula(maxValue))); 583 metricIntf->minValue(unitModifier(conversionFormula(minValue))); 584 metricIntf->unit(metricUnit); 585 } 586 587 hysteresis = unitModifier(conversionFormula(hysteresis)); 588 589 try 590 { 591 availabilityIntf = 592 std::make_unique<AvailabilityIntf>(bus, path.c_str()); 593 } 594 catch (const sdbusplus::exception_t& e) 595 { 596 lg2::error( 597 "Failed to create Availability interface for compact numeric sensor {PATH} error - {ERROR}", 598 "PATH", path, "ERROR", e); 599 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 600 } 601 availabilityIntf->available(true); 602 603 try 604 { 605 operationalStatusIntf = 606 std::make_unique<OperationalStatusIntf>(bus, path.c_str()); 607 } 608 catch (const sdbusplus::exception_t& e) 609 { 610 lg2::error( 611 "Failed to create Operational status interface for compact numeric sensor {PATH} error - {ERROR}", 612 "PATH", path, "ERROR", e); 613 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument(); 614 } 615 operationalStatusIntf->functional(!sensorDisabled); 616 617 if (hasWarningThresholds && !useMetricInterface) 618 { 619 try 620 { 621 thresholdWarningIntf = 622 std::make_unique<ThresholdWarningIntf>(bus, path.c_str()); 623 } 624 catch (const sdbusplus::exception_t& e) 625 { 626 lg2::error( 627 "Failed to create Warning threshold interface for compact numeric sensor {PATH} error - {ERROR}", 628 "PATH", path, "ERROR", e); 629 throw sdbusplus::xyz::openbmc_project::Common::Error:: 630 InvalidArgument(); 631 } 632 thresholdWarningIntf->warningHigh(unitModifier(warningHigh)); 633 thresholdWarningIntf->warningLow(unitModifier(warningLow)); 634 } 635 636 if (hasCriticalThresholds && !useMetricInterface) 637 { 638 try 639 { 640 thresholdCriticalIntf = 641 std::make_unique<ThresholdCriticalIntf>(bus, path.c_str()); 642 } 643 catch (const sdbusplus::exception_t& e) 644 { 645 lg2::error( 646 "Failed to create Critical threshold interface for compact numeric sensor {PATH} error - {ERROR}", 647 "PATH", path, "ERROR", e); 648 throw sdbusplus::xyz::openbmc_project::Common::Error:: 649 InvalidArgument(); 650 } 651 thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh)); 652 thresholdCriticalIntf->criticalLow(unitModifier(criticalLow)); 653 } 654 } 655 656 double NumericSensor::conversionFormula(double value) 657 { 658 double convertedValue = value; 659 convertedValue *= std::isnan(resolution) ? 1 : resolution; 660 convertedValue += std::isnan(offset) ? 0 : offset; 661 return convertedValue; 662 } 663 664 double NumericSensor::unitModifier(double value) 665 { 666 return std::isnan(value) ? value : value * std::pow(10, baseUnitModifier); 667 } 668 669 void NumericSensor::updateReading(bool available, bool functional, double value) 670 { 671 if (!availabilityIntf || !operationalStatusIntf || 672 (!useMetricInterface && !valueIntf) || 673 (useMetricInterface && !metricIntf)) 674 { 675 lg2::error( 676 "Failed to update sensor {NAME} D-Bus interface don't exist.", 677 "NAME", sensorName); 678 return; 679 } 680 availabilityIntf->available(available); 681 operationalStatusIntf->functional(functional); 682 double curValue = 0; 683 if (!useMetricInterface) 684 { 685 curValue = valueIntf->value(); 686 } 687 else 688 { 689 curValue = metricIntf->value(); 690 } 691 692 double newValue = std::numeric_limits<double>::quiet_NaN(); 693 if (functional && available) 694 { 695 newValue = unitModifier(conversionFormula(value)); 696 if (newValue != curValue && 697 (!std::isnan(newValue) || !std::isnan(curValue))) 698 { 699 if (!useMetricInterface) 700 { 701 valueIntf->value(newValue); 702 updateThresholds(); 703 } 704 else 705 { 706 metricIntf->value(newValue); 707 } 708 } 709 } 710 else 711 { 712 if (newValue != curValue && 713 (!std::isnan(newValue) || !std::isnan(curValue))) 714 { 715 if (!useMetricInterface) 716 { 717 valueIntf->value(std::numeric_limits<double>::quiet_NaN()); 718 } 719 else 720 { 721 metricIntf->value(std::numeric_limits<double>::quiet_NaN()); 722 } 723 } 724 } 725 } 726 727 void NumericSensor::handleErrGetSensorReading() 728 { 729 if (!operationalStatusIntf || (!useMetricInterface && !valueIntf) || 730 (useMetricInterface && !metricIntf)) 731 { 732 lg2::error( 733 "Failed to update sensor {NAME} D-Bus interfaces don't exist.", 734 "NAME", sensorName); 735 return; 736 } 737 operationalStatusIntf->functional(false); 738 if (!useMetricInterface) 739 { 740 valueIntf->value(std::numeric_limits<double>::quiet_NaN()); 741 } 742 else 743 { 744 metricIntf->value(std::numeric_limits<double>::quiet_NaN()); 745 } 746 } 747 748 bool NumericSensor::checkThreshold(bool alarm, bool direction, double value, 749 double threshold, double hyst) 750 { 751 if (direction) 752 { 753 if (value >= threshold) 754 { 755 return true; 756 } 757 if (value < (threshold - hyst)) 758 { 759 return false; 760 } 761 } 762 else 763 { 764 if (value <= threshold) 765 { 766 return true; 767 } 768 if (value > (threshold + hyst)) 769 { 770 return false; 771 } 772 } 773 return alarm; 774 } 775 776 void NumericSensor::updateThresholds() 777 { 778 double value = std::numeric_limits<double>::quiet_NaN(); 779 780 if ((!useMetricInterface && !valueIntf) || 781 (useMetricInterface && !metricIntf)) 782 { 783 lg2::error( 784 "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.", 785 "NAME", sensorName); 786 return; 787 } 788 if (!useMetricInterface) 789 { 790 value = valueIntf->value(); 791 } 792 else 793 { 794 value = metricIntf->value(); 795 } 796 if (thresholdWarningIntf && 797 !std::isnan(thresholdWarningIntf->warningHigh())) 798 { 799 auto threshold = thresholdWarningIntf->warningHigh(); 800 auto alarm = thresholdWarningIntf->warningAlarmHigh(); 801 auto newAlarm = 802 checkThreshold(alarm, true, value, threshold, hysteresis); 803 if (alarm != newAlarm) 804 { 805 thresholdWarningIntf->warningAlarmHigh(newAlarm); 806 if (newAlarm) 807 { 808 thresholdWarningIntf->warningHighAlarmAsserted(value); 809 } 810 else 811 { 812 thresholdWarningIntf->warningHighAlarmDeasserted(value); 813 } 814 } 815 } 816 817 if (thresholdWarningIntf && !std::isnan(thresholdWarningIntf->warningLow())) 818 { 819 auto threshold = thresholdWarningIntf->warningLow(); 820 auto alarm = thresholdWarningIntf->warningAlarmLow(); 821 auto newAlarm = 822 checkThreshold(alarm, false, value, threshold, hysteresis); 823 if (alarm != newAlarm) 824 { 825 thresholdWarningIntf->warningAlarmLow(newAlarm); 826 if (newAlarm) 827 { 828 thresholdWarningIntf->warningLowAlarmAsserted(value); 829 } 830 else 831 { 832 thresholdWarningIntf->warningLowAlarmDeasserted(value); 833 } 834 } 835 } 836 837 if (thresholdCriticalIntf && 838 !std::isnan(thresholdCriticalIntf->criticalHigh())) 839 { 840 auto threshold = thresholdCriticalIntf->criticalHigh(); 841 auto alarm = thresholdCriticalIntf->criticalAlarmHigh(); 842 auto newAlarm = 843 checkThreshold(alarm, true, value, threshold, hysteresis); 844 if (alarm != newAlarm) 845 { 846 thresholdCriticalIntf->criticalAlarmHigh(newAlarm); 847 if (newAlarm) 848 { 849 thresholdCriticalIntf->criticalHighAlarmAsserted(value); 850 } 851 else 852 { 853 thresholdCriticalIntf->criticalHighAlarmDeasserted(value); 854 } 855 } 856 } 857 858 if (thresholdCriticalIntf && 859 !std::isnan(thresholdCriticalIntf->criticalLow())) 860 { 861 auto threshold = thresholdCriticalIntf->criticalLow(); 862 auto alarm = thresholdCriticalIntf->criticalAlarmLow(); 863 auto newAlarm = 864 checkThreshold(alarm, false, value, threshold, hysteresis); 865 if (alarm != newAlarm) 866 { 867 thresholdCriticalIntf->criticalAlarmLow(newAlarm); 868 if (newAlarm) 869 { 870 thresholdCriticalIntf->criticalLowAlarmAsserted(value); 871 } 872 else 873 { 874 thresholdCriticalIntf->criticalLowAlarmDeasserted(value); 875 } 876 } 877 } 878 } 879 880 int NumericSensor::triggerThresholdEvent( 881 pldm::utils::Level eventType, pldm::utils::Direction direction, 882 double rawValue, bool newAlarm, bool assert) 883 { 884 if (!valueIntf) 885 { 886 lg2::error( 887 "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.", 888 "NAME", sensorName); 889 return PLDM_ERROR; 890 } 891 892 auto value = unitModifier(conversionFormula(rawValue)); 893 lg2::error( 894 "triggerThresholdEvent eventType {TID}, direction {SID} value {VAL} newAlarm {PSTATE} assert {ESTATE}", 895 "TID", eventType, "SID", direction, "VAL", value, "PSTATE", newAlarm, 896 "ESTATE", assert); 897 898 switch (eventType) 899 { 900 case pldm::utils::Level::WARNING: 901 { 902 if (!thresholdWarningIntf) 903 { 904 lg2::error( 905 "Error:Trigger sensor warning event for non warning threshold sensors {NAME}", 906 "NAME", sensorName); 907 return PLDM_ERROR; 908 } 909 if (direction == pldm::utils::Direction::HIGH && 910 !std::isnan(thresholdWarningIntf->warningHigh())) 911 { 912 auto alarm = thresholdWarningIntf->warningAlarmHigh(); 913 if (alarm == newAlarm) 914 { 915 return PLDM_SUCCESS; 916 } 917 thresholdWarningIntf->warningAlarmHigh(newAlarm); 918 if (assert) 919 { 920 thresholdWarningIntf->warningHighAlarmAsserted(value); 921 } 922 else 923 { 924 thresholdWarningIntf->warningHighAlarmDeasserted(value); 925 } 926 } 927 else if (direction == pldm::utils::Direction::LOW && 928 !std::isnan(thresholdWarningIntf->warningLow())) 929 { 930 auto alarm = thresholdWarningIntf->warningAlarmLow(); 931 if (alarm == newAlarm) 932 { 933 return PLDM_SUCCESS; 934 } 935 thresholdWarningIntf->warningAlarmLow(newAlarm); 936 if (assert) 937 { 938 thresholdWarningIntf->warningLowAlarmAsserted(value); 939 } 940 else 941 { 942 thresholdWarningIntf->warningLowAlarmDeasserted(value); 943 } 944 } 945 break; 946 } 947 case pldm::utils::Level::CRITICAL: 948 { 949 if (!thresholdCriticalIntf) 950 { 951 lg2::error( 952 "Error:Trigger sensor Critical event for non warning threshold sensors {NAME}", 953 "NAME", sensorName); 954 return PLDM_ERROR; 955 } 956 if (direction == pldm::utils::Direction::HIGH && 957 !std::isnan(thresholdCriticalIntf->criticalHigh())) 958 { 959 auto alarm = thresholdCriticalIntf->criticalAlarmHigh(); 960 if (alarm == newAlarm) 961 { 962 return PLDM_SUCCESS; 963 } 964 thresholdCriticalIntf->criticalAlarmHigh(newAlarm); 965 if (assert) 966 { 967 thresholdCriticalIntf->criticalHighAlarmAsserted(value); 968 } 969 else 970 { 971 thresholdCriticalIntf->criticalHighAlarmDeasserted(value); 972 } 973 } 974 else if (direction == pldm::utils::Direction::LOW && 975 !std::isnan(thresholdCriticalIntf->criticalLow())) 976 { 977 auto alarm = thresholdCriticalIntf->criticalAlarmLow(); 978 if (alarm == newAlarm) 979 { 980 return PLDM_SUCCESS; 981 } 982 thresholdCriticalIntf->criticalAlarmLow(newAlarm); 983 if (assert) 984 { 985 thresholdCriticalIntf->criticalLowAlarmAsserted(value); 986 } 987 else 988 { 989 thresholdCriticalIntf->criticalLowAlarmDeasserted(value); 990 } 991 } 992 break; 993 } 994 995 default: 996 break; 997 } 998 999 return PLDM_SUCCESS; 1000 } 1001 } // namespace platform_mc 1002 } // namespace pldm 1003