blob: 10b1674b57a986fc039df6084715a2eff6102cf6 [file] [log] [blame]
James Feist139cb572018-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 Feist39132a62018-10-31 12:53:20 -07005#include <cmath>
James Feist139cb572018-09-10 15:26:18 -07006#include <fstream>
7#include <iostream>
James Feistaf79dd32018-09-12 12:54:15 -07008#include <sensor.hpp>
James Feist139cb572018-09-10 15:26:18 -07009
10static constexpr bool DEBUG = false;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -070011static constexpr size_t maxThresholds = 4;
James Feist139cb572018-09-10 15:26:18 -070012
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -070013namespace variant_ns = sdbusplus::message::variant_ns;
James Feist139cb572018-09-10 15:26:18 -070014namespace thresholds
15{
16unsigned int toBusValue(const Level &level)
17{
18 switch (level)
19 {
20 case (Level::WARNING):
21 {
22 return 0;
23 }
24 case (Level::CRITICAL):
25 {
26 return 1;
27 }
28 default:
29 {
30 return -1;
31 }
32 }
33}
34
35std::string toBusValue(const Direction &direction)
36{
37 switch (direction)
38 {
39 case (Direction::LOW):
40 {
41 return "less than";
42 }
43 case (Direction::HIGH):
44 {
45 return "greater than";
46 }
47 default:
48 {
49 return "err";
50 }
51 }
52}
53
Jae Hyun Yoof78ec412018-10-25 10:42:39 -070054bool parseThresholdsFromConfig(
James Feist139cb572018-09-10 15:26:18 -070055 const SensorData &sensorData,
56 std::vector<thresholds::Threshold> &thresholdVector,
57 const std::string *matchLabel)
58{
59 for (const auto &item : sensorData)
60 {
61 if (item.first.find("Thresholds") == std::string::npos)
62 {
63 continue;
64 }
65 if (matchLabel != nullptr)
66 {
67 auto labelFind = item.second.find("Label");
68 if (labelFind == item.second.end())
69 continue;
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -070070 if (variant_ns::visit(VariantToStringVisitor(),
71 labelFind->second) != *matchLabel)
James Feist139cb572018-09-10 15:26:18 -070072 continue;
73 }
74 auto directionFind = item.second.find("Direction");
75 auto severityFind = item.second.find("Severity");
76 auto valueFind = item.second.find("Value");
77 if (valueFind == item.second.end() ||
78 severityFind == item.second.end() ||
79 directionFind == item.second.end())
80 {
81 std::cerr << "Malformed threshold in configuration\n";
82 return false;
83 }
84 Level level;
85 Direction direction;
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -070086 if (variant_ns::visit(VariantToUnsignedIntVisitor(),
87 severityFind->second) == 0)
James Feist139cb572018-09-10 15:26:18 -070088 {
89 level = Level::WARNING;
90 }
91 else
92 {
93 level = Level::CRITICAL;
94 }
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -070095 if (variant_ns::visit(VariantToStringVisitor(),
96 directionFind->second) == "less than")
James Feist139cb572018-09-10 15:26:18 -070097 {
98 direction = Direction::LOW;
99 }
100 else
101 {
102 direction = Direction::HIGH;
103 }
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -0700104 float val =
105 variant_ns::visit(VariantToFloatVisitor(), valueFind->second);
James Feist139cb572018-09-10 15:26:18 -0700106
107 thresholdVector.emplace_back(level, direction, val);
108 }
109 return true;
110}
111
112void persistThreshold(const std::string &path, const std::string &baseInterface,
113 const thresholds::Threshold &threshold,
114 std::shared_ptr<sdbusplus::asio::connection> &conn)
115{
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700116 for (int ii = 0; ii < maxThresholds; ii++)
James Feist139cb572018-09-10 15:26:18 -0700117 {
118 std::string thresholdInterface =
119 baseInterface + ".Thresholds" + std::to_string(ii);
120 conn->async_method_call(
121 [&, path, threshold, thresholdInterface](
122 const boost::system::error_code &ec,
123 const boost::container::flat_map<std::string, BasicVariantType>
124 &result) {
125 if (ec)
126 {
127 return; // threshold not supported
128 }
129
130 auto directionFind = result.find("Direction");
131 auto severityFind = result.find("Severity");
132 auto valueFind = result.find("Value");
133 if (valueFind == result.end() || severityFind == result.end() ||
134 directionFind == result.end())
135 {
136 std::cerr << "Malformed threshold in configuration\n";
137 return;
138 }
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -0700139 unsigned int level = variant_ns::visit(
James Feist139cb572018-09-10 15:26:18 -0700140 VariantToUnsignedIntVisitor(), severityFind->second);
141
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -0700142 std::string dir = variant_ns::visit(VariantToStringVisitor(),
143 directionFind->second);
James Feist139cb572018-09-10 15:26:18 -0700144 if ((toBusValue(threshold.level) != level) ||
145 (toBusValue(threshold.direction) != dir))
146 {
147 return; // not the droid we're looking for
148 }
149
150 sdbusplus::message::variant<double> value(threshold.value);
151 conn->async_method_call(
152 [](const boost::system::error_code &ec) {
153 if (ec)
154 {
155 std::cerr << "Error setting threshold " << ec
156 << "\n";
157 }
158 },
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700159 entityManagerName, path, "org.freedesktop.DBus.Properties",
160 "Set", thresholdInterface, "Value", value);
James Feist139cb572018-09-10 15:26:18 -0700161 },
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700162 entityManagerName, path, "org.freedesktop.DBus.Properties",
James Feist139cb572018-09-10 15:26:18 -0700163 "GetAll", thresholdInterface);
164 }
165}
166
James Feist39132a62018-10-31 12:53:20 -0700167bool checkThresholds(Sensor *sensor)
James Feistaf79dd32018-09-12 12:54:15 -0700168{
James Feist39132a62018-10-31 12:53:20 -0700169 bool status = true;
James Feistaf79dd32018-09-12 12:54:15 -0700170
171 if (sensor->thresholds.empty())
172 {
James Feist39132a62018-10-31 12:53:20 -0700173 return true;
James Feistaf79dd32018-09-12 12:54:15 -0700174 }
175 for (auto &threshold : sensor->thresholds)
176 {
James Feist39132a62018-10-31 12:53:20 -0700177 if (std::isnan(sensor->value))
178 {
179 threshold.asserted = false;
180 }
181 else if (threshold.direction == thresholds::Direction::HIGH)
James Feistaf79dd32018-09-12 12:54:15 -0700182 {
183 if (sensor->value > threshold.value && !threshold.asserted)
184 {
185 assertThresholds(sensor, threshold.level, threshold.direction,
186 true);
187 threshold.asserted = true;
188 }
189 else if (sensor->value <= threshold.value && threshold.asserted)
190 {
191 assertThresholds(sensor, threshold.level, threshold.direction,
192 false);
193 threshold.asserted = false;
194 }
195 }
196 else
197 {
198 if (sensor->value < threshold.value && !threshold.asserted)
199 {
200 assertThresholds(sensor, threshold.level, threshold.direction,
201 true);
202 threshold.asserted = true;
203 }
204 else if (sensor->value >= threshold.value && threshold.asserted)
205 {
206 assertThresholds(sensor, threshold.level, threshold.direction,
207 false);
208 threshold.asserted = false;
209 }
210 }
James Feist39132a62018-10-31 12:53:20 -0700211 if (threshold.level == thresholds::Level::CRITICAL &&
212 threshold.asserted)
213 {
214 status = false;
215 }
James Feistaf79dd32018-09-12 12:54:15 -0700216 }
James Feist39132a62018-10-31 12:53:20 -0700217 return status;
James Feistaf79dd32018-09-12 12:54:15 -0700218}
219
220void assertThresholds(Sensor *sensor, thresholds::Level level,
221 thresholds::Direction direction, bool assert)
222{
223 std::string property;
224 std::shared_ptr<sdbusplus::asio::dbus_interface> interface;
225 if (level == thresholds::Level::WARNING &&
226 direction == thresholds::Direction::HIGH)
227 {
228 property = "WarningAlarmHigh";
229 interface = sensor->thresholdInterfaceWarning;
230 }
231 else if (level == thresholds::Level::WARNING &&
232 direction == thresholds::Direction::LOW)
233 {
234 property = "WarningAlarmLow";
235 interface = sensor->thresholdInterfaceWarning;
236 }
237 else if (level == thresholds::Level::CRITICAL &&
238 direction == thresholds::Direction::HIGH)
239 {
240 property = "CriticalAlarmHigh";
241 interface = sensor->thresholdInterfaceCritical;
242 }
243 else if (level == thresholds::Level::CRITICAL &&
244 direction == thresholds::Direction::LOW)
245 {
246 property = "CriticalAlarmLow";
247 interface = sensor->thresholdInterfaceCritical;
248 }
249 else
250 {
251 std::cerr << "Unknown threshold, level " << level << "direction "
252 << direction << "\n";
253 return;
254 }
255 if (!interface)
256 {
257 std::cout << "trying to set uninitialized interface\n";
258 return;
259 }
260 interface->set_property(property, assert);
261}
262
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700263static constexpr std::array<const char *, 4> attrTypes = {"lcrit", "min", "max",
264 "crit"};
James Feist139cb572018-09-10 15:26:18 -0700265
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700266bool parseThresholdsFromAttr(
267 std::vector<thresholds::Threshold> &thresholdVector,
268 const std::string &inputPath, const double &scaleFactor)
James Feist139cb572018-09-10 15:26:18 -0700269{
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700270 for (auto &type : attrTypes)
James Feist139cb572018-09-10 15:26:18 -0700271 {
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700272 auto attrPath = boost::replace_all_copy(inputPath, "input", type);
273 std::ifstream attrFile(attrPath);
274 if (!attrFile.good())
275 {
James Feist139cb572018-09-10 15:26:18 -0700276 continue;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700277 }
James Feist139cb572018-09-10 15:26:18 -0700278 std::string attr;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700279 std::getline(attrFile, attr);
280 attrFile.close();
James Feist139cb572018-09-10 15:26:18 -0700281
282 Level level;
283 Direction direction;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700284 double val = std::stod(attr) / scaleFactor;
James Feist139cb572018-09-10 15:26:18 -0700285 if (type == "min" || type == "max")
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700286 {
James Feist139cb572018-09-10 15:26:18 -0700287 level = Level::WARNING;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700288 }
James Feist139cb572018-09-10 15:26:18 -0700289 else
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700290 {
James Feist139cb572018-09-10 15:26:18 -0700291 level = Level::CRITICAL;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700292 }
James Feist139cb572018-09-10 15:26:18 -0700293 if (type == "min" || type == "lcrit")
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700294 {
James Feist139cb572018-09-10 15:26:18 -0700295 direction = Direction::LOW;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700296 }
James Feist139cb572018-09-10 15:26:18 -0700297 else
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700298 {
James Feist139cb572018-09-10 15:26:18 -0700299 direction = Direction::HIGH;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700300 }
James Feist139cb572018-09-10 15:26:18 -0700301
302 if (DEBUG)
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700303 {
304 std::cout << "Threshold: " << attrPath << ": " << val << "\n";
305 }
James Feist139cb572018-09-10 15:26:18 -0700306
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700307 thresholdVector.emplace_back(level, direction, val);
James Feist139cb572018-09-10 15:26:18 -0700308 }
309 // no thresholds is allowed, not an error so return true always
310 return true;
311}
312
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700313bool hasCriticalInterface(
314 const std::vector<thresholds::Threshold> &thresholdVector)
James Feist139cb572018-09-10 15:26:18 -0700315{
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700316 for (auto &threshold : thresholdVector)
James Feist139cb572018-09-10 15:26:18 -0700317 {
318 if (threshold.level == Level::CRITICAL)
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700319 {
James Feist139cb572018-09-10 15:26:18 -0700320 return true;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700321 }
James Feist139cb572018-09-10 15:26:18 -0700322 }
323 return false;
324}
325
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700326bool hasWarningInterface(
327 const std::vector<thresholds::Threshold> &thresholdVector)
James Feist139cb572018-09-10 15:26:18 -0700328{
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700329 for (auto &threshold : thresholdVector)
James Feist139cb572018-09-10 15:26:18 -0700330 {
331 if (threshold.level == Level::WARNING)
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700332 {
James Feist139cb572018-09-10 15:26:18 -0700333 return true;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700334 }
James Feist139cb572018-09-10 15:26:18 -0700335 }
336 return false;
337}
338} // namespace thresholds