xref: /openbmc/pldm/platform-mc/numeric_sensor.cpp (revision 9a224aeba8c274d8dc5ffd6597fe85acd54dfcd8)
1 #include "numeric_sensor.hpp"
2 
3 #include "common/utils.hpp"
4 #include "requester/handler.hpp"
5 
6 #include <libpldm/platform.h>
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     bool hasFatalThresholds = false;
219     double criticalHigh = std::numeric_limits<double>::quiet_NaN();
220     double criticalLow = std::numeric_limits<double>::quiet_NaN();
221     double warningHigh = std::numeric_limits<double>::quiet_NaN();
222     double warningLow = std::numeric_limits<double>::quiet_NaN();
223     double fatalHigh = std::numeric_limits<double>::quiet_NaN();
224     double fatalLow = std::numeric_limits<double>::quiet_NaN();
225 
226     if (pdr->supported_thresholds.bits.bit0)
227     {
228         hasWarningThresholds = true;
229         warningHigh =
230             getRangeFieldValue(pdr->range_field_format, pdr->warning_high);
231     }
232 
233     if (pdr->supported_thresholds.bits.bit3)
234     {
235         hasWarningThresholds = true;
236         warningLow =
237             getRangeFieldValue(pdr->range_field_format, pdr->warning_low);
238     }
239 
240     if (pdr->supported_thresholds.bits.bit1)
241     {
242         hasCriticalThresholds = true;
243         criticalHigh =
244             getRangeFieldValue(pdr->range_field_format, pdr->critical_high);
245     }
246 
247     if (pdr->supported_thresholds.bits.bit4)
248     {
249         hasCriticalThresholds = true;
250         criticalLow =
251             getRangeFieldValue(pdr->range_field_format, pdr->critical_low);
252     }
253     if (pdr->supported_thresholds.bits.bit2)
254     {
255         hasFatalThresholds = true;
256         fatalHigh =
257             getRangeFieldValue(pdr->range_field_format, pdr->fatal_high);
258     }
259     if (pdr->supported_thresholds.bits.bit5)
260     {
261         hasFatalThresholds = true;
262         fatalLow = getRangeFieldValue(pdr->range_field_format, pdr->fatal_low);
263     }
264 
265     resolution = pdr->resolution;
266     offset = pdr->offset;
267     baseUnitModifier = pdr->unit_modifier;
268     timeStamp = 0;
269 
270     /**
271      * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds
272      * updateTime is in microseconds
273      */
274     updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000);
275     if (std::isfinite(pdr->update_interval))
276     {
277         updateTime = pdr->update_interval * 1000000;
278     }
279 
280     if (!useMetricInterface)
281     {
282         try
283         {
284             valueIntf = std::make_unique<ValueIntf>(bus, path.c_str());
285         }
286         catch (const sdbusplus::exception_t& e)
287         {
288             lg2::error(
289                 "Failed to create Value interface for numeric sensor {PATH} error - {ERROR}",
290                 "PATH", path, "ERROR", e);
291             throw sdbusplus::xyz::openbmc_project::Common::Error::
292                 InvalidArgument();
293         }
294         valueIntf->maxValue(unitModifier(conversionFormula(maxValue)));
295         valueIntf->minValue(unitModifier(conversionFormula(minValue)));
296         valueIntf->unit(sensorUnit);
297     }
298     else
299     {
300         try
301         {
302             metricIntf = std::make_unique<MetricIntf>(bus, path.c_str());
303         }
304         catch (const sdbusplus::exception_t& e)
305         {
306             lg2::error(
307                 "Failed to create Metric interface for numeric sensor {PATH} error - {ERROR}",
308                 "PATH", path, "ERROR", e);
309             throw sdbusplus::xyz::openbmc_project::Common::Error::
310                 InvalidArgument();
311         }
312         metricIntf->maxValue(unitModifier(conversionFormula(maxValue)));
313         metricIntf->minValue(unitModifier(conversionFormula(minValue)));
314         metricIntf->unit(metricUnit);
315     }
316 
317     hysteresis = unitModifier(conversionFormula(hysteresis));
318 
319     if (!createInventoryPath(associationPath, sensorName, pdr->entity_type,
320                              pdr->entity_instance_num, pdr->container_id))
321     {
322         throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
323     }
324 
325     try
326     {
327         availabilityIntf =
328             std::make_unique<AvailabilityIntf>(bus, path.c_str());
329     }
330     catch (const sdbusplus::exception_t& e)
331     {
332         lg2::error(
333             "Failed to create Availability interface for numeric sensor {PATH} error - {ERROR}",
334             "PATH", path, "ERROR", e);
335         throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
336     }
337     availabilityIntf->available(true);
338 
339     try
340     {
341         operationalStatusIntf =
342             std::make_unique<OperationalStatusIntf>(bus, path.c_str());
343     }
344     catch (const sdbusplus::exception_t& e)
345     {
346         lg2::error(
347             "Failed to create Operation status interface for numeric sensor {PATH} error - {ERROR}",
348             "PATH", path, "ERROR", e);
349         throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
350     }
351     operationalStatusIntf->functional(!sensorDisabled);
352 
353     if (hasWarningThresholds && !useMetricInterface)
354     {
355         try
356         {
357             thresholdWarningIntf =
358                 std::make_unique<ThresholdWarningIntf>(bus, path.c_str());
359         }
360         catch (const sdbusplus::exception_t& e)
361         {
362             lg2::error(
363                 "Failed to create Threshold warning interface for numeric sensor {PATH} error - {ERROR}",
364                 "PATH", path, "ERROR", e);
365             throw sdbusplus::xyz::openbmc_project::Common::Error::
366                 InvalidArgument();
367         }
368         thresholdWarningIntf->warningHigh(unitModifier(warningHigh));
369         thresholdWarningIntf->warningLow(unitModifier(warningLow));
370     }
371 
372     if (hasCriticalThresholds && !useMetricInterface)
373     {
374         try
375         {
376             thresholdCriticalIntf =
377                 std::make_unique<ThresholdCriticalIntf>(bus, path.c_str());
378         }
379         catch (const sdbusplus::exception_t& e)
380         {
381             lg2::error(
382                 "Failed to create Threshold critical interface for numeric sensor {PATH} error - {ERROR}",
383                 "PATH", path, "ERROR", e);
384             throw sdbusplus::xyz::openbmc_project::Common::Error::
385                 InvalidArgument();
386         }
387         thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh));
388         thresholdCriticalIntf->criticalLow(unitModifier(criticalLow));
389     }
390 
391     if (hasFatalThresholds && !useMetricInterface)
392     {
393         try
394         {
395             thresholdHardShutdownIntf =
396                 std::make_unique<ThresholdHardShutdownIntf>(bus, path.c_str());
397         }
398         catch (const sdbusplus::exception_t& e)
399         {
400             lg2::error(
401                 "Failed to create HardShutdown threshold interface for numeric sensor {PATH} error - {ERROR}",
402                 "PATH", path, "ERROR", e);
403             throw sdbusplus::xyz::openbmc_project::Common::Error::
404                 InvalidArgument();
405         }
406         thresholdHardShutdownIntf->hardShutdownHigh(unitModifier(fatalHigh));
407         thresholdHardShutdownIntf->hardShutdownLow(unitModifier(fatalLow));
408     }
409 }
410 
NumericSensor(const pldm_tid_t tid,const bool sensorDisabled,std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr,std::string & sensorName,std::string & associationPath)411 NumericSensor::NumericSensor(
412     const pldm_tid_t tid, const bool sensorDisabled,
413     std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr,
414     std::string& sensorName, std::string& associationPath) :
415     tid(tid), sensorName(sensorName)
416 {
417     if (!pdr)
418     {
419         throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
420     }
421 
422     sensorId = pdr->sensor_id;
423     std::string path;
424     MetricUnit metricUnit = MetricUnit::Count;
425     setSensorUnit(pdr->base_unit);
426 
427     path = sensorNameSpace + sensorName;
428     try
429     {
430         std::string tmp{};
431         std::string interface = SENSOR_VALUE_INTF;
432         if (useMetricInterface)
433         {
434             interface = METRIC_VALUE_INTF;
435         }
436         tmp = pldm::utils::DBusHandler().getService(path.c_str(),
437                                                     interface.c_str());
438 
439         if (!tmp.empty())
440         {
441             throw sdbusplus::xyz::openbmc_project::Common::Error::
442                 TooManyResources();
443         }
444     }
445     catch (const std::exception&)
446     {
447         /* The sensor object path is not created */
448     }
449 
450     auto& bus = pldm::utils::DBusHandler::getBus();
451     try
452     {
453         associationDefinitionsIntf =
454             std::make_unique<AssociationDefinitionsInft>(bus, path.c_str());
455     }
456     catch (const sdbusplus::exception_t& e)
457     {
458         lg2::error(
459             "Failed to create Association interface for compact numeric sensor {PATH} error - {ERROR}",
460             "PATH", path, "ERROR", e);
461         throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
462     }
463     associationDefinitionsIntf->associations(
464         {{"chassis", "all_sensors", associationPath.c_str()}});
465 
466     double maxValue = std::numeric_limits<double>::quiet_NaN();
467     double minValue = std::numeric_limits<double>::quiet_NaN();
468     bool hasWarningThresholds = false;
469     bool hasCriticalThresholds = false;
470     bool hasFatalThresholds = false;
471     double criticalHigh = std::numeric_limits<double>::quiet_NaN();
472     double criticalLow = std::numeric_limits<double>::quiet_NaN();
473     double warningHigh = std::numeric_limits<double>::quiet_NaN();
474     double warningLow = std::numeric_limits<double>::quiet_NaN();
475     double fatalHigh = std::numeric_limits<double>::quiet_NaN();
476     double fatalLow = std::numeric_limits<double>::quiet_NaN();
477 
478     if (pdr->range_field_support.bits.bit0)
479     {
480         hasWarningThresholds = true;
481         warningHigh = pdr->warning_high;
482     }
483     if (pdr->range_field_support.bits.bit1)
484     {
485         hasWarningThresholds = true;
486         warningLow = pdr->warning_low;
487     }
488 
489     if (pdr->range_field_support.bits.bit2)
490     {
491         hasCriticalThresholds = true;
492         criticalHigh = pdr->critical_high;
493     }
494 
495     if (pdr->range_field_support.bits.bit3)
496     {
497         hasCriticalThresholds = true;
498         criticalLow = pdr->critical_low;
499     }
500     if (pdr->range_field_support.bits.bit4)
501     {
502         hasFatalThresholds = true;
503         fatalHigh = pdr->fatal_high;
504     }
505     if (pdr->range_field_support.bits.bit5)
506     {
507         hasFatalThresholds = true;
508         fatalLow = pdr->fatal_low;
509     }
510 
511     resolution = std::numeric_limits<double>::quiet_NaN();
512     offset = std::numeric_limits<double>::quiet_NaN();
513     baseUnitModifier = pdr->unit_modifier;
514     timeStamp = 0;
515     hysteresis = 0;
516 
517     /**
518      * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds
519      * updateTime is in microseconds
520      */
521     updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000);
522 
523     if (!useMetricInterface)
524     {
525         try
526         {
527             valueIntf = std::make_unique<ValueIntf>(bus, path.c_str());
528         }
529         catch (const sdbusplus::exception_t& e)
530         {
531             lg2::error(
532                 "Failed to create Value interface for compact numeric sensor {PATH} error - {ERROR}",
533                 "PATH", path, "ERROR", e);
534             throw sdbusplus::xyz::openbmc_project::Common::Error::
535                 InvalidArgument();
536         }
537         valueIntf->maxValue(unitModifier(conversionFormula(maxValue)));
538         valueIntf->minValue(unitModifier(conversionFormula(minValue)));
539         valueIntf->unit(sensorUnit);
540     }
541     else
542     {
543         try
544         {
545             metricIntf = std::make_unique<MetricIntf>(bus, path.c_str());
546         }
547         catch (const sdbusplus::exception_t& e)
548         {
549             lg2::error(
550                 "Failed to create Metric interface for compact numeric sensor {PATH} error - {ERROR}",
551                 "PATH", path, "ERROR", e);
552             throw sdbusplus::xyz::openbmc_project::Common::Error::
553                 InvalidArgument();
554         }
555         metricIntf->maxValue(unitModifier(conversionFormula(maxValue)));
556         metricIntf->minValue(unitModifier(conversionFormula(minValue)));
557         metricIntf->unit(metricUnit);
558     }
559 
560     hysteresis = unitModifier(conversionFormula(hysteresis));
561 
562     if (!createInventoryPath(associationPath, sensorName, pdr->entity_type,
563                              pdr->entity_instance, pdr->container_id))
564     {
565         throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
566     }
567 
568     try
569     {
570         availabilityIntf =
571             std::make_unique<AvailabilityIntf>(bus, path.c_str());
572     }
573     catch (const sdbusplus::exception_t& e)
574     {
575         lg2::error(
576             "Failed to create Availability interface for compact numeric sensor {PATH} error - {ERROR}",
577             "PATH", path, "ERROR", e);
578         throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
579     }
580     availabilityIntf->available(true);
581 
582     try
583     {
584         operationalStatusIntf =
585             std::make_unique<OperationalStatusIntf>(bus, path.c_str());
586     }
587     catch (const sdbusplus::exception_t& e)
588     {
589         lg2::error(
590             "Failed to create Operational status interface for compact numeric sensor {PATH} error - {ERROR}",
591             "PATH", path, "ERROR", e);
592         throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
593     }
594     operationalStatusIntf->functional(!sensorDisabled);
595 
596     if (hasWarningThresholds && !useMetricInterface)
597     {
598         try
599         {
600             thresholdWarningIntf =
601                 std::make_unique<ThresholdWarningIntf>(bus, path.c_str());
602         }
603         catch (const sdbusplus::exception_t& e)
604         {
605             lg2::error(
606                 "Failed to create Warning threshold interface for compact numeric sensor {PATH} error - {ERROR}",
607                 "PATH", path, "ERROR", e);
608             throw sdbusplus::xyz::openbmc_project::Common::Error::
609                 InvalidArgument();
610         }
611         thresholdWarningIntf->warningHigh(unitModifier(warningHigh));
612         thresholdWarningIntf->warningLow(unitModifier(warningLow));
613     }
614 
615     if (hasCriticalThresholds && !useMetricInterface)
616     {
617         try
618         {
619             thresholdCriticalIntf =
620                 std::make_unique<ThresholdCriticalIntf>(bus, path.c_str());
621         }
622         catch (const sdbusplus::exception_t& e)
623         {
624             lg2::error(
625                 "Failed to create Critical threshold interface for compact numeric sensor {PATH} error - {ERROR}",
626                 "PATH", path, "ERROR", e);
627             throw sdbusplus::xyz::openbmc_project::Common::Error::
628                 InvalidArgument();
629         }
630         thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh));
631         thresholdCriticalIntf->criticalLow(unitModifier(criticalLow));
632     }
633 
634     if (hasFatalThresholds && !useMetricInterface)
635     {
636         try
637         {
638             thresholdHardShutdownIntf =
639                 std::make_unique<ThresholdHardShutdownIntf>(bus, path.c_str());
640         }
641         catch (const sdbusplus::exception_t& e)
642         {
643             lg2::error(
644                 "Failed to create HardShutdown threshold interface for numeric sensor {PATH} error - {ERROR}",
645                 "PATH", path, "ERROR", e);
646             throw sdbusplus::xyz::openbmc_project::Common::Error::
647                 InvalidArgument();
648         }
649         thresholdHardShutdownIntf->hardShutdownHigh(unitModifier(fatalHigh));
650         thresholdHardShutdownIntf->hardShutdownLow(unitModifier(fatalLow));
651     }
652 }
653 
conversionFormula(double value)654 double NumericSensor::conversionFormula(double value)
655 {
656     double convertedValue = value;
657     if (std::isfinite(resolution))
658     {
659         convertedValue *= resolution;
660     }
661     if (std::isfinite(offset))
662     {
663         convertedValue += offset;
664     }
665     return convertedValue;
666 }
667 
unitModifier(double value)668 double NumericSensor::unitModifier(double value)
669 {
670     if (!std::isfinite(value))
671     {
672         return value;
673     }
674     return value * std::pow(10, baseUnitModifier);
675 }
676 
updateReading(bool available,bool functional,double value)677 void NumericSensor::updateReading(bool available, bool functional, double value)
678 {
679     if (!availabilityIntf || !operationalStatusIntf ||
680         (!useMetricInterface && !valueIntf) ||
681         (useMetricInterface && !metricIntf))
682     {
683         lg2::error(
684             "Failed to update sensor {NAME} D-Bus interface don't exist.",
685             "NAME", sensorName);
686         return;
687     }
688     availabilityIntf->available(available);
689     operationalStatusIntf->functional(functional);
690     double curValue = 0;
691     if (!useMetricInterface)
692     {
693         curValue = valueIntf->value();
694     }
695     else
696     {
697         curValue = metricIntf->value();
698     }
699 
700     double newValue = std::numeric_limits<double>::quiet_NaN();
701     if (functional && available)
702     {
703         newValue = unitModifier(conversionFormula(value));
704         if (newValue != curValue &&
705             (std::isfinite(newValue) || std::isfinite(curValue)))
706         {
707             if (!useMetricInterface)
708             {
709                 valueIntf->value(newValue);
710                 updateThresholds();
711             }
712             else
713             {
714                 metricIntf->value(newValue);
715             }
716         }
717     }
718     else
719     {
720         if (newValue != curValue &&
721             (std::isfinite(newValue) || std::isfinite(curValue)))
722         {
723             if (!useMetricInterface)
724             {
725                 valueIntf->value(std::numeric_limits<double>::quiet_NaN());
726             }
727             else
728             {
729                 metricIntf->value(std::numeric_limits<double>::quiet_NaN());
730             }
731         }
732     }
733 }
734 
handleErrGetSensorReading()735 void NumericSensor::handleErrGetSensorReading()
736 {
737     if (!operationalStatusIntf || (!useMetricInterface && !valueIntf) ||
738         (useMetricInterface && !metricIntf))
739     {
740         lg2::error(
741             "Failed to update sensor {NAME} D-Bus interfaces don't exist.",
742             "NAME", sensorName);
743         return;
744     }
745     operationalStatusIntf->functional(false);
746     if (!useMetricInterface)
747     {
748         valueIntf->value(std::numeric_limits<double>::quiet_NaN());
749     }
750     else
751     {
752         metricIntf->value(std::numeric_limits<double>::quiet_NaN());
753     }
754 }
755 
checkThreshold(bool alarm,bool direction,double value,double threshold,double hyst)756 bool NumericSensor::checkThreshold(bool alarm, bool direction, double value,
757                                    double threshold, double hyst)
758 {
759     if (direction)
760     {
761         if (value >= threshold)
762         {
763             return true;
764         }
765         if (value < (threshold - hyst))
766         {
767             return false;
768         }
769     }
770     else
771     {
772         if (value <= threshold)
773         {
774             return true;
775         }
776         if (value > (threshold + hyst))
777         {
778             return false;
779         }
780     }
781     return alarm;
782 }
783 
updateThresholds()784 void NumericSensor::updateThresholds()
785 {
786     double value = std::numeric_limits<double>::quiet_NaN();
787 
788     if ((!useMetricInterface && !valueIntf) ||
789         (useMetricInterface && !metricIntf))
790     {
791         lg2::error(
792             "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.",
793             "NAME", sensorName);
794         return;
795     }
796     if (!useMetricInterface)
797     {
798         value = valueIntf->value();
799     }
800     else
801     {
802         value = metricIntf->value();
803     }
804     if (thresholdWarningIntf &&
805         std::isfinite(thresholdWarningIntf->warningHigh()))
806     {
807         auto threshold = thresholdWarningIntf->warningHigh();
808         auto alarm = thresholdWarningIntf->warningAlarmHigh();
809         auto newAlarm =
810             checkThreshold(alarm, true, value, threshold, hysteresis);
811         if (alarm != newAlarm)
812         {
813             thresholdWarningIntf->warningAlarmHigh(newAlarm);
814             if (newAlarm)
815             {
816                 thresholdWarningIntf->warningHighAlarmAsserted(value);
817             }
818             else
819             {
820                 thresholdWarningIntf->warningHighAlarmDeasserted(value);
821             }
822         }
823     }
824 
825     if (thresholdWarningIntf &&
826         std::isfinite(thresholdWarningIntf->warningLow()))
827     {
828         auto threshold = thresholdWarningIntf->warningLow();
829         auto alarm = thresholdWarningIntf->warningAlarmLow();
830         auto newAlarm =
831             checkThreshold(alarm, false, value, threshold, hysteresis);
832         if (alarm != newAlarm)
833         {
834             thresholdWarningIntf->warningAlarmLow(newAlarm);
835             if (newAlarm)
836             {
837                 thresholdWarningIntf->warningLowAlarmAsserted(value);
838             }
839             else
840             {
841                 thresholdWarningIntf->warningLowAlarmDeasserted(value);
842             }
843         }
844     }
845 
846     if (thresholdCriticalIntf &&
847         std::isfinite(thresholdCriticalIntf->criticalHigh()))
848     {
849         auto threshold = thresholdCriticalIntf->criticalHigh();
850         auto alarm = thresholdCriticalIntf->criticalAlarmHigh();
851         auto newAlarm =
852             checkThreshold(alarm, true, value, threshold, hysteresis);
853         if (alarm != newAlarm)
854         {
855             thresholdCriticalIntf->criticalAlarmHigh(newAlarm);
856             if (newAlarm)
857             {
858                 thresholdCriticalIntf->criticalHighAlarmAsserted(value);
859             }
860             else
861             {
862                 thresholdCriticalIntf->criticalHighAlarmDeasserted(value);
863             }
864         }
865     }
866 
867     if (thresholdCriticalIntf &&
868         std::isfinite(thresholdCriticalIntf->criticalLow()))
869     {
870         auto threshold = thresholdCriticalIntf->criticalLow();
871         auto alarm = thresholdCriticalIntf->criticalAlarmLow();
872         auto newAlarm =
873             checkThreshold(alarm, false, value, threshold, hysteresis);
874         if (alarm != newAlarm)
875         {
876             thresholdCriticalIntf->criticalAlarmLow(newAlarm);
877             if (newAlarm)
878             {
879                 thresholdCriticalIntf->criticalLowAlarmAsserted(value);
880             }
881             else
882             {
883                 thresholdCriticalIntf->criticalLowAlarmDeasserted(value);
884             }
885         }
886     }
887 
888     if (thresholdHardShutdownIntf &&
889         std::isfinite(thresholdHardShutdownIntf->hardShutdownHigh()))
890     {
891         auto threshold = thresholdHardShutdownIntf->hardShutdownHigh();
892         auto alarm = thresholdHardShutdownIntf->hardShutdownAlarmHigh();
893         auto newAlarm =
894             checkThreshold(alarm, true, value, threshold, hysteresis);
895         if (alarm != newAlarm)
896         {
897             thresholdHardShutdownIntf->hardShutdownAlarmHigh(newAlarm);
898             if (newAlarm)
899             {
900                 thresholdHardShutdownIntf->hardShutdownHighAlarmAsserted(value);
901             }
902             else
903             {
904                 thresholdHardShutdownIntf->hardShutdownHighAlarmDeasserted(
905                     value);
906             }
907         }
908     }
909 
910     if (thresholdHardShutdownIntf &&
911         std::isfinite(thresholdHardShutdownIntf->hardShutdownLow()))
912     {
913         auto threshold = thresholdHardShutdownIntf->hardShutdownLow();
914         auto alarm = thresholdHardShutdownIntf->hardShutdownAlarmLow();
915         auto newAlarm =
916             checkThreshold(alarm, false, value, threshold, hysteresis);
917         if (alarm != newAlarm)
918         {
919             thresholdHardShutdownIntf->hardShutdownAlarmLow(newAlarm);
920             if (newAlarm)
921             {
922                 thresholdHardShutdownIntf->hardShutdownLowAlarmAsserted(value);
923             }
924             else
925             {
926                 thresholdHardShutdownIntf->hardShutdownLowAlarmDeasserted(
927                     value);
928             }
929         }
930     }
931 }
932 
triggerThresholdEvent(pldm::utils::Level eventType,pldm::utils::Direction direction,double rawValue,bool newAlarm,bool assert)933 int NumericSensor::triggerThresholdEvent(
934     pldm::utils::Level eventType, pldm::utils::Direction direction,
935     double rawValue, bool newAlarm, bool assert)
936 {
937     if (!valueIntf)
938     {
939         lg2::error(
940             "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.",
941             "NAME", sensorName);
942         return PLDM_ERROR;
943     }
944 
945     auto value = unitModifier(conversionFormula(rawValue));
946     lg2::error(
947         "triggerThresholdEvent eventType {TID}, direction {SID} value {VAL} newAlarm {PSTATE} assert {ESTATE}",
948         "TID", eventType, "SID", direction, "VAL", value, "PSTATE", newAlarm,
949         "ESTATE", assert);
950 
951     switch (eventType)
952     {
953         case pldm::utils::Level::WARNING:
954         {
955             if (!thresholdWarningIntf)
956             {
957                 lg2::error(
958                     "Error:Trigger sensor warning event for non warning threshold sensors {NAME}",
959                     "NAME", sensorName);
960                 return PLDM_ERROR;
961             }
962             if (direction == pldm::utils::Direction::HIGH &&
963                 std::isfinite(thresholdWarningIntf->warningHigh()))
964             {
965                 auto alarm = thresholdWarningIntf->warningAlarmHigh();
966                 if (alarm == newAlarm)
967                 {
968                     return PLDM_SUCCESS;
969                 }
970                 thresholdWarningIntf->warningAlarmHigh(newAlarm);
971                 if (assert)
972                 {
973                     thresholdWarningIntf->warningHighAlarmAsserted(value);
974                 }
975                 else
976                 {
977                     thresholdWarningIntf->warningHighAlarmDeasserted(value);
978                 }
979             }
980             else if (direction == pldm::utils::Direction::LOW &&
981                      std::isfinite(thresholdWarningIntf->warningLow()))
982             {
983                 auto alarm = thresholdWarningIntf->warningAlarmLow();
984                 if (alarm == newAlarm)
985                 {
986                     return PLDM_SUCCESS;
987                 }
988                 thresholdWarningIntf->warningAlarmLow(newAlarm);
989                 if (assert)
990                 {
991                     thresholdWarningIntf->warningLowAlarmAsserted(value);
992                 }
993                 else
994                 {
995                     thresholdWarningIntf->warningLowAlarmDeasserted(value);
996                 }
997             }
998             break;
999         }
1000         case pldm::utils::Level::CRITICAL:
1001         {
1002             if (!thresholdCriticalIntf)
1003             {
1004                 lg2::error(
1005                     "Error:Trigger sensor Critical event for non warning threshold sensors {NAME}",
1006                     "NAME", sensorName);
1007                 return PLDM_ERROR;
1008             }
1009             if (direction == pldm::utils::Direction::HIGH &&
1010                 std::isfinite(thresholdCriticalIntf->criticalHigh()))
1011             {
1012                 auto alarm = thresholdCriticalIntf->criticalAlarmHigh();
1013                 if (alarm == newAlarm)
1014                 {
1015                     return PLDM_SUCCESS;
1016                 }
1017                 thresholdCriticalIntf->criticalAlarmHigh(newAlarm);
1018                 if (assert)
1019                 {
1020                     thresholdCriticalIntf->criticalHighAlarmAsserted(value);
1021                 }
1022                 else
1023                 {
1024                     thresholdCriticalIntf->criticalHighAlarmDeasserted(value);
1025                 }
1026             }
1027             else if (direction == pldm::utils::Direction::LOW &&
1028                      std::isfinite(thresholdCriticalIntf->criticalLow()))
1029             {
1030                 auto alarm = thresholdCriticalIntf->criticalAlarmLow();
1031                 if (alarm == newAlarm)
1032                 {
1033                     return PLDM_SUCCESS;
1034                 }
1035                 thresholdCriticalIntf->criticalAlarmLow(newAlarm);
1036                 if (assert)
1037                 {
1038                     thresholdCriticalIntf->criticalLowAlarmAsserted(value);
1039                 }
1040                 else
1041                 {
1042                     thresholdCriticalIntf->criticalLowAlarmDeasserted(value);
1043                 }
1044             }
1045             break;
1046         }
1047 
1048         default:
1049             break;
1050     }
1051 
1052     return PLDM_SUCCESS;
1053 }
1054 } // namespace platform_mc
1055 } // namespace pldm
1056