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
createInventoryPath(const std::string & associationPath,const std::string & sensorName,const uint16_t entityType,const uint16_t entityInstanceNum,const uint16_t containerId)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
getSensorDataValue(uint8_t sensor_data_size,union_sensor_data_size & value)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
getRangeFieldValue(uint8_t range_field_format,union_range_field_format & value)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
setSensorUnit(uint8_t baseUnit)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
NumericSensor(const pldm_tid_t tid,const bool sensorDisabled,std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr,std::string & sensorName,std::string & associationPath)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::isfinite(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
NumericSensor(const pldm_tid_t tid,const bool sensorDisabled,std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr,std::string & sensorName,std::string & associationPath)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
conversionFormula(double value)589 double NumericSensor::conversionFormula(double value)
590 {
591 double convertedValue = value;
592 if (std::isfinite(resolution))
593 {
594 convertedValue *= resolution;
595 }
596 if (std::isfinite(offset))
597 {
598 convertedValue += offset;
599 }
600 return convertedValue;
601 }
602
unitModifier(double value)603 double NumericSensor::unitModifier(double value)
604 {
605 if (!std::isfinite(value))
606 {
607 return value;
608 }
609 return value * std::pow(10, baseUnitModifier);
610 }
611
updateReading(bool available,bool functional,double value)612 void NumericSensor::updateReading(bool available, bool functional, double value)
613 {
614 if (!availabilityIntf || !operationalStatusIntf ||
615 (!useMetricInterface && !valueIntf) ||
616 (useMetricInterface && !metricIntf))
617 {
618 lg2::error(
619 "Failed to update sensor {NAME} D-Bus interface don't exist.",
620 "NAME", sensorName);
621 return;
622 }
623 availabilityIntf->available(available);
624 operationalStatusIntf->functional(functional);
625 double curValue = 0;
626 if (!useMetricInterface)
627 {
628 curValue = valueIntf->value();
629 }
630 else
631 {
632 curValue = metricIntf->value();
633 }
634
635 double newValue = std::numeric_limits<double>::quiet_NaN();
636 if (functional && available)
637 {
638 newValue = unitModifier(conversionFormula(value));
639 if (newValue != curValue &&
640 (std::isfinite(newValue) || std::isfinite(curValue)))
641 {
642 if (!useMetricInterface)
643 {
644 valueIntf->value(newValue);
645 updateThresholds();
646 }
647 else
648 {
649 metricIntf->value(newValue);
650 }
651 }
652 }
653 else
654 {
655 if (newValue != curValue &&
656 (std::isfinite(newValue) || std::isfinite(curValue)))
657 {
658 if (!useMetricInterface)
659 {
660 valueIntf->value(std::numeric_limits<double>::quiet_NaN());
661 }
662 else
663 {
664 metricIntf->value(std::numeric_limits<double>::quiet_NaN());
665 }
666 }
667 }
668 }
669
handleErrGetSensorReading()670 void NumericSensor::handleErrGetSensorReading()
671 {
672 if (!operationalStatusIntf || (!useMetricInterface && !valueIntf) ||
673 (useMetricInterface && !metricIntf))
674 {
675 lg2::error(
676 "Failed to update sensor {NAME} D-Bus interfaces don't exist.",
677 "NAME", sensorName);
678 return;
679 }
680 operationalStatusIntf->functional(false);
681 if (!useMetricInterface)
682 {
683 valueIntf->value(std::numeric_limits<double>::quiet_NaN());
684 }
685 else
686 {
687 metricIntf->value(std::numeric_limits<double>::quiet_NaN());
688 }
689 }
690
checkThreshold(bool alarm,bool direction,double value,double threshold,double hyst)691 bool NumericSensor::checkThreshold(bool alarm, bool direction, double value,
692 double threshold, double hyst)
693 {
694 if (direction)
695 {
696 if (value >= threshold)
697 {
698 return true;
699 }
700 if (value < (threshold - hyst))
701 {
702 return false;
703 }
704 }
705 else
706 {
707 if (value <= threshold)
708 {
709 return true;
710 }
711 if (value > (threshold + hyst))
712 {
713 return false;
714 }
715 }
716 return alarm;
717 }
718
updateThresholds()719 void NumericSensor::updateThresholds()
720 {
721 double value = std::numeric_limits<double>::quiet_NaN();
722
723 if ((!useMetricInterface && !valueIntf) ||
724 (useMetricInterface && !metricIntf))
725 {
726 lg2::error(
727 "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.",
728 "NAME", sensorName);
729 return;
730 }
731 if (!useMetricInterface)
732 {
733 value = valueIntf->value();
734 }
735 else
736 {
737 value = metricIntf->value();
738 }
739 if (thresholdWarningIntf &&
740 std::isfinite(thresholdWarningIntf->warningHigh()))
741 {
742 auto threshold = thresholdWarningIntf->warningHigh();
743 auto alarm = thresholdWarningIntf->warningAlarmHigh();
744 auto newAlarm =
745 checkThreshold(alarm, true, value, threshold, hysteresis);
746 if (alarm != newAlarm)
747 {
748 thresholdWarningIntf->warningAlarmHigh(newAlarm);
749 if (newAlarm)
750 {
751 thresholdWarningIntf->warningHighAlarmAsserted(value);
752 }
753 else
754 {
755 thresholdWarningIntf->warningHighAlarmDeasserted(value);
756 }
757 }
758 }
759
760 if (thresholdWarningIntf &&
761 std::isfinite(thresholdWarningIntf->warningLow()))
762 {
763 auto threshold = thresholdWarningIntf->warningLow();
764 auto alarm = thresholdWarningIntf->warningAlarmLow();
765 auto newAlarm =
766 checkThreshold(alarm, false, value, threshold, hysteresis);
767 if (alarm != newAlarm)
768 {
769 thresholdWarningIntf->warningAlarmLow(newAlarm);
770 if (newAlarm)
771 {
772 thresholdWarningIntf->warningLowAlarmAsserted(value);
773 }
774 else
775 {
776 thresholdWarningIntf->warningLowAlarmDeasserted(value);
777 }
778 }
779 }
780
781 if (thresholdCriticalIntf &&
782 std::isfinite(thresholdCriticalIntf->criticalHigh()))
783 {
784 auto threshold = thresholdCriticalIntf->criticalHigh();
785 auto alarm = thresholdCriticalIntf->criticalAlarmHigh();
786 auto newAlarm =
787 checkThreshold(alarm, true, value, threshold, hysteresis);
788 if (alarm != newAlarm)
789 {
790 thresholdCriticalIntf->criticalAlarmHigh(newAlarm);
791 if (newAlarm)
792 {
793 thresholdCriticalIntf->criticalHighAlarmAsserted(value);
794 }
795 else
796 {
797 thresholdCriticalIntf->criticalHighAlarmDeasserted(value);
798 }
799 }
800 }
801
802 if (thresholdCriticalIntf &&
803 std::isfinite(thresholdCriticalIntf->criticalLow()))
804 {
805 auto threshold = thresholdCriticalIntf->criticalLow();
806 auto alarm = thresholdCriticalIntf->criticalAlarmLow();
807 auto newAlarm =
808 checkThreshold(alarm, false, value, threshold, hysteresis);
809 if (alarm != newAlarm)
810 {
811 thresholdCriticalIntf->criticalAlarmLow(newAlarm);
812 if (newAlarm)
813 {
814 thresholdCriticalIntf->criticalLowAlarmAsserted(value);
815 }
816 else
817 {
818 thresholdCriticalIntf->criticalLowAlarmDeasserted(value);
819 }
820 }
821 }
822 }
823
triggerThresholdEvent(pldm::utils::Level eventType,pldm::utils::Direction direction,double rawValue,bool newAlarm,bool assert)824 int NumericSensor::triggerThresholdEvent(
825 pldm::utils::Level eventType, pldm::utils::Direction direction,
826 double rawValue, bool newAlarm, bool assert)
827 {
828 if (!valueIntf)
829 {
830 lg2::error(
831 "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.",
832 "NAME", sensorName);
833 return PLDM_ERROR;
834 }
835
836 auto value = unitModifier(conversionFormula(rawValue));
837 lg2::error(
838 "triggerThresholdEvent eventType {TID}, direction {SID} value {VAL} newAlarm {PSTATE} assert {ESTATE}",
839 "TID", eventType, "SID", direction, "VAL", value, "PSTATE", newAlarm,
840 "ESTATE", assert);
841
842 switch (eventType)
843 {
844 case pldm::utils::Level::WARNING:
845 {
846 if (!thresholdWarningIntf)
847 {
848 lg2::error(
849 "Error:Trigger sensor warning event for non warning threshold sensors {NAME}",
850 "NAME", sensorName);
851 return PLDM_ERROR;
852 }
853 if (direction == pldm::utils::Direction::HIGH &&
854 std::isfinite(thresholdWarningIntf->warningHigh()))
855 {
856 auto alarm = thresholdWarningIntf->warningAlarmHigh();
857 if (alarm == newAlarm)
858 {
859 return PLDM_SUCCESS;
860 }
861 thresholdWarningIntf->warningAlarmHigh(newAlarm);
862 if (assert)
863 {
864 thresholdWarningIntf->warningHighAlarmAsserted(value);
865 }
866 else
867 {
868 thresholdWarningIntf->warningHighAlarmDeasserted(value);
869 }
870 }
871 else if (direction == pldm::utils::Direction::LOW &&
872 std::isfinite(thresholdWarningIntf->warningLow()))
873 {
874 auto alarm = thresholdWarningIntf->warningAlarmLow();
875 if (alarm == newAlarm)
876 {
877 return PLDM_SUCCESS;
878 }
879 thresholdWarningIntf->warningAlarmLow(newAlarm);
880 if (assert)
881 {
882 thresholdWarningIntf->warningLowAlarmAsserted(value);
883 }
884 else
885 {
886 thresholdWarningIntf->warningLowAlarmDeasserted(value);
887 }
888 }
889 break;
890 }
891 case pldm::utils::Level::CRITICAL:
892 {
893 if (!thresholdCriticalIntf)
894 {
895 lg2::error(
896 "Error:Trigger sensor Critical event for non warning threshold sensors {NAME}",
897 "NAME", sensorName);
898 return PLDM_ERROR;
899 }
900 if (direction == pldm::utils::Direction::HIGH &&
901 std::isfinite(thresholdCriticalIntf->criticalHigh()))
902 {
903 auto alarm = thresholdCriticalIntf->criticalAlarmHigh();
904 if (alarm == newAlarm)
905 {
906 return PLDM_SUCCESS;
907 }
908 thresholdCriticalIntf->criticalAlarmHigh(newAlarm);
909 if (assert)
910 {
911 thresholdCriticalIntf->criticalHighAlarmAsserted(value);
912 }
913 else
914 {
915 thresholdCriticalIntf->criticalHighAlarmDeasserted(value);
916 }
917 }
918 else if (direction == pldm::utils::Direction::LOW &&
919 std::isfinite(thresholdCriticalIntf->criticalLow()))
920 {
921 auto alarm = thresholdCriticalIntf->criticalAlarmLow();
922 if (alarm == newAlarm)
923 {
924 return PLDM_SUCCESS;
925 }
926 thresholdCriticalIntf->criticalAlarmLow(newAlarm);
927 if (assert)
928 {
929 thresholdCriticalIntf->criticalLowAlarmAsserted(value);
930 }
931 else
932 {
933 thresholdCriticalIntf->criticalLowAlarmDeasserted(value);
934 }
935 }
936 break;
937 }
938
939 default:
940 break;
941 }
942
943 return PLDM_SUCCESS;
944 }
945 } // namespace platform_mc
946 } // namespace pldm
947