1 #include "numeric_sensor.hpp"
2
3 #include "libpldm/platform.h"
4
5 #include "common/utils.hpp"
6 #include "requester/handler.hpp"
7
8 #include <limits>
9 #include <regex>
10
11 PHOSPHOR_LOG2_USING;
12
13 namespace pldm
14 {
15 namespace platform_mc
16 {
17
createInventoryPath(const std::string & associationPath,const std::string & sensorName,const uint16_t entityType,const uint16_t entityInstanceNum,const uint16_t containerId)18 inline bool NumericSensor::createInventoryPath(
19 const std::string& associationPath, const std::string& sensorName,
20 const uint16_t entityType, const uint16_t entityInstanceNum,
21 const uint16_t containerId)
22 {
23 auto& bus = pldm::utils::DBusHandler::getBus();
24 std::string invPath = associationPath + "/" + sensorName;
25 try
26 {
27 entityIntf = std::make_unique<EntityIntf>(bus, invPath.c_str());
28 }
29 catch (const sdbusplus::exception_t& e)
30 {
31 lg2::error(
32 "Failed to create Entity interface for compact numeric sensor {PATH} error - {ERROR}",
33 "PATH", invPath, "ERROR", e);
34 return false;
35 }
36 entityIntf->entityType(entityType);
37 entityIntf->entityInstanceNumber(entityInstanceNum);
38 entityIntf->containerID(containerId);
39
40 return true;
41 }
42
NumericSensor(const pldm_tid_t tid,const bool sensorDisabled,std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr,std::string & sensorName,std::string & associationPath)43 NumericSensor::NumericSensor(
44 const pldm_tid_t tid, const bool sensorDisabled,
45 std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr, std::string& sensorName,
46 std::string& associationPath) : tid(tid), sensorName(sensorName)
47 {
48 if (!pdr)
49 {
50 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
51 }
52
53 sensorId = pdr->sensor_id;
54 std::string path;
55 SensorUnit sensorUnit = SensorUnit::DegreesC;
56 MetricUnit metricUnit = MetricUnit::Count;
57 useMetricInterface = false;
58
59 switch (pdr->base_unit)
60 {
61 case PLDM_SENSOR_UNIT_DEGRESS_C:
62 sensorNameSpace = "/xyz/openbmc_project/sensors/temperature/";
63 sensorUnit = SensorUnit::DegreesC;
64 break;
65 case PLDM_SENSOR_UNIT_VOLTS:
66 sensorNameSpace = "/xyz/openbmc_project/sensors/voltage/";
67 sensorUnit = SensorUnit::Volts;
68 break;
69 case PLDM_SENSOR_UNIT_AMPS:
70 sensorNameSpace = "/xyz/openbmc_project/sensors/current/";
71 sensorUnit = SensorUnit::Amperes;
72 break;
73 case PLDM_SENSOR_UNIT_RPM:
74 sensorNameSpace = "/xyz/openbmc_project/sensors/fan_pwm/";
75 sensorUnit = SensorUnit::RPMS;
76 break;
77 case PLDM_SENSOR_UNIT_WATTS:
78 sensorNameSpace = "/xyz/openbmc_project/sensors/power/";
79 sensorUnit = SensorUnit::Watts;
80 break;
81 case PLDM_SENSOR_UNIT_JOULES:
82 sensorNameSpace = "/xyz/openbmc_project/sensors/energy/";
83 sensorUnit = SensorUnit::Joules;
84 break;
85 case PLDM_SENSOR_UNIT_PERCENTAGE:
86 sensorNameSpace = "/xyz/openbmc_project/sensors/utilization/";
87 sensorUnit = SensorUnit::Percent;
88 break;
89 case PLDM_SENSOR_UNIT_COUNTS:
90 case PLDM_SENSOR_UNIT_CORRECTED_ERRORS:
91 case PLDM_SENSOR_UNIT_UNCORRECTABLE_ERRORS:
92 sensorNameSpace = "/xyz/openbmc_project/metric/count/";
93 useMetricInterface = true;
94 break;
95 case PLDM_SENSOR_UNIT_OEMUNIT:
96 sensorNameSpace = "/xyz/openbmc_project/metric/oem/";
97 useMetricInterface = true;
98 break;
99 default:
100 lg2::error("Sensor {NAME} has Invalid baseUnit {UNIT}.", "NAME",
101 sensorName, "UNIT", pdr->base_unit);
102 throw sdbusplus::xyz::openbmc_project::Common::Error::
103 InvalidArgument();
104 break;
105 }
106
107 path = sensorNameSpace + sensorName;
108 try
109 {
110 std::string tmp{};
111 std::string interface = SENSOR_VALUE_INTF;
112 if (useMetricInterface)
113 {
114 interface = METRIC_VALUE_INTF;
115 }
116 tmp = pldm::utils::DBusHandler().getService(path.c_str(),
117 interface.c_str());
118
119 if (!tmp.empty())
120 {
121 throw sdbusplus::xyz::openbmc_project::Common::Error::
122 TooManyResources();
123 }
124 }
125 catch (const std::exception&)
126 {
127 /* The sensor object path is not created */
128 }
129
130 auto& bus = pldm::utils::DBusHandler::getBus();
131 try
132 {
133 associationDefinitionsIntf =
134 std::make_unique<AssociationDefinitionsInft>(bus, path.c_str());
135 }
136 catch (const sdbusplus::exception_t& e)
137 {
138 lg2::error(
139 "Failed to create association interface for numeric sensor {PATH} error - {ERROR}",
140 "PATH", path, "ERROR", e);
141 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
142 }
143
144 associationDefinitionsIntf->associations(
145 {{"chassis", "all_sensors", associationPath}});
146
147 double maxValue = std::numeric_limits<double>::quiet_NaN();
148 double minValue = std::numeric_limits<double>::quiet_NaN();
149
150 switch (pdr->sensor_data_size)
151 {
152 case PLDM_SENSOR_DATA_SIZE_UINT8:
153 maxValue = pdr->max_readable.value_u8;
154 minValue = pdr->min_readable.value_u8;
155 hysteresis = pdr->hysteresis.value_u8;
156 break;
157 case PLDM_SENSOR_DATA_SIZE_SINT8:
158 maxValue = pdr->max_readable.value_s8;
159 minValue = pdr->min_readable.value_s8;
160 hysteresis = pdr->hysteresis.value_s8;
161 break;
162 case PLDM_SENSOR_DATA_SIZE_UINT16:
163 maxValue = pdr->max_readable.value_u16;
164 minValue = pdr->min_readable.value_u16;
165 hysteresis = pdr->hysteresis.value_u16;
166 break;
167 case PLDM_SENSOR_DATA_SIZE_SINT16:
168 maxValue = pdr->max_readable.value_s16;
169 minValue = pdr->min_readable.value_s16;
170 hysteresis = pdr->hysteresis.value_s16;
171 break;
172 case PLDM_SENSOR_DATA_SIZE_UINT32:
173 maxValue = pdr->max_readable.value_u32;
174 minValue = pdr->min_readable.value_u32;
175 hysteresis = pdr->hysteresis.value_u32;
176 break;
177 case PLDM_SENSOR_DATA_SIZE_SINT32:
178 maxValue = pdr->max_readable.value_s32;
179 minValue = pdr->min_readable.value_s32;
180 hysteresis = pdr->hysteresis.value_s32;
181 break;
182 }
183
184 bool hasCriticalThresholds = false;
185 bool hasWarningThresholds = false;
186 double criticalHigh = std::numeric_limits<double>::quiet_NaN();
187 double criticalLow = std::numeric_limits<double>::quiet_NaN();
188 double warningHigh = std::numeric_limits<double>::quiet_NaN();
189 double warningLow = std::numeric_limits<double>::quiet_NaN();
190
191 if (pdr->supported_thresholds.bits.bit0)
192 {
193 hasWarningThresholds = true;
194 switch (pdr->range_field_format)
195 {
196 case PLDM_RANGE_FIELD_FORMAT_UINT8:
197 warningHigh = pdr->warning_high.value_u8;
198 break;
199 case PLDM_RANGE_FIELD_FORMAT_SINT8:
200 warningHigh = pdr->warning_high.value_s8;
201 break;
202 case PLDM_RANGE_FIELD_FORMAT_UINT16:
203 warningHigh = pdr->warning_high.value_u16;
204 break;
205 case PLDM_RANGE_FIELD_FORMAT_SINT16:
206 warningHigh = pdr->warning_high.value_s16;
207 break;
208 case PLDM_RANGE_FIELD_FORMAT_UINT32:
209 warningHigh = pdr->warning_high.value_u32;
210 break;
211 case PLDM_RANGE_FIELD_FORMAT_SINT32:
212 warningHigh = pdr->warning_high.value_s32;
213 break;
214 case PLDM_RANGE_FIELD_FORMAT_REAL32:
215 warningHigh = pdr->warning_high.value_f32;
216 break;
217 }
218 }
219
220 if (pdr->supported_thresholds.bits.bit3)
221 {
222 hasWarningThresholds = true;
223 switch (pdr->range_field_format)
224 {
225 case PLDM_RANGE_FIELD_FORMAT_UINT8:
226 warningLow = pdr->warning_low.value_u8;
227 break;
228 case PLDM_RANGE_FIELD_FORMAT_SINT8:
229 warningLow = pdr->warning_low.value_s8;
230 break;
231 case PLDM_RANGE_FIELD_FORMAT_UINT16:
232 warningLow = pdr->warning_low.value_u16;
233 break;
234 case PLDM_RANGE_FIELD_FORMAT_SINT16:
235 warningLow = pdr->warning_low.value_s16;
236 break;
237 case PLDM_RANGE_FIELD_FORMAT_UINT32:
238 warningLow = pdr->warning_low.value_u32;
239 break;
240 case PLDM_RANGE_FIELD_FORMAT_SINT32:
241 warningLow = pdr->warning_low.value_s32;
242 break;
243 case PLDM_RANGE_FIELD_FORMAT_REAL32:
244 warningLow = pdr->warning_low.value_f32;
245 break;
246 }
247 }
248
249 if (pdr->supported_thresholds.bits.bit1)
250 {
251 hasCriticalThresholds = true;
252 switch (pdr->range_field_format)
253 {
254 case PLDM_RANGE_FIELD_FORMAT_UINT8:
255 criticalHigh = pdr->critical_high.value_u8;
256 break;
257 case PLDM_RANGE_FIELD_FORMAT_SINT8:
258 criticalHigh = pdr->critical_high.value_s8;
259 break;
260 case PLDM_RANGE_FIELD_FORMAT_UINT16:
261 criticalHigh = pdr->critical_high.value_u16;
262 break;
263 case PLDM_RANGE_FIELD_FORMAT_SINT16:
264 criticalHigh = pdr->critical_high.value_s16;
265 break;
266 case PLDM_RANGE_FIELD_FORMAT_UINT32:
267 criticalHigh = pdr->critical_high.value_u32;
268 break;
269 case PLDM_RANGE_FIELD_FORMAT_SINT32:
270 criticalHigh = pdr->critical_high.value_s32;
271 break;
272 case PLDM_RANGE_FIELD_FORMAT_REAL32:
273 criticalHigh = pdr->critical_high.value_f32;
274 break;
275 }
276 }
277
278 if (pdr->supported_thresholds.bits.bit4)
279 {
280 hasCriticalThresholds = true;
281 switch (pdr->range_field_format)
282 {
283 case PLDM_RANGE_FIELD_FORMAT_UINT8:
284 criticalLow = pdr->critical_low.value_u8;
285 break;
286 case PLDM_RANGE_FIELD_FORMAT_SINT8:
287 criticalLow = pdr->critical_low.value_s8;
288 break;
289 case PLDM_RANGE_FIELD_FORMAT_UINT16:
290 criticalLow = pdr->critical_low.value_u16;
291 break;
292 case PLDM_RANGE_FIELD_FORMAT_SINT16:
293 criticalLow = pdr->critical_low.value_s16;
294 break;
295 case PLDM_RANGE_FIELD_FORMAT_UINT32:
296 criticalLow = pdr->critical_low.value_u32;
297 break;
298 case PLDM_RANGE_FIELD_FORMAT_SINT32:
299 criticalLow = pdr->critical_low.value_s32;
300 break;
301 case PLDM_RANGE_FIELD_FORMAT_REAL32:
302 criticalLow = pdr->critical_low.value_f32;
303 break;
304 }
305 }
306
307 resolution = pdr->resolution;
308 offset = pdr->offset;
309 baseUnitModifier = pdr->unit_modifier;
310 timeStamp = 0;
311
312 /**
313 * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds
314 * updateTime is in microseconds
315 */
316 updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000);
317 if (!std::isnan(pdr->update_interval))
318 {
319 updateTime = pdr->update_interval * 1000000;
320 }
321
322 if (!useMetricInterface)
323 {
324 try
325 {
326 valueIntf = std::make_unique<ValueIntf>(bus, path.c_str());
327 }
328 catch (const sdbusplus::exception_t& e)
329 {
330 lg2::error(
331 "Failed to create Value interface for numeric sensor {PATH} error - {ERROR}",
332 "PATH", path, "ERROR", e);
333 throw sdbusplus::xyz::openbmc_project::Common::Error::
334 InvalidArgument();
335 }
336 valueIntf->maxValue(unitModifier(conversionFormula(maxValue)));
337 valueIntf->minValue(unitModifier(conversionFormula(minValue)));
338 valueIntf->unit(sensorUnit);
339 }
340 else
341 {
342 try
343 {
344 metricIntf = std::make_unique<MetricIntf>(bus, path.c_str());
345 }
346 catch (const sdbusplus::exception_t& e)
347 {
348 lg2::error(
349 "Failed to create Metric interface for numeric sensor {PATH} error - {ERROR}",
350 "PATH", path, "ERROR", e);
351 throw sdbusplus::xyz::openbmc_project::Common::Error::
352 InvalidArgument();
353 }
354 metricIntf->maxValue(unitModifier(conversionFormula(maxValue)));
355 metricIntf->minValue(unitModifier(conversionFormula(minValue)));
356 metricIntf->unit(metricUnit);
357 }
358
359 hysteresis = unitModifier(conversionFormula(hysteresis));
360
361 if (!createInventoryPath(associationPath, sensorName, pdr->entity_type,
362 pdr->entity_instance_num, pdr->container_id))
363 {
364 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
365 }
366
367 try
368 {
369 availabilityIntf =
370 std::make_unique<AvailabilityIntf>(bus, path.c_str());
371 }
372 catch (const sdbusplus::exception_t& e)
373 {
374 lg2::error(
375 "Failed to create Availability interface for numeric sensor {PATH} error - {ERROR}",
376 "PATH", path, "ERROR", e);
377 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
378 }
379 availabilityIntf->available(true);
380
381 try
382 {
383 operationalStatusIntf =
384 std::make_unique<OperationalStatusIntf>(bus, path.c_str());
385 }
386 catch (const sdbusplus::exception_t& e)
387 {
388 lg2::error(
389 "Failed to create Operation status interface for numeric sensor {PATH} error - {ERROR}",
390 "PATH", path, "ERROR", e);
391 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
392 }
393 operationalStatusIntf->functional(!sensorDisabled);
394
395 if (hasWarningThresholds && !useMetricInterface)
396 {
397 try
398 {
399 thresholdWarningIntf =
400 std::make_unique<ThresholdWarningIntf>(bus, path.c_str());
401 }
402 catch (const sdbusplus::exception_t& e)
403 {
404 lg2::error(
405 "Failed to create Threshold warning interface for numeric sensor {PATH} error - {ERROR}",
406 "PATH", path, "ERROR", e);
407 throw sdbusplus::xyz::openbmc_project::Common::Error::
408 InvalidArgument();
409 }
410 thresholdWarningIntf->warningHigh(unitModifier(warningHigh));
411 thresholdWarningIntf->warningLow(unitModifier(warningLow));
412 }
413
414 if (hasCriticalThresholds && !useMetricInterface)
415 {
416 try
417 {
418 thresholdCriticalIntf =
419 std::make_unique<ThresholdCriticalIntf>(bus, path.c_str());
420 }
421 catch (const sdbusplus::exception_t& e)
422 {
423 lg2::error(
424 "Failed to create Threshold critical interface for numeric sensor {PATH} error - {ERROR}",
425 "PATH", path, "ERROR", e);
426 throw sdbusplus::xyz::openbmc_project::Common::Error::
427 InvalidArgument();
428 }
429 thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh));
430 thresholdCriticalIntf->criticalLow(unitModifier(criticalLow));
431 }
432 }
433
NumericSensor(const pldm_tid_t tid,const bool sensorDisabled,std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr,std::string & sensorName,std::string & associationPath)434 NumericSensor::NumericSensor(
435 const pldm_tid_t tid, const bool sensorDisabled,
436 std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr,
437 std::string& sensorName, std::string& associationPath) :
438 tid(tid), sensorName(sensorName)
439 {
440 if (!pdr)
441 {
442 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
443 }
444
445 sensorId = pdr->sensor_id;
446 std::string path;
447 SensorUnit sensorUnit = SensorUnit::DegreesC;
448 MetricUnit metricUnit = MetricUnit::Count;
449 useMetricInterface = false;
450
451 switch (pdr->base_unit)
452 {
453 case PLDM_SENSOR_UNIT_DEGRESS_C:
454 sensorNameSpace = "/xyz/openbmc_project/sensors/temperature/";
455 sensorUnit = SensorUnit::DegreesC;
456 break;
457 case PLDM_SENSOR_UNIT_VOLTS:
458 sensorNameSpace = "/xyz/openbmc_project/sensors/voltage/";
459 sensorUnit = SensorUnit::Volts;
460 break;
461 case PLDM_SENSOR_UNIT_AMPS:
462 sensorNameSpace = "/xyz/openbmc_project/sensors/current/";
463 sensorUnit = SensorUnit::Amperes;
464 break;
465 case PLDM_SENSOR_UNIT_RPM:
466 sensorNameSpace = "/xyz/openbmc_project/sensors/fan_pwm/";
467 sensorUnit = SensorUnit::RPMS;
468 break;
469 case PLDM_SENSOR_UNIT_WATTS:
470 sensorNameSpace = "/xyz/openbmc_project/sensors/power/";
471 sensorUnit = SensorUnit::Watts;
472 break;
473 case PLDM_SENSOR_UNIT_JOULES:
474 sensorNameSpace = "/xyz/openbmc_project/sensors/energy/";
475 sensorUnit = SensorUnit::Joules;
476 break;
477 case PLDM_SENSOR_UNIT_PERCENTAGE:
478 sensorNameSpace = "/xyz/openbmc_project/sensors/utilization/";
479 sensorUnit = SensorUnit::Percent;
480 break;
481 case PLDM_SENSOR_UNIT_COUNTS:
482 case PLDM_SENSOR_UNIT_CORRECTED_ERRORS:
483 case PLDM_SENSOR_UNIT_UNCORRECTABLE_ERRORS:
484 sensorNameSpace = "/xyz/openbmc_project/metric/count/";
485 useMetricInterface = true;
486 break;
487 case PLDM_SENSOR_UNIT_OEMUNIT:
488 sensorNameSpace = "/xyz/openbmc_project/metric/oem/";
489 useMetricInterface = true;
490 break;
491 default:
492 lg2::error("Sensor {NAME} has Invalid baseUnit {UNIT}.", "NAME",
493 sensorName, "UNIT", pdr->base_unit);
494 throw sdbusplus::xyz::openbmc_project::Common::Error::
495 InvalidArgument();
496 break;
497 }
498
499 path = sensorNameSpace + sensorName;
500 try
501 {
502 std::string tmp{};
503 std::string interface = SENSOR_VALUE_INTF;
504 if (useMetricInterface)
505 {
506 interface = METRIC_VALUE_INTF;
507 }
508 tmp = pldm::utils::DBusHandler().getService(path.c_str(),
509 interface.c_str());
510
511 if (!tmp.empty())
512 {
513 throw sdbusplus::xyz::openbmc_project::Common::Error::
514 TooManyResources();
515 }
516 }
517 catch (const std::exception&)
518 {
519 /* The sensor object path is not created */
520 }
521
522 auto& bus = pldm::utils::DBusHandler::getBus();
523 try
524 {
525 associationDefinitionsIntf =
526 std::make_unique<AssociationDefinitionsInft>(bus, path.c_str());
527 }
528 catch (const sdbusplus::exception_t& e)
529 {
530 lg2::error(
531 "Failed to create Association interface for compact numeric sensor {PATH} error - {ERROR}",
532 "PATH", path, "ERROR", e);
533 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
534 }
535 associationDefinitionsIntf->associations(
536 {{"chassis", "all_sensors", associationPath.c_str()}});
537
538 double maxValue = std::numeric_limits<double>::quiet_NaN();
539 double minValue = std::numeric_limits<double>::quiet_NaN();
540 bool hasWarningThresholds = false;
541 bool hasCriticalThresholds = false;
542 double criticalHigh = std::numeric_limits<double>::quiet_NaN();
543 double criticalLow = std::numeric_limits<double>::quiet_NaN();
544 double warningHigh = std::numeric_limits<double>::quiet_NaN();
545 double warningLow = std::numeric_limits<double>::quiet_NaN();
546
547 if (pdr->range_field_support.bits.bit0)
548 {
549 hasWarningThresholds = true;
550 warningHigh = pdr->warning_high;
551 }
552 if (pdr->range_field_support.bits.bit1)
553 {
554 hasWarningThresholds = true;
555 warningLow = pdr->warning_low;
556 }
557
558 if (pdr->range_field_support.bits.bit2)
559 {
560 hasCriticalThresholds = true;
561 criticalHigh = pdr->critical_high;
562 }
563
564 if (pdr->range_field_support.bits.bit3)
565 {
566 hasCriticalThresholds = true;
567 criticalLow = pdr->critical_low;
568 }
569
570 resolution = std::numeric_limits<double>::quiet_NaN();
571 offset = std::numeric_limits<double>::quiet_NaN();
572 baseUnitModifier = pdr->unit_modifier;
573 timeStamp = 0;
574 hysteresis = 0;
575
576 /**
577 * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds
578 * updateTime is in microseconds
579 */
580 updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000);
581
582 if (!useMetricInterface)
583 {
584 try
585 {
586 valueIntf = std::make_unique<ValueIntf>(bus, path.c_str());
587 }
588 catch (const sdbusplus::exception_t& e)
589 {
590 lg2::error(
591 "Failed to create Value interface for compact numeric sensor {PATH} error - {ERROR}",
592 "PATH", path, "ERROR", e);
593 throw sdbusplus::xyz::openbmc_project::Common::Error::
594 InvalidArgument();
595 }
596 valueIntf->maxValue(unitModifier(conversionFormula(maxValue)));
597 valueIntf->minValue(unitModifier(conversionFormula(minValue)));
598 valueIntf->unit(sensorUnit);
599 }
600 else
601 {
602 try
603 {
604 metricIntf = std::make_unique<MetricIntf>(bus, path.c_str());
605 }
606 catch (const sdbusplus::exception_t& e)
607 {
608 lg2::error(
609 "Failed to create Metric interface for compact numeric sensor {PATH} error - {ERROR}",
610 "PATH", path, "ERROR", e);
611 throw sdbusplus::xyz::openbmc_project::Common::Error::
612 InvalidArgument();
613 }
614 metricIntf->maxValue(unitModifier(conversionFormula(maxValue)));
615 metricIntf->minValue(unitModifier(conversionFormula(minValue)));
616 metricIntf->unit(metricUnit);
617 }
618
619 hysteresis = unitModifier(conversionFormula(hysteresis));
620
621 if (!createInventoryPath(associationPath, sensorName, pdr->entity_type,
622 pdr->entity_instance, pdr->container_id))
623 {
624 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
625 }
626
627 try
628 {
629 availabilityIntf =
630 std::make_unique<AvailabilityIntf>(bus, path.c_str());
631 }
632 catch (const sdbusplus::exception_t& e)
633 {
634 lg2::error(
635 "Failed to create Availability interface for compact numeric sensor {PATH} error - {ERROR}",
636 "PATH", path, "ERROR", e);
637 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
638 }
639 availabilityIntf->available(true);
640
641 try
642 {
643 operationalStatusIntf =
644 std::make_unique<OperationalStatusIntf>(bus, path.c_str());
645 }
646 catch (const sdbusplus::exception_t& e)
647 {
648 lg2::error(
649 "Failed to create Operational status interface for compact numeric sensor {PATH} error - {ERROR}",
650 "PATH", path, "ERROR", e);
651 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
652 }
653 operationalStatusIntf->functional(!sensorDisabled);
654
655 if (hasWarningThresholds && !useMetricInterface)
656 {
657 try
658 {
659 thresholdWarningIntf =
660 std::make_unique<ThresholdWarningIntf>(bus, path.c_str());
661 }
662 catch (const sdbusplus::exception_t& e)
663 {
664 lg2::error(
665 "Failed to create Warning threshold interface for compact numeric sensor {PATH} error - {ERROR}",
666 "PATH", path, "ERROR", e);
667 throw sdbusplus::xyz::openbmc_project::Common::Error::
668 InvalidArgument();
669 }
670 thresholdWarningIntf->warningHigh(unitModifier(warningHigh));
671 thresholdWarningIntf->warningLow(unitModifier(warningLow));
672 }
673
674 if (hasCriticalThresholds && !useMetricInterface)
675 {
676 try
677 {
678 thresholdCriticalIntf =
679 std::make_unique<ThresholdCriticalIntf>(bus, path.c_str());
680 }
681 catch (const sdbusplus::exception_t& e)
682 {
683 lg2::error(
684 "Failed to create Critical threshold interface for compact numeric sensor {PATH} error - {ERROR}",
685 "PATH", path, "ERROR", e);
686 throw sdbusplus::xyz::openbmc_project::Common::Error::
687 InvalidArgument();
688 }
689 thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh));
690 thresholdCriticalIntf->criticalLow(unitModifier(criticalLow));
691 }
692 }
693
conversionFormula(double value)694 double NumericSensor::conversionFormula(double value)
695 {
696 double convertedValue = value;
697 convertedValue *= std::isnan(resolution) ? 1 : resolution;
698 convertedValue += std::isnan(offset) ? 0 : offset;
699 return convertedValue;
700 }
701
unitModifier(double value)702 double NumericSensor::unitModifier(double value)
703 {
704 return std::isnan(value) ? value : value * std::pow(10, baseUnitModifier);
705 }
706
updateReading(bool available,bool functional,double value)707 void NumericSensor::updateReading(bool available, bool functional, double value)
708 {
709 if (!availabilityIntf || !operationalStatusIntf ||
710 (!useMetricInterface && !valueIntf) ||
711 (useMetricInterface && !metricIntf))
712 {
713 lg2::error(
714 "Failed to update sensor {NAME} D-Bus interface don't exist.",
715 "NAME", sensorName);
716 return;
717 }
718 availabilityIntf->available(available);
719 operationalStatusIntf->functional(functional);
720 double curValue = 0;
721 if (!useMetricInterface)
722 {
723 curValue = valueIntf->value();
724 }
725 else
726 {
727 curValue = metricIntf->value();
728 }
729
730 double newValue = std::numeric_limits<double>::quiet_NaN();
731 if (functional && available)
732 {
733 newValue = unitModifier(conversionFormula(value));
734 if (newValue != curValue &&
735 (!std::isnan(newValue) || !std::isnan(curValue)))
736 {
737 if (!useMetricInterface)
738 {
739 valueIntf->value(newValue);
740 updateThresholds();
741 }
742 else
743 {
744 metricIntf->value(newValue);
745 }
746 }
747 }
748 else
749 {
750 if (newValue != curValue &&
751 (!std::isnan(newValue) || !std::isnan(curValue)))
752 {
753 if (!useMetricInterface)
754 {
755 valueIntf->value(std::numeric_limits<double>::quiet_NaN());
756 }
757 else
758 {
759 metricIntf->value(std::numeric_limits<double>::quiet_NaN());
760 }
761 }
762 }
763 }
764
handleErrGetSensorReading()765 void NumericSensor::handleErrGetSensorReading()
766 {
767 if (!operationalStatusIntf || (!useMetricInterface && !valueIntf) ||
768 (useMetricInterface && !metricIntf))
769 {
770 lg2::error(
771 "Failed to update sensor {NAME} D-Bus interfaces don't exist.",
772 "NAME", sensorName);
773 return;
774 }
775 operationalStatusIntf->functional(false);
776 if (!useMetricInterface)
777 {
778 valueIntf->value(std::numeric_limits<double>::quiet_NaN());
779 }
780 else
781 {
782 metricIntf->value(std::numeric_limits<double>::quiet_NaN());
783 }
784 }
785
checkThreshold(bool alarm,bool direction,double value,double threshold,double hyst)786 bool NumericSensor::checkThreshold(bool alarm, bool direction, double value,
787 double threshold, double hyst)
788 {
789 if (direction)
790 {
791 if (value >= threshold)
792 {
793 return true;
794 }
795 if (value < (threshold - hyst))
796 {
797 return false;
798 }
799 }
800 else
801 {
802 if (value <= threshold)
803 {
804 return true;
805 }
806 if (value > (threshold + hyst))
807 {
808 return false;
809 }
810 }
811 return alarm;
812 }
813
updateThresholds()814 void NumericSensor::updateThresholds()
815 {
816 double value = std::numeric_limits<double>::quiet_NaN();
817
818 if ((!useMetricInterface && !valueIntf) ||
819 (useMetricInterface && !metricIntf))
820 {
821 lg2::error(
822 "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.",
823 "NAME", sensorName);
824 return;
825 }
826 if (!useMetricInterface)
827 {
828 value = valueIntf->value();
829 }
830 else
831 {
832 value = metricIntf->value();
833 }
834 if (thresholdWarningIntf &&
835 !std::isnan(thresholdWarningIntf->warningHigh()))
836 {
837 auto threshold = thresholdWarningIntf->warningHigh();
838 auto alarm = thresholdWarningIntf->warningAlarmHigh();
839 auto newAlarm =
840 checkThreshold(alarm, true, value, threshold, hysteresis);
841 if (alarm != newAlarm)
842 {
843 thresholdWarningIntf->warningAlarmHigh(newAlarm);
844 if (newAlarm)
845 {
846 thresholdWarningIntf->warningHighAlarmAsserted(value);
847 }
848 else
849 {
850 thresholdWarningIntf->warningHighAlarmDeasserted(value);
851 }
852 }
853 }
854
855 if (thresholdWarningIntf && !std::isnan(thresholdWarningIntf->warningLow()))
856 {
857 auto threshold = thresholdWarningIntf->warningLow();
858 auto alarm = thresholdWarningIntf->warningAlarmLow();
859 auto newAlarm =
860 checkThreshold(alarm, false, value, threshold, hysteresis);
861 if (alarm != newAlarm)
862 {
863 thresholdWarningIntf->warningAlarmLow(newAlarm);
864 if (newAlarm)
865 {
866 thresholdWarningIntf->warningLowAlarmAsserted(value);
867 }
868 else
869 {
870 thresholdWarningIntf->warningLowAlarmDeasserted(value);
871 }
872 }
873 }
874
875 if (thresholdCriticalIntf &&
876 !std::isnan(thresholdCriticalIntf->criticalHigh()))
877 {
878 auto threshold = thresholdCriticalIntf->criticalHigh();
879 auto alarm = thresholdCriticalIntf->criticalAlarmHigh();
880 auto newAlarm =
881 checkThreshold(alarm, true, value, threshold, hysteresis);
882 if (alarm != newAlarm)
883 {
884 thresholdCriticalIntf->criticalAlarmHigh(newAlarm);
885 if (newAlarm)
886 {
887 thresholdCriticalIntf->criticalHighAlarmAsserted(value);
888 }
889 else
890 {
891 thresholdCriticalIntf->criticalHighAlarmDeasserted(value);
892 }
893 }
894 }
895
896 if (thresholdCriticalIntf &&
897 !std::isnan(thresholdCriticalIntf->criticalLow()))
898 {
899 auto threshold = thresholdCriticalIntf->criticalLow();
900 auto alarm = thresholdCriticalIntf->criticalAlarmLow();
901 auto newAlarm =
902 checkThreshold(alarm, false, value, threshold, hysteresis);
903 if (alarm != newAlarm)
904 {
905 thresholdCriticalIntf->criticalAlarmLow(newAlarm);
906 if (newAlarm)
907 {
908 thresholdCriticalIntf->criticalLowAlarmAsserted(value);
909 }
910 else
911 {
912 thresholdCriticalIntf->criticalLowAlarmDeasserted(value);
913 }
914 }
915 }
916 }
917
triggerThresholdEvent(pldm::utils::Level eventType,pldm::utils::Direction direction,double rawValue,bool newAlarm,bool assert)918 int NumericSensor::triggerThresholdEvent(
919 pldm::utils::Level eventType, pldm::utils::Direction direction,
920 double rawValue, bool newAlarm, bool assert)
921 {
922 if (!valueIntf)
923 {
924 lg2::error(
925 "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.",
926 "NAME", sensorName);
927 return PLDM_ERROR;
928 }
929
930 auto value = unitModifier(conversionFormula(rawValue));
931 lg2::error(
932 "triggerThresholdEvent eventType {TID}, direction {SID} value {VAL} newAlarm {PSTATE} assert {ESTATE}",
933 "TID", eventType, "SID", direction, "VAL", value, "PSTATE", newAlarm,
934 "ESTATE", assert);
935
936 switch (eventType)
937 {
938 case pldm::utils::Level::WARNING:
939 {
940 if (!thresholdWarningIntf)
941 {
942 lg2::error(
943 "Error:Trigger sensor warning event for non warning threshold sensors {NAME}",
944 "NAME", sensorName);
945 return PLDM_ERROR;
946 }
947 if (direction == pldm::utils::Direction::HIGH &&
948 !std::isnan(thresholdWarningIntf->warningHigh()))
949 {
950 auto alarm = thresholdWarningIntf->warningAlarmHigh();
951 if (alarm == newAlarm)
952 {
953 return PLDM_SUCCESS;
954 }
955 thresholdWarningIntf->warningAlarmHigh(newAlarm);
956 if (assert)
957 {
958 thresholdWarningIntf->warningHighAlarmAsserted(value);
959 }
960 else
961 {
962 thresholdWarningIntf->warningHighAlarmDeasserted(value);
963 }
964 }
965 else if (direction == pldm::utils::Direction::LOW &&
966 !std::isnan(thresholdWarningIntf->warningLow()))
967 {
968 auto alarm = thresholdWarningIntf->warningAlarmLow();
969 if (alarm == newAlarm)
970 {
971 return PLDM_SUCCESS;
972 }
973 thresholdWarningIntf->warningAlarmLow(newAlarm);
974 if (assert)
975 {
976 thresholdWarningIntf->warningLowAlarmAsserted(value);
977 }
978 else
979 {
980 thresholdWarningIntf->warningLowAlarmDeasserted(value);
981 }
982 }
983 break;
984 }
985 case pldm::utils::Level::CRITICAL:
986 {
987 if (!thresholdCriticalIntf)
988 {
989 lg2::error(
990 "Error:Trigger sensor Critical event for non warning threshold sensors {NAME}",
991 "NAME", sensorName);
992 return PLDM_ERROR;
993 }
994 if (direction == pldm::utils::Direction::HIGH &&
995 !std::isnan(thresholdCriticalIntf->criticalHigh()))
996 {
997 auto alarm = thresholdCriticalIntf->criticalAlarmHigh();
998 if (alarm == newAlarm)
999 {
1000 return PLDM_SUCCESS;
1001 }
1002 thresholdCriticalIntf->criticalAlarmHigh(newAlarm);
1003 if (assert)
1004 {
1005 thresholdCriticalIntf->criticalHighAlarmAsserted(value);
1006 }
1007 else
1008 {
1009 thresholdCriticalIntf->criticalHighAlarmDeasserted(value);
1010 }
1011 }
1012 else if (direction == pldm::utils::Direction::LOW &&
1013 !std::isnan(thresholdCriticalIntf->criticalLow()))
1014 {
1015 auto alarm = thresholdCriticalIntf->criticalAlarmLow();
1016 if (alarm == newAlarm)
1017 {
1018 return PLDM_SUCCESS;
1019 }
1020 thresholdCriticalIntf->criticalAlarmLow(newAlarm);
1021 if (assert)
1022 {
1023 thresholdCriticalIntf->criticalLowAlarmAsserted(value);
1024 }
1025 else
1026 {
1027 thresholdCriticalIntf->criticalLowAlarmDeasserted(value);
1028 }
1029 }
1030 break;
1031 }
1032
1033 default:
1034 break;
1035 }
1036
1037 return PLDM_SUCCESS;
1038 }
1039 } // namespace platform_mc
1040 } // namespace pldm
1041