blob: fe5537f2dd2155b450c268035ebfb30d51ea03ea [file] [log] [blame]
Patrick Ventureca44b2f2019-10-31 11:02:26 -07001#include "Thresholds.hpp"
2
3#include "VariantVisitors.hpp"
4#include "sensor.hpp"
5
Patrick Venture96e97db2019-10-31 13:44:38 -07006#include <array>
James Feist6714a252018-09-10 15:26:18 -07007#include <boost/algorithm/string/replace.hpp>
Patrick Venture96e97db2019-10-31 13:44:38 -07008#include <boost/container/flat_map.hpp>
James Feist6714a252018-09-10 15:26:18 -07009#include <boost/lexical_cast.hpp>
James Feistdc6c55f2018-10-31 12:53:20 -070010#include <cmath>
James Feist6714a252018-09-10 15:26:18 -070011#include <fstream>
12#include <iostream>
Patrick Venture96e97db2019-10-31 13:44:38 -070013#include <memory>
14#include <stdexcept>
15#include <string>
16#include <utility>
17#include <variant>
18#include <vector>
James Feist6714a252018-09-10 15:26:18 -070019
20static constexpr bool DEBUG = false;
James Feist6714a252018-09-10 15:26:18 -070021namespace thresholds
22{
James Feistd8705872019-02-08 13:26:09 -080023unsigned int toBusValue(const Level& level)
James Feist6714a252018-09-10 15:26:18 -070024{
25 switch (level)
26 {
27 case (Level::WARNING):
28 {
29 return 0;
30 }
31 case (Level::CRITICAL):
32 {
33 return 1;
34 }
35 default:
36 {
37 return -1;
38 }
39 }
40}
41
James Feistd8705872019-02-08 13:26:09 -080042std::string toBusValue(const Direction& direction)
James Feist6714a252018-09-10 15:26:18 -070043{
44 switch (direction)
45 {
46 case (Direction::LOW):
47 {
48 return "less than";
49 }
50 case (Direction::HIGH):
51 {
52 return "greater than";
53 }
54 default:
55 {
56 return "err";
57 }
58 }
59}
60
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -070061bool parseThresholdsFromConfig(
James Feistd8705872019-02-08 13:26:09 -080062 const SensorData& sensorData,
63 std::vector<thresholds::Threshold>& thresholdVector,
64 const std::string* matchLabel)
James Feist6714a252018-09-10 15:26:18 -070065{
James Feistd8705872019-02-08 13:26:09 -080066 for (const auto& item : sensorData)
James Feist6714a252018-09-10 15:26:18 -070067 {
68 if (item.first.find("Thresholds") == std::string::npos)
69 {
70 continue;
71 }
72 if (matchLabel != nullptr)
73 {
74 auto labelFind = item.second.find("Label");
75 if (labelFind == item.second.end())
76 continue;
James Feist3eb82622019-02-08 13:10:22 -080077 if (std::visit(VariantToStringVisitor(), labelFind->second) !=
78 *matchLabel)
James Feist6714a252018-09-10 15:26:18 -070079 continue;
80 }
81 auto directionFind = item.second.find("Direction");
82 auto severityFind = item.second.find("Severity");
83 auto valueFind = item.second.find("Value");
84 if (valueFind == item.second.end() ||
85 severityFind == item.second.end() ||
86 directionFind == item.second.end())
87 {
88 std::cerr << "Malformed threshold in configuration\n";
89 return false;
90 }
91 Level level;
92 Direction direction;
James Feist3eb82622019-02-08 13:10:22 -080093 if (std::visit(VariantToUnsignedIntVisitor(), severityFind->second) ==
94 0)
James Feist6714a252018-09-10 15:26:18 -070095 {
96 level = Level::WARNING;
97 }
98 else
99 {
100 level = Level::CRITICAL;
101 }
James Feist3eb82622019-02-08 13:10:22 -0800102 if (std::visit(VariantToStringVisitor(), directionFind->second) ==
103 "less than")
James Feist6714a252018-09-10 15:26:18 -0700104 {
105 direction = Direction::LOW;
106 }
107 else
108 {
109 direction = Direction::HIGH;
110 }
James Feist13f340b2019-03-07 16:36:11 -0800111 double val = std::visit(VariantToDoubleVisitor(), valueFind->second);
James Feist6714a252018-09-10 15:26:18 -0700112
113 thresholdVector.emplace_back(level, direction, val);
114 }
115 return true;
116}
117
James Feistd8705872019-02-08 13:26:09 -0800118void persistThreshold(const std::string& path, const std::string& baseInterface,
119 const thresholds::Threshold& threshold,
James Feista222ba72019-03-01 15:57:51 -0800120 std::shared_ptr<sdbusplus::asio::connection>& conn,
121 size_t thresholdCount)
James Feist6714a252018-09-10 15:26:18 -0700122{
Brad Bishopfbb44ad2019-11-08 09:42:37 -0500123 for (size_t ii = 0; ii < thresholdCount; ii++)
James Feist6714a252018-09-10 15:26:18 -0700124 {
125 std::string thresholdInterface =
126 baseInterface + ".Thresholds" + std::to_string(ii);
127 conn->async_method_call(
128 [&, path, threshold, thresholdInterface](
James Feistd8705872019-02-08 13:26:09 -0800129 const boost::system::error_code& ec,
130 const boost::container::flat_map<std::string, BasicVariantType>&
131 result) {
James Feist6714a252018-09-10 15:26:18 -0700132 if (ec)
133 {
134 return; // threshold not supported
135 }
136
137 auto directionFind = result.find("Direction");
138 auto severityFind = result.find("Severity");
139 auto valueFind = result.find("Value");
140 if (valueFind == result.end() || severityFind == result.end() ||
141 directionFind == result.end())
142 {
143 std::cerr << "Malformed threshold in configuration\n";
144 return;
145 }
James Feist3eb82622019-02-08 13:10:22 -0800146 unsigned int level = std::visit(VariantToUnsignedIntVisitor(),
147 severityFind->second);
James Feist6714a252018-09-10 15:26:18 -0700148
James Feist3eb82622019-02-08 13:10:22 -0800149 std::string dir =
150 std::visit(VariantToStringVisitor(), directionFind->second);
James Feist6714a252018-09-10 15:26:18 -0700151 if ((toBusValue(threshold.level) != level) ||
152 (toBusValue(threshold.direction) != dir))
153 {
154 return; // not the droid we're looking for
155 }
156
James Feist3eb82622019-02-08 13:10:22 -0800157 std::variant<double> value(threshold.value);
James Feist6714a252018-09-10 15:26:18 -0700158 conn->async_method_call(
James Feistd8705872019-02-08 13:26:09 -0800159 [](const boost::system::error_code& ec) {
James Feist6714a252018-09-10 15:26:18 -0700160 if (ec)
161 {
162 std::cerr << "Error setting threshold " << ec
163 << "\n";
164 }
165 },
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700166 entityManagerName, path, "org.freedesktop.DBus.Properties",
167 "Set", thresholdInterface, "Value", value);
James Feist6714a252018-09-10 15:26:18 -0700168 },
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700169 entityManagerName, path, "org.freedesktop.DBus.Properties",
James Feist6714a252018-09-10 15:26:18 -0700170 "GetAll", thresholdInterface);
171 }
172}
173
Jae Hyun Yoo95b8a2d2019-02-25 20:15:09 -0800174void updateThresholds(Sensor* sensor)
175{
176 if (sensor->thresholds.empty())
177 {
178 return;
179 }
180
181 for (const auto& threshold : sensor->thresholds)
182 {
183 std::shared_ptr<sdbusplus::asio::dbus_interface> interface;
184 std::string property;
185 if (threshold.level == thresholds::Level::CRITICAL)
186 {
187 interface = sensor->thresholdInterfaceCritical;
188 if (threshold.direction == thresholds::Direction::HIGH)
189 {
190 property = "CriticalHigh";
191 }
192 else
193 {
194 property = "CriticalLow";
195 }
196 }
197 else if (threshold.level == thresholds::Level::WARNING)
198 {
199 interface = sensor->thresholdInterfaceWarning;
200 if (threshold.direction == thresholds::Direction::HIGH)
201 {
202 property = "WarningHigh";
203 }
204 else
205 {
206 property = "WarningLow";
207 }
208 }
209 else
210 {
211 continue;
212 }
213 if (!interface)
214 {
215 continue;
216 }
217 interface->set_property(property, threshold.value);
218 }
219}
220
James Feist46342ec2019-03-06 14:03:41 -0800221static std::vector<std::pair<Threshold, bool>> checkThresholds(Sensor* sensor,
222 double value)
James Feist251c7822018-09-12 12:54:15 -0700223{
James Feist46342ec2019-03-06 14:03:41 -0800224 std::vector<std::pair<Threshold, bool>> thresholdChanges;
James Feist251c7822018-09-12 12:54:15 -0700225 if (sensor->thresholds.empty())
226 {
James Feist46342ec2019-03-06 14:03:41 -0800227 return thresholdChanges;
James Feist251c7822018-09-12 12:54:15 -0700228 }
James Feist46342ec2019-03-06 14:03:41 -0800229
James Feistd8705872019-02-08 13:26:09 -0800230 for (auto& threshold : sensor->thresholds)
James Feist251c7822018-09-12 12:54:15 -0700231 {
James Feist46342ec2019-03-06 14:03:41 -0800232 if (threshold.direction == thresholds::Direction::HIGH)
James Feistdc6c55f2018-10-31 12:53:20 -0700233 {
James Feist46342ec2019-03-06 14:03:41 -0800234 if (value > threshold.value)
James Feist251c7822018-09-12 12:54:15 -0700235 {
James Feist46342ec2019-03-06 14:03:41 -0800236 thresholdChanges.push_back(std::make_pair(threshold, true));
James Feist251c7822018-09-12 12:54:15 -0700237 }
Patrick Venture66235d42019-10-11 08:31:27 -0700238 else
James Feist251c7822018-09-12 12:54:15 -0700239 {
James Feist46342ec2019-03-06 14:03:41 -0800240 thresholdChanges.push_back(std::make_pair(threshold, false));
James Feist251c7822018-09-12 12:54:15 -0700241 }
242 }
243 else
244 {
James Feist46342ec2019-03-06 14:03:41 -0800245 if (value < threshold.value)
James Feist251c7822018-09-12 12:54:15 -0700246 {
James Feist46342ec2019-03-06 14:03:41 -0800247 thresholdChanges.push_back(std::make_pair(threshold, true));
James Feist251c7822018-09-12 12:54:15 -0700248 }
Patrick Venture66235d42019-10-11 08:31:27 -0700249 else
James Feist251c7822018-09-12 12:54:15 -0700250 {
James Feist46342ec2019-03-06 14:03:41 -0800251 thresholdChanges.push_back(std::make_pair(threshold, false));
James Feist251c7822018-09-12 12:54:15 -0700252 }
253 }
254 }
James Feist46342ec2019-03-06 14:03:41 -0800255 return thresholdChanges;
256}
257
258bool checkThresholds(Sensor* sensor)
259{
James Feist7b18b1e2019-05-14 13:42:09 -0700260 bool status = true;
James Feist46342ec2019-03-06 14:03:41 -0800261 std::vector<std::pair<Threshold, bool>> changes =
262 checkThresholds(sensor, sensor->value);
263 for (const auto& [threshold, asserted] : changes)
264 {
265 assertThresholds(sensor, threshold.level, threshold.direction,
266 asserted);
267 if (threshold.level == thresholds::Level::CRITICAL && asserted)
268 {
James Feist7b18b1e2019-05-14 13:42:09 -0700269 status = false;
James Feist46342ec2019-03-06 14:03:41 -0800270 }
271 }
272
James Feistdc6c55f2018-10-31 12:53:20 -0700273 return status;
James Feist251c7822018-09-12 12:54:15 -0700274}
275
James Feist46342ec2019-03-06 14:03:41 -0800276void checkThresholdsPowerDelay(Sensor* sensor, ThresholdTimer& thresholdTimer)
277{
278
279 std::vector<std::pair<Threshold, bool>> changes =
280 checkThresholds(sensor, sensor->value);
281 for (const auto& [threshold, asserted] : changes)
282 {
283 if (asserted)
284 {
285 thresholdTimer.startTimer(threshold);
286 }
287 else
288 {
289 assertThresholds(sensor, threshold.level, threshold.direction,
290 false);
291 }
292 }
293}
294
James Feistd8705872019-02-08 13:26:09 -0800295void assertThresholds(Sensor* sensor, thresholds::Level level,
James Feist251c7822018-09-12 12:54:15 -0700296 thresholds::Direction direction, bool assert)
297{
298 std::string property;
299 std::shared_ptr<sdbusplus::asio::dbus_interface> interface;
300 if (level == thresholds::Level::WARNING &&
301 direction == thresholds::Direction::HIGH)
302 {
303 property = "WarningAlarmHigh";
304 interface = sensor->thresholdInterfaceWarning;
305 }
306 else if (level == thresholds::Level::WARNING &&
307 direction == thresholds::Direction::LOW)
308 {
309 property = "WarningAlarmLow";
310 interface = sensor->thresholdInterfaceWarning;
311 }
312 else if (level == thresholds::Level::CRITICAL &&
313 direction == thresholds::Direction::HIGH)
314 {
315 property = "CriticalAlarmHigh";
316 interface = sensor->thresholdInterfaceCritical;
317 }
318 else if (level == thresholds::Level::CRITICAL &&
319 direction == thresholds::Direction::LOW)
320 {
321 property = "CriticalAlarmLow";
322 interface = sensor->thresholdInterfaceCritical;
323 }
324 else
325 {
326 std::cerr << "Unknown threshold, level " << level << "direction "
327 << direction << "\n";
328 return;
329 }
330 if (!interface)
331 {
332 std::cout << "trying to set uninitialized interface\n";
333 return;
334 }
335 interface->set_property(property, assert);
336}
337
James Feistd8705872019-02-08 13:26:09 -0800338static constexpr std::array<const char*, 4> attrTypes = {"lcrit", "min", "max",
339 "crit"};
James Feist6714a252018-09-10 15:26:18 -0700340
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700341bool parseThresholdsFromAttr(
James Feistd8705872019-02-08 13:26:09 -0800342 std::vector<thresholds::Threshold>& thresholdVector,
Vijay Khemka86dea2b2019-06-06 11:14:37 -0700343 const std::string& inputPath, const double& scaleFactor,
344 const double& offset)
James Feist6714a252018-09-10 15:26:18 -0700345{
James Feistb6c0b912019-07-09 12:21:44 -0700346 for (const std::string& type : attrTypes)
James Feist6714a252018-09-10 15:26:18 -0700347 {
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700348 auto attrPath = boost::replace_all_copy(inputPath, "input", type);
349 std::ifstream attrFile(attrPath);
350 if (!attrFile.good())
351 {
James Feist6714a252018-09-10 15:26:18 -0700352 continue;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700353 }
James Feist6714a252018-09-10 15:26:18 -0700354 std::string attr;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700355 std::getline(attrFile, attr);
356 attrFile.close();
James Feist6714a252018-09-10 15:26:18 -0700357
358 Level level;
359 Direction direction;
Jae Hyun Yoo7fa17c42019-09-09 13:20:37 -0700360 double val;
361 try
362 {
363 val = std::stod(attr) / scaleFactor;
364 }
365 catch (const std::invalid_argument&)
366 {
367 return false;
368 }
369
James Feist6714a252018-09-10 15:26:18 -0700370 if (type == "min" || type == "max")
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700371 {
James Feist6714a252018-09-10 15:26:18 -0700372 level = Level::WARNING;
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 level = Level::CRITICAL;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700377 }
James Feist6714a252018-09-10 15:26:18 -0700378 if (type == "min" || type == "lcrit")
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700379 {
James Feist6714a252018-09-10 15:26:18 -0700380 direction = Direction::LOW;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700381 }
James Feist6714a252018-09-10 15:26:18 -0700382 else
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700383 {
James Feist6714a252018-09-10 15:26:18 -0700384 direction = Direction::HIGH;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700385 }
James Feist6714a252018-09-10 15:26:18 -0700386
Vijay Khemka86dea2b2019-06-06 11:14:37 -0700387 if (type == "crit")
388 {
389 val += offset;
390 }
391
James Feist6714a252018-09-10 15:26:18 -0700392 if (DEBUG)
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700393 {
394 std::cout << "Threshold: " << attrPath << ": " << val << "\n";
395 }
James Feist6714a252018-09-10 15:26:18 -0700396
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700397 thresholdVector.emplace_back(level, direction, val);
James Feist6714a252018-09-10 15:26:18 -0700398 }
Jae Hyun Yoo7fa17c42019-09-09 13:20:37 -0700399 // no thresholds is allowed, not an error so return true.
James Feist6714a252018-09-10 15:26:18 -0700400 return true;
401}
402
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700403bool hasCriticalInterface(
James Feistd8705872019-02-08 13:26:09 -0800404 const std::vector<thresholds::Threshold>& thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700405{
James Feistd8705872019-02-08 13:26:09 -0800406 for (auto& threshold : thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700407 {
408 if (threshold.level == Level::CRITICAL)
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700409 {
James Feist6714a252018-09-10 15:26:18 -0700410 return true;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700411 }
James Feist6714a252018-09-10 15:26:18 -0700412 }
413 return false;
414}
415
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700416bool hasWarningInterface(
James Feistd8705872019-02-08 13:26:09 -0800417 const std::vector<thresholds::Threshold>& thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700418{
James Feistd8705872019-02-08 13:26:09 -0800419 for (auto& threshold : thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700420 {
421 if (threshold.level == Level::WARNING)
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700422 {
James Feist6714a252018-09-10 15:26:18 -0700423 return true;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700424 }
James Feist6714a252018-09-10 15:26:18 -0700425 }
426 return false;
427}
428} // namespace thresholds