blob: 49dca1f6ad7c72ad9f355c37db9ad3dc9665ddc4 [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;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -070011static constexpr size_t maxThresholds = 4;
James Feist6714a252018-09-10 15:26:18 -070012
13namespace 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 Feist3eb82622019-02-08 13:10:22 -0800103 float val = std::visit(VariantToFloatVisitor(), 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,
112 std::shared_ptr<sdbusplus::asio::connection>& conn)
James Feist6714a252018-09-10 15:26:18 -0700113{
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700114 for (int ii = 0; ii < maxThresholds; ii++)
James Feist6714a252018-09-10 15:26:18 -0700115 {
116 std::string thresholdInterface =
117 baseInterface + ".Thresholds" + std::to_string(ii);
118 conn->async_method_call(
119 [&, path, threshold, thresholdInterface](
James Feistd8705872019-02-08 13:26:09 -0800120 const boost::system::error_code& ec,
121 const boost::container::flat_map<std::string, BasicVariantType>&
122 result) {
James Feist6714a252018-09-10 15:26:18 -0700123 if (ec)
124 {
125 return; // threshold not supported
126 }
127
128 auto directionFind = result.find("Direction");
129 auto severityFind = result.find("Severity");
130 auto valueFind = result.find("Value");
131 if (valueFind == result.end() || severityFind == result.end() ||
132 directionFind == result.end())
133 {
134 std::cerr << "Malformed threshold in configuration\n";
135 return;
136 }
James Feist3eb82622019-02-08 13:10:22 -0800137 unsigned int level = std::visit(VariantToUnsignedIntVisitor(),
138 severityFind->second);
James Feist6714a252018-09-10 15:26:18 -0700139
James Feist3eb82622019-02-08 13:10:22 -0800140 std::string dir =
141 std::visit(VariantToStringVisitor(), directionFind->second);
James Feist6714a252018-09-10 15:26:18 -0700142 if ((toBusValue(threshold.level) != level) ||
143 (toBusValue(threshold.direction) != dir))
144 {
145 return; // not the droid we're looking for
146 }
147
James Feist3eb82622019-02-08 13:10:22 -0800148 std::variant<double> value(threshold.value);
James Feist6714a252018-09-10 15:26:18 -0700149 conn->async_method_call(
James Feistd8705872019-02-08 13:26:09 -0800150 [](const boost::system::error_code& ec) {
James Feist6714a252018-09-10 15:26:18 -0700151 if (ec)
152 {
153 std::cerr << "Error setting threshold " << ec
154 << "\n";
155 }
156 },
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700157 entityManagerName, path, "org.freedesktop.DBus.Properties",
158 "Set", thresholdInterface, "Value", value);
James Feist6714a252018-09-10 15:26:18 -0700159 },
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700160 entityManagerName, path, "org.freedesktop.DBus.Properties",
James Feist6714a252018-09-10 15:26:18 -0700161 "GetAll", thresholdInterface);
162 }
163}
164
Jae Hyun Yoo95b8a2d2019-02-25 20:15:09 -0800165void updateThresholds(Sensor* sensor)
166{
167 if (sensor->thresholds.empty())
168 {
169 return;
170 }
171
172 for (const auto& threshold : sensor->thresholds)
173 {
174 std::shared_ptr<sdbusplus::asio::dbus_interface> interface;
175 std::string property;
176 if (threshold.level == thresholds::Level::CRITICAL)
177 {
178 interface = sensor->thresholdInterfaceCritical;
179 if (threshold.direction == thresholds::Direction::HIGH)
180 {
181 property = "CriticalHigh";
182 }
183 else
184 {
185 property = "CriticalLow";
186 }
187 }
188 else if (threshold.level == thresholds::Level::WARNING)
189 {
190 interface = sensor->thresholdInterfaceWarning;
191 if (threshold.direction == thresholds::Direction::HIGH)
192 {
193 property = "WarningHigh";
194 }
195 else
196 {
197 property = "WarningLow";
198 }
199 }
200 else
201 {
202 continue;
203 }
204 if (!interface)
205 {
206 continue;
207 }
208 interface->set_property(property, threshold.value);
209 }
210}
211
James Feistd8705872019-02-08 13:26:09 -0800212bool checkThresholds(Sensor* sensor)
James Feist251c7822018-09-12 12:54:15 -0700213{
James Feistdc6c55f2018-10-31 12:53:20 -0700214 bool status = true;
James Feist251c7822018-09-12 12:54:15 -0700215
216 if (sensor->thresholds.empty())
217 {
James Feistdc6c55f2018-10-31 12:53:20 -0700218 return true;
James Feist251c7822018-09-12 12:54:15 -0700219 }
James Feistd8705872019-02-08 13:26:09 -0800220 for (auto& threshold : sensor->thresholds)
James Feist251c7822018-09-12 12:54:15 -0700221 {
James Feistdc6c55f2018-10-31 12:53:20 -0700222 if (std::isnan(sensor->value))
223 {
224 threshold.asserted = false;
225 }
226 else if (threshold.direction == thresholds::Direction::HIGH)
James Feist251c7822018-09-12 12:54:15 -0700227 {
228 if (sensor->value > threshold.value && !threshold.asserted)
229 {
230 assertThresholds(sensor, threshold.level, threshold.direction,
231 true);
232 threshold.asserted = true;
233 }
234 else if (sensor->value <= threshold.value && threshold.asserted)
235 {
236 assertThresholds(sensor, threshold.level, threshold.direction,
237 false);
238 threshold.asserted = false;
239 }
240 }
241 else
242 {
243 if (sensor->value < threshold.value && !threshold.asserted)
244 {
245 assertThresholds(sensor, threshold.level, threshold.direction,
246 true);
247 threshold.asserted = true;
248 }
249 else if (sensor->value >= threshold.value && threshold.asserted)
250 {
251 assertThresholds(sensor, threshold.level, threshold.direction,
252 false);
253 threshold.asserted = false;
254 }
255 }
James Feistdc6c55f2018-10-31 12:53:20 -0700256 if (threshold.level == thresholds::Level::CRITICAL &&
257 threshold.asserted)
258 {
259 status = false;
260 }
James Feist251c7822018-09-12 12:54:15 -0700261 }
James Feistdc6c55f2018-10-31 12:53:20 -0700262 return status;
James Feist251c7822018-09-12 12:54:15 -0700263}
264
James Feistd8705872019-02-08 13:26:09 -0800265void assertThresholds(Sensor* sensor, thresholds::Level level,
James Feist251c7822018-09-12 12:54:15 -0700266 thresholds::Direction direction, bool assert)
267{
268 std::string property;
269 std::shared_ptr<sdbusplus::asio::dbus_interface> interface;
270 if (level == thresholds::Level::WARNING &&
271 direction == thresholds::Direction::HIGH)
272 {
273 property = "WarningAlarmHigh";
274 interface = sensor->thresholdInterfaceWarning;
275 }
276 else if (level == thresholds::Level::WARNING &&
277 direction == thresholds::Direction::LOW)
278 {
279 property = "WarningAlarmLow";
280 interface = sensor->thresholdInterfaceWarning;
281 }
282 else if (level == thresholds::Level::CRITICAL &&
283 direction == thresholds::Direction::HIGH)
284 {
285 property = "CriticalAlarmHigh";
286 interface = sensor->thresholdInterfaceCritical;
287 }
288 else if (level == thresholds::Level::CRITICAL &&
289 direction == thresholds::Direction::LOW)
290 {
291 property = "CriticalAlarmLow";
292 interface = sensor->thresholdInterfaceCritical;
293 }
294 else
295 {
296 std::cerr << "Unknown threshold, level " << level << "direction "
297 << direction << "\n";
298 return;
299 }
300 if (!interface)
301 {
302 std::cout << "trying to set uninitialized interface\n";
303 return;
304 }
305 interface->set_property(property, assert);
306}
307
James Feistd8705872019-02-08 13:26:09 -0800308static constexpr std::array<const char*, 4> attrTypes = {"lcrit", "min", "max",
309 "crit"};
James Feist6714a252018-09-10 15:26:18 -0700310
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700311bool parseThresholdsFromAttr(
James Feistd8705872019-02-08 13:26:09 -0800312 std::vector<thresholds::Threshold>& thresholdVector,
313 const std::string& inputPath, const double& scaleFactor)
James Feist6714a252018-09-10 15:26:18 -0700314{
James Feistd8705872019-02-08 13:26:09 -0800315 for (auto& type : attrTypes)
James Feist6714a252018-09-10 15:26:18 -0700316 {
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700317 auto attrPath = boost::replace_all_copy(inputPath, "input", type);
318 std::ifstream attrFile(attrPath);
319 if (!attrFile.good())
320 {
James Feist6714a252018-09-10 15:26:18 -0700321 continue;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700322 }
James Feist6714a252018-09-10 15:26:18 -0700323 std::string attr;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700324 std::getline(attrFile, attr);
325 attrFile.close();
James Feist6714a252018-09-10 15:26:18 -0700326
327 Level level;
328 Direction direction;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700329 double val = std::stod(attr) / scaleFactor;
James Feist6714a252018-09-10 15:26:18 -0700330 if (type == "min" || type == "max")
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700331 {
James Feist6714a252018-09-10 15:26:18 -0700332 level = Level::WARNING;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700333 }
James Feist6714a252018-09-10 15:26:18 -0700334 else
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700335 {
James Feist6714a252018-09-10 15:26:18 -0700336 level = Level::CRITICAL;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700337 }
James Feist6714a252018-09-10 15:26:18 -0700338 if (type == "min" || type == "lcrit")
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700339 {
James Feist6714a252018-09-10 15:26:18 -0700340 direction = Direction::LOW;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700341 }
James Feist6714a252018-09-10 15:26:18 -0700342 else
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700343 {
James Feist6714a252018-09-10 15:26:18 -0700344 direction = Direction::HIGH;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700345 }
James Feist6714a252018-09-10 15:26:18 -0700346
347 if (DEBUG)
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700348 {
349 std::cout << "Threshold: " << attrPath << ": " << val << "\n";
350 }
James Feist6714a252018-09-10 15:26:18 -0700351
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700352 thresholdVector.emplace_back(level, direction, val);
James Feist6714a252018-09-10 15:26:18 -0700353 }
354 // no thresholds is allowed, not an error so return true always
355 return true;
356}
357
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700358bool hasCriticalInterface(
James Feistd8705872019-02-08 13:26:09 -0800359 const std::vector<thresholds::Threshold>& thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700360{
James Feistd8705872019-02-08 13:26:09 -0800361 for (auto& threshold : thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700362 {
363 if (threshold.level == Level::CRITICAL)
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700364 {
James Feist6714a252018-09-10 15:26:18 -0700365 return true;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700366 }
James Feist6714a252018-09-10 15:26:18 -0700367 }
368 return false;
369}
370
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700371bool hasWarningInterface(
James Feistd8705872019-02-08 13:26:09 -0800372 const std::vector<thresholds::Threshold>& thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700373{
James Feistd8705872019-02-08 13:26:09 -0800374 for (auto& threshold : thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700375 {
376 if (threshold.level == Level::WARNING)
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700377 {
James Feist6714a252018-09-10 15:26:18 -0700378 return true;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700379 }
James Feist6714a252018-09-10 15:26:18 -0700380 }
381 return false;
382}
383} // namespace thresholds