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