blob: ee4f7d0bdc3d83db791752f84d82f8854da537f6 [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>
5#include <fstream>
6#include <iostream>
James Feistaf79dd32018-09-12 12:54:15 -07007#include <sensor.hpp>
James Feist139cb572018-09-10 15:26:18 -07008
9static constexpr bool DEBUG = false;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -070010static constexpr size_t maxThresholds = 4;
James Feist139cb572018-09-10 15:26:18 -070011
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -070012namespace variant_ns = sdbusplus::message::variant_ns;
James Feist139cb572018-09-10 15:26:18 -070013namespace thresholds
14{
15unsigned int toBusValue(const Level &level)
16{
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
34std::string toBusValue(const Direction &direction)
35{
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 Yoof78ec412018-10-25 10:42:39 -070053bool parseThresholdsFromConfig(
James Feist139cb572018-09-10 15:26:18 -070054 const SensorData &sensorData,
55 std::vector<thresholds::Threshold> &thresholdVector,
56 const std::string *matchLabel)
57{
58 for (const auto &item : sensorData)
59 {
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;
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -070069 if (variant_ns::visit(VariantToStringVisitor(),
70 labelFind->second) != *matchLabel)
James Feist139cb572018-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;
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -070085 if (variant_ns::visit(VariantToUnsignedIntVisitor(),
86 severityFind->second) == 0)
James Feist139cb572018-09-10 15:26:18 -070087 {
88 level = Level::WARNING;
89 }
90 else
91 {
92 level = Level::CRITICAL;
93 }
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -070094 if (variant_ns::visit(VariantToStringVisitor(),
95 directionFind->second) == "less than")
James Feist139cb572018-09-10 15:26:18 -070096 {
97 direction = Direction::LOW;
98 }
99 else
100 {
101 direction = Direction::HIGH;
102 }
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -0700103 float val =
104 variant_ns::visit(VariantToFloatVisitor(), valueFind->second);
James Feist139cb572018-09-10 15:26:18 -0700105
106 thresholdVector.emplace_back(level, direction, val);
107 }
108 return true;
109}
110
111void persistThreshold(const std::string &path, const std::string &baseInterface,
112 const thresholds::Threshold &threshold,
113 std::shared_ptr<sdbusplus::asio::connection> &conn)
114{
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700115 for (int ii = 0; ii < maxThresholds; ii++)
James Feist139cb572018-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](
121 const boost::system::error_code &ec,
122 const boost::container::flat_map<std::string, BasicVariantType>
123 &result) {
124 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 }
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -0700138 unsigned int level = variant_ns::visit(
James Feist139cb572018-09-10 15:26:18 -0700139 VariantToUnsignedIntVisitor(), severityFind->second);
140
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -0700141 std::string dir = variant_ns::visit(VariantToStringVisitor(),
142 directionFind->second);
James Feist139cb572018-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
149 sdbusplus::message::variant<double> value(threshold.value);
150 conn->async_method_call(
151 [](const boost::system::error_code &ec) {
152 if (ec)
153 {
154 std::cerr << "Error setting threshold " << ec
155 << "\n";
156 }
157 },
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700158 entityManagerName, path, "org.freedesktop.DBus.Properties",
159 "Set", thresholdInterface, "Value", value);
James Feist139cb572018-09-10 15:26:18 -0700160 },
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700161 entityManagerName, path, "org.freedesktop.DBus.Properties",
James Feist139cb572018-09-10 15:26:18 -0700162 "GetAll", thresholdInterface);
163 }
164}
165
James Feistaf79dd32018-09-12 12:54:15 -0700166void checkThresholds(Sensor *sensor)
167{
168
169 if (sensor->thresholds.empty())
170 {
171 return;
172 }
173 for (auto &threshold : sensor->thresholds)
174 {
175 if (threshold.direction == thresholds::Direction::HIGH)
176 {
177 if (sensor->value > threshold.value && !threshold.asserted)
178 {
179 assertThresholds(sensor, threshold.level, threshold.direction,
180 true);
181 threshold.asserted = true;
182 }
183 else if (sensor->value <= threshold.value && threshold.asserted)
184 {
185 assertThresholds(sensor, threshold.level, threshold.direction,
186 false);
187 threshold.asserted = false;
188 }
189 }
190 else
191 {
192 if (sensor->value < threshold.value && !threshold.asserted)
193 {
194 assertThresholds(sensor, threshold.level, threshold.direction,
195 true);
196 threshold.asserted = true;
197 }
198 else if (sensor->value >= threshold.value && threshold.asserted)
199 {
200 assertThresholds(sensor, threshold.level, threshold.direction,
201 false);
202 threshold.asserted = false;
203 }
204 }
205 }
206}
207
208void assertThresholds(Sensor *sensor, thresholds::Level level,
209 thresholds::Direction direction, bool assert)
210{
211 std::string property;
212 std::shared_ptr<sdbusplus::asio::dbus_interface> interface;
213 if (level == thresholds::Level::WARNING &&
214 direction == thresholds::Direction::HIGH)
215 {
216 property = "WarningAlarmHigh";
217 interface = sensor->thresholdInterfaceWarning;
218 }
219 else if (level == thresholds::Level::WARNING &&
220 direction == thresholds::Direction::LOW)
221 {
222 property = "WarningAlarmLow";
223 interface = sensor->thresholdInterfaceWarning;
224 }
225 else if (level == thresholds::Level::CRITICAL &&
226 direction == thresholds::Direction::HIGH)
227 {
228 property = "CriticalAlarmHigh";
229 interface = sensor->thresholdInterfaceCritical;
230 }
231 else if (level == thresholds::Level::CRITICAL &&
232 direction == thresholds::Direction::LOW)
233 {
234 property = "CriticalAlarmLow";
235 interface = sensor->thresholdInterfaceCritical;
236 }
237 else
238 {
239 std::cerr << "Unknown threshold, level " << level << "direction "
240 << direction << "\n";
241 return;
242 }
243 if (!interface)
244 {
245 std::cout << "trying to set uninitialized interface\n";
246 return;
247 }
248 interface->set_property(property, assert);
249}
250
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700251static constexpr std::array<const char *, 4> attrTypes = {"lcrit", "min", "max",
252 "crit"};
James Feist139cb572018-09-10 15:26:18 -0700253
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700254bool parseThresholdsFromAttr(
255 std::vector<thresholds::Threshold> &thresholdVector,
256 const std::string &inputPath, const double &scaleFactor)
James Feist139cb572018-09-10 15:26:18 -0700257{
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700258 for (auto &type : attrTypes)
James Feist139cb572018-09-10 15:26:18 -0700259 {
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700260 auto attrPath = boost::replace_all_copy(inputPath, "input", type);
261 std::ifstream attrFile(attrPath);
262 if (!attrFile.good())
263 {
James Feist139cb572018-09-10 15:26:18 -0700264 continue;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700265 }
James Feist139cb572018-09-10 15:26:18 -0700266 std::string attr;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700267 std::getline(attrFile, attr);
268 attrFile.close();
James Feist139cb572018-09-10 15:26:18 -0700269
270 Level level;
271 Direction direction;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700272 double val = std::stod(attr) / scaleFactor;
James Feist139cb572018-09-10 15:26:18 -0700273 if (type == "min" || type == "max")
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700274 {
James Feist139cb572018-09-10 15:26:18 -0700275 level = Level::WARNING;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700276 }
James Feist139cb572018-09-10 15:26:18 -0700277 else
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700278 {
James Feist139cb572018-09-10 15:26:18 -0700279 level = Level::CRITICAL;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700280 }
James Feist139cb572018-09-10 15:26:18 -0700281 if (type == "min" || type == "lcrit")
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700282 {
James Feist139cb572018-09-10 15:26:18 -0700283 direction = Direction::LOW;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700284 }
James Feist139cb572018-09-10 15:26:18 -0700285 else
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700286 {
James Feist139cb572018-09-10 15:26:18 -0700287 direction = Direction::HIGH;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700288 }
James Feist139cb572018-09-10 15:26:18 -0700289
290 if (DEBUG)
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700291 {
292 std::cout << "Threshold: " << attrPath << ": " << val << "\n";
293 }
James Feist139cb572018-09-10 15:26:18 -0700294
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700295 thresholdVector.emplace_back(level, direction, val);
James Feist139cb572018-09-10 15:26:18 -0700296 }
297 // no thresholds is allowed, not an error so return true always
298 return true;
299}
300
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700301bool hasCriticalInterface(
302 const std::vector<thresholds::Threshold> &thresholdVector)
James Feist139cb572018-09-10 15:26:18 -0700303{
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700304 for (auto &threshold : thresholdVector)
James Feist139cb572018-09-10 15:26:18 -0700305 {
306 if (threshold.level == Level::CRITICAL)
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700307 {
James Feist139cb572018-09-10 15:26:18 -0700308 return true;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700309 }
James Feist139cb572018-09-10 15:26:18 -0700310 }
311 return false;
312}
313
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700314bool hasWarningInterface(
315 const std::vector<thresholds::Threshold> &thresholdVector)
James Feist139cb572018-09-10 15:26:18 -0700316{
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700317 for (auto &threshold : thresholdVector)
James Feist139cb572018-09-10 15:26:18 -0700318 {
319 if (threshold.level == Level::WARNING)
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700320 {
James Feist139cb572018-09-10 15:26:18 -0700321 return true;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700322 }
James Feist139cb572018-09-10 15:26:18 -0700323 }
324 return false;
325}
326} // namespace thresholds