xref: /openbmc/pldm/platform-mc/numeric_sensor.hpp (revision 2480c5790a88749a6f3f1c341b4f736035da7ded)
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 constexpr const char* SENSOR_VALUE_INTF = "xyz.openbmc_project.Sensor.Value";
28 constexpr const char* METRIC_VALUE_INTF = "xyz.openbmc_project.Metric.Value";
29 
30 using SensorUnit = sdbusplus::xyz::openbmc_project::Sensor::server::Value::Unit;
31 using ValueIntf = sdbusplus::server::object_t<
32     sdbusplus::xyz::openbmc_project::Sensor::server::Value>;
33 using MetricUnit = sdbusplus::xyz::openbmc_project::Metric::server::Value::Unit;
34 using MetricIntf = sdbusplus::server::object_t<
35     sdbusplus::xyz::openbmc_project::Metric::server::Value>;
36 using ThresholdWarningIntf = sdbusplus::server::object_t<
37     sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::Warning>;
38 using ThresholdCriticalIntf = sdbusplus::server::object_t<
39     sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::Critical>;
40 using ThresholdHardShutdownIntf = sdbusplus::server::object_t<
41     sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::HardShutdown>;
42 using OperationalStatusIntf =
43     sdbusplus::server::object_t<sdbusplus::xyz::openbmc_project::State::
44                                     Decorator::server::OperationalStatus>;
45 using AvailabilityIntf = sdbusplus::server::object_t<
46     sdbusplus::xyz::openbmc_project::State::Decorator::server::Availability>;
47 using AssociationDefinitionsInft = sdbusplus::server::object_t<
48     sdbusplus::xyz::openbmc_project::Association::server::Definitions>;
49 using EntityIntf = sdbusplus::server::object_t<
50     sdbusplus::xyz::openbmc_project::Inventory::Source::PLDM::server::Entity>;
51 
52 /**
53  * @brief NumericSensor
54  *
55  * This class handles sensor reading updated by sensor manager and export
56  * status to D-Bus interface.
57  */
58 class NumericSensor
59 {
60   public:
61     NumericSensor(const pldm_tid_t tid, const bool sensorDisabled,
62                   std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr,
63                   std::string& sensorName, std::string& associationPath);
64 
65     NumericSensor(const pldm_tid_t tid, const bool sensorDisabled,
66                   std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr,
67                   std::string& sensorName, std::string& associationPath);
68 
~NumericSensor()69     ~NumericSensor() {};
70 
71     /** @brief The function called by Sensor Manager to set sensor to
72      * error status.
73      */
74     void handleErrGetSensorReading();
75 
76     /** @brief Updating the sensor status to D-Bus interface
77      */
78     void updateReading(bool available, bool functional, double value = 0);
79 
80     /** @brief ConversionFormula is used to convert raw value to the unit
81      * specified in PDR
82      *
83      *  @param[in] value - raw value
84      *  @return double - converted value
85      */
86     double conversionFormula(double value);
87 
88     /** @brief UnitModifier is used to apply the unit modifier specified in PDR
89      *
90      *  @param[in] value - raw value
91      *  @return double - converted value
92      */
93     double unitModifier(double value);
94 
95     /** @brief Check if value is over threshold.
96      *
97      *  @param[in] alarm - previous alarm state
98      *  @param[in] direction - upper or lower threshold checking
99      *  @param[in] value - raw value
100      *  @param[in] threshold - threshold value
101      *  @param[in] hyst - hysteresis value
102      *  @return bool - new alarm state
103      */
104     bool checkThreshold(bool alarm, bool direction, double value,
105                         double threshold, double hyst);
106 
107     /** @brief Updating the association to D-Bus interface
108      *  @param[in] inventoryPath - inventory path of the entity
109      */
setInventoryPath(const std::string & inventoryPath)110     inline void setInventoryPath(const std::string& inventoryPath)
111     {
112         if (associationDefinitionsIntf)
113         {
114             associationDefinitionsIntf->associations(
115                 {{"chassis", "all_sensors", inventoryPath}});
116         }
117     }
118 
119     /** @brief Get Upper Critical threshold
120      *
121      *  @return double - Upper Critical threshold
122      */
getThresholdUpperCritical()123     double getThresholdUpperCritical()
124     {
125         if (thresholdCriticalIntf)
126         {
127             return thresholdCriticalIntf->criticalHigh();
128         }
129         else
130         {
131             return std::numeric_limits<double>::quiet_NaN();
132         }
133     };
134 
135     /** @brief Get Lower Critical threshold
136      *
137      *  @return double - Lower Critical threshold
138      */
getThresholdLowerCritical()139     double getThresholdLowerCritical()
140     {
141         if (thresholdCriticalIntf)
142         {
143             return thresholdCriticalIntf->criticalLow();
144         }
145         else
146         {
147             return std::numeric_limits<double>::quiet_NaN();
148         }
149     };
150 
151     /** @brief Get Upper Warning threshold
152      *
153      *  @return double - Upper Warning threshold
154      */
getThresholdUpperWarning()155     double getThresholdUpperWarning()
156     {
157         if (thresholdWarningIntf)
158         {
159             return thresholdWarningIntf->warningHigh();
160         }
161         else
162         {
163             return std::numeric_limits<double>::quiet_NaN();
164         }
165     };
166 
167     /** @brief Get Lower Warning threshold
168      *
169      *  @return double - Lower Warning threshold
170      */
getThresholdLowerWarning()171     double getThresholdLowerWarning()
172     {
173         if (thresholdWarningIntf)
174         {
175             return thresholdWarningIntf->warningLow();
176         }
177         else
178         {
179             return std::numeric_limits<double>::quiet_NaN();
180         }
181     };
182 
183     /** @brief Get Upper HardShutdown threshold
184      *
185      *  @return double - Upper HardShutdown threshold
186      */
getThresholdUpperHardShutdown()187     double getThresholdUpperHardShutdown()
188     {
189         if (thresholdHardShutdownIntf)
190         {
191             return thresholdHardShutdownIntf->hardShutdownHigh();
192         }
193         else
194         {
195             return std::numeric_limits<double>::quiet_NaN();
196         }
197     };
198 
199     /** @brief Get Lower HardShutdown threshold
200      *
201      *  @return double - Lower HardShutdown threshold
202      */
getThresholdLowerHardShutdown()203     double getThresholdLowerHardShutdown()
204     {
205         if (thresholdHardShutdownIntf)
206         {
207             return thresholdHardShutdownIntf->hardShutdownLow();
208         }
209         else
210         {
211             return std::numeric_limits<double>::quiet_NaN();
212         }
213     };
214 
215     /** @brief Get threshold given level and direction
216      *
217      * @param[in] level - The threshold level (WARNING/CRITICAL/etc)
218      * @param[in] direction - The threshold direction (HIGH/LOW)
219      *
220      * @return double - The requested threshold.
221      */
getThreshold(pldm::utils::Level level,pldm::utils::Direction direction)222     double getThreshold(pldm::utils::Level level,
223                         pldm::utils::Direction direction)
224     {
225         if (direction != pldm::utils::Direction::HIGH &&
226             direction != pldm::utils::Direction::LOW)
227         {
228             return std::numeric_limits<double>::quiet_NaN();
229         }
230         switch (level)
231         {
232             case pldm::utils::Level::WARNING:
233                 return direction == pldm::utils::Direction::HIGH
234                            ? getThresholdUpperWarning()
235                            : getThresholdLowerWarning();
236             case pldm::utils::Level::CRITICAL:
237                 return direction == pldm::utils::Direction::HIGH
238                            ? getThresholdUpperCritical()
239                            : getThresholdLowerCritical();
240             case pldm::utils::Level::HARDSHUTDOWN:
241                 return direction == pldm::utils::Direction::HIGH
242                            ? getThresholdUpperHardShutdown()
243                            : getThresholdLowerHardShutdown();
244             default:
245                 break;
246         }
247         return std::numeric_limits<double>::quiet_NaN();
248     }
249 
250     /* @brief returns true if the given threshold at level/direction is defined.
251      *
252      * @param[in] level - The threshold level (WARNING/CRITICAL/etc)
253      * @param[in] direction - The threshold direction (HIGH/LOW)
254      *
255      * @return true if the threshold is valid
256      */
isThresholdValid(pldm::utils::Level level,pldm::utils::Direction direction)257     bool isThresholdValid(pldm::utils::Level level,
258                           pldm::utils::Direction direction)
259     {
260         return std::isfinite(getThreshold(level, direction));
261     }
262 
263     /* @brief Get the alarm status of the given threshold
264      *
265      * @param[in] level - The threshold level (WARNING/CRITICAL/etc)
266      * @param[in] direction - The threshold direction (HIGH/LOW)
267      *
268      * @return true if the current alarm status is asserted.
269      */
getThresholdAlarm(pldm::utils::Level level,pldm::utils::Direction direction)270     bool getThresholdAlarm(pldm::utils::Level level,
271                            pldm::utils::Direction direction)
272     {
273         if (!isThresholdValid(level, direction))
274         {
275             return false;
276         }
277         switch (level)
278         {
279             case pldm::utils::Level::WARNING:
280                 return direction == pldm::utils::Direction::HIGH
281                            ? thresholdWarningIntf->warningAlarmHigh()
282                            : thresholdWarningIntf->warningAlarmLow();
283             case pldm::utils::Level::CRITICAL:
284                 return direction == pldm::utils::Direction::HIGH
285                            ? thresholdCriticalIntf->criticalAlarmHigh()
286                            : thresholdCriticalIntf->criticalAlarmLow();
287             case pldm::utils::Level::HARDSHUTDOWN:
288                 return direction == pldm::utils::Direction::HIGH
289                            ? thresholdHardShutdownIntf->hardShutdownAlarmHigh()
290                            : thresholdHardShutdownIntf->hardShutdownAlarmLow();
291             default:
292                 break;
293         }
294         return false;
295     }
296 
297     /* @brief raises the alarm on the warning threshold
298      *
299      * @param[in] direction - The threshold direction (HIGH/LOW)
300      * @param[in] value - The current numeric sensor reading
301      * @param[in] asserted - true if we want to set the alarm, false
302      *                       if we want to clear it.
303      *
304      * @return PLDM_SUCCESS or a valid error code.
305      */
306     void setWarningThresholdAlarm(pldm::utils::Direction direction,
307                                   double value, bool asserted);
308 
309     /* @brief raises the alarm on the critical threshold
310      *
311      * @param[in] direction - The threshold direction (HIGH/LOW)
312      * @param[in] value - The current numeric sensor reading
313      * @param[in] asserted - true if we want to set the alarm, false
314      *                       if we want to clear it.
315      *
316      * @return PLDM_SUCCESS or a valid error code.
317      */
318     void setCriticalThresholdAlarm(pldm::utils::Direction direction,
319                                    double value, bool asserted);
320 
321     /* @brief raises the alarm on the hard-shutdown threshold
322      *
323      * @param[in] direction - The threshold direction (HIGH/LOW)
324      * @param[in] value - The current numeric sensor reading
325      * @param[in] asserted - true if we want to set the alarm, false
326      *                       if we want to clear it.
327      *
328      * @return PLDM_SUCCESS or a valid error code.
329      */
330     void setHardShutdownThresholdAlarm(pldm::utils::Direction direction,
331                                        double value, bool asserted);
332 
333     /* @brief raises the alarm on the threshold
334      *
335      * @param[in] level - The threshold level (WARNING/CRITICAL/etc)
336      * @param[in] direction - The threshold direction (HIGH/LOW)
337      * @param[in] value - The current numeric sensor reading
338      * @param[in] asserted - true if we want to set the alarm, false
339      *                       if we want to clear it.
340      *
341      * @return PLDM_SUCCESS or a valid error code.
342      */
343     int setThresholdAlarm(pldm::utils::Level level,
344                           pldm::utils::Direction direction, double value,
345                           bool asserted);
346 
347     /** @brief Check if value is over threshold.
348      *
349      *  @param[in] eventType - event level in pldm::utils::Level
350      *  @param[in] direction - direction type in pldm::utils::Direction
351      *  @param[in] rawValue - sensor raw value
352      *  @param[in] newAlarm - trigger alarm true/false
353      *  @param[in] assert - event type asserted/deasserted
354      *
355      *  @return PLDM completion code
356      */
357     int triggerThresholdEvent(pldm::utils::Level eventType,
358                               pldm::utils::Direction direction, double rawValue,
359                               bool newAlarm, bool assert);
360 
361     /** @brief Terminus ID which the sensor belongs to */
362     pldm_tid_t tid;
363 
364     /** @brief Sensor ID */
365     uint16_t sensorId;
366 
367     /** @brief  The time stamp since last getSensorReading command in usec */
368     uint64_t timeStamp;
369 
370     /** @brief  The time of sensor update interval in usec */
371     uint64_t updateTime;
372 
373     /** @brief  sensorName */
374     std::string sensorName;
375 
376     /** @brief  sensorNameSpace */
377     std::string sensorNameSpace;
378 
379     /** @brief Sensor Unit */
380     SensorUnit sensorUnit;
381 
382   private:
383     /**
384      * @brief Check sensor reading if any threshold has been crossed and update
385      * Threshold interfaces accordingly
386      */
387     void updateThresholds();
388 
389     /**
390      * @brief Update the object units based on the PDR baseUnit
391      */
392     void setSensorUnit(uint8_t baseUnit);
393 
394     /** @brief Create the sensor inventory path.
395      *
396      *  @param[in] associationPath - sensor association path
397      *  @param[in] sensorName - sensor name
398      *  @param[in] entityType - sensor PDR entity type
399      *  @param[in] entityInstanceNum - sensor PDR entity instance number
400      *  @param[in] containerId - sensor PDR entity container ID
401      *
402      *  @return True when success otherwise return False
403      */
404     inline bool createInventoryPath(
405         const std::string& associationPath, const std::string& sensorName,
406         const uint16_t entityType, const uint16_t entityInstanceNum,
407         const uint16_t containerId);
408 
409     std::unique_ptr<MetricIntf> metricIntf = nullptr;
410     std::unique_ptr<ValueIntf> valueIntf = nullptr;
411     std::unique_ptr<ThresholdWarningIntf> thresholdWarningIntf = nullptr;
412     std::unique_ptr<ThresholdCriticalIntf> thresholdCriticalIntf = nullptr;
413     std::unique_ptr<ThresholdHardShutdownIntf> thresholdHardShutdownIntf =
414         nullptr;
415     std::unique_ptr<AvailabilityIntf> availabilityIntf = nullptr;
416     std::unique_ptr<OperationalStatusIntf> operationalStatusIntf = nullptr;
417     std::unique_ptr<AssociationDefinitionsInft> associationDefinitionsIntf =
418         nullptr;
419     std::unique_ptr<EntityIntf> entityIntf = nullptr;
420 
421     /** @brief Amount of hysteresis associated with the sensor thresholds */
422     double hysteresis;
423 
424     /** @brief The resolution of sensor in Units */
425     double resolution;
426 
427     /** @brief A constant value that is added in as part of conversion process
428      * of converting a raw sensor reading to Units */
429     double offset;
430 
431     /** @brief A power-of-10 multiplier for baseUnit */
432     int8_t baseUnitModifier;
433     bool useMetricInterface = false;
434 };
435 } // namespace platform_mc
436 } // namespace pldm
437