blob: 72697deede2b597c58372658bff00e205166d3b2 [file] [log] [blame]
Patrick Ventureca44b2f2019-10-31 11:02:26 -07001#include "Thresholds.hpp"
2
3#include "VariantVisitors.hpp"
4#include "sensor.hpp"
5
James Feist6714a252018-09-10 15:26:18 -07006#include <boost/algorithm/string/replace.hpp>
7#include <boost/lexical_cast.hpp>
James Feistdc6c55f2018-10-31 12:53:20 -07008#include <cmath>
James Feist6714a252018-09-10 15:26:18 -07009#include <fstream>
10#include <iostream>
11
12static constexpr bool DEBUG = false;
James Feist6714a252018-09-10 15:26:18 -070013namespace thresholds
14{
James Feistd8705872019-02-08 13:26:09 -080015unsigned int toBusValue(const Level& level)
James Feist6714a252018-09-10 15:26:18 -070016{
17 switch (level)
18 {
19 case (Level::WARNING):
20 {
21 return 0;
22 }
23 case (Level::CRITICAL):
24 {
25 return 1;
26 }
27 default:
28 {
29 return -1;
30 }
31 }
32}
33
James Feistd8705872019-02-08 13:26:09 -080034std::string toBusValue(const Direction& direction)
James Feist6714a252018-09-10 15:26:18 -070035{
36 switch (direction)
37 {
38 case (Direction::LOW):
39 {
40 return "less than";
41 }
42 case (Direction::HIGH):
43 {
44 return "greater than";
45 }
46 default:
47 {
48 return "err";
49 }
50 }
51}
52
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -070053bool parseThresholdsFromConfig(
James Feistd8705872019-02-08 13:26:09 -080054 const SensorData& sensorData,
55 std::vector<thresholds::Threshold>& thresholdVector,
56 const std::string* matchLabel)
James Feist6714a252018-09-10 15:26:18 -070057{
James Feistd8705872019-02-08 13:26:09 -080058 for (const auto& item : sensorData)
James Feist6714a252018-09-10 15:26:18 -070059 {
60 if (item.first.find("Thresholds") == std::string::npos)
61 {
62 continue;
63 }
64 if (matchLabel != nullptr)
65 {
66 auto labelFind = item.second.find("Label");
67 if (labelFind == item.second.end())
68 continue;
James Feist3eb82622019-02-08 13:10:22 -080069 if (std::visit(VariantToStringVisitor(), labelFind->second) !=
70 *matchLabel)
James Feist6714a252018-09-10 15:26:18 -070071 continue;
72 }
73 auto directionFind = item.second.find("Direction");
74 auto severityFind = item.second.find("Severity");
75 auto valueFind = item.second.find("Value");
76 if (valueFind == item.second.end() ||
77 severityFind == item.second.end() ||
78 directionFind == item.second.end())
79 {
80 std::cerr << "Malformed threshold in configuration\n";
81 return false;
82 }
83 Level level;
84 Direction direction;
James Feist3eb82622019-02-08 13:10:22 -080085 if (std::visit(VariantToUnsignedIntVisitor(), severityFind->second) ==
86 0)
James Feist6714a252018-09-10 15:26:18 -070087 {
88 level = Level::WARNING;
89 }
90 else
91 {
92 level = Level::CRITICAL;
93 }
James Feist3eb82622019-02-08 13:10:22 -080094 if (std::visit(VariantToStringVisitor(), directionFind->second) ==
95 "less than")
James Feist6714a252018-09-10 15:26:18 -070096 {
97 direction = Direction::LOW;
98 }
99 else
100 {
101 direction = Direction::HIGH;
102 }
James Feist13f340b2019-03-07 16:36:11 -0800103 double val = std::visit(VariantToDoubleVisitor(), valueFind->second);
James Feist6714a252018-09-10 15:26:18 -0700104
105 thresholdVector.emplace_back(level, direction, val);
106 }
107 return true;
108}
109
James Feistd8705872019-02-08 13:26:09 -0800110void persistThreshold(const std::string& path, const std::string& baseInterface,
111 const thresholds::Threshold& threshold,
James Feista222ba72019-03-01 15:57:51 -0800112 std::shared_ptr<sdbusplus::asio::connection>& conn,
113 size_t thresholdCount)
James Feist6714a252018-09-10 15:26:18 -0700114{
James Feista222ba72019-03-01 15:57:51 -0800115 for (int ii = 0; ii < thresholdCount; ii++)
James Feist6714a252018-09-10 15:26:18 -0700116 {
117 std::string thresholdInterface =
118 baseInterface + ".Thresholds" + std::to_string(ii);
119 conn->async_method_call(
120 [&, path, threshold, thresholdInterface](
James Feistd8705872019-02-08 13:26:09 -0800121 const boost::system::error_code& ec,
122 const boost::container::flat_map<std::string, BasicVariantType>&
123 result) {
James Feist6714a252018-09-10 15:26:18 -0700124 if (ec)
125 {
126 return; // threshold not supported
127 }
128
129 auto directionFind = result.find("Direction");
130 auto severityFind = result.find("Severity");
131 auto valueFind = result.find("Value");
132 if (valueFind == result.end() || severityFind == result.end() ||
133 directionFind == result.end())
134 {
135 std::cerr << "Malformed threshold in configuration\n";
136 return;
137 }
James Feist3eb82622019-02-08 13:10:22 -0800138 unsigned int level = std::visit(VariantToUnsignedIntVisitor(),
139 severityFind->second);
James Feist6714a252018-09-10 15:26:18 -0700140
James Feist3eb82622019-02-08 13:10:22 -0800141 std::string dir =
142 std::visit(VariantToStringVisitor(), directionFind->second);
James Feist6714a252018-09-10 15:26:18 -0700143 if ((toBusValue(threshold.level) != level) ||
144 (toBusValue(threshold.direction) != dir))
145 {
146 return; // not the droid we're looking for
147 }
148
James Feist3eb82622019-02-08 13:10:22 -0800149 std::variant<double> value(threshold.value);
James Feist6714a252018-09-10 15:26:18 -0700150 conn->async_method_call(
James Feistd8705872019-02-08 13:26:09 -0800151 [](const boost::system::error_code& ec) {
James Feist6714a252018-09-10 15:26:18 -0700152 if (ec)
153 {
154 std::cerr << "Error setting threshold " << ec
155 << "\n";
156 }
157 },
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700158 entityManagerName, path, "org.freedesktop.DBus.Properties",
159 "Set", thresholdInterface, "Value", value);
James Feist6714a252018-09-10 15:26:18 -0700160 },
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700161 entityManagerName, path, "org.freedesktop.DBus.Properties",
James Feist6714a252018-09-10 15:26:18 -0700162 "GetAll", thresholdInterface);
163 }
164}
165
Jae Hyun Yoo95b8a2d2019-02-25 20:15:09 -0800166void updateThresholds(Sensor* sensor)
167{
168 if (sensor->thresholds.empty())
169 {
170 return;
171 }
172
173 for (const auto& threshold : sensor->thresholds)
174 {
175 std::shared_ptr<sdbusplus::asio::dbus_interface> interface;
176 std::string property;
177 if (threshold.level == thresholds::Level::CRITICAL)
178 {
179 interface = sensor->thresholdInterfaceCritical;
180 if (threshold.direction == thresholds::Direction::HIGH)
181 {
182 property = "CriticalHigh";
183 }
184 else
185 {
186 property = "CriticalLow";
187 }
188 }
189 else if (threshold.level == thresholds::Level::WARNING)
190 {
191 interface = sensor->thresholdInterfaceWarning;
192 if (threshold.direction == thresholds::Direction::HIGH)
193 {
194 property = "WarningHigh";
195 }
196 else
197 {
198 property = "WarningLow";
199 }
200 }
201 else
202 {
203 continue;
204 }
205 if (!interface)
206 {
207 continue;
208 }
209 interface->set_property(property, threshold.value);
210 }
211}
212
James Feist46342ec2019-03-06 14:03:41 -0800213static std::vector<std::pair<Threshold, bool>> checkThresholds(Sensor* sensor,
214 double value)
James Feist251c7822018-09-12 12:54:15 -0700215{
James Feist46342ec2019-03-06 14:03:41 -0800216 std::vector<std::pair<Threshold, bool>> thresholdChanges;
James Feist251c7822018-09-12 12:54:15 -0700217 if (sensor->thresholds.empty())
218 {
James Feist46342ec2019-03-06 14:03:41 -0800219 return thresholdChanges;
James Feist251c7822018-09-12 12:54:15 -0700220 }
James Feist46342ec2019-03-06 14:03:41 -0800221
James Feistd8705872019-02-08 13:26:09 -0800222 for (auto& threshold : sensor->thresholds)
James Feist251c7822018-09-12 12:54:15 -0700223 {
James Feist46342ec2019-03-06 14:03:41 -0800224 if (threshold.direction == thresholds::Direction::HIGH)
James Feistdc6c55f2018-10-31 12:53:20 -0700225 {
James Feist46342ec2019-03-06 14:03:41 -0800226 if (value > threshold.value)
James Feist251c7822018-09-12 12:54:15 -0700227 {
James Feist46342ec2019-03-06 14:03:41 -0800228 thresholdChanges.push_back(std::make_pair(threshold, true));
James Feist251c7822018-09-12 12:54:15 -0700229 }
Patrick Venture66235d42019-10-11 08:31:27 -0700230 else
James Feist251c7822018-09-12 12:54:15 -0700231 {
James Feist46342ec2019-03-06 14:03:41 -0800232 thresholdChanges.push_back(std::make_pair(threshold, false));
James Feist251c7822018-09-12 12:54:15 -0700233 }
234 }
235 else
236 {
James Feist46342ec2019-03-06 14:03:41 -0800237 if (value < threshold.value)
James Feist251c7822018-09-12 12:54:15 -0700238 {
James Feist46342ec2019-03-06 14:03:41 -0800239 thresholdChanges.push_back(std::make_pair(threshold, true));
James Feist251c7822018-09-12 12:54:15 -0700240 }
Patrick Venture66235d42019-10-11 08:31:27 -0700241 else
James Feist251c7822018-09-12 12:54:15 -0700242 {
James Feist46342ec2019-03-06 14:03:41 -0800243 thresholdChanges.push_back(std::make_pair(threshold, false));
James Feist251c7822018-09-12 12:54:15 -0700244 }
245 }
246 }
James Feist46342ec2019-03-06 14:03:41 -0800247 return thresholdChanges;
248}
249
250bool checkThresholds(Sensor* sensor)
251{
James Feist7b18b1e2019-05-14 13:42:09 -0700252 bool status = true;
James Feist46342ec2019-03-06 14:03:41 -0800253 std::vector<std::pair<Threshold, bool>> changes =
254 checkThresholds(sensor, sensor->value);
255 for (const auto& [threshold, asserted] : changes)
256 {
257 assertThresholds(sensor, threshold.level, threshold.direction,
258 asserted);
259 if (threshold.level == thresholds::Level::CRITICAL && asserted)
260 {
James Feist7b18b1e2019-05-14 13:42:09 -0700261 status = false;
James Feist46342ec2019-03-06 14:03:41 -0800262 }
263 }
264
James Feistdc6c55f2018-10-31 12:53:20 -0700265 return status;
James Feist251c7822018-09-12 12:54:15 -0700266}
267
James Feist46342ec2019-03-06 14:03:41 -0800268void checkThresholdsPowerDelay(Sensor* sensor, ThresholdTimer& thresholdTimer)
269{
270
271 std::vector<std::pair<Threshold, bool>> changes =
272 checkThresholds(sensor, sensor->value);
273 for (const auto& [threshold, asserted] : changes)
274 {
275 if (asserted)
276 {
277 thresholdTimer.startTimer(threshold);
278 }
279 else
280 {
281 assertThresholds(sensor, threshold.level, threshold.direction,
282 false);
283 }
284 }
285}
286
James Feistd8705872019-02-08 13:26:09 -0800287void assertThresholds(Sensor* sensor, thresholds::Level level,
James Feist251c7822018-09-12 12:54:15 -0700288 thresholds::Direction direction, bool assert)
289{
290 std::string property;
291 std::shared_ptr<sdbusplus::asio::dbus_interface> interface;
292 if (level == thresholds::Level::WARNING &&
293 direction == thresholds::Direction::HIGH)
294 {
295 property = "WarningAlarmHigh";
296 interface = sensor->thresholdInterfaceWarning;
297 }
298 else if (level == thresholds::Level::WARNING &&
299 direction == thresholds::Direction::LOW)
300 {
301 property = "WarningAlarmLow";
302 interface = sensor->thresholdInterfaceWarning;
303 }
304 else if (level == thresholds::Level::CRITICAL &&
305 direction == thresholds::Direction::HIGH)
306 {
307 property = "CriticalAlarmHigh";
308 interface = sensor->thresholdInterfaceCritical;
309 }
310 else if (level == thresholds::Level::CRITICAL &&
311 direction == thresholds::Direction::LOW)
312 {
313 property = "CriticalAlarmLow";
314 interface = sensor->thresholdInterfaceCritical;
315 }
316 else
317 {
318 std::cerr << "Unknown threshold, level " << level << "direction "
319 << direction << "\n";
320 return;
321 }
322 if (!interface)
323 {
324 std::cout << "trying to set uninitialized interface\n";
325 return;
326 }
327 interface->set_property(property, assert);
328}
329
James Feistd8705872019-02-08 13:26:09 -0800330static constexpr std::array<const char*, 4> attrTypes = {"lcrit", "min", "max",
331 "crit"};
James Feist6714a252018-09-10 15:26:18 -0700332
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700333bool parseThresholdsFromAttr(
James Feistd8705872019-02-08 13:26:09 -0800334 std::vector<thresholds::Threshold>& thresholdVector,
Vijay Khemka86dea2b2019-06-06 11:14:37 -0700335 const std::string& inputPath, const double& scaleFactor,
336 const double& offset)
James Feist6714a252018-09-10 15:26:18 -0700337{
James Feistb6c0b912019-07-09 12:21:44 -0700338 for (const std::string& type : attrTypes)
James Feist6714a252018-09-10 15:26:18 -0700339 {
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700340 auto attrPath = boost::replace_all_copy(inputPath, "input", type);
341 std::ifstream attrFile(attrPath);
342 if (!attrFile.good())
343 {
James Feist6714a252018-09-10 15:26:18 -0700344 continue;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700345 }
James Feist6714a252018-09-10 15:26:18 -0700346 std::string attr;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700347 std::getline(attrFile, attr);
348 attrFile.close();
James Feist6714a252018-09-10 15:26:18 -0700349
350 Level level;
351 Direction direction;
Jae Hyun Yoo7fa17c42019-09-09 13:20:37 -0700352 double val;
353 try
354 {
355 val = std::stod(attr) / scaleFactor;
356 }
357 catch (const std::invalid_argument&)
358 {
359 return false;
360 }
361
James Feist6714a252018-09-10 15:26:18 -0700362 if (type == "min" || type == "max")
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700363 {
James Feist6714a252018-09-10 15:26:18 -0700364 level = Level::WARNING;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700365 }
James Feist6714a252018-09-10 15:26:18 -0700366 else
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700367 {
James Feist6714a252018-09-10 15:26:18 -0700368 level = Level::CRITICAL;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700369 }
James Feist6714a252018-09-10 15:26:18 -0700370 if (type == "min" || type == "lcrit")
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700371 {
James Feist6714a252018-09-10 15:26:18 -0700372 direction = Direction::LOW;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700373 }
James Feist6714a252018-09-10 15:26:18 -0700374 else
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700375 {
James Feist6714a252018-09-10 15:26:18 -0700376 direction = Direction::HIGH;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700377 }
James Feist6714a252018-09-10 15:26:18 -0700378
Vijay Khemka86dea2b2019-06-06 11:14:37 -0700379 if (type == "crit")
380 {
381 val += offset;
382 }
383
James Feist6714a252018-09-10 15:26:18 -0700384 if (DEBUG)
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700385 {
386 std::cout << "Threshold: " << attrPath << ": " << val << "\n";
387 }
James Feist6714a252018-09-10 15:26:18 -0700388
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700389 thresholdVector.emplace_back(level, direction, val);
James Feist6714a252018-09-10 15:26:18 -0700390 }
Jae Hyun Yoo7fa17c42019-09-09 13:20:37 -0700391 // no thresholds is allowed, not an error so return true.
James Feist6714a252018-09-10 15:26:18 -0700392 return true;
393}
394
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700395bool hasCriticalInterface(
James Feistd8705872019-02-08 13:26:09 -0800396 const std::vector<thresholds::Threshold>& thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700397{
James Feistd8705872019-02-08 13:26:09 -0800398 for (auto& threshold : thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700399 {
400 if (threshold.level == Level::CRITICAL)
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700401 {
James Feist6714a252018-09-10 15:26:18 -0700402 return true;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700403 }
James Feist6714a252018-09-10 15:26:18 -0700404 }
405 return false;
406}
407
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700408bool hasWarningInterface(
James Feistd8705872019-02-08 13:26:09 -0800409 const std::vector<thresholds::Threshold>& thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700410{
James Feistd8705872019-02-08 13:26:09 -0800411 for (auto& threshold : thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700412 {
413 if (threshold.level == Level::WARNING)
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700414 {
James Feist6714a252018-09-10 15:26:18 -0700415 return true;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700416 }
James Feist6714a252018-09-10 15:26:18 -0700417 }
418 return false;
419}
420} // namespace thresholds