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