blob: 7536fe439cba7ff38511900bc66b2fc2dca81a8a [file] [log] [blame]
Thu Nguyen3c5486d2024-08-01 08:03:08 +00001#include "numeric_sensor.hpp"
2
Thu Nguyen3c5486d2024-08-01 08:03:08 +00003#include "common/utils.hpp"
4#include "requester/handler.hpp"
5
Manojkiran Edafe252792025-03-13 19:24:19 +05306#include <libpldm/platform.h>
7
Thu Nguyen3c5486d2024-08-01 08:03:08 +00008#include <limits>
9#include <regex>
10
11PHOSPHOR_LOG2_USING;
12
13namespace pldm
14{
15namespace platform_mc
16{
Amithash Prasad2480c572025-05-01 15:34:34 -070017static const std::array<pldm::utils::Level, 3> allThresholdLevels = {
18 pldm::utils::Level::WARNING, pldm::utils::Level::CRITICAL,
19 pldm::utils::Level::HARDSHUTDOWN};
20static const std::array<pldm::utils::Direction, 2> allThresholdDirections = {
21 pldm::utils::Direction::HIGH, pldm::utils::Direction::LOW};
Thu Nguyen3c5486d2024-08-01 08:03:08 +000022
Chau Lyd197f092023-11-06 07:29:06 +000023inline bool NumericSensor::createInventoryPath(
24 const std::string& associationPath, const std::string& sensorName,
25 const uint16_t entityType, const uint16_t entityInstanceNum,
26 const uint16_t containerId)
27{
28 auto& bus = pldm::utils::DBusHandler::getBus();
29 std::string invPath = associationPath + "/" + sensorName;
30 try
31 {
32 entityIntf = std::make_unique<EntityIntf>(bus, invPath.c_str());
33 }
34 catch (const sdbusplus::exception_t& e)
35 {
36 lg2::error(
37 "Failed to create Entity interface for compact numeric sensor {PATH} error - {ERROR}",
38 "PATH", invPath, "ERROR", e);
39 return false;
40 }
41 entityIntf->entityType(entityType);
42 entityIntf->entityInstanceNumber(entityInstanceNum);
43 entityIntf->containerID(containerId);
44
45 return true;
46}
47
Amithash Prasada1871172024-12-19 14:26:10 -080048inline double getSensorDataValue(uint8_t sensor_data_size,
49 union_sensor_data_size& value)
50{
51 double ret = std::numeric_limits<double>::quiet_NaN();
52 switch (sensor_data_size)
53 {
54 case PLDM_SENSOR_DATA_SIZE_UINT8:
55 ret = value.value_u8;
56 break;
57 case PLDM_SENSOR_DATA_SIZE_SINT8:
58 ret = value.value_s8;
59 break;
60 case PLDM_SENSOR_DATA_SIZE_UINT16:
61 ret = value.value_u16;
62 break;
63 case PLDM_SENSOR_DATA_SIZE_SINT16:
64 ret = value.value_s16;
65 break;
66 case PLDM_SENSOR_DATA_SIZE_UINT32:
67 ret = value.value_u32;
68 break;
69 case PLDM_SENSOR_DATA_SIZE_SINT32:
70 ret = value.value_s32;
71 break;
72 }
73 return ret;
74}
75
76inline double getRangeFieldValue(uint8_t range_field_format,
77 union_range_field_format& value)
78{
79 double ret = std::numeric_limits<double>::quiet_NaN();
80 switch (range_field_format)
81 {
82 case PLDM_RANGE_FIELD_FORMAT_UINT8:
83 ret = value.value_u8;
84 break;
85 case PLDM_RANGE_FIELD_FORMAT_SINT8:
86 ret = value.value_s8;
87 break;
88 case PLDM_RANGE_FIELD_FORMAT_UINT16:
89 ret = value.value_u16;
90 break;
91 case PLDM_RANGE_FIELD_FORMAT_SINT16:
92 ret = value.value_s16;
93 break;
94 case PLDM_RANGE_FIELD_FORMAT_UINT32:
95 ret = value.value_u32;
96 break;
97 case PLDM_RANGE_FIELD_FORMAT_SINT32:
98 ret = value.value_s32;
99 break;
100 case PLDM_RANGE_FIELD_FORMAT_REAL32:
101 ret = value.value_f32;
102 break;
103 }
104 return ret;
105}
106
Amithash Prasad98256602024-12-19 14:02:30 -0800107void NumericSensor::setSensorUnit(uint8_t baseUnit)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000108{
Amithash Prasad98256602024-12-19 14:02:30 -0800109 sensorUnit = SensorUnit::DegreesC;
Thu Nguyen6d615f12024-04-24 05:02:03 +0000110 useMetricInterface = false;
Amithash Prasad98256602024-12-19 14:02:30 -0800111 switch (baseUnit)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000112 {
113 case PLDM_SENSOR_UNIT_DEGRESS_C:
114 sensorNameSpace = "/xyz/openbmc_project/sensors/temperature/";
115 sensorUnit = SensorUnit::DegreesC;
116 break;
117 case PLDM_SENSOR_UNIT_VOLTS:
118 sensorNameSpace = "/xyz/openbmc_project/sensors/voltage/";
119 sensorUnit = SensorUnit::Volts;
120 break;
121 case PLDM_SENSOR_UNIT_AMPS:
122 sensorNameSpace = "/xyz/openbmc_project/sensors/current/";
123 sensorUnit = SensorUnit::Amperes;
124 break;
125 case PLDM_SENSOR_UNIT_RPM:
126 sensorNameSpace = "/xyz/openbmc_project/sensors/fan_pwm/";
127 sensorUnit = SensorUnit::RPMS;
128 break;
129 case PLDM_SENSOR_UNIT_WATTS:
130 sensorNameSpace = "/xyz/openbmc_project/sensors/power/";
131 sensorUnit = SensorUnit::Watts;
132 break;
133 case PLDM_SENSOR_UNIT_JOULES:
134 sensorNameSpace = "/xyz/openbmc_project/sensors/energy/";
135 sensorUnit = SensorUnit::Joules;
136 break;
137 case PLDM_SENSOR_UNIT_PERCENTAGE:
138 sensorNameSpace = "/xyz/openbmc_project/sensors/utilization/";
139 sensorUnit = SensorUnit::Percent;
140 break;
Thu Nguyen6d615f12024-04-24 05:02:03 +0000141 case PLDM_SENSOR_UNIT_COUNTS:
142 case PLDM_SENSOR_UNIT_CORRECTED_ERRORS:
143 case PLDM_SENSOR_UNIT_UNCORRECTABLE_ERRORS:
144 sensorNameSpace = "/xyz/openbmc_project/metric/count/";
145 useMetricInterface = true;
146 break;
147 case PLDM_SENSOR_UNIT_OEMUNIT:
148 sensorNameSpace = "/xyz/openbmc_project/metric/oem/";
149 useMetricInterface = true;
150 break;
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000151 default:
152 lg2::error("Sensor {NAME} has Invalid baseUnit {UNIT}.", "NAME",
Amithash Prasad98256602024-12-19 14:02:30 -0800153 sensorName, "UNIT", baseUnit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000154 throw sdbusplus::xyz::openbmc_project::Common::Error::
155 InvalidArgument();
156 break;
157 }
Amithash Prasad98256602024-12-19 14:02:30 -0800158}
159
160NumericSensor::NumericSensor(
161 const pldm_tid_t tid, const bool sensorDisabled,
162 std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr, std::string& sensorName,
163 std::string& associationPath) : tid(tid), sensorName(sensorName)
164{
165 if (!pdr)
166 {
167 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
168 }
169
170 sensorId = pdr->sensor_id;
171 std::string path;
172 MetricUnit metricUnit = MetricUnit::Count;
173 setSensorUnit(pdr->base_unit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000174
175 path = sensorNameSpace + sensorName;
176 try
177 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000178 std::string tmp{};
179 std::string interface = SENSOR_VALUE_INTF;
180 if (useMetricInterface)
181 {
182 interface = METRIC_VALUE_INTF;
183 }
184 tmp = pldm::utils::DBusHandler().getService(path.c_str(),
185 interface.c_str());
186
187 if (!tmp.empty())
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000188 {
189 throw sdbusplus::xyz::openbmc_project::Common::Error::
190 TooManyResources();
191 }
192 }
193 catch (const std::exception&)
194 {
195 /* The sensor object path is not created */
196 }
197
198 auto& bus = pldm::utils::DBusHandler::getBus();
199 try
200 {
201 associationDefinitionsIntf =
202 std::make_unique<AssociationDefinitionsInft>(bus, path.c_str());
203 }
204 catch (const sdbusplus::exception_t& e)
205 {
206 lg2::error(
207 "Failed to create association interface for numeric sensor {PATH} error - {ERROR}",
208 "PATH", path, "ERROR", e);
209 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
210 }
211
212 associationDefinitionsIntf->associations(
213 {{"chassis", "all_sensors", associationPath}});
214
Amithash Prasada1871172024-12-19 14:26:10 -0800215 double maxValue =
216 getSensorDataValue(pdr->sensor_data_size, pdr->max_readable);
217 double minValue =
218 getSensorDataValue(pdr->sensor_data_size, pdr->min_readable);
219 hysteresis = getSensorDataValue(pdr->sensor_data_size, pdr->hysteresis);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000220
221 bool hasCriticalThresholds = false;
222 bool hasWarningThresholds = false;
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800223 bool hasFatalThresholds = false;
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000224 double criticalHigh = std::numeric_limits<double>::quiet_NaN();
225 double criticalLow = std::numeric_limits<double>::quiet_NaN();
226 double warningHigh = std::numeric_limits<double>::quiet_NaN();
227 double warningLow = std::numeric_limits<double>::quiet_NaN();
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800228 double fatalHigh = std::numeric_limits<double>::quiet_NaN();
229 double fatalLow = std::numeric_limits<double>::quiet_NaN();
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000230
231 if (pdr->supported_thresholds.bits.bit0)
232 {
233 hasWarningThresholds = true;
Amithash Prasada1871172024-12-19 14:26:10 -0800234 warningHigh =
235 getRangeFieldValue(pdr->range_field_format, pdr->warning_high);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000236 }
237
238 if (pdr->supported_thresholds.bits.bit3)
239 {
240 hasWarningThresholds = true;
Amithash Prasada1871172024-12-19 14:26:10 -0800241 warningLow =
242 getRangeFieldValue(pdr->range_field_format, pdr->warning_low);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000243 }
244
245 if (pdr->supported_thresholds.bits.bit1)
246 {
247 hasCriticalThresholds = true;
Amithash Prasada1871172024-12-19 14:26:10 -0800248 criticalHigh =
249 getRangeFieldValue(pdr->range_field_format, pdr->critical_high);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000250 }
251
252 if (pdr->supported_thresholds.bits.bit4)
253 {
254 hasCriticalThresholds = true;
Amithash Prasada1871172024-12-19 14:26:10 -0800255 criticalLow =
256 getRangeFieldValue(pdr->range_field_format, pdr->critical_low);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000257 }
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800258 if (pdr->supported_thresholds.bits.bit2)
259 {
260 hasFatalThresholds = true;
261 fatalHigh =
262 getRangeFieldValue(pdr->range_field_format, pdr->fatal_high);
263 }
264 if (pdr->supported_thresholds.bits.bit5)
265 {
266 hasFatalThresholds = true;
267 fatalLow = getRangeFieldValue(pdr->range_field_format, pdr->fatal_low);
268 }
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000269
270 resolution = pdr->resolution;
271 offset = pdr->offset;
272 baseUnitModifier = pdr->unit_modifier;
Gilbert Cheneac61a42022-02-23 20:56:19 +0000273 timeStamp = 0;
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000274
275 /**
276 * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds
277 * updateTime is in microseconds
278 */
279 updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000);
Ed Tanous0469b562025-01-06 12:35:10 -0800280 if (std::isfinite(pdr->update_interval))
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000281 {
282 updateTime = pdr->update_interval * 1000000;
283 }
284
Thu Nguyen6d615f12024-04-24 05:02:03 +0000285 if (!useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000286 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000287 try
288 {
289 valueIntf = std::make_unique<ValueIntf>(bus, path.c_str());
290 }
291 catch (const sdbusplus::exception_t& e)
292 {
293 lg2::error(
294 "Failed to create Value interface for numeric sensor {PATH} error - {ERROR}",
295 "PATH", path, "ERROR", e);
296 throw sdbusplus::xyz::openbmc_project::Common::Error::
297 InvalidArgument();
298 }
299 valueIntf->maxValue(unitModifier(conversionFormula(maxValue)));
300 valueIntf->minValue(unitModifier(conversionFormula(minValue)));
301 valueIntf->unit(sensorUnit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000302 }
Thu Nguyen6d615f12024-04-24 05:02:03 +0000303 else
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000304 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000305 try
306 {
307 metricIntf = std::make_unique<MetricIntf>(bus, path.c_str());
308 }
309 catch (const sdbusplus::exception_t& e)
310 {
311 lg2::error(
312 "Failed to create Metric interface for numeric sensor {PATH} error - {ERROR}",
313 "PATH", path, "ERROR", e);
314 throw sdbusplus::xyz::openbmc_project::Common::Error::
315 InvalidArgument();
316 }
317 metricIntf->maxValue(unitModifier(conversionFormula(maxValue)));
318 metricIntf->minValue(unitModifier(conversionFormula(minValue)));
319 metricIntf->unit(metricUnit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000320 }
Thu Nguyen6d615f12024-04-24 05:02:03 +0000321
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000322 hysteresis = unitModifier(conversionFormula(hysteresis));
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000323
Chau Lyd197f092023-11-06 07:29:06 +0000324 if (!createInventoryPath(associationPath, sensorName, pdr->entity_type,
325 pdr->entity_instance_num, pdr->container_id))
326 {
327 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
328 }
329
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000330 try
331 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400332 availabilityIntf =
333 std::make_unique<AvailabilityIntf>(bus, path.c_str());
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000334 }
335 catch (const sdbusplus::exception_t& e)
336 {
337 lg2::error(
338 "Failed to create Availability interface for numeric sensor {PATH} error - {ERROR}",
339 "PATH", path, "ERROR", e);
340 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
341 }
342 availabilityIntf->available(true);
343
344 try
345 {
346 operationalStatusIntf =
347 std::make_unique<OperationalStatusIntf>(bus, path.c_str());
348 }
349 catch (const sdbusplus::exception_t& e)
350 {
351 lg2::error(
352 "Failed to create Operation status interface for numeric sensor {PATH} error - {ERROR}",
353 "PATH", path, "ERROR", e);
354 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
355 }
356 operationalStatusIntf->functional(!sensorDisabled);
357
Thu Nguyen6d615f12024-04-24 05:02:03 +0000358 if (hasWarningThresholds && !useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000359 {
360 try
361 {
362 thresholdWarningIntf =
363 std::make_unique<ThresholdWarningIntf>(bus, path.c_str());
364 }
365 catch (const sdbusplus::exception_t& e)
366 {
367 lg2::error(
368 "Failed to create Threshold warning interface for numeric sensor {PATH} error - {ERROR}",
369 "PATH", path, "ERROR", e);
370 throw sdbusplus::xyz::openbmc_project::Common::Error::
371 InvalidArgument();
372 }
373 thresholdWarningIntf->warningHigh(unitModifier(warningHigh));
374 thresholdWarningIntf->warningLow(unitModifier(warningLow));
375 }
376
Thu Nguyen6d615f12024-04-24 05:02:03 +0000377 if (hasCriticalThresholds && !useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000378 {
379 try
380 {
381 thresholdCriticalIntf =
382 std::make_unique<ThresholdCriticalIntf>(bus, path.c_str());
383 }
384 catch (const sdbusplus::exception_t& e)
385 {
386 lg2::error(
387 "Failed to create Threshold critical interface for numeric sensor {PATH} error - {ERROR}",
388 "PATH", path, "ERROR", e);
389 throw sdbusplus::xyz::openbmc_project::Common::Error::
390 InvalidArgument();
391 }
392 thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh));
393 thresholdCriticalIntf->criticalLow(unitModifier(criticalLow));
394 }
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800395
396 if (hasFatalThresholds && !useMetricInterface)
397 {
398 try
399 {
400 thresholdHardShutdownIntf =
401 std::make_unique<ThresholdHardShutdownIntf>(bus, path.c_str());
402 }
403 catch (const sdbusplus::exception_t& e)
404 {
405 lg2::error(
406 "Failed to create HardShutdown threshold interface for numeric sensor {PATH} error - {ERROR}",
407 "PATH", path, "ERROR", e);
408 throw sdbusplus::xyz::openbmc_project::Common::Error::
409 InvalidArgument();
410 }
411 thresholdHardShutdownIntf->hardShutdownHigh(unitModifier(fatalHigh));
412 thresholdHardShutdownIntf->hardShutdownLow(unitModifier(fatalLow));
413 }
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000414}
415
416NumericSensor::NumericSensor(
417 const pldm_tid_t tid, const bool sensorDisabled,
418 std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr,
419 std::string& sensorName, std::string& associationPath) :
Gilbert Cheneac61a42022-02-23 20:56:19 +0000420 tid(tid), sensorName(sensorName)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000421{
422 if (!pdr)
423 {
424 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
425 }
426
427 sensorId = pdr->sensor_id;
428 std::string path;
Thu Nguyen6d615f12024-04-24 05:02:03 +0000429 MetricUnit metricUnit = MetricUnit::Count;
Amithash Prasad98256602024-12-19 14:02:30 -0800430 setSensorUnit(pdr->base_unit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000431
432 path = sensorNameSpace + sensorName;
433 try
434 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000435 std::string tmp{};
436 std::string interface = SENSOR_VALUE_INTF;
437 if (useMetricInterface)
438 {
439 interface = METRIC_VALUE_INTF;
440 }
441 tmp = pldm::utils::DBusHandler().getService(path.c_str(),
442 interface.c_str());
443
444 if (!tmp.empty())
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000445 {
446 throw sdbusplus::xyz::openbmc_project::Common::Error::
447 TooManyResources();
448 }
449 }
450 catch (const std::exception&)
451 {
452 /* The sensor object path is not created */
453 }
454
455 auto& bus = pldm::utils::DBusHandler::getBus();
456 try
457 {
458 associationDefinitionsIntf =
459 std::make_unique<AssociationDefinitionsInft>(bus, path.c_str());
460 }
461 catch (const sdbusplus::exception_t& e)
462 {
463 lg2::error(
464 "Failed to create Association interface for compact numeric sensor {PATH} error - {ERROR}",
465 "PATH", path, "ERROR", e);
466 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
467 }
468 associationDefinitionsIntf->associations(
469 {{"chassis", "all_sensors", associationPath.c_str()}});
470
471 double maxValue = std::numeric_limits<double>::quiet_NaN();
472 double minValue = std::numeric_limits<double>::quiet_NaN();
473 bool hasWarningThresholds = false;
474 bool hasCriticalThresholds = false;
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800475 bool hasFatalThresholds = false;
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000476 double criticalHigh = std::numeric_limits<double>::quiet_NaN();
477 double criticalLow = std::numeric_limits<double>::quiet_NaN();
478 double warningHigh = std::numeric_limits<double>::quiet_NaN();
479 double warningLow = std::numeric_limits<double>::quiet_NaN();
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800480 double fatalHigh = std::numeric_limits<double>::quiet_NaN();
481 double fatalLow = std::numeric_limits<double>::quiet_NaN();
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000482
483 if (pdr->range_field_support.bits.bit0)
484 {
485 hasWarningThresholds = true;
486 warningHigh = pdr->warning_high;
487 }
488 if (pdr->range_field_support.bits.bit1)
489 {
490 hasWarningThresholds = true;
491 warningLow = pdr->warning_low;
492 }
493
494 if (pdr->range_field_support.bits.bit2)
495 {
496 hasCriticalThresholds = true;
497 criticalHigh = pdr->critical_high;
498 }
499
500 if (pdr->range_field_support.bits.bit3)
501 {
502 hasCriticalThresholds = true;
503 criticalLow = pdr->critical_low;
504 }
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800505 if (pdr->range_field_support.bits.bit4)
506 {
507 hasFatalThresholds = true;
508 fatalHigh = pdr->fatal_high;
509 }
510 if (pdr->range_field_support.bits.bit5)
511 {
512 hasFatalThresholds = true;
513 fatalLow = pdr->fatal_low;
514 }
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000515
516 resolution = std::numeric_limits<double>::quiet_NaN();
517 offset = std::numeric_limits<double>::quiet_NaN();
518 baseUnitModifier = pdr->unit_modifier;
Gilbert Cheneac61a42022-02-23 20:56:19 +0000519 timeStamp = 0;
Thu Nguyen2027ff52024-10-03 21:58:22 +0000520 hysteresis = 0;
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000521
522 /**
523 * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds
524 * updateTime is in microseconds
525 */
526 updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000);
Thu Nguyen6d615f12024-04-24 05:02:03 +0000527
528 if (!useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000529 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000530 try
531 {
532 valueIntf = std::make_unique<ValueIntf>(bus, path.c_str());
533 }
534 catch (const sdbusplus::exception_t& e)
535 {
536 lg2::error(
537 "Failed to create Value interface for compact numeric sensor {PATH} error - {ERROR}",
538 "PATH", path, "ERROR", e);
539 throw sdbusplus::xyz::openbmc_project::Common::Error::
540 InvalidArgument();
541 }
542 valueIntf->maxValue(unitModifier(conversionFormula(maxValue)));
543 valueIntf->minValue(unitModifier(conversionFormula(minValue)));
544 valueIntf->unit(sensorUnit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000545 }
Thu Nguyen6d615f12024-04-24 05:02:03 +0000546 else
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000547 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000548 try
549 {
550 metricIntf = std::make_unique<MetricIntf>(bus, path.c_str());
551 }
552 catch (const sdbusplus::exception_t& e)
553 {
554 lg2::error(
555 "Failed to create Metric interface for compact numeric sensor {PATH} error - {ERROR}",
556 "PATH", path, "ERROR", e);
557 throw sdbusplus::xyz::openbmc_project::Common::Error::
558 InvalidArgument();
559 }
560 metricIntf->maxValue(unitModifier(conversionFormula(maxValue)));
561 metricIntf->minValue(unitModifier(conversionFormula(minValue)));
562 metricIntf->unit(metricUnit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000563 }
Thu Nguyen6d615f12024-04-24 05:02:03 +0000564
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000565 hysteresis = unitModifier(conversionFormula(hysteresis));
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000566
Chau Lyd197f092023-11-06 07:29:06 +0000567 if (!createInventoryPath(associationPath, sensorName, pdr->entity_type,
568 pdr->entity_instance, pdr->container_id))
569 {
570 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
571 }
572
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000573 try
574 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400575 availabilityIntf =
576 std::make_unique<AvailabilityIntf>(bus, path.c_str());
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000577 }
578 catch (const sdbusplus::exception_t& e)
579 {
580 lg2::error(
581 "Failed to create Availability interface for compact numeric sensor {PATH} error - {ERROR}",
582 "PATH", path, "ERROR", e);
583 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
584 }
585 availabilityIntf->available(true);
586
587 try
588 {
589 operationalStatusIntf =
590 std::make_unique<OperationalStatusIntf>(bus, path.c_str());
591 }
592 catch (const sdbusplus::exception_t& e)
593 {
594 lg2::error(
595 "Failed to create Operational status interface for compact numeric sensor {PATH} error - {ERROR}",
596 "PATH", path, "ERROR", e);
597 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
598 }
599 operationalStatusIntf->functional(!sensorDisabled);
600
Thu Nguyen6d615f12024-04-24 05:02:03 +0000601 if (hasWarningThresholds && !useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000602 {
603 try
604 {
605 thresholdWarningIntf =
606 std::make_unique<ThresholdWarningIntf>(bus, path.c_str());
607 }
608 catch (const sdbusplus::exception_t& e)
609 {
610 lg2::error(
611 "Failed to create Warning threshold interface for compact numeric sensor {PATH} error - {ERROR}",
612 "PATH", path, "ERROR", e);
613 throw sdbusplus::xyz::openbmc_project::Common::Error::
614 InvalidArgument();
615 }
616 thresholdWarningIntf->warningHigh(unitModifier(warningHigh));
617 thresholdWarningIntf->warningLow(unitModifier(warningLow));
618 }
619
Thu Nguyen6d615f12024-04-24 05:02:03 +0000620 if (hasCriticalThresholds && !useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000621 {
622 try
623 {
624 thresholdCriticalIntf =
625 std::make_unique<ThresholdCriticalIntf>(bus, path.c_str());
626 }
627 catch (const sdbusplus::exception_t& e)
628 {
629 lg2::error(
630 "Failed to create Critical threshold interface for compact numeric sensor {PATH} error - {ERROR}",
631 "PATH", path, "ERROR", e);
632 throw sdbusplus::xyz::openbmc_project::Common::Error::
633 InvalidArgument();
634 }
635 thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh));
636 thresholdCriticalIntf->criticalLow(unitModifier(criticalLow));
637 }
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800638
639 if (hasFatalThresholds && !useMetricInterface)
640 {
641 try
642 {
643 thresholdHardShutdownIntf =
644 std::make_unique<ThresholdHardShutdownIntf>(bus, path.c_str());
645 }
646 catch (const sdbusplus::exception_t& e)
647 {
648 lg2::error(
649 "Failed to create HardShutdown threshold interface for numeric sensor {PATH} error - {ERROR}",
650 "PATH", path, "ERROR", e);
651 throw sdbusplus::xyz::openbmc_project::Common::Error::
652 InvalidArgument();
653 }
654 thresholdHardShutdownIntf->hardShutdownHigh(unitModifier(fatalHigh));
655 thresholdHardShutdownIntf->hardShutdownLow(unitModifier(fatalLow));
656 }
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000657}
658
659double NumericSensor::conversionFormula(double value)
660{
661 double convertedValue = value;
Ed Tanous0469b562025-01-06 12:35:10 -0800662 if (std::isfinite(resolution))
663 {
664 convertedValue *= resolution;
665 }
666 if (std::isfinite(offset))
667 {
668 convertedValue += offset;
669 }
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000670 return convertedValue;
671}
672
673double NumericSensor::unitModifier(double value)
674{
Ed Tanous0469b562025-01-06 12:35:10 -0800675 if (!std::isfinite(value))
676 {
677 return value;
678 }
679 return value * std::pow(10, baseUnitModifier);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000680}
Gilbert Cheneac61a42022-02-23 20:56:19 +0000681
682void NumericSensor::updateReading(bool available, bool functional, double value)
683{
Thu Nguyen6d615f12024-04-24 05:02:03 +0000684 if (!availabilityIntf || !operationalStatusIntf ||
685 (!useMetricInterface && !valueIntf) ||
686 (useMetricInterface && !metricIntf))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000687 {
688 lg2::error(
689 "Failed to update sensor {NAME} D-Bus interface don't exist.",
690 "NAME", sensorName);
691 return;
692 }
693 availabilityIntf->available(available);
694 operationalStatusIntf->functional(functional);
Thu Nguyen6d615f12024-04-24 05:02:03 +0000695 double curValue = 0;
696 if (!useMetricInterface)
697 {
698 curValue = valueIntf->value();
699 }
700 else
701 {
702 curValue = metricIntf->value();
703 }
704
Gilbert Cheneac61a42022-02-23 20:56:19 +0000705 double newValue = std::numeric_limits<double>::quiet_NaN();
706 if (functional && available)
707 {
708 newValue = unitModifier(conversionFormula(value));
709 if (newValue != curValue &&
Ed Tanous0469b562025-01-06 12:35:10 -0800710 (std::isfinite(newValue) || std::isfinite(curValue)))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000711 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000712 if (!useMetricInterface)
713 {
714 valueIntf->value(newValue);
715 updateThresholds();
716 }
717 else
718 {
719 metricIntf->value(newValue);
720 }
Gilbert Cheneac61a42022-02-23 20:56:19 +0000721 }
722 }
723 else
724 {
725 if (newValue != curValue &&
Ed Tanous0469b562025-01-06 12:35:10 -0800726 (std::isfinite(newValue) || std::isfinite(curValue)))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000727 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000728 if (!useMetricInterface)
729 {
730 valueIntf->value(std::numeric_limits<double>::quiet_NaN());
731 }
732 else
733 {
734 metricIntf->value(std::numeric_limits<double>::quiet_NaN());
735 }
Gilbert Cheneac61a42022-02-23 20:56:19 +0000736 }
737 }
738}
739
740void NumericSensor::handleErrGetSensorReading()
741{
Thu Nguyen6d615f12024-04-24 05:02:03 +0000742 if (!operationalStatusIntf || (!useMetricInterface && !valueIntf) ||
743 (useMetricInterface && !metricIntf))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000744 {
745 lg2::error(
746 "Failed to update sensor {NAME} D-Bus interfaces don't exist.",
747 "NAME", sensorName);
748 return;
749 }
750 operationalStatusIntf->functional(false);
Thu Nguyen6d615f12024-04-24 05:02:03 +0000751 if (!useMetricInterface)
752 {
753 valueIntf->value(std::numeric_limits<double>::quiet_NaN());
754 }
755 else
756 {
757 metricIntf->value(std::numeric_limits<double>::quiet_NaN());
758 }
Gilbert Cheneac61a42022-02-23 20:56:19 +0000759}
760
761bool NumericSensor::checkThreshold(bool alarm, bool direction, double value,
762 double threshold, double hyst)
763{
764 if (direction)
765 {
766 if (value >= threshold)
767 {
768 return true;
769 }
770 if (value < (threshold - hyst))
771 {
772 return false;
773 }
774 }
775 else
776 {
777 if (value <= threshold)
778 {
779 return true;
780 }
781 if (value > (threshold + hyst))
782 {
783 return false;
784 }
785 }
786 return alarm;
787}
Amithash Prasad2480c572025-05-01 15:34:34 -0700788void NumericSensor::setWarningThresholdAlarm(pldm::utils::Direction direction,
789 double value, bool newAlarm)
790{
791 if (direction == pldm::utils::Direction::HIGH)
792 {
793 thresholdWarningIntf->warningAlarmHigh(newAlarm);
794 if (newAlarm)
795 {
796 thresholdWarningIntf->warningHighAlarmAsserted(value);
797 }
798 else
799 {
800 thresholdWarningIntf->warningHighAlarmDeasserted(value);
801 }
802 }
803 else
804 {
805 thresholdWarningIntf->warningAlarmLow(newAlarm);
806 if (newAlarm)
807 {
808 thresholdWarningIntf->warningLowAlarmAsserted(value);
809 }
810 else
811 {
812 thresholdWarningIntf->warningLowAlarmDeasserted(value);
813 }
814 }
815}
816
817void NumericSensor::setCriticalThresholdAlarm(pldm::utils::Direction direction,
818 double value, bool newAlarm)
819{
820 if (direction == pldm::utils::Direction::HIGH)
821 {
822 thresholdCriticalIntf->criticalAlarmHigh(newAlarm);
823 if (newAlarm)
824 {
825 thresholdCriticalIntf->criticalHighAlarmAsserted(value);
826 }
827 else
828 {
829 thresholdCriticalIntf->criticalHighAlarmDeasserted(value);
830 }
831 }
832 else
833 {
834 thresholdCriticalIntf->criticalAlarmLow(newAlarm);
835 if (newAlarm)
836 {
837 thresholdCriticalIntf->criticalLowAlarmAsserted(value);
838 }
839 else
840 {
841 thresholdCriticalIntf->criticalLowAlarmDeasserted(value);
842 }
843 }
844}
845
846void NumericSensor::setHardShutdownThresholdAlarm(
847 pldm::utils::Direction direction, double value, bool newAlarm)
848{
849 if (direction == pldm::utils::Direction::HIGH)
850 {
851 thresholdHardShutdownIntf->hardShutdownAlarmHigh(newAlarm);
852 if (newAlarm)
853 {
854 thresholdHardShutdownIntf->hardShutdownHighAlarmAsserted(value);
855 }
856 else
857 {
858 thresholdHardShutdownIntf->hardShutdownHighAlarmDeasserted(value);
859 }
860 }
861 else
862 {
863 thresholdHardShutdownIntf->hardShutdownAlarmLow(newAlarm);
864 if (newAlarm)
865 {
866 thresholdHardShutdownIntf->hardShutdownLowAlarmAsserted(value);
867 }
868 else
869 {
870 thresholdHardShutdownIntf->hardShutdownLowAlarmDeasserted(value);
871 }
872 }
873}
874
875int NumericSensor::setThresholdAlarm(pldm::utils::Level level,
876 pldm::utils::Direction direction,
877 double value, bool newAlarm)
878{
879 if (!isThresholdValid(level, direction))
880 {
881 lg2::error(
882 "Error:Trigger sensor warning event for non warning threshold sensors {NAME}",
883 "NAME", sensorName);
884 return PLDM_ERROR;
885 }
886 auto alarm = getThresholdAlarm(level, direction);
887 if (alarm == newAlarm)
888 {
889 return PLDM_SUCCESS;
890 }
891 switch (level)
892 {
893 case pldm::utils::Level::WARNING:
894 setWarningThresholdAlarm(direction, value, newAlarm);
895 break;
896 case pldm::utils::Level::CRITICAL:
897 setCriticalThresholdAlarm(direction, value, newAlarm);
898 break;
899 case pldm::utils::Level::HARDSHUTDOWN:
900 setHardShutdownThresholdAlarm(direction, value, newAlarm);
901 break;
902 default:
903 return PLDM_ERROR;
904 }
905 return PLDM_SUCCESS;
906}
Gilbert Cheneac61a42022-02-23 20:56:19 +0000907
908void NumericSensor::updateThresholds()
909{
Thu Nguyen6d615f12024-04-24 05:02:03 +0000910 double value = std::numeric_limits<double>::quiet_NaN();
911
912 if ((!useMetricInterface && !valueIntf) ||
913 (useMetricInterface && !metricIntf))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000914 {
915 lg2::error(
916 "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.",
917 "NAME", sensorName);
918 return;
919 }
Thu Nguyen6d615f12024-04-24 05:02:03 +0000920 if (!useMetricInterface)
921 {
922 value = valueIntf->value();
923 }
924 else
925 {
926 value = metricIntf->value();
927 }
Gilbert Cheneac61a42022-02-23 20:56:19 +0000928
Amithash Prasad2480c572025-05-01 15:34:34 -0700929 for (auto level : allThresholdLevels)
Gilbert Cheneac61a42022-02-23 20:56:19 +0000930 {
Amithash Prasad2480c572025-05-01 15:34:34 -0700931 for (auto direction : allThresholdDirections)
Gilbert Cheneac61a42022-02-23 20:56:19 +0000932 {
Amithash Prasad2480c572025-05-01 15:34:34 -0700933 auto threshold = getThreshold(level, direction);
934 if (!std::isfinite(threshold))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000935 {
Amithash Prasad2480c572025-05-01 15:34:34 -0700936 continue;
Gilbert Cheneac61a42022-02-23 20:56:19 +0000937 }
Amithash Prasad2480c572025-05-01 15:34:34 -0700938 auto alarm = getThresholdAlarm(level, direction);
939 auto newAlarm =
940 checkThreshold(alarm, direction == pldm::utils::Direction::HIGH,
941 value, threshold, hysteresis);
942 setThresholdAlarm(level, direction, value, newAlarm);
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800943 }
944 }
Gilbert Cheneac61a42022-02-23 20:56:19 +0000945}
Gilbert Chen77e6fe72024-08-06 09:23:30 +0000946
947int NumericSensor::triggerThresholdEvent(
948 pldm::utils::Level eventType, pldm::utils::Direction direction,
949 double rawValue, bool newAlarm, bool assert)
950{
951 if (!valueIntf)
952 {
953 lg2::error(
954 "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.",
955 "NAME", sensorName);
956 return PLDM_ERROR;
957 }
958
959 auto value = unitModifier(conversionFormula(rawValue));
960 lg2::error(
961 "triggerThresholdEvent eventType {TID}, direction {SID} value {VAL} newAlarm {PSTATE} assert {ESTATE}",
962 "TID", eventType, "SID", direction, "VAL", value, "PSTATE", newAlarm,
963 "ESTATE", assert);
964
Amithash Prasad2480c572025-05-01 15:34:34 -0700965 return setThresholdAlarm(eventType, direction, value, newAlarm);
Gilbert Chen77e6fe72024-08-06 09:23:30 +0000966}
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000967} // namespace platform_mc
968} // namespace pldm