blob: 0c40f2c8afb4ac73ef1d7e47d4ce3b57eea4f6e0 [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 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;
218 double criticalHigh = std::numeric_limits<double>::quiet_NaN();
219 double criticalLow = std::numeric_limits<double>::quiet_NaN();
220 double warningHigh = std::numeric_limits<double>::quiet_NaN();
221 double warningLow = std::numeric_limits<double>::quiet_NaN();
222
223 if (pdr->supported_thresholds.bits.bit0)
224 {
225 hasWarningThresholds = true;
Amithash Prasada1871172024-12-19 14:26:10 -0800226 warningHigh =
227 getRangeFieldValue(pdr->range_field_format, pdr->warning_high);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000228 }
229
230 if (pdr->supported_thresholds.bits.bit3)
231 {
232 hasWarningThresholds = true;
Amithash Prasada1871172024-12-19 14:26:10 -0800233 warningLow =
234 getRangeFieldValue(pdr->range_field_format, pdr->warning_low);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000235 }
236
237 if (pdr->supported_thresholds.bits.bit1)
238 {
239 hasCriticalThresholds = true;
Amithash Prasada1871172024-12-19 14:26:10 -0800240 criticalHigh =
241 getRangeFieldValue(pdr->range_field_format, pdr->critical_high);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000242 }
243
244 if (pdr->supported_thresholds.bits.bit4)
245 {
246 hasCriticalThresholds = true;
Amithash Prasada1871172024-12-19 14:26:10 -0800247 criticalLow =
248 getRangeFieldValue(pdr->range_field_format, pdr->critical_low);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000249 }
250
251 resolution = pdr->resolution;
252 offset = pdr->offset;
253 baseUnitModifier = pdr->unit_modifier;
Gilbert Cheneac61a42022-02-23 20:56:19 +0000254 timeStamp = 0;
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000255
256 /**
257 * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds
258 * updateTime is in microseconds
259 */
260 updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000);
261 if (!std::isnan(pdr->update_interval))
262 {
263 updateTime = pdr->update_interval * 1000000;
264 }
265
Thu Nguyen6d615f12024-04-24 05:02:03 +0000266 if (!useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000267 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000268 try
269 {
270 valueIntf = std::make_unique<ValueIntf>(bus, path.c_str());
271 }
272 catch (const sdbusplus::exception_t& e)
273 {
274 lg2::error(
275 "Failed to create Value interface for numeric sensor {PATH} error - {ERROR}",
276 "PATH", path, "ERROR", e);
277 throw sdbusplus::xyz::openbmc_project::Common::Error::
278 InvalidArgument();
279 }
280 valueIntf->maxValue(unitModifier(conversionFormula(maxValue)));
281 valueIntf->minValue(unitModifier(conversionFormula(minValue)));
282 valueIntf->unit(sensorUnit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000283 }
Thu Nguyen6d615f12024-04-24 05:02:03 +0000284 else
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000285 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000286 try
287 {
288 metricIntf = std::make_unique<MetricIntf>(bus, path.c_str());
289 }
290 catch (const sdbusplus::exception_t& e)
291 {
292 lg2::error(
293 "Failed to create Metric interface for numeric sensor {PATH} error - {ERROR}",
294 "PATH", path, "ERROR", e);
295 throw sdbusplus::xyz::openbmc_project::Common::Error::
296 InvalidArgument();
297 }
298 metricIntf->maxValue(unitModifier(conversionFormula(maxValue)));
299 metricIntf->minValue(unitModifier(conversionFormula(minValue)));
300 metricIntf->unit(metricUnit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000301 }
Thu Nguyen6d615f12024-04-24 05:02:03 +0000302
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000303 hysteresis = unitModifier(conversionFormula(hysteresis));
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000304
Chau Lyd197f092023-11-06 07:29:06 +0000305 if (!createInventoryPath(associationPath, sensorName, pdr->entity_type,
306 pdr->entity_instance_num, pdr->container_id))
307 {
308 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
309 }
310
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000311 try
312 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400313 availabilityIntf =
314 std::make_unique<AvailabilityIntf>(bus, path.c_str());
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000315 }
316 catch (const sdbusplus::exception_t& e)
317 {
318 lg2::error(
319 "Failed to create Availability interface for numeric sensor {PATH} error - {ERROR}",
320 "PATH", path, "ERROR", e);
321 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
322 }
323 availabilityIntf->available(true);
324
325 try
326 {
327 operationalStatusIntf =
328 std::make_unique<OperationalStatusIntf>(bus, path.c_str());
329 }
330 catch (const sdbusplus::exception_t& e)
331 {
332 lg2::error(
333 "Failed to create Operation status interface for numeric sensor {PATH} error - {ERROR}",
334 "PATH", path, "ERROR", e);
335 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
336 }
337 operationalStatusIntf->functional(!sensorDisabled);
338
Thu Nguyen6d615f12024-04-24 05:02:03 +0000339 if (hasWarningThresholds && !useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000340 {
341 try
342 {
343 thresholdWarningIntf =
344 std::make_unique<ThresholdWarningIntf>(bus, path.c_str());
345 }
346 catch (const sdbusplus::exception_t& e)
347 {
348 lg2::error(
349 "Failed to create Threshold warning interface for numeric sensor {PATH} error - {ERROR}",
350 "PATH", path, "ERROR", e);
351 throw sdbusplus::xyz::openbmc_project::Common::Error::
352 InvalidArgument();
353 }
354 thresholdWarningIntf->warningHigh(unitModifier(warningHigh));
355 thresholdWarningIntf->warningLow(unitModifier(warningLow));
356 }
357
Thu Nguyen6d615f12024-04-24 05:02:03 +0000358 if (hasCriticalThresholds && !useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000359 {
360 try
361 {
362 thresholdCriticalIntf =
363 std::make_unique<ThresholdCriticalIntf>(bus, path.c_str());
364 }
365 catch (const sdbusplus::exception_t& e)
366 {
367 lg2::error(
368 "Failed to create Threshold critical interface for numeric sensor {PATH} error - {ERROR}",
369 "PATH", path, "ERROR", e);
370 throw sdbusplus::xyz::openbmc_project::Common::Error::
371 InvalidArgument();
372 }
373 thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh));
374 thresholdCriticalIntf->criticalLow(unitModifier(criticalLow));
375 }
376}
377
378NumericSensor::NumericSensor(
379 const pldm_tid_t tid, const bool sensorDisabled,
380 std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr,
381 std::string& sensorName, std::string& associationPath) :
Gilbert Cheneac61a42022-02-23 20:56:19 +0000382 tid(tid), sensorName(sensorName)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000383{
384 if (!pdr)
385 {
386 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
387 }
388
389 sensorId = pdr->sensor_id;
390 std::string path;
Thu Nguyen6d615f12024-04-24 05:02:03 +0000391 MetricUnit metricUnit = MetricUnit::Count;
Amithash Prasad98256602024-12-19 14:02:30 -0800392 setSensorUnit(pdr->base_unit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000393
394 path = sensorNameSpace + sensorName;
395 try
396 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000397 std::string tmp{};
398 std::string interface = SENSOR_VALUE_INTF;
399 if (useMetricInterface)
400 {
401 interface = METRIC_VALUE_INTF;
402 }
403 tmp = pldm::utils::DBusHandler().getService(path.c_str(),
404 interface.c_str());
405
406 if (!tmp.empty())
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000407 {
408 throw sdbusplus::xyz::openbmc_project::Common::Error::
409 TooManyResources();
410 }
411 }
412 catch (const std::exception&)
413 {
414 /* The sensor object path is not created */
415 }
416
417 auto& bus = pldm::utils::DBusHandler::getBus();
418 try
419 {
420 associationDefinitionsIntf =
421 std::make_unique<AssociationDefinitionsInft>(bus, path.c_str());
422 }
423 catch (const sdbusplus::exception_t& e)
424 {
425 lg2::error(
426 "Failed to create Association interface for compact numeric sensor {PATH} error - {ERROR}",
427 "PATH", path, "ERROR", e);
428 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
429 }
430 associationDefinitionsIntf->associations(
431 {{"chassis", "all_sensors", associationPath.c_str()}});
432
433 double maxValue = std::numeric_limits<double>::quiet_NaN();
434 double minValue = std::numeric_limits<double>::quiet_NaN();
435 bool hasWarningThresholds = false;
436 bool hasCriticalThresholds = false;
437 double criticalHigh = std::numeric_limits<double>::quiet_NaN();
438 double criticalLow = std::numeric_limits<double>::quiet_NaN();
439 double warningHigh = std::numeric_limits<double>::quiet_NaN();
440 double warningLow = std::numeric_limits<double>::quiet_NaN();
441
442 if (pdr->range_field_support.bits.bit0)
443 {
444 hasWarningThresholds = true;
445 warningHigh = pdr->warning_high;
446 }
447 if (pdr->range_field_support.bits.bit1)
448 {
449 hasWarningThresholds = true;
450 warningLow = pdr->warning_low;
451 }
452
453 if (pdr->range_field_support.bits.bit2)
454 {
455 hasCriticalThresholds = true;
456 criticalHigh = pdr->critical_high;
457 }
458
459 if (pdr->range_field_support.bits.bit3)
460 {
461 hasCriticalThresholds = true;
462 criticalLow = pdr->critical_low;
463 }
464
465 resolution = std::numeric_limits<double>::quiet_NaN();
466 offset = std::numeric_limits<double>::quiet_NaN();
467 baseUnitModifier = pdr->unit_modifier;
Gilbert Cheneac61a42022-02-23 20:56:19 +0000468 timeStamp = 0;
Thu Nguyen2027ff52024-10-03 21:58:22 +0000469 hysteresis = 0;
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000470
471 /**
472 * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds
473 * updateTime is in microseconds
474 */
475 updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000);
Thu Nguyen6d615f12024-04-24 05:02:03 +0000476
477 if (!useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000478 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000479 try
480 {
481 valueIntf = std::make_unique<ValueIntf>(bus, path.c_str());
482 }
483 catch (const sdbusplus::exception_t& e)
484 {
485 lg2::error(
486 "Failed to create Value interface for compact numeric sensor {PATH} error - {ERROR}",
487 "PATH", path, "ERROR", e);
488 throw sdbusplus::xyz::openbmc_project::Common::Error::
489 InvalidArgument();
490 }
491 valueIntf->maxValue(unitModifier(conversionFormula(maxValue)));
492 valueIntf->minValue(unitModifier(conversionFormula(minValue)));
493 valueIntf->unit(sensorUnit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000494 }
Thu Nguyen6d615f12024-04-24 05:02:03 +0000495 else
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000496 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000497 try
498 {
499 metricIntf = std::make_unique<MetricIntf>(bus, path.c_str());
500 }
501 catch (const sdbusplus::exception_t& e)
502 {
503 lg2::error(
504 "Failed to create Metric interface for compact numeric sensor {PATH} error - {ERROR}",
505 "PATH", path, "ERROR", e);
506 throw sdbusplus::xyz::openbmc_project::Common::Error::
507 InvalidArgument();
508 }
509 metricIntf->maxValue(unitModifier(conversionFormula(maxValue)));
510 metricIntf->minValue(unitModifier(conversionFormula(minValue)));
511 metricIntf->unit(metricUnit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000512 }
Thu Nguyen6d615f12024-04-24 05:02:03 +0000513
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000514 hysteresis = unitModifier(conversionFormula(hysteresis));
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000515
Chau Lyd197f092023-11-06 07:29:06 +0000516 if (!createInventoryPath(associationPath, sensorName, pdr->entity_type,
517 pdr->entity_instance, pdr->container_id))
518 {
519 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
520 }
521
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000522 try
523 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400524 availabilityIntf =
525 std::make_unique<AvailabilityIntf>(bus, path.c_str());
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000526 }
527 catch (const sdbusplus::exception_t& e)
528 {
529 lg2::error(
530 "Failed to create Availability interface for compact numeric sensor {PATH} error - {ERROR}",
531 "PATH", path, "ERROR", e);
532 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
533 }
534 availabilityIntf->available(true);
535
536 try
537 {
538 operationalStatusIntf =
539 std::make_unique<OperationalStatusIntf>(bus, path.c_str());
540 }
541 catch (const sdbusplus::exception_t& e)
542 {
543 lg2::error(
544 "Failed to create Operational status interface for compact numeric sensor {PATH} error - {ERROR}",
545 "PATH", path, "ERROR", e);
546 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
547 }
548 operationalStatusIntf->functional(!sensorDisabled);
549
Thu Nguyen6d615f12024-04-24 05:02:03 +0000550 if (hasWarningThresholds && !useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000551 {
552 try
553 {
554 thresholdWarningIntf =
555 std::make_unique<ThresholdWarningIntf>(bus, path.c_str());
556 }
557 catch (const sdbusplus::exception_t& e)
558 {
559 lg2::error(
560 "Failed to create Warning threshold interface for compact numeric sensor {PATH} error - {ERROR}",
561 "PATH", path, "ERROR", e);
562 throw sdbusplus::xyz::openbmc_project::Common::Error::
563 InvalidArgument();
564 }
565 thresholdWarningIntf->warningHigh(unitModifier(warningHigh));
566 thresholdWarningIntf->warningLow(unitModifier(warningLow));
567 }
568
Thu Nguyen6d615f12024-04-24 05:02:03 +0000569 if (hasCriticalThresholds && !useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000570 {
571 try
572 {
573 thresholdCriticalIntf =
574 std::make_unique<ThresholdCriticalIntf>(bus, path.c_str());
575 }
576 catch (const sdbusplus::exception_t& e)
577 {
578 lg2::error(
579 "Failed to create Critical threshold interface for compact numeric sensor {PATH} error - {ERROR}",
580 "PATH", path, "ERROR", e);
581 throw sdbusplus::xyz::openbmc_project::Common::Error::
582 InvalidArgument();
583 }
584 thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh));
585 thresholdCriticalIntf->criticalLow(unitModifier(criticalLow));
586 }
587}
588
589double NumericSensor::conversionFormula(double value)
590{
591 double convertedValue = value;
592 convertedValue *= std::isnan(resolution) ? 1 : resolution;
593 convertedValue += std::isnan(offset) ? 0 : offset;
594 return convertedValue;
595}
596
597double NumericSensor::unitModifier(double value)
598{
599 return std::isnan(value) ? value : value * std::pow(10, baseUnitModifier);
600}
Gilbert Cheneac61a42022-02-23 20:56:19 +0000601
602void NumericSensor::updateReading(bool available, bool functional, double value)
603{
Thu Nguyen6d615f12024-04-24 05:02:03 +0000604 if (!availabilityIntf || !operationalStatusIntf ||
605 (!useMetricInterface && !valueIntf) ||
606 (useMetricInterface && !metricIntf))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000607 {
608 lg2::error(
609 "Failed to update sensor {NAME} D-Bus interface don't exist.",
610 "NAME", sensorName);
611 return;
612 }
613 availabilityIntf->available(available);
614 operationalStatusIntf->functional(functional);
Thu Nguyen6d615f12024-04-24 05:02:03 +0000615 double curValue = 0;
616 if (!useMetricInterface)
617 {
618 curValue = valueIntf->value();
619 }
620 else
621 {
622 curValue = metricIntf->value();
623 }
624
Gilbert Cheneac61a42022-02-23 20:56:19 +0000625 double newValue = std::numeric_limits<double>::quiet_NaN();
626 if (functional && available)
627 {
628 newValue = unitModifier(conversionFormula(value));
629 if (newValue != curValue &&
630 (!std::isnan(newValue) || !std::isnan(curValue)))
631 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000632 if (!useMetricInterface)
633 {
634 valueIntf->value(newValue);
635 updateThresholds();
636 }
637 else
638 {
639 metricIntf->value(newValue);
640 }
Gilbert Cheneac61a42022-02-23 20:56:19 +0000641 }
642 }
643 else
644 {
645 if (newValue != curValue &&
646 (!std::isnan(newValue) || !std::isnan(curValue)))
647 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000648 if (!useMetricInterface)
649 {
650 valueIntf->value(std::numeric_limits<double>::quiet_NaN());
651 }
652 else
653 {
654 metricIntf->value(std::numeric_limits<double>::quiet_NaN());
655 }
Gilbert Cheneac61a42022-02-23 20:56:19 +0000656 }
657 }
658}
659
660void NumericSensor::handleErrGetSensorReading()
661{
Thu Nguyen6d615f12024-04-24 05:02:03 +0000662 if (!operationalStatusIntf || (!useMetricInterface && !valueIntf) ||
663 (useMetricInterface && !metricIntf))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000664 {
665 lg2::error(
666 "Failed to update sensor {NAME} D-Bus interfaces don't exist.",
667 "NAME", sensorName);
668 return;
669 }
670 operationalStatusIntf->functional(false);
Thu Nguyen6d615f12024-04-24 05:02:03 +0000671 if (!useMetricInterface)
672 {
673 valueIntf->value(std::numeric_limits<double>::quiet_NaN());
674 }
675 else
676 {
677 metricIntf->value(std::numeric_limits<double>::quiet_NaN());
678 }
Gilbert Cheneac61a42022-02-23 20:56:19 +0000679}
680
681bool NumericSensor::checkThreshold(bool alarm, bool direction, double value,
682 double threshold, double hyst)
683{
684 if (direction)
685 {
686 if (value >= threshold)
687 {
688 return true;
689 }
690 if (value < (threshold - hyst))
691 {
692 return false;
693 }
694 }
695 else
696 {
697 if (value <= threshold)
698 {
699 return true;
700 }
701 if (value > (threshold + hyst))
702 {
703 return false;
704 }
705 }
706 return alarm;
707}
708
709void NumericSensor::updateThresholds()
710{
Thu Nguyen6d615f12024-04-24 05:02:03 +0000711 double value = std::numeric_limits<double>::quiet_NaN();
712
713 if ((!useMetricInterface && !valueIntf) ||
714 (useMetricInterface && !metricIntf))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000715 {
716 lg2::error(
717 "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.",
718 "NAME", sensorName);
719 return;
720 }
Thu Nguyen6d615f12024-04-24 05:02:03 +0000721 if (!useMetricInterface)
722 {
723 value = valueIntf->value();
724 }
725 else
726 {
727 value = metricIntf->value();
728 }
Gilbert Cheneac61a42022-02-23 20:56:19 +0000729 if (thresholdWarningIntf &&
730 !std::isnan(thresholdWarningIntf->warningHigh()))
731 {
732 auto threshold = thresholdWarningIntf->warningHigh();
733 auto alarm = thresholdWarningIntf->warningAlarmHigh();
734 auto newAlarm =
735 checkThreshold(alarm, true, value, threshold, hysteresis);
736 if (alarm != newAlarm)
737 {
738 thresholdWarningIntf->warningAlarmHigh(newAlarm);
739 if (newAlarm)
740 {
741 thresholdWarningIntf->warningHighAlarmAsserted(value);
742 }
743 else
744 {
745 thresholdWarningIntf->warningHighAlarmDeasserted(value);
746 }
747 }
748 }
749
750 if (thresholdWarningIntf && !std::isnan(thresholdWarningIntf->warningLow()))
751 {
752 auto threshold = thresholdWarningIntf->warningLow();
753 auto alarm = thresholdWarningIntf->warningAlarmLow();
754 auto newAlarm =
755 checkThreshold(alarm, false, value, threshold, hysteresis);
756 if (alarm != newAlarm)
757 {
758 thresholdWarningIntf->warningAlarmLow(newAlarm);
759 if (newAlarm)
760 {
761 thresholdWarningIntf->warningLowAlarmAsserted(value);
762 }
763 else
764 {
765 thresholdWarningIntf->warningLowAlarmDeasserted(value);
766 }
767 }
768 }
769
770 if (thresholdCriticalIntf &&
771 !std::isnan(thresholdCriticalIntf->criticalHigh()))
772 {
773 auto threshold = thresholdCriticalIntf->criticalHigh();
774 auto alarm = thresholdCriticalIntf->criticalAlarmHigh();
775 auto newAlarm =
776 checkThreshold(alarm, true, value, threshold, hysteresis);
777 if (alarm != newAlarm)
778 {
779 thresholdCriticalIntf->criticalAlarmHigh(newAlarm);
780 if (newAlarm)
781 {
782 thresholdCriticalIntf->criticalHighAlarmAsserted(value);
783 }
784 else
785 {
786 thresholdCriticalIntf->criticalHighAlarmDeasserted(value);
787 }
788 }
789 }
790
791 if (thresholdCriticalIntf &&
792 !std::isnan(thresholdCriticalIntf->criticalLow()))
793 {
794 auto threshold = thresholdCriticalIntf->criticalLow();
795 auto alarm = thresholdCriticalIntf->criticalAlarmLow();
796 auto newAlarm =
797 checkThreshold(alarm, false, value, threshold, hysteresis);
798 if (alarm != newAlarm)
799 {
800 thresholdCriticalIntf->criticalAlarmLow(newAlarm);
801 if (newAlarm)
802 {
803 thresholdCriticalIntf->criticalLowAlarmAsserted(value);
804 }
805 else
806 {
807 thresholdCriticalIntf->criticalLowAlarmDeasserted(value);
808 }
809 }
810 }
811}
Gilbert Chen77e6fe72024-08-06 09:23:30 +0000812
813int NumericSensor::triggerThresholdEvent(
814 pldm::utils::Level eventType, pldm::utils::Direction direction,
815 double rawValue, bool newAlarm, bool assert)
816{
817 if (!valueIntf)
818 {
819 lg2::error(
820 "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.",
821 "NAME", sensorName);
822 return PLDM_ERROR;
823 }
824
825 auto value = unitModifier(conversionFormula(rawValue));
826 lg2::error(
827 "triggerThresholdEvent eventType {TID}, direction {SID} value {VAL} newAlarm {PSTATE} assert {ESTATE}",
828 "TID", eventType, "SID", direction, "VAL", value, "PSTATE", newAlarm,
829 "ESTATE", assert);
830
831 switch (eventType)
832 {
833 case pldm::utils::Level::WARNING:
834 {
835 if (!thresholdWarningIntf)
836 {
837 lg2::error(
838 "Error:Trigger sensor warning event for non warning threshold sensors {NAME}",
839 "NAME", sensorName);
840 return PLDM_ERROR;
841 }
842 if (direction == pldm::utils::Direction::HIGH &&
843 !std::isnan(thresholdWarningIntf->warningHigh()))
844 {
845 auto alarm = thresholdWarningIntf->warningAlarmHigh();
846 if (alarm == newAlarm)
847 {
848 return PLDM_SUCCESS;
849 }
850 thresholdWarningIntf->warningAlarmHigh(newAlarm);
851 if (assert)
852 {
853 thresholdWarningIntf->warningHighAlarmAsserted(value);
854 }
855 else
856 {
857 thresholdWarningIntf->warningHighAlarmDeasserted(value);
858 }
859 }
860 else if (direction == pldm::utils::Direction::LOW &&
861 !std::isnan(thresholdWarningIntf->warningLow()))
862 {
863 auto alarm = thresholdWarningIntf->warningAlarmLow();
864 if (alarm == newAlarm)
865 {
866 return PLDM_SUCCESS;
867 }
868 thresholdWarningIntf->warningAlarmLow(newAlarm);
869 if (assert)
870 {
871 thresholdWarningIntf->warningLowAlarmAsserted(value);
872 }
873 else
874 {
875 thresholdWarningIntf->warningLowAlarmDeasserted(value);
876 }
877 }
878 break;
879 }
880 case pldm::utils::Level::CRITICAL:
881 {
882 if (!thresholdCriticalIntf)
883 {
884 lg2::error(
885 "Error:Trigger sensor Critical event for non warning threshold sensors {NAME}",
886 "NAME", sensorName);
887 return PLDM_ERROR;
888 }
889 if (direction == pldm::utils::Direction::HIGH &&
890 !std::isnan(thresholdCriticalIntf->criticalHigh()))
891 {
892 auto alarm = thresholdCriticalIntf->criticalAlarmHigh();
893 if (alarm == newAlarm)
894 {
895 return PLDM_SUCCESS;
896 }
897 thresholdCriticalIntf->criticalAlarmHigh(newAlarm);
898 if (assert)
899 {
900 thresholdCriticalIntf->criticalHighAlarmAsserted(value);
901 }
902 else
903 {
904 thresholdCriticalIntf->criticalHighAlarmDeasserted(value);
905 }
906 }
907 else if (direction == pldm::utils::Direction::LOW &&
908 !std::isnan(thresholdCriticalIntf->criticalLow()))
909 {
910 auto alarm = thresholdCriticalIntf->criticalAlarmLow();
911 if (alarm == newAlarm)
912 {
913 return PLDM_SUCCESS;
914 }
915 thresholdCriticalIntf->criticalAlarmLow(newAlarm);
916 if (assert)
917 {
918 thresholdCriticalIntf->criticalLowAlarmAsserted(value);
919 }
920 else
921 {
922 thresholdCriticalIntf->criticalLowAlarmDeasserted(value);
923 }
924 }
925 break;
926 }
927
928 default:
929 break;
930 }
931
932 return PLDM_SUCCESS;
933}
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000934} // namespace platform_mc
935} // namespace pldm