blob: 4932bce4d0bf95357bd703406ee66390c8f2929b [file] [log] [blame]
James Feist6714a252018-09-10 15:26:18 -07001#include <Thresholds.hpp>
2#include <VariantVisitors.hpp>
3#include <boost/algorithm/string/replace.hpp>
4#include <boost/lexical_cast.hpp>
James Feistdc6c55f2018-10-31 12:53:20 -07005#include <cmath>
James Feist6714a252018-09-10 15:26:18 -07006#include <fstream>
7#include <iostream>
James Feist251c7822018-09-12 12:54:15 -07008#include <sensor.hpp>
James Feist6714a252018-09-10 15:26:18 -07009
10static constexpr bool DEBUG = false;
James Feist6714a252018-09-10 15:26:18 -070011namespace thresholds
12{
James Feistd8705872019-02-08 13:26:09 -080013unsigned int toBusValue(const Level& level)
James Feist6714a252018-09-10 15:26:18 -070014{
15 switch (level)
16 {
17 case (Level::WARNING):
18 {
19 return 0;
20 }
21 case (Level::CRITICAL):
22 {
23 return 1;
24 }
25 default:
26 {
27 return -1;
28 }
29 }
30}
31
James Feistd8705872019-02-08 13:26:09 -080032std::string toBusValue(const Direction& direction)
James Feist6714a252018-09-10 15:26:18 -070033{
34 switch (direction)
35 {
36 case (Direction::LOW):
37 {
38 return "less than";
39 }
40 case (Direction::HIGH):
41 {
42 return "greater than";
43 }
44 default:
45 {
46 return "err";
47 }
48 }
49}
50
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -070051bool parseThresholdsFromConfig(
James Feistd8705872019-02-08 13:26:09 -080052 const SensorData& sensorData,
53 std::vector<thresholds::Threshold>& thresholdVector,
54 const std::string* matchLabel)
James Feist6714a252018-09-10 15:26:18 -070055{
James Feistd8705872019-02-08 13:26:09 -080056 for (const auto& item : sensorData)
James Feist6714a252018-09-10 15:26:18 -070057 {
58 if (item.first.find("Thresholds") == std::string::npos)
59 {
60 continue;
61 }
62 if (matchLabel != nullptr)
63 {
64 auto labelFind = item.second.find("Label");
65 if (labelFind == item.second.end())
66 continue;
James Feist3eb82622019-02-08 13:10:22 -080067 if (std::visit(VariantToStringVisitor(), labelFind->second) !=
68 *matchLabel)
James Feist6714a252018-09-10 15:26:18 -070069 continue;
70 }
71 auto directionFind = item.second.find("Direction");
72 auto severityFind = item.second.find("Severity");
73 auto valueFind = item.second.find("Value");
74 if (valueFind == item.second.end() ||
75 severityFind == item.second.end() ||
76 directionFind == item.second.end())
77 {
78 std::cerr << "Malformed threshold in configuration\n";
79 return false;
80 }
81 Level level;
82 Direction direction;
James Feist3eb82622019-02-08 13:10:22 -080083 if (std::visit(VariantToUnsignedIntVisitor(), severityFind->second) ==
84 0)
James Feist6714a252018-09-10 15:26:18 -070085 {
86 level = Level::WARNING;
87 }
88 else
89 {
90 level = Level::CRITICAL;
91 }
James Feist3eb82622019-02-08 13:10:22 -080092 if (std::visit(VariantToStringVisitor(), directionFind->second) ==
93 "less than")
James Feist6714a252018-09-10 15:26:18 -070094 {
95 direction = Direction::LOW;
96 }
97 else
98 {
99 direction = Direction::HIGH;
100 }
James Feist3eb82622019-02-08 13:10:22 -0800101 float val = std::visit(VariantToFloatVisitor(), valueFind->second);
James Feist6714a252018-09-10 15:26:18 -0700102
103 thresholdVector.emplace_back(level, direction, val);
104 }
105 return true;
106}
107
James Feistd8705872019-02-08 13:26:09 -0800108void persistThreshold(const std::string& path, const std::string& baseInterface,
109 const thresholds::Threshold& threshold,
James Feista222ba72019-03-01 15:57:51 -0800110 std::shared_ptr<sdbusplus::asio::connection>& conn,
111 size_t thresholdCount)
James Feist6714a252018-09-10 15:26:18 -0700112{
James Feista222ba72019-03-01 15:57:51 -0800113 for (int ii = 0; ii < thresholdCount; ii++)
James Feist6714a252018-09-10 15:26:18 -0700114 {
115 std::string thresholdInterface =
116 baseInterface + ".Thresholds" + std::to_string(ii);
117 conn->async_method_call(
118 [&, path, threshold, thresholdInterface](
James Feistd8705872019-02-08 13:26:09 -0800119 const boost::system::error_code& ec,
120 const boost::container::flat_map<std::string, BasicVariantType>&
121 result) {
James Feist6714a252018-09-10 15:26:18 -0700122 if (ec)
123 {
124 return; // threshold not supported
125 }
126
127 auto directionFind = result.find("Direction");
128 auto severityFind = result.find("Severity");
129 auto valueFind = result.find("Value");
130 if (valueFind == result.end() || severityFind == result.end() ||
131 directionFind == result.end())
132 {
133 std::cerr << "Malformed threshold in configuration\n";
134 return;
135 }
James Feist3eb82622019-02-08 13:10:22 -0800136 unsigned int level = std::visit(VariantToUnsignedIntVisitor(),
137 severityFind->second);
James Feist6714a252018-09-10 15:26:18 -0700138
James Feist3eb82622019-02-08 13:10:22 -0800139 std::string dir =
140 std::visit(VariantToStringVisitor(), directionFind->second);
James Feist6714a252018-09-10 15:26:18 -0700141 if ((toBusValue(threshold.level) != level) ||
142 (toBusValue(threshold.direction) != dir))
143 {
144 return; // not the droid we're looking for
145 }
146
James Feist3eb82622019-02-08 13:10:22 -0800147 std::variant<double> value(threshold.value);
James Feist6714a252018-09-10 15:26:18 -0700148 conn->async_method_call(
James Feistd8705872019-02-08 13:26:09 -0800149 [](const boost::system::error_code& ec) {
James Feist6714a252018-09-10 15:26:18 -0700150 if (ec)
151 {
152 std::cerr << "Error setting threshold " << ec
153 << "\n";
154 }
155 },
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700156 entityManagerName, path, "org.freedesktop.DBus.Properties",
157 "Set", thresholdInterface, "Value", value);
James Feist6714a252018-09-10 15:26:18 -0700158 },
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700159 entityManagerName, path, "org.freedesktop.DBus.Properties",
James Feist6714a252018-09-10 15:26:18 -0700160 "GetAll", thresholdInterface);
161 }
162}
163
Jae Hyun Yoo95b8a2d2019-02-25 20:15:09 -0800164void updateThresholds(Sensor* sensor)
165{
166 if (sensor->thresholds.empty())
167 {
168 return;
169 }
170
171 for (const auto& threshold : sensor->thresholds)
172 {
173 std::shared_ptr<sdbusplus::asio::dbus_interface> interface;
174 std::string property;
175 if (threshold.level == thresholds::Level::CRITICAL)
176 {
177 interface = sensor->thresholdInterfaceCritical;
178 if (threshold.direction == thresholds::Direction::HIGH)
179 {
180 property = "CriticalHigh";
181 }
182 else
183 {
184 property = "CriticalLow";
185 }
186 }
187 else if (threshold.level == thresholds::Level::WARNING)
188 {
189 interface = sensor->thresholdInterfaceWarning;
190 if (threshold.direction == thresholds::Direction::HIGH)
191 {
192 property = "WarningHigh";
193 }
194 else
195 {
196 property = "WarningLow";
197 }
198 }
199 else
200 {
201 continue;
202 }
203 if (!interface)
204 {
205 continue;
206 }
207 interface->set_property(property, threshold.value);
208 }
209}
210
James Feistd8705872019-02-08 13:26:09 -0800211bool checkThresholds(Sensor* sensor)
James Feist251c7822018-09-12 12:54:15 -0700212{
James Feistdc6c55f2018-10-31 12:53:20 -0700213 bool status = true;
James Feist251c7822018-09-12 12:54:15 -0700214
215 if (sensor->thresholds.empty())
216 {
James Feistdc6c55f2018-10-31 12:53:20 -0700217 return true;
James Feist251c7822018-09-12 12:54:15 -0700218 }
James Feistd8705872019-02-08 13:26:09 -0800219 for (auto& threshold : sensor->thresholds)
James Feist251c7822018-09-12 12:54:15 -0700220 {
James Feistdc6c55f2018-10-31 12:53:20 -0700221 if (std::isnan(sensor->value))
222 {
223 threshold.asserted = false;
224 }
225 else if (threshold.direction == thresholds::Direction::HIGH)
James Feist251c7822018-09-12 12:54:15 -0700226 {
227 if (sensor->value > threshold.value && !threshold.asserted)
228 {
229 assertThresholds(sensor, threshold.level, threshold.direction,
230 true);
231 threshold.asserted = true;
232 }
233 else if (sensor->value <= threshold.value && threshold.asserted)
234 {
235 assertThresholds(sensor, threshold.level, threshold.direction,
236 false);
237 threshold.asserted = false;
238 }
239 }
240 else
241 {
242 if (sensor->value < threshold.value && !threshold.asserted)
243 {
244 assertThresholds(sensor, threshold.level, threshold.direction,
245 true);
246 threshold.asserted = true;
247 }
248 else if (sensor->value >= threshold.value && threshold.asserted)
249 {
250 assertThresholds(sensor, threshold.level, threshold.direction,
251 false);
252 threshold.asserted = false;
253 }
254 }
James Feistdc6c55f2018-10-31 12:53:20 -0700255 if (threshold.level == thresholds::Level::CRITICAL &&
256 threshold.asserted)
257 {
258 status = false;
259 }
James Feist251c7822018-09-12 12:54:15 -0700260 }
James Feistdc6c55f2018-10-31 12:53:20 -0700261 return status;
James Feist251c7822018-09-12 12:54:15 -0700262}
263
James Feistd8705872019-02-08 13:26:09 -0800264void assertThresholds(Sensor* sensor, thresholds::Level level,
James Feist251c7822018-09-12 12:54:15 -0700265 thresholds::Direction direction, bool assert)
266{
267 std::string property;
268 std::shared_ptr<sdbusplus::asio::dbus_interface> interface;
269 if (level == thresholds::Level::WARNING &&
270 direction == thresholds::Direction::HIGH)
271 {
272 property = "WarningAlarmHigh";
273 interface = sensor->thresholdInterfaceWarning;
274 }
275 else if (level == thresholds::Level::WARNING &&
276 direction == thresholds::Direction::LOW)
277 {
278 property = "WarningAlarmLow";
279 interface = sensor->thresholdInterfaceWarning;
280 }
281 else if (level == thresholds::Level::CRITICAL &&
282 direction == thresholds::Direction::HIGH)
283 {
284 property = "CriticalAlarmHigh";
285 interface = sensor->thresholdInterfaceCritical;
286 }
287 else if (level == thresholds::Level::CRITICAL &&
288 direction == thresholds::Direction::LOW)
289 {
290 property = "CriticalAlarmLow";
291 interface = sensor->thresholdInterfaceCritical;
292 }
293 else
294 {
295 std::cerr << "Unknown threshold, level " << level << "direction "
296 << direction << "\n";
297 return;
298 }
299 if (!interface)
300 {
301 std::cout << "trying to set uninitialized interface\n";
302 return;
303 }
304 interface->set_property(property, assert);
305}
306
James Feistd8705872019-02-08 13:26:09 -0800307static constexpr std::array<const char*, 4> attrTypes = {"lcrit", "min", "max",
308 "crit"};
James Feist6714a252018-09-10 15:26:18 -0700309
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700310bool parseThresholdsFromAttr(
James Feistd8705872019-02-08 13:26:09 -0800311 std::vector<thresholds::Threshold>& thresholdVector,
312 const std::string& inputPath, const double& scaleFactor)
James Feist6714a252018-09-10 15:26:18 -0700313{
James Feistd8705872019-02-08 13:26:09 -0800314 for (auto& type : attrTypes)
James Feist6714a252018-09-10 15:26:18 -0700315 {
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700316 auto attrPath = boost::replace_all_copy(inputPath, "input", type);
317 std::ifstream attrFile(attrPath);
318 if (!attrFile.good())
319 {
James Feist6714a252018-09-10 15:26:18 -0700320 continue;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700321 }
James Feist6714a252018-09-10 15:26:18 -0700322 std::string attr;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700323 std::getline(attrFile, attr);
324 attrFile.close();
James Feist6714a252018-09-10 15:26:18 -0700325
326 Level level;
327 Direction direction;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700328 double val = std::stod(attr) / scaleFactor;
James Feist6714a252018-09-10 15:26:18 -0700329 if (type == "min" || type == "max")
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700330 {
James Feist6714a252018-09-10 15:26:18 -0700331 level = Level::WARNING;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700332 }
James Feist6714a252018-09-10 15:26:18 -0700333 else
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700334 {
James Feist6714a252018-09-10 15:26:18 -0700335 level = Level::CRITICAL;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700336 }
James Feist6714a252018-09-10 15:26:18 -0700337 if (type == "min" || type == "lcrit")
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700338 {
James Feist6714a252018-09-10 15:26:18 -0700339 direction = Direction::LOW;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700340 }
James Feist6714a252018-09-10 15:26:18 -0700341 else
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700342 {
James Feist6714a252018-09-10 15:26:18 -0700343 direction = Direction::HIGH;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700344 }
James Feist6714a252018-09-10 15:26:18 -0700345
346 if (DEBUG)
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700347 {
348 std::cout << "Threshold: " << attrPath << ": " << val << "\n";
349 }
James Feist6714a252018-09-10 15:26:18 -0700350
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700351 thresholdVector.emplace_back(level, direction, val);
James Feist6714a252018-09-10 15:26:18 -0700352 }
353 // no thresholds is allowed, not an error so return true always
354 return true;
355}
356
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700357bool hasCriticalInterface(
James Feistd8705872019-02-08 13:26:09 -0800358 const std::vector<thresholds::Threshold>& thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700359{
James Feistd8705872019-02-08 13:26:09 -0800360 for (auto& threshold : thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700361 {
362 if (threshold.level == Level::CRITICAL)
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700363 {
James Feist6714a252018-09-10 15:26:18 -0700364 return true;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700365 }
James Feist6714a252018-09-10 15:26:18 -0700366 }
367 return false;
368}
369
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700370bool hasWarningInterface(
James Feistd8705872019-02-08 13:26:09 -0800371 const std::vector<thresholds::Threshold>& thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700372{
James Feistd8705872019-02-08 13:26:09 -0800373 for (auto& threshold : thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700374 {
375 if (threshold.level == Level::WARNING)
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700376 {
James Feist6714a252018-09-10 15:26:18 -0700377 return true;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700378 }
James Feist6714a252018-09-10 15:26:18 -0700379 }
380 return false;
381}
382} // namespace thresholds