blob: 1ecceb1e1de7a3be854526e6c23fe4d70a84a89c [file] [log] [blame]
Thu Nguyen3c5486d2024-08-01 08:03:08 +00001#pragma once
2
Thu Nguyen3c5486d2024-08-01 08:03:08 +00003#include "common/types.hpp"
Gilbert Chen77e6fe72024-08-06 09:23:30 +00004#include "common/utils.hpp"
Thu Nguyen3c5486d2024-08-01 08:03:08 +00005
Manojkiran Edafe252792025-03-13 19:24:19 +05306#include <libpldm/platform.h>
7#include <libpldm/pldm.h>
8
Thu Nguyen3c5486d2024-08-01 08:03:08 +00009#include <sdbusplus/server/object.hpp>
10#include <xyz/openbmc_project/Association/Definitions/server.hpp>
Chau Lyd197f092023-11-06 07:29:06 +000011#include <xyz/openbmc_project/Inventory/Source/PLDM/Entity/server.hpp>
Thu Nguyen6d615f12024-04-24 05:02:03 +000012#include <xyz/openbmc_project/Metric/Value/server.hpp>
Thu Nguyen3c5486d2024-08-01 08:03:08 +000013#include <xyz/openbmc_project/Sensor/Threshold/Critical/server.hpp>
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +080014#include <xyz/openbmc_project/Sensor/Threshold/HardShutdown/server.hpp>
Thu Nguyen3c5486d2024-08-01 08:03:08 +000015#include <xyz/openbmc_project/Sensor/Threshold/Warning/server.hpp>
16#include <xyz/openbmc_project/Sensor/Value/server.hpp>
17#include <xyz/openbmc_project/State/Decorator/Availability/server.hpp>
18#include <xyz/openbmc_project/State/Decorator/OperationalStatus/server.hpp>
19
20#include <string>
21
22namespace pldm
23{
24namespace platform_mc
25{
26
27using SensorUnit = sdbusplus::xyz::openbmc_project::Sensor::server::Value::Unit;
28using ValueIntf = sdbusplus::server::object_t<
29 sdbusplus::xyz::openbmc_project::Sensor::server::Value>;
Thu Nguyen6d615f12024-04-24 05:02:03 +000030using MetricUnit = sdbusplus::xyz::openbmc_project::Metric::server::Value::Unit;
31using MetricIntf = sdbusplus::server::object_t<
32 sdbusplus::xyz::openbmc_project::Metric::server::Value>;
Thu Nguyen3c5486d2024-08-01 08:03:08 +000033using ThresholdWarningIntf = sdbusplus::server::object_t<
34 sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::Warning>;
35using ThresholdCriticalIntf = sdbusplus::server::object_t<
36 sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::Critical>;
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +080037using ThresholdHardShutdownIntf = sdbusplus::server::object_t<
38 sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::HardShutdown>;
Thu Nguyen3c5486d2024-08-01 08:03:08 +000039using OperationalStatusIntf =
40 sdbusplus::server::object_t<sdbusplus::xyz::openbmc_project::State::
41 Decorator::server::OperationalStatus>;
42using AvailabilityIntf = sdbusplus::server::object_t<
43 sdbusplus::xyz::openbmc_project::State::Decorator::server::Availability>;
44using AssociationDefinitionsInft = sdbusplus::server::object_t<
45 sdbusplus::xyz::openbmc_project::Association::server::Definitions>;
Chau Lyd197f092023-11-06 07:29:06 +000046using EntityIntf = sdbusplus::server::object_t<
47 sdbusplus::xyz::openbmc_project::Inventory::Source::PLDM::server::Entity>;
Thu Nguyen3c5486d2024-08-01 08:03:08 +000048
49/**
50 * @brief NumericSensor
51 *
52 * This class handles sensor reading updated by sensor manager and export
53 * status to D-Bus interface.
54 */
55class NumericSensor
56{
57 public:
58 NumericSensor(const pldm_tid_t tid, const bool sensorDisabled,
59 std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr,
60 std::string& sensorName, std::string& associationPath);
61
62 NumericSensor(const pldm_tid_t tid, const bool sensorDisabled,
63 std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr,
64 std::string& sensorName, std::string& associationPath);
65
Patrick Williams16c2a0a2024-08-16 15:20:59 -040066 ~NumericSensor() {};
Thu Nguyen3c5486d2024-08-01 08:03:08 +000067
Gilbert Cheneac61a42022-02-23 20:56:19 +000068 /** @brief The function called by Sensor Manager to set sensor to
69 * error status.
70 */
71 void handleErrGetSensorReading();
72
73 /** @brief Updating the sensor status to D-Bus interface
74 */
75 void updateReading(bool available, bool functional, double value = 0);
76
Thu Nguyen3c5486d2024-08-01 08:03:08 +000077 /** @brief ConversionFormula is used to convert raw value to the unit
78 * specified in PDR
79 *
80 * @param[in] value - raw value
81 * @return double - converted value
82 */
83 double conversionFormula(double value);
84
85 /** @brief UnitModifier is used to apply the unit modifier specified in PDR
86 *
87 * @param[in] value - raw value
88 * @return double - converted value
89 */
90 double unitModifier(double value);
91
Gilbert Cheneac61a42022-02-23 20:56:19 +000092 /** @brief Check if value is over threshold.
93 *
94 * @param[in] alarm - previous alarm state
95 * @param[in] direction - upper or lower threshold checking
96 * @param[in] value - raw value
97 * @param[in] threshold - threshold value
98 * @param[in] hyst - hysteresis value
99 * @return bool - new alarm state
100 */
101 bool checkThreshold(bool alarm, bool direction, double value,
102 double threshold, double hyst);
103
104 /** @brief Updating the association to D-Bus interface
105 * @param[in] inventoryPath - inventory path of the entity
106 */
107 inline void setInventoryPath(const std::string& inventoryPath)
108 {
109 if (associationDefinitionsIntf)
110 {
111 associationDefinitionsIntf->associations(
112 {{"chassis", "all_sensors", inventoryPath}});
113 }
114 }
115
116 /** @brief Get Upper Critical threshold
117 *
118 * @return double - Upper Critical threshold
119 */
120 double getThresholdUpperCritical()
121 {
122 if (thresholdCriticalIntf)
123 {
124 return thresholdCriticalIntf->criticalHigh();
125 }
126 else
127 {
128 return std::numeric_limits<double>::quiet_NaN();
129 }
130 };
131
132 /** @brief Get Lower Critical threshold
133 *
134 * @return double - Lower Critical threshold
135 */
136 double getThresholdLowerCritical()
137 {
138 if (thresholdCriticalIntf)
139 {
140 return thresholdCriticalIntf->criticalLow();
141 }
142 else
143 {
144 return std::numeric_limits<double>::quiet_NaN();
145 }
146 };
147
148 /** @brief Get Upper Warning threshold
149 *
150 * @return double - Upper Warning threshold
151 */
152 double getThresholdUpperWarning()
153 {
154 if (thresholdWarningIntf)
155 {
156 return thresholdWarningIntf->warningHigh();
157 }
158 else
159 {
160 return std::numeric_limits<double>::quiet_NaN();
161 }
162 };
163
164 /** @brief Get Lower Warning threshold
165 *
166 * @return double - Lower Warning threshold
167 */
168 double getThresholdLowerWarning()
169 {
170 if (thresholdWarningIntf)
171 {
172 return thresholdWarningIntf->warningLow();
173 }
174 else
175 {
176 return std::numeric_limits<double>::quiet_NaN();
177 }
178 };
179
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800180 /** @brief Get Upper HardShutdown threshold
181 *
182 * @return double - Upper HardShutdown threshold
183 */
184 double getThresholdUpperHardShutdown()
185 {
186 if (thresholdHardShutdownIntf)
187 {
188 return thresholdHardShutdownIntf->hardShutdownHigh();
189 }
190 else
191 {
192 return std::numeric_limits<double>::quiet_NaN();
193 }
194 };
195
196 /** @brief Get Lower HardShutdown threshold
197 *
198 * @return double - Lower HardShutdown threshold
199 */
Amithash Prasad2480c572025-05-01 15:34:34 -0700200 double getThresholdLowerHardShutdown()
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800201 {
202 if (thresholdHardShutdownIntf)
203 {
204 return thresholdHardShutdownIntf->hardShutdownLow();
205 }
206 else
207 {
208 return std::numeric_limits<double>::quiet_NaN();
209 }
210 };
211
Amithash Prasad2480c572025-05-01 15:34:34 -0700212 /** @brief Get threshold given level and direction
213 *
214 * @param[in] level - The threshold level (WARNING/CRITICAL/etc)
215 * @param[in] direction - The threshold direction (HIGH/LOW)
216 *
217 * @return double - The requested threshold.
218 */
219 double getThreshold(pldm::utils::Level level,
220 pldm::utils::Direction direction)
221 {
222 if (direction != pldm::utils::Direction::HIGH &&
223 direction != pldm::utils::Direction::LOW)
224 {
225 return std::numeric_limits<double>::quiet_NaN();
226 }
227 switch (level)
228 {
229 case pldm::utils::Level::WARNING:
230 return direction == pldm::utils::Direction::HIGH
231 ? getThresholdUpperWarning()
232 : getThresholdLowerWarning();
233 case pldm::utils::Level::CRITICAL:
234 return direction == pldm::utils::Direction::HIGH
235 ? getThresholdUpperCritical()
236 : getThresholdLowerCritical();
237 case pldm::utils::Level::HARDSHUTDOWN:
238 return direction == pldm::utils::Direction::HIGH
239 ? getThresholdUpperHardShutdown()
240 : getThresholdLowerHardShutdown();
241 default:
242 break;
243 }
244 return std::numeric_limits<double>::quiet_NaN();
245 }
246
247 /* @brief returns true if the given threshold at level/direction is defined.
248 *
249 * @param[in] level - The threshold level (WARNING/CRITICAL/etc)
250 * @param[in] direction - The threshold direction (HIGH/LOW)
251 *
252 * @return true if the threshold is valid
253 */
254 bool isThresholdValid(pldm::utils::Level level,
255 pldm::utils::Direction direction)
256 {
257 return std::isfinite(getThreshold(level, direction));
258 }
259
260 /* @brief Get the alarm status of the given threshold
261 *
262 * @param[in] level - The threshold level (WARNING/CRITICAL/etc)
263 * @param[in] direction - The threshold direction (HIGH/LOW)
264 *
265 * @return true if the current alarm status is asserted.
266 */
267 bool getThresholdAlarm(pldm::utils::Level level,
268 pldm::utils::Direction direction)
269 {
270 if (!isThresholdValid(level, direction))
271 {
272 return false;
273 }
274 switch (level)
275 {
276 case pldm::utils::Level::WARNING:
277 return direction == pldm::utils::Direction::HIGH
278 ? thresholdWarningIntf->warningAlarmHigh()
279 : thresholdWarningIntf->warningAlarmLow();
280 case pldm::utils::Level::CRITICAL:
281 return direction == pldm::utils::Direction::HIGH
282 ? thresholdCriticalIntf->criticalAlarmHigh()
283 : thresholdCriticalIntf->criticalAlarmLow();
284 case pldm::utils::Level::HARDSHUTDOWN:
285 return direction == pldm::utils::Direction::HIGH
286 ? thresholdHardShutdownIntf->hardShutdownAlarmHigh()
287 : thresholdHardShutdownIntf->hardShutdownAlarmLow();
288 default:
289 break;
290 }
291 return false;
292 }
293
Amithash Prasad79931b62025-05-01 15:34:59 -0700294 /* @brief Returns true if at least one threshold alarm is set
295 *
296 * @return true if at least one threshold alarm is set
297 */
298 bool hasThresholdAlarm();
299
Amithash Prasad2480c572025-05-01 15:34:34 -0700300 /* @brief raises the alarm on the warning threshold
301 *
302 * @param[in] direction - The threshold direction (HIGH/LOW)
303 * @param[in] value - The current numeric sensor reading
304 * @param[in] asserted - true if we want to set the alarm, false
305 * if we want to clear it.
306 *
307 * @return PLDM_SUCCESS or a valid error code.
308 */
309 void setWarningThresholdAlarm(pldm::utils::Direction direction,
310 double value, bool asserted);
311
312 /* @brief raises the alarm on the critical threshold
313 *
314 * @param[in] direction - The threshold direction (HIGH/LOW)
315 * @param[in] value - The current numeric sensor reading
316 * @param[in] asserted - true if we want to set the alarm, false
317 * if we want to clear it.
318 *
319 * @return PLDM_SUCCESS or a valid error code.
320 */
321 void setCriticalThresholdAlarm(pldm::utils::Direction direction,
322 double value, bool asserted);
323
324 /* @brief raises the alarm on the hard-shutdown threshold
325 *
326 * @param[in] direction - The threshold direction (HIGH/LOW)
327 * @param[in] value - The current numeric sensor reading
328 * @param[in] asserted - true if we want to set the alarm, false
329 * if we want to clear it.
330 *
331 * @return PLDM_SUCCESS or a valid error code.
332 */
333 void setHardShutdownThresholdAlarm(pldm::utils::Direction direction,
334 double value, bool asserted);
335
336 /* @brief raises the alarm on the threshold
337 *
338 * @param[in] level - The threshold level (WARNING/CRITICAL/etc)
339 * @param[in] direction - The threshold direction (HIGH/LOW)
340 * @param[in] value - The current numeric sensor reading
341 * @param[in] asserted - true if we want to set the alarm, false
342 * if we want to clear it.
343 *
344 * @return PLDM_SUCCESS or a valid error code.
345 */
346 int setThresholdAlarm(pldm::utils::Level level,
347 pldm::utils::Direction direction, double value,
348 bool asserted);
349
Gilbert Chen77e6fe72024-08-06 09:23:30 +0000350 /** @brief Check if value is over threshold.
351 *
352 * @param[in] eventType - event level in pldm::utils::Level
353 * @param[in] direction - direction type in pldm::utils::Direction
354 * @param[in] rawValue - sensor raw value
355 * @param[in] newAlarm - trigger alarm true/false
356 * @param[in] assert - event type asserted/deasserted
357 *
358 * @return PLDM completion code
359 */
360 int triggerThresholdEvent(pldm::utils::Level eventType,
361 pldm::utils::Direction direction, double rawValue,
362 bool newAlarm, bool assert);
363
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000364 /** @brief Terminus ID which the sensor belongs to */
365 pldm_tid_t tid;
366
367 /** @brief Sensor ID */
368 uint16_t sensorId;
369
Gilbert Cheneac61a42022-02-23 20:56:19 +0000370 /** @brief The time stamp since last getSensorReading command in usec */
371 uint64_t timeStamp;
372
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000373 /** @brief The time of sensor update interval in usec */
374 uint64_t updateTime;
375
376 /** @brief sensorName */
377 std::string sensorName;
378
379 /** @brief sensorNameSpace */
380 std::string sensorNameSpace;
381
Amithash Prasad98256602024-12-19 14:02:30 -0800382 /** @brief Sensor Unit */
383 SensorUnit sensorUnit;
384
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000385 private:
Gilbert Cheneac61a42022-02-23 20:56:19 +0000386 /**
Amithash Prasad79931b62025-05-01 15:34:59 -0700387 * @brief resolve and clear a log entry
388 *
389 * @param[inout] log - dbus path to log entry. The log will be resolve
390 * and the optional reset.
391 */
392 void clearThresholdLog(std::optional<sdbusplus::message::object_path>& log);
393
394 /** @brief create a log entry that all sensor alarms have cleared and is now
395 * operating in the normal operating range.
396 *
397 * @param[in] value - The current sensor value in normal range.
398 */
399 void createNormalRangeLog(double value);
400
401 /**
402 * @brief Create a threshold log for the given level/direction tuple.
403 *
404 * @param[in] level - The level of the threshold.
405 * @param[in] direction - The direction of the threshold.
406 * @param[in] value - The current sensor value.
407 */
408 void createThresholdLog(pldm::utils::Level level,
409 pldm::utils::Direction direction, double value);
410
411 /**
Gilbert Cheneac61a42022-02-23 20:56:19 +0000412 * @brief Check sensor reading if any threshold has been crossed and update
413 * Threshold interfaces accordingly
414 */
415 void updateThresholds();
416
Amithash Prasad98256602024-12-19 14:02:30 -0800417 /**
418 * @brief Update the object units based on the PDR baseUnit
419 */
420 void setSensorUnit(uint8_t baseUnit);
421
Chau Lyd197f092023-11-06 07:29:06 +0000422 /** @brief Create the sensor inventory path.
423 *
424 * @param[in] associationPath - sensor association path
425 * @param[in] sensorName - sensor name
426 * @param[in] entityType - sensor PDR entity type
427 * @param[in] entityInstanceNum - sensor PDR entity instance number
428 * @param[in] containerId - sensor PDR entity container ID
429 *
430 * @return True when success otherwise return False
431 */
432 inline bool createInventoryPath(
433 const std::string& associationPath, const std::string& sensorName,
434 const uint16_t entityType, const uint16_t entityInstanceNum,
435 const uint16_t containerId);
436
Thu Nguyen6d615f12024-04-24 05:02:03 +0000437 std::unique_ptr<MetricIntf> metricIntf = nullptr;
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000438 std::unique_ptr<ValueIntf> valueIntf = nullptr;
439 std::unique_ptr<ThresholdWarningIntf> thresholdWarningIntf = nullptr;
440 std::unique_ptr<ThresholdCriticalIntf> thresholdCriticalIntf = nullptr;
Zoey YJ Chung9a224ae2025-04-11 15:40:42 +0800441 std::unique_ptr<ThresholdHardShutdownIntf> thresholdHardShutdownIntf =
442 nullptr;
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000443 std::unique_ptr<AvailabilityIntf> availabilityIntf = nullptr;
444 std::unique_ptr<OperationalStatusIntf> operationalStatusIntf = nullptr;
445 std::unique_ptr<AssociationDefinitionsInft> associationDefinitionsIntf =
446 nullptr;
Chau Lyd197f092023-11-06 07:29:06 +0000447 std::unique_ptr<EntityIntf> entityIntf = nullptr;
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000448
449 /** @brief Amount of hysteresis associated with the sensor thresholds */
450 double hysteresis;
451
452 /** @brief The resolution of sensor in Units */
453 double resolution;
454
455 /** @brief A constant value that is added in as part of conversion process
456 * of converting a raw sensor reading to Units */
457 double offset;
458
459 /** @brief A power-of-10 multiplier for baseUnit */
460 int8_t baseUnitModifier;
Thu Nguyen6d615f12024-04-24 05:02:03 +0000461 bool useMetricInterface = false;
Amithash Prasad79931b62025-05-01 15:34:59 -0700462
463 /** @brief An internal mapping of thresholds and its associated log
464 * entry. */
465 std::map<std::tuple<pldm::utils::Level, pldm::utils::Direction>,
466 std::optional<sdbusplus::message::object_path>>
467 assertedLog;
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000468};
469} // namespace platform_mc
470} // namespace pldm