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