xref: /openbmc/dbus-sensors/src/Thresholds.hpp (revision 18b6186e531ae37dd22b634c6530f793528473f4)
1 #pragma once
2 
3 #include "Utils.hpp"
4 
5 #include <boost/asio/io_context.hpp>
6 #include <boost/asio/steady_timer.hpp>
7 #include <sdbusplus/asio/connection.hpp>
8 
9 #include <array>
10 #include <cstddef>
11 #include <cstdint>
12 #include <limits>
13 #include <list>
14 #include <memory>
15 #include <string>
16 #include <utility>
17 #include <vector>
18 
19 struct Sensor;
20 namespace thresholds
21 {
22 enum class Level
23 {
24     WARNING,
25     CRITICAL,
26     PERFORMANCELOSS,
27     SOFTSHUTDOWN,
28     HARDSHUTDOWN,
29     ERROR
30 };
31 enum class Direction
32 {
33     HIGH,
34     LOW,
35     ERROR
36 };
37 struct Threshold
38 {
Thresholdthresholds::Threshold39     Threshold(
40         const Level& lev, const Direction& dir, const double& val,
41         const double hysteresis = std::numeric_limits<double>::quiet_NaN(),
42         bool write = true) :
43         level(lev), direction(dir), value(val), hysteresis(hysteresis),
44         writeable(write)
45     {}
46     Level level;
47     Direction direction;
48     double value;
49     double hysteresis;
50     bool writeable;
51 
operator ==thresholds::Threshold52     bool operator==(const Threshold& rhs) const
53     {
54         return (level == rhs.level && direction == rhs.direction &&
55                 value == rhs.value);
56     }
57 };
58 
59 void assertThresholds(Sensor* sensor, double assertValue,
60                       thresholds::Level level, thresholds::Direction direction,
61                       bool assert);
62 
63 struct TimerUsed
64 {
65     bool used;
66     Level level;
67     Direction direction;
68     bool assert;
69 };
70 
71 using TimerPair = std::pair<struct TimerUsed, boost::asio::steady_timer>;
72 
73 struct ThresholdTimer
74 {
ThresholdTimerthresholds::ThresholdTimer75     explicit ThresholdTimer(boost::asio::io_context& ioService) : io(ioService)
76     {}
77 
hasActiveTimerthresholds::ThresholdTimer78     bool hasActiveTimer(const Threshold& threshold, bool assert)
79     {
80         for (TimerPair& timer : timers)
81         {
82             if (timer.first.used)
83             {
84                 if ((timer.first.level == threshold.level) &&
85                     (timer.first.direction == threshold.direction) &&
86                     (timer.first.assert == assert))
87                 {
88                     return true;
89                 }
90             }
91         }
92         return false;
93     }
94 
stopTimerthresholds::ThresholdTimer95     void stopTimer(const Threshold& threshold, bool assert)
96     {
97         struct TimerUsed timerUsed = {};
98         for (TimerPair& timer : timers)
99         {
100             timerUsed = timer.first;
101             if (timerUsed.used)
102             {
103                 if ((timerUsed.level == threshold.level) &&
104                     (timerUsed.direction == threshold.direction) &&
105                     (timerUsed.assert == assert))
106                 {
107                     timer.second.cancel();
108                 }
109             }
110         }
111     }
112 
113     void startTimer(const std::weak_ptr<Sensor>& weakSensor,
114                     const Threshold& threshold, bool assert,
115                     double assertValue);
116 
117     boost::asio::io_context& io;
118     std::list<TimerPair> timers;
119 };
120 
121 bool parseThresholdsFromConfig(
122     const SensorData& sensorData,
123     std::vector<thresholds::Threshold>& thresholdVector,
124     const std::string* matchLabel = nullptr, const int* sensorIndex = nullptr);
125 
126 // Sensors touched by parseThresholdFromAttr() are forcibly updated with given
127 // parameters, so callers are encouraged to specify a sane hysteresis value for
128 // their HW. For reference, the hysteresis fomula used in Sensor.hpp is:
129 //  hysteresis.trigger = (max_val - min_val) * 0.01
130 bool parseThresholdsFromAttr(
131     std::vector<thresholds::Threshold>& thresholdVector,
132     const std::string& inputPath, const double& scaleFactor,
133     const double& offset = 0,
134     const double& hysteresis = std::numeric_limits<double>::quiet_NaN());
135 
136 struct ThresholdDefinition
137 {
138     Level level;
139     uint8_t sevOrder;
140     const char* levelName;
141 };
142 
143 constexpr static std::array<thresholds::ThresholdDefinition, 5> thresProp = {
144     {{Level::WARNING, 0, "Warning"},
145      {Level::CRITICAL, 1, "Critical"},
146      {Level::PERFORMANCELOSS, 2, "PerformanceLoss"},
147      {Level::SOFTSHUTDOWN, 3, "SoftShutdown"},
148      {Level::HARDSHUTDOWN, 4, "HardShutdown"}}};
149 
150 std::string getInterface(Level level);
151 
152 void persistThreshold(const std::string& path, const std::string& baseInterface,
153                       const thresholds::Threshold& threshold,
154                       std::shared_ptr<sdbusplus::asio::connection>& conn,
155                       size_t thresholdCount, const std::string& label);
156 
157 void updateThresholds(Sensor* sensor);
158 // returns false if a critical threshold has been crossed, true otherwise
159 bool checkThresholds(Sensor* sensor);
160 void checkThresholdsPowerDelay(const std::weak_ptr<Sensor>& weakSensor,
161                                ThresholdTimer& thresholdTimer);
162 
163 } // namespace thresholds
164