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