blob: ca6a0a12a1c26126d1f0667340d093ff6cf735e1 [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 Feist13f340b2019-03-07 16:36:11 -0800101 double val = std::visit(VariantToDoubleVisitor(), 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 Feist46342ec2019-03-06 14:03:41 -0800211static std::vector<std::pair<Threshold, bool>> checkThresholds(Sensor* sensor,
212 double value)
James Feist251c7822018-09-12 12:54:15 -0700213{
James Feist46342ec2019-03-06 14:03:41 -0800214 std::vector<std::pair<Threshold, bool>> thresholdChanges;
James Feist251c7822018-09-12 12:54:15 -0700215 if (sensor->thresholds.empty())
216 {
James Feist46342ec2019-03-06 14:03:41 -0800217 return thresholdChanges;
James Feist251c7822018-09-12 12:54:15 -0700218 }
James Feist46342ec2019-03-06 14:03:41 -0800219
James Feistd8705872019-02-08 13:26:09 -0800220 for (auto& threshold : sensor->thresholds)
James Feist251c7822018-09-12 12:54:15 -0700221 {
James Feist46342ec2019-03-06 14:03:41 -0800222 if (threshold.direction == thresholds::Direction::HIGH)
James Feistdc6c55f2018-10-31 12:53:20 -0700223 {
James Feist46342ec2019-03-06 14:03:41 -0800224 if (value > threshold.value)
James Feist251c7822018-09-12 12:54:15 -0700225 {
James Feist46342ec2019-03-06 14:03:41 -0800226 thresholdChanges.push_back(std::make_pair(threshold, true));
James Feist251c7822018-09-12 12:54:15 -0700227 }
Patrick Venture66235d42019-10-11 08:31:27 -0700228 else
James Feist251c7822018-09-12 12:54:15 -0700229 {
James Feist46342ec2019-03-06 14:03:41 -0800230 thresholdChanges.push_back(std::make_pair(threshold, false));
James Feist251c7822018-09-12 12:54:15 -0700231 }
232 }
233 else
234 {
James Feist46342ec2019-03-06 14:03:41 -0800235 if (value < threshold.value)
James Feist251c7822018-09-12 12:54:15 -0700236 {
James Feist46342ec2019-03-06 14:03:41 -0800237 thresholdChanges.push_back(std::make_pair(threshold, true));
James Feist251c7822018-09-12 12:54:15 -0700238 }
Patrick Venture66235d42019-10-11 08:31:27 -0700239 else
James Feist251c7822018-09-12 12:54:15 -0700240 {
James Feist46342ec2019-03-06 14:03:41 -0800241 thresholdChanges.push_back(std::make_pair(threshold, false));
James Feist251c7822018-09-12 12:54:15 -0700242 }
243 }
244 }
James Feist46342ec2019-03-06 14:03:41 -0800245 return thresholdChanges;
246}
247
248bool checkThresholds(Sensor* sensor)
249{
James Feist7b18b1e2019-05-14 13:42:09 -0700250 bool status = true;
James Feist46342ec2019-03-06 14:03:41 -0800251 std::vector<std::pair<Threshold, bool>> changes =
252 checkThresholds(sensor, sensor->value);
253 for (const auto& [threshold, asserted] : changes)
254 {
255 assertThresholds(sensor, threshold.level, threshold.direction,
256 asserted);
257 if (threshold.level == thresholds::Level::CRITICAL && asserted)
258 {
James Feist7b18b1e2019-05-14 13:42:09 -0700259 status = false;
James Feist46342ec2019-03-06 14:03:41 -0800260 }
261 }
262
James Feistdc6c55f2018-10-31 12:53:20 -0700263 return status;
James Feist251c7822018-09-12 12:54:15 -0700264}
265
James Feist46342ec2019-03-06 14:03:41 -0800266void checkThresholdsPowerDelay(Sensor* sensor, ThresholdTimer& thresholdTimer)
267{
268
269 std::vector<std::pair<Threshold, bool>> changes =
270 checkThresholds(sensor, sensor->value);
271 for (const auto& [threshold, asserted] : changes)
272 {
273 if (asserted)
274 {
275 thresholdTimer.startTimer(threshold);
276 }
277 else
278 {
279 assertThresholds(sensor, threshold.level, threshold.direction,
280 false);
281 }
282 }
283}
284
James Feistd8705872019-02-08 13:26:09 -0800285void assertThresholds(Sensor* sensor, thresholds::Level level,
James Feist251c7822018-09-12 12:54:15 -0700286 thresholds::Direction direction, bool assert)
287{
288 std::string property;
289 std::shared_ptr<sdbusplus::asio::dbus_interface> interface;
290 if (level == thresholds::Level::WARNING &&
291 direction == thresholds::Direction::HIGH)
292 {
293 property = "WarningAlarmHigh";
294 interface = sensor->thresholdInterfaceWarning;
295 }
296 else if (level == thresholds::Level::WARNING &&
297 direction == thresholds::Direction::LOW)
298 {
299 property = "WarningAlarmLow";
300 interface = sensor->thresholdInterfaceWarning;
301 }
302 else if (level == thresholds::Level::CRITICAL &&
303 direction == thresholds::Direction::HIGH)
304 {
305 property = "CriticalAlarmHigh";
306 interface = sensor->thresholdInterfaceCritical;
307 }
308 else if (level == thresholds::Level::CRITICAL &&
309 direction == thresholds::Direction::LOW)
310 {
311 property = "CriticalAlarmLow";
312 interface = sensor->thresholdInterfaceCritical;
313 }
314 else
315 {
316 std::cerr << "Unknown threshold, level " << level << "direction "
317 << direction << "\n";
318 return;
319 }
320 if (!interface)
321 {
322 std::cout << "trying to set uninitialized interface\n";
323 return;
324 }
325 interface->set_property(property, assert);
326}
327
James Feistd8705872019-02-08 13:26:09 -0800328static constexpr std::array<const char*, 4> attrTypes = {"lcrit", "min", "max",
329 "crit"};
James Feist6714a252018-09-10 15:26:18 -0700330
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700331bool parseThresholdsFromAttr(
James Feistd8705872019-02-08 13:26:09 -0800332 std::vector<thresholds::Threshold>& thresholdVector,
Vijay Khemka86dea2b2019-06-06 11:14:37 -0700333 const std::string& inputPath, const double& scaleFactor,
334 const double& offset)
James Feist6714a252018-09-10 15:26:18 -0700335{
James Feistb6c0b912019-07-09 12:21:44 -0700336 for (const std::string& type : attrTypes)
James Feist6714a252018-09-10 15:26:18 -0700337 {
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700338 auto attrPath = boost::replace_all_copy(inputPath, "input", type);
339 std::ifstream attrFile(attrPath);
340 if (!attrFile.good())
341 {
James Feist6714a252018-09-10 15:26:18 -0700342 continue;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700343 }
James Feist6714a252018-09-10 15:26:18 -0700344 std::string attr;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700345 std::getline(attrFile, attr);
346 attrFile.close();
James Feist6714a252018-09-10 15:26:18 -0700347
348 Level level;
349 Direction direction;
Jae Hyun Yoo7fa17c42019-09-09 13:20:37 -0700350 double val;
351 try
352 {
353 val = std::stod(attr) / scaleFactor;
354 }
355 catch (const std::invalid_argument&)
356 {
357 return false;
358 }
359
James Feist6714a252018-09-10 15:26:18 -0700360 if (type == "min" || type == "max")
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700361 {
James Feist6714a252018-09-10 15:26:18 -0700362 level = Level::WARNING;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700363 }
James Feist6714a252018-09-10 15:26:18 -0700364 else
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700365 {
James Feist6714a252018-09-10 15:26:18 -0700366 level = Level::CRITICAL;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700367 }
James Feist6714a252018-09-10 15:26:18 -0700368 if (type == "min" || type == "lcrit")
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700369 {
James Feist6714a252018-09-10 15:26:18 -0700370 direction = Direction::LOW;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700371 }
James Feist6714a252018-09-10 15:26:18 -0700372 else
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700373 {
James Feist6714a252018-09-10 15:26:18 -0700374 direction = Direction::HIGH;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700375 }
James Feist6714a252018-09-10 15:26:18 -0700376
Vijay Khemka86dea2b2019-06-06 11:14:37 -0700377 if (type == "crit")
378 {
379 val += offset;
380 }
381
James Feist6714a252018-09-10 15:26:18 -0700382 if (DEBUG)
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700383 {
384 std::cout << "Threshold: " << attrPath << ": " << val << "\n";
385 }
James Feist6714a252018-09-10 15:26:18 -0700386
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700387 thresholdVector.emplace_back(level, direction, val);
James Feist6714a252018-09-10 15:26:18 -0700388 }
Jae Hyun Yoo7fa17c42019-09-09 13:20:37 -0700389 // no thresholds is allowed, not an error so return true.
James Feist6714a252018-09-10 15:26:18 -0700390 return true;
391}
392
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700393bool hasCriticalInterface(
James Feistd8705872019-02-08 13:26:09 -0800394 const std::vector<thresholds::Threshold>& thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700395{
James Feistd8705872019-02-08 13:26:09 -0800396 for (auto& threshold : thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700397 {
398 if (threshold.level == Level::CRITICAL)
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700399 {
James Feist6714a252018-09-10 15:26:18 -0700400 return true;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700401 }
James Feist6714a252018-09-10 15:26:18 -0700402 }
403 return false;
404}
405
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700406bool hasWarningInterface(
James Feistd8705872019-02-08 13:26:09 -0800407 const std::vector<thresholds::Threshold>& thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700408{
James Feistd8705872019-02-08 13:26:09 -0800409 for (auto& threshold : thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700410 {
411 if (threshold.level == Level::WARNING)
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700412 {
James Feist6714a252018-09-10 15:26:18 -0700413 return true;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700414 }
James Feist6714a252018-09-10 15:26:18 -0700415 }
416 return false;
417}
418} // namespace thresholds