blob: 725829e3fe566319a713de50675c2433c2a17110 [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
James Feistd8705872019-02-08 13:26:09 -0800165bool checkThresholds(Sensor* sensor)
James Feist251c7822018-09-12 12:54:15 -0700166{
James Feistdc6c55f2018-10-31 12:53:20 -0700167 bool status = true;
James Feist251c7822018-09-12 12:54:15 -0700168
169 if (sensor->thresholds.empty())
170 {
James Feistdc6c55f2018-10-31 12:53:20 -0700171 return true;
James Feist251c7822018-09-12 12:54:15 -0700172 }
James Feistd8705872019-02-08 13:26:09 -0800173 for (auto& threshold : sensor->thresholds)
James Feist251c7822018-09-12 12:54:15 -0700174 {
James Feistdc6c55f2018-10-31 12:53:20 -0700175 if (std::isnan(sensor->value))
176 {
177 threshold.asserted = false;
178 }
179 else if (threshold.direction == thresholds::Direction::HIGH)
James Feist251c7822018-09-12 12:54:15 -0700180 {
181 if (sensor->value > threshold.value && !threshold.asserted)
182 {
183 assertThresholds(sensor, threshold.level, threshold.direction,
184 true);
185 threshold.asserted = true;
186 }
187 else if (sensor->value <= threshold.value && threshold.asserted)
188 {
189 assertThresholds(sensor, threshold.level, threshold.direction,
190 false);
191 threshold.asserted = false;
192 }
193 }
194 else
195 {
196 if (sensor->value < threshold.value && !threshold.asserted)
197 {
198 assertThresholds(sensor, threshold.level, threshold.direction,
199 true);
200 threshold.asserted = true;
201 }
202 else if (sensor->value >= threshold.value && threshold.asserted)
203 {
204 assertThresholds(sensor, threshold.level, threshold.direction,
205 false);
206 threshold.asserted = false;
207 }
208 }
James Feistdc6c55f2018-10-31 12:53:20 -0700209 if (threshold.level == thresholds::Level::CRITICAL &&
210 threshold.asserted)
211 {
212 status = false;
213 }
James Feist251c7822018-09-12 12:54:15 -0700214 }
James Feistdc6c55f2018-10-31 12:53:20 -0700215 return status;
James Feist251c7822018-09-12 12:54:15 -0700216}
217
James Feistd8705872019-02-08 13:26:09 -0800218void assertThresholds(Sensor* sensor, thresholds::Level level,
James Feist251c7822018-09-12 12:54:15 -0700219 thresholds::Direction direction, bool assert)
220{
221 std::string property;
222 std::shared_ptr<sdbusplus::asio::dbus_interface> interface;
223 if (level == thresholds::Level::WARNING &&
224 direction == thresholds::Direction::HIGH)
225 {
226 property = "WarningAlarmHigh";
227 interface = sensor->thresholdInterfaceWarning;
228 }
229 else if (level == thresholds::Level::WARNING &&
230 direction == thresholds::Direction::LOW)
231 {
232 property = "WarningAlarmLow";
233 interface = sensor->thresholdInterfaceWarning;
234 }
235 else if (level == thresholds::Level::CRITICAL &&
236 direction == thresholds::Direction::HIGH)
237 {
238 property = "CriticalAlarmHigh";
239 interface = sensor->thresholdInterfaceCritical;
240 }
241 else if (level == thresholds::Level::CRITICAL &&
242 direction == thresholds::Direction::LOW)
243 {
244 property = "CriticalAlarmLow";
245 interface = sensor->thresholdInterfaceCritical;
246 }
247 else
248 {
249 std::cerr << "Unknown threshold, level " << level << "direction "
250 << direction << "\n";
251 return;
252 }
253 if (!interface)
254 {
255 std::cout << "trying to set uninitialized interface\n";
256 return;
257 }
258 interface->set_property(property, assert);
259}
260
James Feistd8705872019-02-08 13:26:09 -0800261static constexpr std::array<const char*, 4> attrTypes = {"lcrit", "min", "max",
262 "crit"};
James Feist6714a252018-09-10 15:26:18 -0700263
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700264bool parseThresholdsFromAttr(
James Feistd8705872019-02-08 13:26:09 -0800265 std::vector<thresholds::Threshold>& thresholdVector,
266 const std::string& inputPath, const double& scaleFactor)
James Feist6714a252018-09-10 15:26:18 -0700267{
James Feistd8705872019-02-08 13:26:09 -0800268 for (auto& type : attrTypes)
James Feist6714a252018-09-10 15:26:18 -0700269 {
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700270 auto attrPath = boost::replace_all_copy(inputPath, "input", type);
271 std::ifstream attrFile(attrPath);
272 if (!attrFile.good())
273 {
James Feist6714a252018-09-10 15:26:18 -0700274 continue;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700275 }
James Feist6714a252018-09-10 15:26:18 -0700276 std::string attr;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700277 std::getline(attrFile, attr);
278 attrFile.close();
James Feist6714a252018-09-10 15:26:18 -0700279
280 Level level;
281 Direction direction;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700282 double val = std::stod(attr) / scaleFactor;
James Feist6714a252018-09-10 15:26:18 -0700283 if (type == "min" || type == "max")
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700284 {
James Feist6714a252018-09-10 15:26:18 -0700285 level = Level::WARNING;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700286 }
James Feist6714a252018-09-10 15:26:18 -0700287 else
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700288 {
James Feist6714a252018-09-10 15:26:18 -0700289 level = Level::CRITICAL;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700290 }
James Feist6714a252018-09-10 15:26:18 -0700291 if (type == "min" || type == "lcrit")
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700292 {
James Feist6714a252018-09-10 15:26:18 -0700293 direction = Direction::LOW;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700294 }
James Feist6714a252018-09-10 15:26:18 -0700295 else
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700296 {
James Feist6714a252018-09-10 15:26:18 -0700297 direction = Direction::HIGH;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700298 }
James Feist6714a252018-09-10 15:26:18 -0700299
300 if (DEBUG)
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700301 {
302 std::cout << "Threshold: " << attrPath << ": " << val << "\n";
303 }
James Feist6714a252018-09-10 15:26:18 -0700304
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700305 thresholdVector.emplace_back(level, direction, val);
James Feist6714a252018-09-10 15:26:18 -0700306 }
307 // no thresholds is allowed, not an error so return true always
308 return true;
309}
310
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700311bool hasCriticalInterface(
James Feistd8705872019-02-08 13:26:09 -0800312 const std::vector<thresholds::Threshold>& thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700313{
James Feistd8705872019-02-08 13:26:09 -0800314 for (auto& threshold : thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700315 {
316 if (threshold.level == Level::CRITICAL)
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700317 {
James Feist6714a252018-09-10 15:26:18 -0700318 return true;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700319 }
James Feist6714a252018-09-10 15:26:18 -0700320 }
321 return false;
322}
323
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700324bool hasWarningInterface(
James Feistd8705872019-02-08 13:26:09 -0800325 const std::vector<thresholds::Threshold>& thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700326{
James Feistd8705872019-02-08 13:26:09 -0800327 for (auto& threshold : thresholdVector)
James Feist6714a252018-09-10 15:26:18 -0700328 {
329 if (threshold.level == Level::WARNING)
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700330 {
James Feist6714a252018-09-10 15:26:18 -0700331 return true;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700332 }
James Feist6714a252018-09-10 15:26:18 -0700333 }
334 return false;
335}
336} // namespace thresholds