xref: /openbmc/pldm/platform-mc/numeric_sensor.hpp (revision cfc27c25a9748d22513fe85d42a1ee96ba44d2ac)
1 #pragma once
2 
3 #include "common/types.hpp"
4 #include "common/utils.hpp"
5 
6 #include <libpldm/platform.h>
7 #include <libpldm/pldm.h>
8 
9 #include <sdbusplus/server/object.hpp>
10 #include <xyz/openbmc_project/Association/Definitions/server.hpp>
11 #include <xyz/openbmc_project/Inventory/Source/PLDM/Entity/server.hpp>
12 #include <xyz/openbmc_project/Metric/Value/server.hpp>
13 #include <xyz/openbmc_project/Sensor/Threshold/Critical/server.hpp>
14 #include <xyz/openbmc_project/Sensor/Threshold/HardShutdown/server.hpp>
15 #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 
22 namespace pldm
23 {
24 namespace platform_mc
25 {
26 
27 using SensorUnit = sdbusplus::xyz::openbmc_project::Sensor::server::Value::Unit;
28 using ValueIntf = sdbusplus::server::object_t<
29     sdbusplus::xyz::openbmc_project::Sensor::server::Value>;
30 using MetricUnit = sdbusplus::xyz::openbmc_project::Metric::server::Value::Unit;
31 using MetricIntf = sdbusplus::server::object_t<
32     sdbusplus::xyz::openbmc_project::Metric::server::Value>;
33 using ThresholdWarningIntf = sdbusplus::server::object_t<
34     sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::Warning>;
35 using ThresholdCriticalIntf = sdbusplus::server::object_t<
36     sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::Critical>;
37 using ThresholdHardShutdownIntf = sdbusplus::server::object_t<
38     sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::HardShutdown>;
39 using OperationalStatusIntf =
40     sdbusplus::server::object_t<sdbusplus::xyz::openbmc_project::State::
41                                     Decorator::server::OperationalStatus>;
42 using AvailabilityIntf = sdbusplus::server::object_t<
43     sdbusplus::xyz::openbmc_project::State::Decorator::server::Availability>;
44 using AssociationDefinitionsInft = sdbusplus::server::object_t<
45     sdbusplus::xyz::openbmc_project::Association::server::Definitions>;
46 using EntityIntf = sdbusplus::server::object_t<
47     sdbusplus::xyz::openbmc_project::Inventory::Source::PLDM::server::Entity>;
48 
49 /**
50  * @brief NumericSensor
51  *
52  * This class handles sensor reading updated by sensor manager and export
53  * status to D-Bus interface.
54  */
55 class 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 
~NumericSensor()66     ~NumericSensor() {};
67 
68     /** @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 
77     /** @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 
92     /** @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      */
setInventoryPath(const std::string & inventoryPath)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      */
getThresholdUpperCritical()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      */
getThresholdLowerCritical()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      */
getThresholdUpperWarning()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      */
getThresholdLowerWarning()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 
180     /** @brief Get Upper HardShutdown threshold
181      *
182      *  @return double - Upper HardShutdown threshold
183      */
getThresholdUpperHardShutdown()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      */
getThresholdLowerHardShutdown()200     double getThresholdLowerHardShutdown()
201     {
202         if (thresholdHardShutdownIntf)
203         {
204             return thresholdHardShutdownIntf->hardShutdownLow();
205         }
206         else
207         {
208             return std::numeric_limits<double>::quiet_NaN();
209         }
210     };
211 
212     /** @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      */
getThreshold(pldm::utils::Level level,pldm::utils::Direction direction)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      */
isThresholdValid(pldm::utils::Level level,pldm::utils::Direction direction)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      */
getThresholdAlarm(pldm::utils::Level level,pldm::utils::Direction direction)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 
294     /* @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 
300     /* @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 
350     /** @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 
364     /** @brief Terminus ID which the sensor belongs to */
365     pldm_tid_t tid;
366 
367     /** @brief Sensor ID */
368     uint16_t sensorId;
369 
370     /** @brief  The time stamp since last getSensorReading command in usec */
371     uint64_t timeStamp;
372 
373     /** @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 
382     /** @brief Sensor Unit */
383     SensorUnit sensorUnit;
384 
385   private:
386     /**
387      * @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     /**
412      * @brief Check sensor reading if any threshold has been crossed and update
413      * Threshold interfaces accordingly
414      */
415     void updateThresholds();
416 
417     /**
418      * @brief Update the object units based on the PDR baseUnit
419      */
420     void setSensorUnit(uint8_t baseUnit);
421 
422     /** @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 
437     std::unique_ptr<MetricIntf> metricIntf = nullptr;
438     std::unique_ptr<ValueIntf> valueIntf = nullptr;
439     std::unique_ptr<ThresholdWarningIntf> thresholdWarningIntf = nullptr;
440     std::unique_ptr<ThresholdCriticalIntf> thresholdCriticalIntf = nullptr;
441     std::unique_ptr<ThresholdHardShutdownIntf> thresholdHardShutdownIntf =
442         nullptr;
443     std::unique_ptr<AvailabilityIntf> availabilityIntf = nullptr;
444     std::unique_ptr<OperationalStatusIntf> operationalStatusIntf = nullptr;
445     std::unique_ptr<AssociationDefinitionsInft> associationDefinitionsIntf =
446         nullptr;
447     std::unique_ptr<EntityIntf> entityIntf = nullptr;
448 
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;
461     bool useMetricInterface = false;
462 
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;
468 };
469 } // namespace platform_mc
470 } // namespace pldm
471