blob: e501ed6ec0ed75d79ab9d8449f1a600445d6e2be [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{
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 Prasada1871172024-12-19 14:26:10 -080043inline double getSensorDataValue(uint8_t sensor_data_size,
44 union_sensor_data_size& value)
45{
46 double ret = std::numeric_limits<double>::quiet_NaN();
47 switch (sensor_data_size)
48 {
49 case PLDM_SENSOR_DATA_SIZE_UINT8:
50 ret = value.value_u8;
51 break;
52 case PLDM_SENSOR_DATA_SIZE_SINT8:
53 ret = value.value_s8;
54 break;
55 case PLDM_SENSOR_DATA_SIZE_UINT16:
56 ret = value.value_u16;
57 break;
58 case PLDM_SENSOR_DATA_SIZE_SINT16:
59 ret = value.value_s16;
60 break;
61 case PLDM_SENSOR_DATA_SIZE_UINT32:
62 ret = value.value_u32;
63 break;
64 case PLDM_SENSOR_DATA_SIZE_SINT32:
65 ret = value.value_s32;
66 break;
67 }
68 return ret;
69}
70
71inline double getRangeFieldValue(uint8_t range_field_format,
72 union_range_field_format& value)
73{
74 double ret = std::numeric_limits<double>::quiet_NaN();
75 switch (range_field_format)
76 {
77 case PLDM_RANGE_FIELD_FORMAT_UINT8:
78 ret = value.value_u8;
79 break;
80 case PLDM_RANGE_FIELD_FORMAT_SINT8:
81 ret = value.value_s8;
82 break;
83 case PLDM_RANGE_FIELD_FORMAT_UINT16:
84 ret = value.value_u16;
85 break;
86 case PLDM_RANGE_FIELD_FORMAT_SINT16:
87 ret = value.value_s16;
88 break;
89 case PLDM_RANGE_FIELD_FORMAT_UINT32:
90 ret = value.value_u32;
91 break;
92 case PLDM_RANGE_FIELD_FORMAT_SINT32:
93 ret = value.value_s32;
94 break;
95 case PLDM_RANGE_FIELD_FORMAT_REAL32:
96 ret = value.value_f32;
97 break;
98 }
99 return ret;
100}
101
Amithash Prasad98256602024-12-19 14:02:30 -0800102void NumericSensor::setSensorUnit(uint8_t baseUnit)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000103{
Amithash Prasad98256602024-12-19 14:02:30 -0800104 sensorUnit = SensorUnit::DegreesC;
Thu Nguyen6d615f12024-04-24 05:02:03 +0000105 useMetricInterface = false;
Amithash Prasad98256602024-12-19 14:02:30 -0800106 switch (baseUnit)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000107 {
108 case PLDM_SENSOR_UNIT_DEGRESS_C:
109 sensorNameSpace = "/xyz/openbmc_project/sensors/temperature/";
110 sensorUnit = SensorUnit::DegreesC;
111 break;
112 case PLDM_SENSOR_UNIT_VOLTS:
113 sensorNameSpace = "/xyz/openbmc_project/sensors/voltage/";
114 sensorUnit = SensorUnit::Volts;
115 break;
116 case PLDM_SENSOR_UNIT_AMPS:
117 sensorNameSpace = "/xyz/openbmc_project/sensors/current/";
118 sensorUnit = SensorUnit::Amperes;
119 break;
120 case PLDM_SENSOR_UNIT_RPM:
121 sensorNameSpace = "/xyz/openbmc_project/sensors/fan_pwm/";
122 sensorUnit = SensorUnit::RPMS;
123 break;
124 case PLDM_SENSOR_UNIT_WATTS:
125 sensorNameSpace = "/xyz/openbmc_project/sensors/power/";
126 sensorUnit = SensorUnit::Watts;
127 break;
128 case PLDM_SENSOR_UNIT_JOULES:
129 sensorNameSpace = "/xyz/openbmc_project/sensors/energy/";
130 sensorUnit = SensorUnit::Joules;
131 break;
132 case PLDM_SENSOR_UNIT_PERCENTAGE:
133 sensorNameSpace = "/xyz/openbmc_project/sensors/utilization/";
134 sensorUnit = SensorUnit::Percent;
135 break;
Thu Nguyen6d615f12024-04-24 05:02:03 +0000136 case PLDM_SENSOR_UNIT_COUNTS:
137 case PLDM_SENSOR_UNIT_CORRECTED_ERRORS:
138 case PLDM_SENSOR_UNIT_UNCORRECTABLE_ERRORS:
139 sensorNameSpace = "/xyz/openbmc_project/metric/count/";
140 useMetricInterface = true;
141 break;
142 case PLDM_SENSOR_UNIT_OEMUNIT:
143 sensorNameSpace = "/xyz/openbmc_project/metric/oem/";
144 useMetricInterface = true;
145 break;
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000146 default:
147 lg2::error("Sensor {NAME} has Invalid baseUnit {UNIT}.", "NAME",
Amithash Prasad98256602024-12-19 14:02:30 -0800148 sensorName, "UNIT", baseUnit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000149 throw sdbusplus::xyz::openbmc_project::Common::Error::
150 InvalidArgument();
151 break;
152 }
Amithash Prasad98256602024-12-19 14:02:30 -0800153}
154
155NumericSensor::NumericSensor(
156 const pldm_tid_t tid, const bool sensorDisabled,
157 std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr, std::string& sensorName,
158 std::string& associationPath) : tid(tid), sensorName(sensorName)
159{
160 if (!pdr)
161 {
162 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
163 }
164
165 sensorId = pdr->sensor_id;
166 std::string path;
167 MetricUnit metricUnit = MetricUnit::Count;
168 setSensorUnit(pdr->base_unit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000169
170 path = sensorNameSpace + sensorName;
171 try
172 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000173 std::string tmp{};
174 std::string interface = SENSOR_VALUE_INTF;
175 if (useMetricInterface)
176 {
177 interface = METRIC_VALUE_INTF;
178 }
179 tmp = pldm::utils::DBusHandler().getService(path.c_str(),
180 interface.c_str());
181
182 if (!tmp.empty())
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000183 {
184 throw sdbusplus::xyz::openbmc_project::Common::Error::
185 TooManyResources();
186 }
187 }
188 catch (const std::exception&)
189 {
190 /* The sensor object path is not created */
191 }
192
193 auto& bus = pldm::utils::DBusHandler::getBus();
194 try
195 {
196 associationDefinitionsIntf =
197 std::make_unique<AssociationDefinitionsInft>(bus, path.c_str());
198 }
199 catch (const sdbusplus::exception_t& e)
200 {
201 lg2::error(
202 "Failed to create association interface for numeric sensor {PATH} error - {ERROR}",
203 "PATH", path, "ERROR", e);
204 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
205 }
206
207 associationDefinitionsIntf->associations(
208 {{"chassis", "all_sensors", associationPath}});
209
Amithash Prasada1871172024-12-19 14:26:10 -0800210 double maxValue =
211 getSensorDataValue(pdr->sensor_data_size, pdr->max_readable);
212 double minValue =
213 getSensorDataValue(pdr->sensor_data_size, pdr->min_readable);
214 hysteresis = getSensorDataValue(pdr->sensor_data_size, pdr->hysteresis);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000215
216 bool hasCriticalThresholds = false;
217 bool hasWarningThresholds = false;
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800218 bool hasFatalThresholds = false;
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000219 double criticalHigh = std::numeric_limits<double>::quiet_NaN();
220 double criticalLow = std::numeric_limits<double>::quiet_NaN();
221 double warningHigh = std::numeric_limits<double>::quiet_NaN();
222 double warningLow = std::numeric_limits<double>::quiet_NaN();
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800223 double fatalHigh = std::numeric_limits<double>::quiet_NaN();
224 double fatalLow = std::numeric_limits<double>::quiet_NaN();
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000225
226 if (pdr->supported_thresholds.bits.bit0)
227 {
228 hasWarningThresholds = true;
Amithash Prasada1871172024-12-19 14:26:10 -0800229 warningHigh =
230 getRangeFieldValue(pdr->range_field_format, pdr->warning_high);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000231 }
232
233 if (pdr->supported_thresholds.bits.bit3)
234 {
235 hasWarningThresholds = true;
Amithash Prasada1871172024-12-19 14:26:10 -0800236 warningLow =
237 getRangeFieldValue(pdr->range_field_format, pdr->warning_low);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000238 }
239
240 if (pdr->supported_thresholds.bits.bit1)
241 {
242 hasCriticalThresholds = true;
Amithash Prasada1871172024-12-19 14:26:10 -0800243 criticalHigh =
244 getRangeFieldValue(pdr->range_field_format, pdr->critical_high);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000245 }
246
247 if (pdr->supported_thresholds.bits.bit4)
248 {
249 hasCriticalThresholds = true;
Amithash Prasada1871172024-12-19 14:26:10 -0800250 criticalLow =
251 getRangeFieldValue(pdr->range_field_format, pdr->critical_low);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000252 }
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800253 if (pdr->supported_thresholds.bits.bit2)
254 {
255 hasFatalThresholds = true;
256 fatalHigh =
257 getRangeFieldValue(pdr->range_field_format, pdr->fatal_high);
258 }
259 if (pdr->supported_thresholds.bits.bit5)
260 {
261 hasFatalThresholds = true;
262 fatalLow = getRangeFieldValue(pdr->range_field_format, pdr->fatal_low);
263 }
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000264
265 resolution = pdr->resolution;
266 offset = pdr->offset;
267 baseUnitModifier = pdr->unit_modifier;
Gilbert Cheneac61a42022-02-23 20:56:19 +0000268 timeStamp = 0;
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000269
270 /**
271 * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds
272 * updateTime is in microseconds
273 */
274 updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000);
Ed Tanous0469b562025-01-06 12:35:10 -0800275 if (std::isfinite(pdr->update_interval))
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000276 {
277 updateTime = pdr->update_interval * 1000000;
278 }
279
Thu Nguyen6d615f12024-04-24 05:02:03 +0000280 if (!useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000281 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000282 try
283 {
284 valueIntf = std::make_unique<ValueIntf>(bus, path.c_str());
285 }
286 catch (const sdbusplus::exception_t& e)
287 {
288 lg2::error(
289 "Failed to create Value interface for numeric sensor {PATH} error - {ERROR}",
290 "PATH", path, "ERROR", e);
291 throw sdbusplus::xyz::openbmc_project::Common::Error::
292 InvalidArgument();
293 }
294 valueIntf->maxValue(unitModifier(conversionFormula(maxValue)));
295 valueIntf->minValue(unitModifier(conversionFormula(minValue)));
296 valueIntf->unit(sensorUnit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000297 }
Thu Nguyen6d615f12024-04-24 05:02:03 +0000298 else
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000299 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000300 try
301 {
302 metricIntf = std::make_unique<MetricIntf>(bus, path.c_str());
303 }
304 catch (const sdbusplus::exception_t& e)
305 {
306 lg2::error(
307 "Failed to create Metric interface for numeric sensor {PATH} error - {ERROR}",
308 "PATH", path, "ERROR", e);
309 throw sdbusplus::xyz::openbmc_project::Common::Error::
310 InvalidArgument();
311 }
312 metricIntf->maxValue(unitModifier(conversionFormula(maxValue)));
313 metricIntf->minValue(unitModifier(conversionFormula(minValue)));
314 metricIntf->unit(metricUnit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000315 }
Thu Nguyen6d615f12024-04-24 05:02:03 +0000316
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000317 hysteresis = unitModifier(conversionFormula(hysteresis));
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000318
Chau Lyd197f092023-11-06 07:29:06 +0000319 if (!createInventoryPath(associationPath, sensorName, pdr->entity_type,
320 pdr->entity_instance_num, pdr->container_id))
321 {
322 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
323 }
324
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000325 try
326 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400327 availabilityIntf =
328 std::make_unique<AvailabilityIntf>(bus, path.c_str());
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000329 }
330 catch (const sdbusplus::exception_t& e)
331 {
332 lg2::error(
333 "Failed to create Availability interface for numeric sensor {PATH} error - {ERROR}",
334 "PATH", path, "ERROR", e);
335 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
336 }
337 availabilityIntf->available(true);
338
339 try
340 {
341 operationalStatusIntf =
342 std::make_unique<OperationalStatusIntf>(bus, path.c_str());
343 }
344 catch (const sdbusplus::exception_t& e)
345 {
346 lg2::error(
347 "Failed to create Operation status interface for numeric sensor {PATH} error - {ERROR}",
348 "PATH", path, "ERROR", e);
349 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
350 }
351 operationalStatusIntf->functional(!sensorDisabled);
352
Thu Nguyen6d615f12024-04-24 05:02:03 +0000353 if (hasWarningThresholds && !useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000354 {
355 try
356 {
357 thresholdWarningIntf =
358 std::make_unique<ThresholdWarningIntf>(bus, path.c_str());
359 }
360 catch (const sdbusplus::exception_t& e)
361 {
362 lg2::error(
363 "Failed to create Threshold warning interface for numeric sensor {PATH} error - {ERROR}",
364 "PATH", path, "ERROR", e);
365 throw sdbusplus::xyz::openbmc_project::Common::Error::
366 InvalidArgument();
367 }
368 thresholdWarningIntf->warningHigh(unitModifier(warningHigh));
369 thresholdWarningIntf->warningLow(unitModifier(warningLow));
370 }
371
Thu Nguyen6d615f12024-04-24 05:02:03 +0000372 if (hasCriticalThresholds && !useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000373 {
374 try
375 {
376 thresholdCriticalIntf =
377 std::make_unique<ThresholdCriticalIntf>(bus, path.c_str());
378 }
379 catch (const sdbusplus::exception_t& e)
380 {
381 lg2::error(
382 "Failed to create Threshold critical interface for numeric sensor {PATH} error - {ERROR}",
383 "PATH", path, "ERROR", e);
384 throw sdbusplus::xyz::openbmc_project::Common::Error::
385 InvalidArgument();
386 }
387 thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh));
388 thresholdCriticalIntf->criticalLow(unitModifier(criticalLow));
389 }
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800390
391 if (hasFatalThresholds && !useMetricInterface)
392 {
393 try
394 {
395 thresholdHardShutdownIntf =
396 std::make_unique<ThresholdHardShutdownIntf>(bus, path.c_str());
397 }
398 catch (const sdbusplus::exception_t& e)
399 {
400 lg2::error(
401 "Failed to create HardShutdown threshold interface for numeric sensor {PATH} error - {ERROR}",
402 "PATH", path, "ERROR", e);
403 throw sdbusplus::xyz::openbmc_project::Common::Error::
404 InvalidArgument();
405 }
406 thresholdHardShutdownIntf->hardShutdownHigh(unitModifier(fatalHigh));
407 thresholdHardShutdownIntf->hardShutdownLow(unitModifier(fatalLow));
408 }
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000409}
410
411NumericSensor::NumericSensor(
412 const pldm_tid_t tid, const bool sensorDisabled,
413 std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr,
414 std::string& sensorName, std::string& associationPath) :
Gilbert Cheneac61a42022-02-23 20:56:19 +0000415 tid(tid), sensorName(sensorName)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000416{
417 if (!pdr)
418 {
419 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
420 }
421
422 sensorId = pdr->sensor_id;
423 std::string path;
Thu Nguyen6d615f12024-04-24 05:02:03 +0000424 MetricUnit metricUnit = MetricUnit::Count;
Amithash Prasad98256602024-12-19 14:02:30 -0800425 setSensorUnit(pdr->base_unit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000426
427 path = sensorNameSpace + sensorName;
428 try
429 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000430 std::string tmp{};
431 std::string interface = SENSOR_VALUE_INTF;
432 if (useMetricInterface)
433 {
434 interface = METRIC_VALUE_INTF;
435 }
436 tmp = pldm::utils::DBusHandler().getService(path.c_str(),
437 interface.c_str());
438
439 if (!tmp.empty())
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000440 {
441 throw sdbusplus::xyz::openbmc_project::Common::Error::
442 TooManyResources();
443 }
444 }
445 catch (const std::exception&)
446 {
447 /* The sensor object path is not created */
448 }
449
450 auto& bus = pldm::utils::DBusHandler::getBus();
451 try
452 {
453 associationDefinitionsIntf =
454 std::make_unique<AssociationDefinitionsInft>(bus, path.c_str());
455 }
456 catch (const sdbusplus::exception_t& e)
457 {
458 lg2::error(
459 "Failed to create Association interface for compact numeric sensor {PATH} error - {ERROR}",
460 "PATH", path, "ERROR", e);
461 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
462 }
463 associationDefinitionsIntf->associations(
464 {{"chassis", "all_sensors", associationPath.c_str()}});
465
466 double maxValue = std::numeric_limits<double>::quiet_NaN();
467 double minValue = std::numeric_limits<double>::quiet_NaN();
468 bool hasWarningThresholds = false;
469 bool hasCriticalThresholds = false;
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800470 bool hasFatalThresholds = false;
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000471 double criticalHigh = std::numeric_limits<double>::quiet_NaN();
472 double criticalLow = std::numeric_limits<double>::quiet_NaN();
473 double warningHigh = std::numeric_limits<double>::quiet_NaN();
474 double warningLow = std::numeric_limits<double>::quiet_NaN();
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800475 double fatalHigh = std::numeric_limits<double>::quiet_NaN();
476 double fatalLow = std::numeric_limits<double>::quiet_NaN();
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000477
478 if (pdr->range_field_support.bits.bit0)
479 {
480 hasWarningThresholds = true;
481 warningHigh = pdr->warning_high;
482 }
483 if (pdr->range_field_support.bits.bit1)
484 {
485 hasWarningThresholds = true;
486 warningLow = pdr->warning_low;
487 }
488
489 if (pdr->range_field_support.bits.bit2)
490 {
491 hasCriticalThresholds = true;
492 criticalHigh = pdr->critical_high;
493 }
494
495 if (pdr->range_field_support.bits.bit3)
496 {
497 hasCriticalThresholds = true;
498 criticalLow = pdr->critical_low;
499 }
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800500 if (pdr->range_field_support.bits.bit4)
501 {
502 hasFatalThresholds = true;
503 fatalHigh = pdr->fatal_high;
504 }
505 if (pdr->range_field_support.bits.bit5)
506 {
507 hasFatalThresholds = true;
508 fatalLow = pdr->fatal_low;
509 }
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000510
511 resolution = std::numeric_limits<double>::quiet_NaN();
512 offset = std::numeric_limits<double>::quiet_NaN();
513 baseUnitModifier = pdr->unit_modifier;
Gilbert Cheneac61a42022-02-23 20:56:19 +0000514 timeStamp = 0;
Thu Nguyen2027ff52024-10-03 21:58:22 +0000515 hysteresis = 0;
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000516
517 /**
518 * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds
519 * updateTime is in microseconds
520 */
521 updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000);
Thu Nguyen6d615f12024-04-24 05:02:03 +0000522
523 if (!useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000524 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000525 try
526 {
527 valueIntf = std::make_unique<ValueIntf>(bus, path.c_str());
528 }
529 catch (const sdbusplus::exception_t& e)
530 {
531 lg2::error(
532 "Failed to create Value interface for compact numeric sensor {PATH} error - {ERROR}",
533 "PATH", path, "ERROR", e);
534 throw sdbusplus::xyz::openbmc_project::Common::Error::
535 InvalidArgument();
536 }
537 valueIntf->maxValue(unitModifier(conversionFormula(maxValue)));
538 valueIntf->minValue(unitModifier(conversionFormula(minValue)));
539 valueIntf->unit(sensorUnit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000540 }
Thu Nguyen6d615f12024-04-24 05:02:03 +0000541 else
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000542 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000543 try
544 {
545 metricIntf = std::make_unique<MetricIntf>(bus, path.c_str());
546 }
547 catch (const sdbusplus::exception_t& e)
548 {
549 lg2::error(
550 "Failed to create Metric interface for compact numeric sensor {PATH} error - {ERROR}",
551 "PATH", path, "ERROR", e);
552 throw sdbusplus::xyz::openbmc_project::Common::Error::
553 InvalidArgument();
554 }
555 metricIntf->maxValue(unitModifier(conversionFormula(maxValue)));
556 metricIntf->minValue(unitModifier(conversionFormula(minValue)));
557 metricIntf->unit(metricUnit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000558 }
Thu Nguyen6d615f12024-04-24 05:02:03 +0000559
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000560 hysteresis = unitModifier(conversionFormula(hysteresis));
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000561
Chau Lyd197f092023-11-06 07:29:06 +0000562 if (!createInventoryPath(associationPath, sensorName, pdr->entity_type,
563 pdr->entity_instance, pdr->container_id))
564 {
565 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
566 }
567
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000568 try
569 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400570 availabilityIntf =
571 std::make_unique<AvailabilityIntf>(bus, path.c_str());
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000572 }
573 catch (const sdbusplus::exception_t& e)
574 {
575 lg2::error(
576 "Failed to create Availability interface for compact numeric sensor {PATH} error - {ERROR}",
577 "PATH", path, "ERROR", e);
578 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
579 }
580 availabilityIntf->available(true);
581
582 try
583 {
584 operationalStatusIntf =
585 std::make_unique<OperationalStatusIntf>(bus, path.c_str());
586 }
587 catch (const sdbusplus::exception_t& e)
588 {
589 lg2::error(
590 "Failed to create Operational status interface for compact numeric sensor {PATH} error - {ERROR}",
591 "PATH", path, "ERROR", e);
592 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
593 }
594 operationalStatusIntf->functional(!sensorDisabled);
595
Thu Nguyen6d615f12024-04-24 05:02:03 +0000596 if (hasWarningThresholds && !useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000597 {
598 try
599 {
600 thresholdWarningIntf =
601 std::make_unique<ThresholdWarningIntf>(bus, path.c_str());
602 }
603 catch (const sdbusplus::exception_t& e)
604 {
605 lg2::error(
606 "Failed to create Warning threshold interface for compact numeric sensor {PATH} error - {ERROR}",
607 "PATH", path, "ERROR", e);
608 throw sdbusplus::xyz::openbmc_project::Common::Error::
609 InvalidArgument();
610 }
611 thresholdWarningIntf->warningHigh(unitModifier(warningHigh));
612 thresholdWarningIntf->warningLow(unitModifier(warningLow));
613 }
614
Thu Nguyen6d615f12024-04-24 05:02:03 +0000615 if (hasCriticalThresholds && !useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000616 {
617 try
618 {
619 thresholdCriticalIntf =
620 std::make_unique<ThresholdCriticalIntf>(bus, path.c_str());
621 }
622 catch (const sdbusplus::exception_t& e)
623 {
624 lg2::error(
625 "Failed to create Critical threshold interface for compact numeric sensor {PATH} error - {ERROR}",
626 "PATH", path, "ERROR", e);
627 throw sdbusplus::xyz::openbmc_project::Common::Error::
628 InvalidArgument();
629 }
630 thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh));
631 thresholdCriticalIntf->criticalLow(unitModifier(criticalLow));
632 }
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800633
634 if (hasFatalThresholds && !useMetricInterface)
635 {
636 try
637 {
638 thresholdHardShutdownIntf =
639 std::make_unique<ThresholdHardShutdownIntf>(bus, path.c_str());
640 }
641 catch (const sdbusplus::exception_t& e)
642 {
643 lg2::error(
644 "Failed to create HardShutdown threshold interface for numeric sensor {PATH} error - {ERROR}",
645 "PATH", path, "ERROR", e);
646 throw sdbusplus::xyz::openbmc_project::Common::Error::
647 InvalidArgument();
648 }
649 thresholdHardShutdownIntf->hardShutdownHigh(unitModifier(fatalHigh));
650 thresholdHardShutdownIntf->hardShutdownLow(unitModifier(fatalLow));
651 }
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000652}
653
654double NumericSensor::conversionFormula(double value)
655{
656 double convertedValue = value;
Ed Tanous0469b562025-01-06 12:35:10 -0800657 if (std::isfinite(resolution))
658 {
659 convertedValue *= resolution;
660 }
661 if (std::isfinite(offset))
662 {
663 convertedValue += offset;
664 }
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000665 return convertedValue;
666}
667
668double NumericSensor::unitModifier(double value)
669{
Ed Tanous0469b562025-01-06 12:35:10 -0800670 if (!std::isfinite(value))
671 {
672 return value;
673 }
674 return value * std::pow(10, baseUnitModifier);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000675}
Gilbert Cheneac61a42022-02-23 20:56:19 +0000676
677void NumericSensor::updateReading(bool available, bool functional, double value)
678{
Thu Nguyen6d615f12024-04-24 05:02:03 +0000679 if (!availabilityIntf || !operationalStatusIntf ||
680 (!useMetricInterface && !valueIntf) ||
681 (useMetricInterface && !metricIntf))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000682 {
683 lg2::error(
684 "Failed to update sensor {NAME} D-Bus interface don't exist.",
685 "NAME", sensorName);
686 return;
687 }
688 availabilityIntf->available(available);
689 operationalStatusIntf->functional(functional);
Thu Nguyen6d615f12024-04-24 05:02:03 +0000690 double curValue = 0;
691 if (!useMetricInterface)
692 {
693 curValue = valueIntf->value();
694 }
695 else
696 {
697 curValue = metricIntf->value();
698 }
699
Gilbert Cheneac61a42022-02-23 20:56:19 +0000700 double newValue = std::numeric_limits<double>::quiet_NaN();
701 if (functional && available)
702 {
703 newValue = unitModifier(conversionFormula(value));
704 if (newValue != curValue &&
Ed Tanous0469b562025-01-06 12:35:10 -0800705 (std::isfinite(newValue) || std::isfinite(curValue)))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000706 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000707 if (!useMetricInterface)
708 {
709 valueIntf->value(newValue);
710 updateThresholds();
711 }
712 else
713 {
714 metricIntf->value(newValue);
715 }
Gilbert Cheneac61a42022-02-23 20:56:19 +0000716 }
717 }
718 else
719 {
720 if (newValue != curValue &&
Ed Tanous0469b562025-01-06 12:35:10 -0800721 (std::isfinite(newValue) || std::isfinite(curValue)))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000722 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000723 if (!useMetricInterface)
724 {
725 valueIntf->value(std::numeric_limits<double>::quiet_NaN());
726 }
727 else
728 {
729 metricIntf->value(std::numeric_limits<double>::quiet_NaN());
730 }
Gilbert Cheneac61a42022-02-23 20:56:19 +0000731 }
732 }
733}
734
735void NumericSensor::handleErrGetSensorReading()
736{
Thu Nguyen6d615f12024-04-24 05:02:03 +0000737 if (!operationalStatusIntf || (!useMetricInterface && !valueIntf) ||
738 (useMetricInterface && !metricIntf))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000739 {
740 lg2::error(
741 "Failed to update sensor {NAME} D-Bus interfaces don't exist.",
742 "NAME", sensorName);
743 return;
744 }
745 operationalStatusIntf->functional(false);
Thu Nguyen6d615f12024-04-24 05:02:03 +0000746 if (!useMetricInterface)
747 {
748 valueIntf->value(std::numeric_limits<double>::quiet_NaN());
749 }
750 else
751 {
752 metricIntf->value(std::numeric_limits<double>::quiet_NaN());
753 }
Gilbert Cheneac61a42022-02-23 20:56:19 +0000754}
755
756bool NumericSensor::checkThreshold(bool alarm, bool direction, double value,
757 double threshold, double hyst)
758{
759 if (direction)
760 {
761 if (value >= threshold)
762 {
763 return true;
764 }
765 if (value < (threshold - hyst))
766 {
767 return false;
768 }
769 }
770 else
771 {
772 if (value <= threshold)
773 {
774 return true;
775 }
776 if (value > (threshold + hyst))
777 {
778 return false;
779 }
780 }
781 return alarm;
782}
783
784void NumericSensor::updateThresholds()
785{
Thu Nguyen6d615f12024-04-24 05:02:03 +0000786 double value = std::numeric_limits<double>::quiet_NaN();
787
788 if ((!useMetricInterface && !valueIntf) ||
789 (useMetricInterface && !metricIntf))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000790 {
791 lg2::error(
792 "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.",
793 "NAME", sensorName);
794 return;
795 }
Thu Nguyen6d615f12024-04-24 05:02:03 +0000796 if (!useMetricInterface)
797 {
798 value = valueIntf->value();
799 }
800 else
801 {
802 value = metricIntf->value();
803 }
Gilbert Cheneac61a42022-02-23 20:56:19 +0000804 if (thresholdWarningIntf &&
Ed Tanous0469b562025-01-06 12:35:10 -0800805 std::isfinite(thresholdWarningIntf->warningHigh()))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000806 {
807 auto threshold = thresholdWarningIntf->warningHigh();
808 auto alarm = thresholdWarningIntf->warningAlarmHigh();
809 auto newAlarm =
810 checkThreshold(alarm, true, value, threshold, hysteresis);
811 if (alarm != newAlarm)
812 {
813 thresholdWarningIntf->warningAlarmHigh(newAlarm);
814 if (newAlarm)
815 {
816 thresholdWarningIntf->warningHighAlarmAsserted(value);
817 }
818 else
819 {
820 thresholdWarningIntf->warningHighAlarmDeasserted(value);
821 }
822 }
823 }
824
Ed Tanous0469b562025-01-06 12:35:10 -0800825 if (thresholdWarningIntf &&
826 std::isfinite(thresholdWarningIntf->warningLow()))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000827 {
828 auto threshold = thresholdWarningIntf->warningLow();
829 auto alarm = thresholdWarningIntf->warningAlarmLow();
830 auto newAlarm =
831 checkThreshold(alarm, false, value, threshold, hysteresis);
832 if (alarm != newAlarm)
833 {
834 thresholdWarningIntf->warningAlarmLow(newAlarm);
835 if (newAlarm)
836 {
837 thresholdWarningIntf->warningLowAlarmAsserted(value);
838 }
839 else
840 {
841 thresholdWarningIntf->warningLowAlarmDeasserted(value);
842 }
843 }
844 }
845
846 if (thresholdCriticalIntf &&
Ed Tanous0469b562025-01-06 12:35:10 -0800847 std::isfinite(thresholdCriticalIntf->criticalHigh()))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000848 {
849 auto threshold = thresholdCriticalIntf->criticalHigh();
850 auto alarm = thresholdCriticalIntf->criticalAlarmHigh();
851 auto newAlarm =
852 checkThreshold(alarm, true, value, threshold, hysteresis);
853 if (alarm != newAlarm)
854 {
855 thresholdCriticalIntf->criticalAlarmHigh(newAlarm);
856 if (newAlarm)
857 {
858 thresholdCriticalIntf->criticalHighAlarmAsserted(value);
859 }
860 else
861 {
862 thresholdCriticalIntf->criticalHighAlarmDeasserted(value);
863 }
864 }
865 }
866
867 if (thresholdCriticalIntf &&
Ed Tanous0469b562025-01-06 12:35:10 -0800868 std::isfinite(thresholdCriticalIntf->criticalLow()))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000869 {
870 auto threshold = thresholdCriticalIntf->criticalLow();
871 auto alarm = thresholdCriticalIntf->criticalAlarmLow();
872 auto newAlarm =
873 checkThreshold(alarm, false, value, threshold, hysteresis);
874 if (alarm != newAlarm)
875 {
876 thresholdCriticalIntf->criticalAlarmLow(newAlarm);
877 if (newAlarm)
878 {
879 thresholdCriticalIntf->criticalLowAlarmAsserted(value);
880 }
881 else
882 {
883 thresholdCriticalIntf->criticalLowAlarmDeasserted(value);
884 }
885 }
886 }
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800887
888 if (thresholdHardShutdownIntf &&
889 std::isfinite(thresholdHardShutdownIntf->hardShutdownHigh()))
890 {
891 auto threshold = thresholdHardShutdownIntf->hardShutdownHigh();
892 auto alarm = thresholdHardShutdownIntf->hardShutdownAlarmHigh();
893 auto newAlarm =
894 checkThreshold(alarm, true, value, threshold, hysteresis);
895 if (alarm != newAlarm)
896 {
897 thresholdHardShutdownIntf->hardShutdownAlarmHigh(newAlarm);
898 if (newAlarm)
899 {
900 thresholdHardShutdownIntf->hardShutdownHighAlarmAsserted(value);
901 }
902 else
903 {
904 thresholdHardShutdownIntf->hardShutdownHighAlarmDeasserted(
905 value);
906 }
907 }
908 }
909
910 if (thresholdHardShutdownIntf &&
911 std::isfinite(thresholdHardShutdownIntf->hardShutdownLow()))
912 {
913 auto threshold = thresholdHardShutdownIntf->hardShutdownLow();
914 auto alarm = thresholdHardShutdownIntf->hardShutdownAlarmLow();
915 auto newAlarm =
916 checkThreshold(alarm, false, value, threshold, hysteresis);
917 if (alarm != newAlarm)
918 {
919 thresholdHardShutdownIntf->hardShutdownAlarmLow(newAlarm);
920 if (newAlarm)
921 {
922 thresholdHardShutdownIntf->hardShutdownLowAlarmAsserted(value);
923 }
924 else
925 {
926 thresholdHardShutdownIntf->hardShutdownLowAlarmDeasserted(
927 value);
928 }
929 }
930 }
Gilbert Cheneac61a42022-02-23 20:56:19 +0000931}
Gilbert Chen77e6fe72024-08-06 09:23:30 +0000932
933int NumericSensor::triggerThresholdEvent(
934 pldm::utils::Level eventType, pldm::utils::Direction direction,
935 double rawValue, bool newAlarm, bool assert)
936{
937 if (!valueIntf)
938 {
939 lg2::error(
940 "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.",
941 "NAME", sensorName);
942 return PLDM_ERROR;
943 }
944
945 auto value = unitModifier(conversionFormula(rawValue));
946 lg2::error(
947 "triggerThresholdEvent eventType {TID}, direction {SID} value {VAL} newAlarm {PSTATE} assert {ESTATE}",
948 "TID", eventType, "SID", direction, "VAL", value, "PSTATE", newAlarm,
949 "ESTATE", assert);
950
951 switch (eventType)
952 {
953 case pldm::utils::Level::WARNING:
954 {
955 if (!thresholdWarningIntf)
956 {
957 lg2::error(
958 "Error:Trigger sensor warning event for non warning threshold sensors {NAME}",
959 "NAME", sensorName);
960 return PLDM_ERROR;
961 }
962 if (direction == pldm::utils::Direction::HIGH &&
Ed Tanous0469b562025-01-06 12:35:10 -0800963 std::isfinite(thresholdWarningIntf->warningHigh()))
Gilbert Chen77e6fe72024-08-06 09:23:30 +0000964 {
965 auto alarm = thresholdWarningIntf->warningAlarmHigh();
966 if (alarm == newAlarm)
967 {
968 return PLDM_SUCCESS;
969 }
970 thresholdWarningIntf->warningAlarmHigh(newAlarm);
971 if (assert)
972 {
973 thresholdWarningIntf->warningHighAlarmAsserted(value);
974 }
975 else
976 {
977 thresholdWarningIntf->warningHighAlarmDeasserted(value);
978 }
979 }
980 else if (direction == pldm::utils::Direction::LOW &&
Ed Tanous0469b562025-01-06 12:35:10 -0800981 std::isfinite(thresholdWarningIntf->warningLow()))
Gilbert Chen77e6fe72024-08-06 09:23:30 +0000982 {
983 auto alarm = thresholdWarningIntf->warningAlarmLow();
984 if (alarm == newAlarm)
985 {
986 return PLDM_SUCCESS;
987 }
988 thresholdWarningIntf->warningAlarmLow(newAlarm);
989 if (assert)
990 {
991 thresholdWarningIntf->warningLowAlarmAsserted(value);
992 }
993 else
994 {
995 thresholdWarningIntf->warningLowAlarmDeasserted(value);
996 }
997 }
998 break;
999 }
1000 case pldm::utils::Level::CRITICAL:
1001 {
1002 if (!thresholdCriticalIntf)
1003 {
1004 lg2::error(
1005 "Error:Trigger sensor Critical event for non warning threshold sensors {NAME}",
1006 "NAME", sensorName);
1007 return PLDM_ERROR;
1008 }
1009 if (direction == pldm::utils::Direction::HIGH &&
Ed Tanous0469b562025-01-06 12:35:10 -08001010 std::isfinite(thresholdCriticalIntf->criticalHigh()))
Gilbert Chen77e6fe72024-08-06 09:23:30 +00001011 {
1012 auto alarm = thresholdCriticalIntf->criticalAlarmHigh();
1013 if (alarm == newAlarm)
1014 {
1015 return PLDM_SUCCESS;
1016 }
1017 thresholdCriticalIntf->criticalAlarmHigh(newAlarm);
1018 if (assert)
1019 {
1020 thresholdCriticalIntf->criticalHighAlarmAsserted(value);
1021 }
1022 else
1023 {
1024 thresholdCriticalIntf->criticalHighAlarmDeasserted(value);
1025 }
1026 }
1027 else if (direction == pldm::utils::Direction::LOW &&
Ed Tanous0469b562025-01-06 12:35:10 -08001028 std::isfinite(thresholdCriticalIntf->criticalLow()))
Gilbert Chen77e6fe72024-08-06 09:23:30 +00001029 {
1030 auto alarm = thresholdCriticalIntf->criticalAlarmLow();
1031 if (alarm == newAlarm)
1032 {
1033 return PLDM_SUCCESS;
1034 }
1035 thresholdCriticalIntf->criticalAlarmLow(newAlarm);
1036 if (assert)
1037 {
1038 thresholdCriticalIntf->criticalLowAlarmAsserted(value);
1039 }
1040 else
1041 {
1042 thresholdCriticalIntf->criticalLowAlarmDeasserted(value);
1043 }
1044 }
1045 break;
1046 }
1047
1048 default:
1049 break;
1050 }
1051
1052 return PLDM_SUCCESS;
1053}
Thu Nguyen3c5486d2024-08-01 08:03:08 +00001054} // namespace platform_mc
1055} // namespace pldm