xref: /openbmc/pldm/platform-mc/numeric_sensor.cpp (revision 0469b56837cf4c972609832ae00f0441ec76049b)
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