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 
NumericSensor(const pldm_tid_t tid,const bool sensorDisabled,std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr,std::string & sensorName,std::string & associationPath)18 NumericSensor::NumericSensor(
19     const pldm_tid_t tid, const bool sensorDisabled,
20     std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr, std::string& sensorName,
21     std::string& associationPath) : tid(tid), sensorName(sensorName)
22 {
23     if (!pdr)
24     {
25         throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
26     }
27 
28     sensorId = pdr->sensor_id;
29     std::string path;
30     SensorUnit sensorUnit = SensorUnit::DegreesC;
31 
32     switch (pdr->base_unit)
33     {
34         case PLDM_SENSOR_UNIT_DEGRESS_C:
35             sensorNameSpace = "/xyz/openbmc_project/sensors/temperature/";
36             sensorUnit = SensorUnit::DegreesC;
37             break;
38         case PLDM_SENSOR_UNIT_VOLTS:
39             sensorNameSpace = "/xyz/openbmc_project/sensors/voltage/";
40             sensorUnit = SensorUnit::Volts;
41             break;
42         case PLDM_SENSOR_UNIT_AMPS:
43             sensorNameSpace = "/xyz/openbmc_project/sensors/current/";
44             sensorUnit = SensorUnit::Amperes;
45             break;
46         case PLDM_SENSOR_UNIT_RPM:
47             sensorNameSpace = "/xyz/openbmc_project/sensors/fan_pwm/";
48             sensorUnit = SensorUnit::RPMS;
49             break;
50         case PLDM_SENSOR_UNIT_WATTS:
51             sensorNameSpace = "/xyz/openbmc_project/sensors/power/";
52             sensorUnit = SensorUnit::Watts;
53             break;
54         case PLDM_SENSOR_UNIT_JOULES:
55             sensorNameSpace = "/xyz/openbmc_project/sensors/energy/";
56             sensorUnit = SensorUnit::Joules;
57             break;
58         case PLDM_SENSOR_UNIT_PERCENTAGE:
59             sensorNameSpace = "/xyz/openbmc_project/sensors/utilization/";
60             sensorUnit = SensorUnit::Percent;
61             break;
62         default:
63             lg2::error("Sensor {NAME} has Invalid baseUnit {UNIT}.", "NAME",
64                        sensorName, "UNIT", pdr->base_unit);
65             throw sdbusplus::xyz::openbmc_project::Common::Error::
66                 InvalidArgument();
67             break;
68     }
69 
70     path = sensorNameSpace + sensorName;
71     try
72     {
73         auto service = pldm::utils::DBusHandler().getService(
74             path.c_str(), "xyz.openbmc_project.Sensor.Value");
75         if (!service.empty())
76         {
77             throw sdbusplus::xyz::openbmc_project::Common::Error::
78                 TooManyResources();
79         }
80     }
81     catch (const std::exception&)
82     {
83         /* The sensor object path is not created */
84     }
85 
86     auto& bus = pldm::utils::DBusHandler::getBus();
87     try
88     {
89         associationDefinitionsIntf =
90             std::make_unique<AssociationDefinitionsInft>(bus, path.c_str());
91     }
92     catch (const sdbusplus::exception_t& e)
93     {
94         lg2::error(
95             "Failed to create association interface for numeric sensor {PATH} error - {ERROR}",
96             "PATH", path, "ERROR", e);
97         throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
98     }
99 
100     associationDefinitionsIntf->associations(
101         {{"chassis", "all_sensors", associationPath}});
102 
103     double maxValue = std::numeric_limits<double>::quiet_NaN();
104     double minValue = std::numeric_limits<double>::quiet_NaN();
105 
106     switch (pdr->sensor_data_size)
107     {
108         case PLDM_SENSOR_DATA_SIZE_UINT8:
109             maxValue = pdr->max_readable.value_u8;
110             minValue = pdr->min_readable.value_u8;
111             hysteresis = pdr->hysteresis.value_u8;
112             break;
113         case PLDM_SENSOR_DATA_SIZE_SINT8:
114             maxValue = pdr->max_readable.value_s8;
115             minValue = pdr->min_readable.value_s8;
116             hysteresis = pdr->hysteresis.value_s8;
117             break;
118         case PLDM_SENSOR_DATA_SIZE_UINT16:
119             maxValue = pdr->max_readable.value_u16;
120             minValue = pdr->min_readable.value_u16;
121             hysteresis = pdr->hysteresis.value_u16;
122             break;
123         case PLDM_SENSOR_DATA_SIZE_SINT16:
124             maxValue = pdr->max_readable.value_s16;
125             minValue = pdr->min_readable.value_s16;
126             hysteresis = pdr->hysteresis.value_s16;
127             break;
128         case PLDM_SENSOR_DATA_SIZE_UINT32:
129             maxValue = pdr->max_readable.value_u32;
130             minValue = pdr->min_readable.value_u32;
131             hysteresis = pdr->hysteresis.value_u32;
132             break;
133         case PLDM_SENSOR_DATA_SIZE_SINT32:
134             maxValue = pdr->max_readable.value_s32;
135             minValue = pdr->min_readable.value_s32;
136             hysteresis = pdr->hysteresis.value_s32;
137             break;
138     }
139 
140     bool hasCriticalThresholds = false;
141     bool hasWarningThresholds = false;
142     double criticalHigh = std::numeric_limits<double>::quiet_NaN();
143     double criticalLow = std::numeric_limits<double>::quiet_NaN();
144     double warningHigh = std::numeric_limits<double>::quiet_NaN();
145     double warningLow = std::numeric_limits<double>::quiet_NaN();
146 
147     if (pdr->supported_thresholds.bits.bit0)
148     {
149         hasWarningThresholds = true;
150         switch (pdr->range_field_format)
151         {
152             case PLDM_RANGE_FIELD_FORMAT_UINT8:
153                 warningHigh = pdr->warning_high.value_u8;
154                 break;
155             case PLDM_RANGE_FIELD_FORMAT_SINT8:
156                 warningHigh = pdr->warning_high.value_s8;
157                 break;
158             case PLDM_RANGE_FIELD_FORMAT_UINT16:
159                 warningHigh = pdr->warning_high.value_u16;
160                 break;
161             case PLDM_RANGE_FIELD_FORMAT_SINT16:
162                 warningHigh = pdr->warning_high.value_s16;
163                 break;
164             case PLDM_RANGE_FIELD_FORMAT_UINT32:
165                 warningHigh = pdr->warning_high.value_u32;
166                 break;
167             case PLDM_RANGE_FIELD_FORMAT_SINT32:
168                 warningHigh = pdr->warning_high.value_s32;
169                 break;
170             case PLDM_RANGE_FIELD_FORMAT_REAL32:
171                 warningHigh = pdr->warning_high.value_f32;
172                 break;
173         }
174     }
175 
176     if (pdr->supported_thresholds.bits.bit3)
177     {
178         hasWarningThresholds = true;
179         switch (pdr->range_field_format)
180         {
181             case PLDM_RANGE_FIELD_FORMAT_UINT8:
182                 warningLow = pdr->warning_low.value_u8;
183                 break;
184             case PLDM_RANGE_FIELD_FORMAT_SINT8:
185                 warningLow = pdr->warning_low.value_s8;
186                 break;
187             case PLDM_RANGE_FIELD_FORMAT_UINT16:
188                 warningLow = pdr->warning_low.value_u16;
189                 break;
190             case PLDM_RANGE_FIELD_FORMAT_SINT16:
191                 warningLow = pdr->warning_low.value_s16;
192                 break;
193             case PLDM_RANGE_FIELD_FORMAT_UINT32:
194                 warningLow = pdr->warning_low.value_u32;
195                 break;
196             case PLDM_RANGE_FIELD_FORMAT_SINT32:
197                 warningLow = pdr->warning_low.value_s32;
198                 break;
199             case PLDM_RANGE_FIELD_FORMAT_REAL32:
200                 warningLow = pdr->warning_low.value_f32;
201                 break;
202         }
203     }
204 
205     if (pdr->supported_thresholds.bits.bit1)
206     {
207         hasCriticalThresholds = true;
208         switch (pdr->range_field_format)
209         {
210             case PLDM_RANGE_FIELD_FORMAT_UINT8:
211                 criticalHigh = pdr->critical_high.value_u8;
212                 break;
213             case PLDM_RANGE_FIELD_FORMAT_SINT8:
214                 criticalHigh = pdr->critical_high.value_s8;
215                 break;
216             case PLDM_RANGE_FIELD_FORMAT_UINT16:
217                 criticalHigh = pdr->critical_high.value_u16;
218                 break;
219             case PLDM_RANGE_FIELD_FORMAT_SINT16:
220                 criticalHigh = pdr->critical_high.value_s16;
221                 break;
222             case PLDM_RANGE_FIELD_FORMAT_UINT32:
223                 criticalHigh = pdr->critical_high.value_u32;
224                 break;
225             case PLDM_RANGE_FIELD_FORMAT_SINT32:
226                 criticalHigh = pdr->critical_high.value_s32;
227                 break;
228             case PLDM_RANGE_FIELD_FORMAT_REAL32:
229                 criticalHigh = pdr->critical_high.value_f32;
230                 break;
231         }
232     }
233 
234     if (pdr->supported_thresholds.bits.bit4)
235     {
236         hasCriticalThresholds = true;
237         switch (pdr->range_field_format)
238         {
239             case PLDM_RANGE_FIELD_FORMAT_UINT8:
240                 criticalLow = pdr->critical_low.value_u8;
241                 break;
242             case PLDM_RANGE_FIELD_FORMAT_SINT8:
243                 criticalLow = pdr->critical_low.value_s8;
244                 break;
245             case PLDM_RANGE_FIELD_FORMAT_UINT16:
246                 criticalLow = pdr->critical_low.value_u16;
247                 break;
248             case PLDM_RANGE_FIELD_FORMAT_SINT16:
249                 criticalLow = pdr->critical_low.value_s16;
250                 break;
251             case PLDM_RANGE_FIELD_FORMAT_UINT32:
252                 criticalLow = pdr->critical_low.value_u32;
253                 break;
254             case PLDM_RANGE_FIELD_FORMAT_SINT32:
255                 criticalLow = pdr->critical_low.value_s32;
256                 break;
257             case PLDM_RANGE_FIELD_FORMAT_REAL32:
258                 criticalLow = pdr->critical_low.value_f32;
259                 break;
260         }
261     }
262 
263     resolution = pdr->resolution;
264     offset = pdr->offset;
265     baseUnitModifier = pdr->unit_modifier;
266     timeStamp = 0;
267 
268     /**
269      * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds
270      * updateTime is in microseconds
271      */
272     updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000);
273     if (!std::isnan(pdr->update_interval))
274     {
275         updateTime = pdr->update_interval * 1000000;
276     }
277 
278     try
279     {
280         valueIntf = std::make_unique<ValueIntf>(bus, path.c_str());
281     }
282     catch (const sdbusplus::exception_t& e)
283     {
284         lg2::error(
285             "Failed to create Value interface for numeric sensor {PATH} error - {ERROR}",
286             "PATH", path, "ERROR", e);
287         throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
288     }
289     valueIntf->maxValue(unitModifier(conversionFormula(maxValue)));
290     valueIntf->minValue(unitModifier(conversionFormula(minValue)));
291     hysteresis = unitModifier(conversionFormula(hysteresis));
292     valueIntf->unit(sensorUnit);
293 
294     try
295     {
296         availabilityIntf =
297             std::make_unique<AvailabilityIntf>(bus, path.c_str());
298     }
299     catch (const sdbusplus::exception_t& e)
300     {
301         lg2::error(
302             "Failed to create Availability interface for numeric sensor {PATH} error - {ERROR}",
303             "PATH", path, "ERROR", e);
304         throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
305     }
306     availabilityIntf->available(true);
307 
308     try
309     {
310         operationalStatusIntf =
311             std::make_unique<OperationalStatusIntf>(bus, path.c_str());
312     }
313     catch (const sdbusplus::exception_t& e)
314     {
315         lg2::error(
316             "Failed to create Operation status interface for numeric sensor {PATH} error - {ERROR}",
317             "PATH", path, "ERROR", e);
318         throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
319     }
320     operationalStatusIntf->functional(!sensorDisabled);
321 
322     if (hasWarningThresholds)
323     {
324         try
325         {
326             thresholdWarningIntf =
327                 std::make_unique<ThresholdWarningIntf>(bus, path.c_str());
328         }
329         catch (const sdbusplus::exception_t& e)
330         {
331             lg2::error(
332                 "Failed to create Threshold warning interface for numeric sensor {PATH} error - {ERROR}",
333                 "PATH", path, "ERROR", e);
334             throw sdbusplus::xyz::openbmc_project::Common::Error::
335                 InvalidArgument();
336         }
337         thresholdWarningIntf->warningHigh(unitModifier(warningHigh));
338         thresholdWarningIntf->warningLow(unitModifier(warningLow));
339     }
340 
341     if (hasCriticalThresholds)
342     {
343         try
344         {
345             thresholdCriticalIntf =
346                 std::make_unique<ThresholdCriticalIntf>(bus, path.c_str());
347         }
348         catch (const sdbusplus::exception_t& e)
349         {
350             lg2::error(
351                 "Failed to create Threshold critical interface for numeric sensor {PATH} error - {ERROR}",
352                 "PATH", path, "ERROR", e);
353             throw sdbusplus::xyz::openbmc_project::Common::Error::
354                 InvalidArgument();
355         }
356         thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh));
357         thresholdCriticalIntf->criticalLow(unitModifier(criticalLow));
358     }
359 }
360 
NumericSensor(const pldm_tid_t tid,const bool sensorDisabled,std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr,std::string & sensorName,std::string & associationPath)361 NumericSensor::NumericSensor(
362     const pldm_tid_t tid, const bool sensorDisabled,
363     std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr,
364     std::string& sensorName, std::string& associationPath) :
365     tid(tid), sensorName(sensorName)
366 {
367     if (!pdr)
368     {
369         throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
370     }
371 
372     sensorId = pdr->sensor_id;
373     std::string path;
374     SensorUnit sensorUnit = SensorUnit::DegreesC;
375 
376     switch (pdr->base_unit)
377     {
378         case PLDM_SENSOR_UNIT_DEGRESS_C:
379             sensorNameSpace = "/xyz/openbmc_project/sensors/temperature/";
380             sensorUnit = SensorUnit::DegreesC;
381             break;
382         case PLDM_SENSOR_UNIT_VOLTS:
383             sensorNameSpace = "/xyz/openbmc_project/sensors/voltage/";
384             sensorUnit = SensorUnit::Volts;
385             break;
386         case PLDM_SENSOR_UNIT_AMPS:
387             sensorNameSpace = "/xyz/openbmc_project/sensors/current/";
388             sensorUnit = SensorUnit::Amperes;
389             break;
390         case PLDM_SENSOR_UNIT_RPM:
391             sensorNameSpace = "/xyz/openbmc_project/sensors/fan_pwm/";
392             sensorUnit = SensorUnit::RPMS;
393             break;
394         case PLDM_SENSOR_UNIT_WATTS:
395             sensorNameSpace = "/xyz/openbmc_project/sensors/power/";
396             sensorUnit = SensorUnit::Watts;
397             break;
398         case PLDM_SENSOR_UNIT_JOULES:
399             sensorNameSpace = "/xyz/openbmc_project/sensors/energy/";
400             sensorUnit = SensorUnit::Joules;
401             break;
402         case PLDM_SENSOR_UNIT_PERCENTAGE:
403             sensorNameSpace = "/xyz/openbmc_project/sensors/utilization/";
404             sensorUnit = SensorUnit::Percent;
405             break;
406         default:
407             lg2::error("Sensor {NAME} has Invalid baseUnit {UNIT}.", "NAME",
408                        sensorName, "UNIT", pdr->base_unit);
409             throw sdbusplus::xyz::openbmc_project::Common::Error::
410                 InvalidArgument();
411             break;
412     }
413 
414     path = sensorNameSpace + sensorName;
415     try
416     {
417         auto service = pldm::utils::DBusHandler().getService(
418             path.c_str(), "xyz.openbmc_project.Sensor.Value");
419         if (!service.empty())
420         {
421             throw sdbusplus::xyz::openbmc_project::Common::Error::
422                 TooManyResources();
423         }
424     }
425     catch (const std::exception&)
426     {
427         /* The sensor object path is not created */
428     }
429 
430     auto& bus = pldm::utils::DBusHandler::getBus();
431     try
432     {
433         associationDefinitionsIntf =
434             std::make_unique<AssociationDefinitionsInft>(bus, path.c_str());
435     }
436     catch (const sdbusplus::exception_t& e)
437     {
438         lg2::error(
439             "Failed to create Association interface for compact numeric sensor {PATH} error - {ERROR}",
440             "PATH", path, "ERROR", e);
441         throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
442     }
443     associationDefinitionsIntf->associations(
444         {{"chassis", "all_sensors", associationPath.c_str()}});
445 
446     double maxValue = std::numeric_limits<double>::quiet_NaN();
447     double minValue = std::numeric_limits<double>::quiet_NaN();
448     bool hasWarningThresholds = false;
449     bool hasCriticalThresholds = false;
450     double criticalHigh = std::numeric_limits<double>::quiet_NaN();
451     double criticalLow = std::numeric_limits<double>::quiet_NaN();
452     double warningHigh = std::numeric_limits<double>::quiet_NaN();
453     double warningLow = std::numeric_limits<double>::quiet_NaN();
454 
455     if (pdr->range_field_support.bits.bit0)
456     {
457         hasWarningThresholds = true;
458         warningHigh = pdr->warning_high;
459     }
460     if (pdr->range_field_support.bits.bit1)
461     {
462         hasWarningThresholds = true;
463         warningLow = pdr->warning_low;
464     }
465 
466     if (pdr->range_field_support.bits.bit2)
467     {
468         hasCriticalThresholds = true;
469         criticalHigh = pdr->critical_high;
470     }
471 
472     if (pdr->range_field_support.bits.bit3)
473     {
474         hasCriticalThresholds = true;
475         criticalLow = pdr->critical_low;
476     }
477 
478     resolution = std::numeric_limits<double>::quiet_NaN();
479     offset = std::numeric_limits<double>::quiet_NaN();
480     baseUnitModifier = pdr->unit_modifier;
481     timeStamp = 0;
482 
483     /**
484      * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds
485      * updateTime is in microseconds
486      */
487     updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000);
488     try
489     {
490         valueIntf = std::make_unique<ValueIntf>(bus, path.c_str());
491     }
492     catch (const sdbusplus::exception_t& e)
493     {
494         lg2::error(
495             "Failed to create Value interface for compact numeric sensor {PATH} error - {ERROR}",
496             "PATH", path, "ERROR", e);
497         throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
498     }
499     valueIntf->maxValue(unitModifier(conversionFormula(maxValue)));
500     valueIntf->minValue(unitModifier(conversionFormula(minValue)));
501     hysteresis = unitModifier(conversionFormula(hysteresis));
502     valueIntf->unit(sensorUnit);
503 
504     try
505     {
506         availabilityIntf =
507             std::make_unique<AvailabilityIntf>(bus, path.c_str());
508     }
509     catch (const sdbusplus::exception_t& e)
510     {
511         lg2::error(
512             "Failed to create Availability interface for compact numeric sensor {PATH} error - {ERROR}",
513             "PATH", path, "ERROR", e);
514         throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
515     }
516     availabilityIntf->available(true);
517 
518     try
519     {
520         operationalStatusIntf =
521             std::make_unique<OperationalStatusIntf>(bus, path.c_str());
522     }
523     catch (const sdbusplus::exception_t& e)
524     {
525         lg2::error(
526             "Failed to create Operational status interface for compact numeric sensor {PATH} error - {ERROR}",
527             "PATH", path, "ERROR", e);
528         throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
529     }
530     operationalStatusIntf->functional(!sensorDisabled);
531 
532     if (hasWarningThresholds)
533     {
534         try
535         {
536             thresholdWarningIntf =
537                 std::make_unique<ThresholdWarningIntf>(bus, path.c_str());
538         }
539         catch (const sdbusplus::exception_t& e)
540         {
541             lg2::error(
542                 "Failed to create Warning threshold interface for compact numeric sensor {PATH} error - {ERROR}",
543                 "PATH", path, "ERROR", e);
544             throw sdbusplus::xyz::openbmc_project::Common::Error::
545                 InvalidArgument();
546         }
547         thresholdWarningIntf->warningHigh(unitModifier(warningHigh));
548         thresholdWarningIntf->warningLow(unitModifier(warningLow));
549     }
550 
551     if (hasCriticalThresholds)
552     {
553         try
554         {
555             thresholdCriticalIntf =
556                 std::make_unique<ThresholdCriticalIntf>(bus, path.c_str());
557         }
558         catch (const sdbusplus::exception_t& e)
559         {
560             lg2::error(
561                 "Failed to create Critical threshold interface for compact numeric sensor {PATH} error - {ERROR}",
562                 "PATH", path, "ERROR", e);
563             throw sdbusplus::xyz::openbmc_project::Common::Error::
564                 InvalidArgument();
565         }
566         thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh));
567         thresholdCriticalIntf->criticalLow(unitModifier(criticalLow));
568     }
569 }
570 
conversionFormula(double value)571 double NumericSensor::conversionFormula(double value)
572 {
573     double convertedValue = value;
574     convertedValue *= std::isnan(resolution) ? 1 : resolution;
575     convertedValue += std::isnan(offset) ? 0 : offset;
576     return convertedValue;
577 }
578 
unitModifier(double value)579 double NumericSensor::unitModifier(double value)
580 {
581     return std::isnan(value) ? value : value * std::pow(10, baseUnitModifier);
582 }
583 
updateReading(bool available,bool functional,double value)584 void NumericSensor::updateReading(bool available, bool functional, double value)
585 {
586     if (!availabilityIntf || !operationalStatusIntf || !valueIntf)
587     {
588         lg2::error(
589             "Failed to update sensor {NAME} D-Bus interface don't exist.",
590             "NAME", sensorName);
591         return;
592     }
593     availabilityIntf->available(available);
594     operationalStatusIntf->functional(functional);
595     double curValue = valueIntf->value();
596     double newValue = std::numeric_limits<double>::quiet_NaN();
597     if (functional && available)
598     {
599         newValue = unitModifier(conversionFormula(value));
600         if (newValue != curValue &&
601             (!std::isnan(newValue) || !std::isnan(curValue)))
602         {
603             valueIntf->value(newValue);
604             updateThresholds();
605         }
606     }
607     else
608     {
609         if (newValue != curValue &&
610             (!std::isnan(newValue) || !std::isnan(curValue)))
611         {
612             valueIntf->value(std::numeric_limits<double>::quiet_NaN());
613         }
614     }
615 }
616 
handleErrGetSensorReading()617 void NumericSensor::handleErrGetSensorReading()
618 {
619     if (!operationalStatusIntf || !valueIntf)
620     {
621         lg2::error(
622             "Failed to update sensor {NAME} D-Bus interfaces don't exist.",
623             "NAME", sensorName);
624         return;
625     }
626     operationalStatusIntf->functional(false);
627     valueIntf->value(std::numeric_limits<double>::quiet_NaN());
628 }
629 
checkThreshold(bool alarm,bool direction,double value,double threshold,double hyst)630 bool NumericSensor::checkThreshold(bool alarm, bool direction, double value,
631                                    double threshold, double hyst)
632 {
633     if (direction)
634     {
635         if (value >= threshold)
636         {
637             return true;
638         }
639         if (value < (threshold - hyst))
640         {
641             return false;
642         }
643     }
644     else
645     {
646         if (value <= threshold)
647         {
648             return true;
649         }
650         if (value > (threshold + hyst))
651         {
652             return false;
653         }
654     }
655     return alarm;
656 }
657 
updateThresholds()658 void NumericSensor::updateThresholds()
659 {
660     if (!valueIntf)
661     {
662         lg2::error(
663             "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.",
664             "NAME", sensorName);
665         return;
666     }
667 
668     auto value = valueIntf->value();
669 
670     if (thresholdWarningIntf &&
671         !std::isnan(thresholdWarningIntf->warningHigh()))
672     {
673         auto threshold = thresholdWarningIntf->warningHigh();
674         auto alarm = thresholdWarningIntf->warningAlarmHigh();
675         auto newAlarm =
676             checkThreshold(alarm, true, value, threshold, hysteresis);
677         if (alarm != newAlarm)
678         {
679             thresholdWarningIntf->warningAlarmHigh(newAlarm);
680             if (newAlarm)
681             {
682                 thresholdWarningIntf->warningHighAlarmAsserted(value);
683             }
684             else
685             {
686                 thresholdWarningIntf->warningHighAlarmDeasserted(value);
687             }
688         }
689     }
690 
691     if (thresholdWarningIntf && !std::isnan(thresholdWarningIntf->warningLow()))
692     {
693         auto threshold = thresholdWarningIntf->warningLow();
694         auto alarm = thresholdWarningIntf->warningAlarmLow();
695         auto newAlarm =
696             checkThreshold(alarm, false, value, threshold, hysteresis);
697         if (alarm != newAlarm)
698         {
699             thresholdWarningIntf->warningAlarmLow(newAlarm);
700             if (newAlarm)
701             {
702                 thresholdWarningIntf->warningLowAlarmAsserted(value);
703             }
704             else
705             {
706                 thresholdWarningIntf->warningLowAlarmDeasserted(value);
707             }
708         }
709     }
710 
711     if (thresholdCriticalIntf &&
712         !std::isnan(thresholdCriticalIntf->criticalHigh()))
713     {
714         auto threshold = thresholdCriticalIntf->criticalHigh();
715         auto alarm = thresholdCriticalIntf->criticalAlarmHigh();
716         auto newAlarm =
717             checkThreshold(alarm, true, value, threshold, hysteresis);
718         if (alarm != newAlarm)
719         {
720             thresholdCriticalIntf->criticalAlarmHigh(newAlarm);
721             if (newAlarm)
722             {
723                 thresholdCriticalIntf->criticalHighAlarmAsserted(value);
724             }
725             else
726             {
727                 thresholdCriticalIntf->criticalHighAlarmDeasserted(value);
728             }
729         }
730     }
731 
732     if (thresholdCriticalIntf &&
733         !std::isnan(thresholdCriticalIntf->criticalLow()))
734     {
735         auto threshold = thresholdCriticalIntf->criticalLow();
736         auto alarm = thresholdCriticalIntf->criticalAlarmLow();
737         auto newAlarm =
738             checkThreshold(alarm, false, value, threshold, hysteresis);
739         if (alarm != newAlarm)
740         {
741             thresholdCriticalIntf->criticalAlarmLow(newAlarm);
742             if (newAlarm)
743             {
744                 thresholdCriticalIntf->criticalLowAlarmAsserted(value);
745             }
746             else
747             {
748                 thresholdCriticalIntf->criticalLowAlarmDeasserted(value);
749             }
750         }
751     }
752 }
753 } // namespace platform_mc
754 } // namespace pldm
755