blob: 2f56bbf313749335f116318db3637b0e89f84937 [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 Nguyen3c5486d2024-08-01 08:03:08 +0000543
544 /**
545 * DEFAULT_SENSOR_UPDATER_INTERVAL is in milliseconds
546 * updateTime is in microseconds
547 */
548 updateTime = static_cast<uint64_t>(DEFAULT_SENSOR_UPDATER_INTERVAL * 1000);
Thu Nguyen6d615f12024-04-24 05:02:03 +0000549
550 if (!useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000551 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000552 try
553 {
554 valueIntf = std::make_unique<ValueIntf>(bus, path.c_str());
555 }
556 catch (const sdbusplus::exception_t& e)
557 {
558 lg2::error(
559 "Failed to create Value interface for compact numeric sensor {PATH} error - {ERROR}",
560 "PATH", path, "ERROR", e);
561 throw sdbusplus::xyz::openbmc_project::Common::Error::
562 InvalidArgument();
563 }
564 valueIntf->maxValue(unitModifier(conversionFormula(maxValue)));
565 valueIntf->minValue(unitModifier(conversionFormula(minValue)));
566 valueIntf->unit(sensorUnit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000567 }
Thu Nguyen6d615f12024-04-24 05:02:03 +0000568 else
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000569 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000570 try
571 {
572 metricIntf = std::make_unique<MetricIntf>(bus, path.c_str());
573 }
574 catch (const sdbusplus::exception_t& e)
575 {
576 lg2::error(
577 "Failed to create Metric interface for compact numeric sensor {PATH} error - {ERROR}",
578 "PATH", path, "ERROR", e);
579 throw sdbusplus::xyz::openbmc_project::Common::Error::
580 InvalidArgument();
581 }
582 metricIntf->maxValue(unitModifier(conversionFormula(maxValue)));
583 metricIntf->minValue(unitModifier(conversionFormula(minValue)));
584 metricIntf->unit(metricUnit);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000585 }
Thu Nguyen6d615f12024-04-24 05:02:03 +0000586
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000587 hysteresis = unitModifier(conversionFormula(hysteresis));
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000588
589 try
590 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400591 availabilityIntf =
592 std::make_unique<AvailabilityIntf>(bus, path.c_str());
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000593 }
594 catch (const sdbusplus::exception_t& e)
595 {
596 lg2::error(
597 "Failed to create Availability interface for compact numeric sensor {PATH} error - {ERROR}",
598 "PATH", path, "ERROR", e);
599 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
600 }
601 availabilityIntf->available(true);
602
603 try
604 {
605 operationalStatusIntf =
606 std::make_unique<OperationalStatusIntf>(bus, path.c_str());
607 }
608 catch (const sdbusplus::exception_t& e)
609 {
610 lg2::error(
611 "Failed to create Operational status interface for compact numeric sensor {PATH} error - {ERROR}",
612 "PATH", path, "ERROR", e);
613 throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument();
614 }
615 operationalStatusIntf->functional(!sensorDisabled);
616
Thu Nguyen6d615f12024-04-24 05:02:03 +0000617 if (hasWarningThresholds && !useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000618 {
619 try
620 {
621 thresholdWarningIntf =
622 std::make_unique<ThresholdWarningIntf>(bus, path.c_str());
623 }
624 catch (const sdbusplus::exception_t& e)
625 {
626 lg2::error(
627 "Failed to create Warning threshold interface for compact numeric sensor {PATH} error - {ERROR}",
628 "PATH", path, "ERROR", e);
629 throw sdbusplus::xyz::openbmc_project::Common::Error::
630 InvalidArgument();
631 }
632 thresholdWarningIntf->warningHigh(unitModifier(warningHigh));
633 thresholdWarningIntf->warningLow(unitModifier(warningLow));
634 }
635
Thu Nguyen6d615f12024-04-24 05:02:03 +0000636 if (hasCriticalThresholds && !useMetricInterface)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000637 {
638 try
639 {
640 thresholdCriticalIntf =
641 std::make_unique<ThresholdCriticalIntf>(bus, path.c_str());
642 }
643 catch (const sdbusplus::exception_t& e)
644 {
645 lg2::error(
646 "Failed to create Critical threshold interface for compact numeric sensor {PATH} error - {ERROR}",
647 "PATH", path, "ERROR", e);
648 throw sdbusplus::xyz::openbmc_project::Common::Error::
649 InvalidArgument();
650 }
651 thresholdCriticalIntf->criticalHigh(unitModifier(criticalHigh));
652 thresholdCriticalIntf->criticalLow(unitModifier(criticalLow));
653 }
654}
655
656double NumericSensor::conversionFormula(double value)
657{
658 double convertedValue = value;
659 convertedValue *= std::isnan(resolution) ? 1 : resolution;
660 convertedValue += std::isnan(offset) ? 0 : offset;
661 return convertedValue;
662}
663
664double NumericSensor::unitModifier(double value)
665{
666 return std::isnan(value) ? value : value * std::pow(10, baseUnitModifier);
667}
Gilbert Cheneac61a42022-02-23 20:56:19 +0000668
669void NumericSensor::updateReading(bool available, bool functional, double value)
670{
Thu Nguyen6d615f12024-04-24 05:02:03 +0000671 if (!availabilityIntf || !operationalStatusIntf ||
672 (!useMetricInterface && !valueIntf) ||
673 (useMetricInterface && !metricIntf))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000674 {
675 lg2::error(
676 "Failed to update sensor {NAME} D-Bus interface don't exist.",
677 "NAME", sensorName);
678 return;
679 }
680 availabilityIntf->available(available);
681 operationalStatusIntf->functional(functional);
Thu Nguyen6d615f12024-04-24 05:02:03 +0000682 double curValue = 0;
683 if (!useMetricInterface)
684 {
685 curValue = valueIntf->value();
686 }
687 else
688 {
689 curValue = metricIntf->value();
690 }
691
Gilbert Cheneac61a42022-02-23 20:56:19 +0000692 double newValue = std::numeric_limits<double>::quiet_NaN();
693 if (functional && available)
694 {
695 newValue = unitModifier(conversionFormula(value));
696 if (newValue != curValue &&
697 (!std::isnan(newValue) || !std::isnan(curValue)))
698 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000699 if (!useMetricInterface)
700 {
701 valueIntf->value(newValue);
702 updateThresholds();
703 }
704 else
705 {
706 metricIntf->value(newValue);
707 }
Gilbert Cheneac61a42022-02-23 20:56:19 +0000708 }
709 }
710 else
711 {
712 if (newValue != curValue &&
713 (!std::isnan(newValue) || !std::isnan(curValue)))
714 {
Thu Nguyen6d615f12024-04-24 05:02:03 +0000715 if (!useMetricInterface)
716 {
717 valueIntf->value(std::numeric_limits<double>::quiet_NaN());
718 }
719 else
720 {
721 metricIntf->value(std::numeric_limits<double>::quiet_NaN());
722 }
Gilbert Cheneac61a42022-02-23 20:56:19 +0000723 }
724 }
725}
726
727void NumericSensor::handleErrGetSensorReading()
728{
Thu Nguyen6d615f12024-04-24 05:02:03 +0000729 if (!operationalStatusIntf || (!useMetricInterface && !valueIntf) ||
730 (useMetricInterface && !metricIntf))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000731 {
732 lg2::error(
733 "Failed to update sensor {NAME} D-Bus interfaces don't exist.",
734 "NAME", sensorName);
735 return;
736 }
737 operationalStatusIntf->functional(false);
Thu Nguyen6d615f12024-04-24 05:02:03 +0000738 if (!useMetricInterface)
739 {
740 valueIntf->value(std::numeric_limits<double>::quiet_NaN());
741 }
742 else
743 {
744 metricIntf->value(std::numeric_limits<double>::quiet_NaN());
745 }
Gilbert Cheneac61a42022-02-23 20:56:19 +0000746}
747
748bool NumericSensor::checkThreshold(bool alarm, bool direction, double value,
749 double threshold, double hyst)
750{
751 if (direction)
752 {
753 if (value >= threshold)
754 {
755 return true;
756 }
757 if (value < (threshold - hyst))
758 {
759 return false;
760 }
761 }
762 else
763 {
764 if (value <= threshold)
765 {
766 return true;
767 }
768 if (value > (threshold + hyst))
769 {
770 return false;
771 }
772 }
773 return alarm;
774}
775
776void NumericSensor::updateThresholds()
777{
Thu Nguyen6d615f12024-04-24 05:02:03 +0000778 double value = std::numeric_limits<double>::quiet_NaN();
779
780 if ((!useMetricInterface && !valueIntf) ||
781 (useMetricInterface && !metricIntf))
Gilbert Cheneac61a42022-02-23 20:56:19 +0000782 {
783 lg2::error(
784 "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.",
785 "NAME", sensorName);
786 return;
787 }
Thu Nguyen6d615f12024-04-24 05:02:03 +0000788 if (!useMetricInterface)
789 {
790 value = valueIntf->value();
791 }
792 else
793 {
794 value = metricIntf->value();
795 }
Gilbert Cheneac61a42022-02-23 20:56:19 +0000796 if (thresholdWarningIntf &&
797 !std::isnan(thresholdWarningIntf->warningHigh()))
798 {
799 auto threshold = thresholdWarningIntf->warningHigh();
800 auto alarm = thresholdWarningIntf->warningAlarmHigh();
801 auto newAlarm =
802 checkThreshold(alarm, true, value, threshold, hysteresis);
803 if (alarm != newAlarm)
804 {
805 thresholdWarningIntf->warningAlarmHigh(newAlarm);
806 if (newAlarm)
807 {
808 thresholdWarningIntf->warningHighAlarmAsserted(value);
809 }
810 else
811 {
812 thresholdWarningIntf->warningHighAlarmDeasserted(value);
813 }
814 }
815 }
816
817 if (thresholdWarningIntf && !std::isnan(thresholdWarningIntf->warningLow()))
818 {
819 auto threshold = thresholdWarningIntf->warningLow();
820 auto alarm = thresholdWarningIntf->warningAlarmLow();
821 auto newAlarm =
822 checkThreshold(alarm, false, value, threshold, hysteresis);
823 if (alarm != newAlarm)
824 {
825 thresholdWarningIntf->warningAlarmLow(newAlarm);
826 if (newAlarm)
827 {
828 thresholdWarningIntf->warningLowAlarmAsserted(value);
829 }
830 else
831 {
832 thresholdWarningIntf->warningLowAlarmDeasserted(value);
833 }
834 }
835 }
836
837 if (thresholdCriticalIntf &&
838 !std::isnan(thresholdCriticalIntf->criticalHigh()))
839 {
840 auto threshold = thresholdCriticalIntf->criticalHigh();
841 auto alarm = thresholdCriticalIntf->criticalAlarmHigh();
842 auto newAlarm =
843 checkThreshold(alarm, true, value, threshold, hysteresis);
844 if (alarm != newAlarm)
845 {
846 thresholdCriticalIntf->criticalAlarmHigh(newAlarm);
847 if (newAlarm)
848 {
849 thresholdCriticalIntf->criticalHighAlarmAsserted(value);
850 }
851 else
852 {
853 thresholdCriticalIntf->criticalHighAlarmDeasserted(value);
854 }
855 }
856 }
857
858 if (thresholdCriticalIntf &&
859 !std::isnan(thresholdCriticalIntf->criticalLow()))
860 {
861 auto threshold = thresholdCriticalIntf->criticalLow();
862 auto alarm = thresholdCriticalIntf->criticalAlarmLow();
863 auto newAlarm =
864 checkThreshold(alarm, false, value, threshold, hysteresis);
865 if (alarm != newAlarm)
866 {
867 thresholdCriticalIntf->criticalAlarmLow(newAlarm);
868 if (newAlarm)
869 {
870 thresholdCriticalIntf->criticalLowAlarmAsserted(value);
871 }
872 else
873 {
874 thresholdCriticalIntf->criticalLowAlarmDeasserted(value);
875 }
876 }
877 }
878}
Gilbert Chen77e6fe72024-08-06 09:23:30 +0000879
880int NumericSensor::triggerThresholdEvent(
881 pldm::utils::Level eventType, pldm::utils::Direction direction,
882 double rawValue, bool newAlarm, bool assert)
883{
884 if (!valueIntf)
885 {
886 lg2::error(
887 "Failed to update thresholds sensor {NAME} D-Bus interfaces don't exist.",
888 "NAME", sensorName);
889 return PLDM_ERROR;
890 }
891
892 auto value = unitModifier(conversionFormula(rawValue));
893 lg2::error(
894 "triggerThresholdEvent eventType {TID}, direction {SID} value {VAL} newAlarm {PSTATE} assert {ESTATE}",
895 "TID", eventType, "SID", direction, "VAL", value, "PSTATE", newAlarm,
896 "ESTATE", assert);
897
898 switch (eventType)
899 {
900 case pldm::utils::Level::WARNING:
901 {
902 if (!thresholdWarningIntf)
903 {
904 lg2::error(
905 "Error:Trigger sensor warning event for non warning threshold sensors {NAME}",
906 "NAME", sensorName);
907 return PLDM_ERROR;
908 }
909 if (direction == pldm::utils::Direction::HIGH &&
910 !std::isnan(thresholdWarningIntf->warningHigh()))
911 {
912 auto alarm = thresholdWarningIntf->warningAlarmHigh();
913 if (alarm == newAlarm)
914 {
915 return PLDM_SUCCESS;
916 }
917 thresholdWarningIntf->warningAlarmHigh(newAlarm);
918 if (assert)
919 {
920 thresholdWarningIntf->warningHighAlarmAsserted(value);
921 }
922 else
923 {
924 thresholdWarningIntf->warningHighAlarmDeasserted(value);
925 }
926 }
927 else if (direction == pldm::utils::Direction::LOW &&
928 !std::isnan(thresholdWarningIntf->warningLow()))
929 {
930 auto alarm = thresholdWarningIntf->warningAlarmLow();
931 if (alarm == newAlarm)
932 {
933 return PLDM_SUCCESS;
934 }
935 thresholdWarningIntf->warningAlarmLow(newAlarm);
936 if (assert)
937 {
938 thresholdWarningIntf->warningLowAlarmAsserted(value);
939 }
940 else
941 {
942 thresholdWarningIntf->warningLowAlarmDeasserted(value);
943 }
944 }
945 break;
946 }
947 case pldm::utils::Level::CRITICAL:
948 {
949 if (!thresholdCriticalIntf)
950 {
951 lg2::error(
952 "Error:Trigger sensor Critical event for non warning threshold sensors {NAME}",
953 "NAME", sensorName);
954 return PLDM_ERROR;
955 }
956 if (direction == pldm::utils::Direction::HIGH &&
957 !std::isnan(thresholdCriticalIntf->criticalHigh()))
958 {
959 auto alarm = thresholdCriticalIntf->criticalAlarmHigh();
960 if (alarm == newAlarm)
961 {
962 return PLDM_SUCCESS;
963 }
964 thresholdCriticalIntf->criticalAlarmHigh(newAlarm);
965 if (assert)
966 {
967 thresholdCriticalIntf->criticalHighAlarmAsserted(value);
968 }
969 else
970 {
971 thresholdCriticalIntf->criticalHighAlarmDeasserted(value);
972 }
973 }
974 else if (direction == pldm::utils::Direction::LOW &&
975 !std::isnan(thresholdCriticalIntf->criticalLow()))
976 {
977 auto alarm = thresholdCriticalIntf->criticalAlarmLow();
978 if (alarm == newAlarm)
979 {
980 return PLDM_SUCCESS;
981 }
982 thresholdCriticalIntf->criticalAlarmLow(newAlarm);
983 if (assert)
984 {
985 thresholdCriticalIntf->criticalLowAlarmAsserted(value);
986 }
987 else
988 {
989 thresholdCriticalIntf->criticalLowAlarmDeasserted(value);
990 }
991 }
992 break;
993 }
994
995 default:
996 break;
997 }
998
999 return PLDM_SUCCESS;
1000}
Thu Nguyen3c5486d2024-08-01 08:03:08 +00001001} // namespace platform_mc
1002} // namespace pldm