blob: b792a9bbc3e4ae5a44142456c17bb9d21e8e0175 [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;
10constexpr size_t MAX_THRESHOLDS = 4;
11
12namespace thresholds
13{
14unsigned int toBusValue(const Level &level)
15{
16 switch (level)
17 {
18 case (Level::WARNING):
19 {
20 return 0;
21 }
22 case (Level::CRITICAL):
23 {
24 return 1;
25 }
26 default:
27 {
28 return -1;
29 }
30 }
31}
32
33std::string toBusValue(const Direction &direction)
34{
35 switch (direction)
36 {
37 case (Direction::LOW):
38 {
39 return "less than";
40 }
41 case (Direction::HIGH):
42 {
43 return "greater than";
44 }
45 default:
46 {
47 return "err";
48 }
49 }
50}
51
52bool ParseThresholdsFromConfig(
53 const SensorData &sensorData,
54 std::vector<thresholds::Threshold> &thresholdVector,
55 const std::string *matchLabel)
56{
57 for (const auto &item : sensorData)
58 {
59 if (item.first.find("Thresholds") == std::string::npos)
60 {
61 continue;
62 }
63 if (matchLabel != nullptr)
64 {
65 auto labelFind = item.second.find("Label");
66 if (labelFind == item.second.end())
67 continue;
68 if (mapbox::util::apply_visitor(VariantToStringVisitor(),
69 labelFind->second) != *matchLabel)
70 continue;
71 }
72 auto directionFind = item.second.find("Direction");
73 auto severityFind = item.second.find("Severity");
74 auto valueFind = item.second.find("Value");
75 if (valueFind == item.second.end() ||
76 severityFind == item.second.end() ||
77 directionFind == item.second.end())
78 {
79 std::cerr << "Malformed threshold in configuration\n";
80 return false;
81 }
82 Level level;
83 Direction direction;
84 if (mapbox::util::apply_visitor(VariantToUnsignedIntVisitor(),
85 severityFind->second) == 0)
86 {
87 level = Level::WARNING;
88 }
89 else
90 {
91 level = Level::CRITICAL;
92 }
93 if (mapbox::util::apply_visitor(VariantToStringVisitor(),
94 directionFind->second) == "less than")
95 {
96 direction = Direction::LOW;
97 }
98 else
99 {
100 direction = Direction::HIGH;
101 }
102 float val = mapbox::util::apply_visitor(VariantToFloatVisitor(),
103 valueFind->second);
104
105 thresholdVector.emplace_back(level, direction, val);
106 }
107 return true;
108}
109
110void persistThreshold(const std::string &path, const std::string &baseInterface,
111 const thresholds::Threshold &threshold,
112 std::shared_ptr<sdbusplus::asio::connection> &conn)
113{
114 for (int ii = 0; ii < MAX_THRESHOLDS; ii++)
115 {
116 std::string thresholdInterface =
117 baseInterface + ".Thresholds" + std::to_string(ii);
118 conn->async_method_call(
119 [&, path, threshold, thresholdInterface](
120 const boost::system::error_code &ec,
121 const boost::container::flat_map<std::string, BasicVariantType>
122 &result) {
123 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 }
137 unsigned int level = mapbox::util::apply_visitor(
138 VariantToUnsignedIntVisitor(), severityFind->second);
139
140 std::string dir = mapbox::util::apply_visitor(
141 VariantToStringVisitor(), directionFind->second);
142 if ((toBusValue(threshold.level) != level) ||
143 (toBusValue(threshold.direction) != dir))
144 {
145 return; // not the droid we're looking for
146 }
147
148 sdbusplus::message::variant<double> value(threshold.value);
149 conn->async_method_call(
150 [](const boost::system::error_code &ec) {
151 if (ec)
152 {
153 std::cerr << "Error setting threshold " << ec
154 << "\n";
155 }
156 },
157 ENTITY_MANAGER_NAME, path,
158 "org.freedesktop.DBus.Properties", "Set",
159 thresholdInterface, "Value", value);
160 },
161 ENTITY_MANAGER_NAME, path, "org.freedesktop.DBus.Properties",
162 "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
James Feist139cb572018-09-10 15:26:18 -0700251static constexpr std::array<const char *, 4> ATTR_TYPES = {"lcrit", "min",
252 "max", "crit"};
253
254bool ParseThresholdsFromAttr(
255 std::vector<thresholds::Threshold> &threshold_vector,
256 const std::string &input_path, const double scale_factor)
257{
258 for (auto &type : ATTR_TYPES)
259 {
260 auto attr_path = boost::replace_all_copy(input_path, "input", type);
261 std::ifstream attr_file(attr_path);
262 if (!attr_file.good())
263 continue;
264 std::string attr;
265 std::getline(attr_file, attr);
266 attr_file.close();
267
268 Level level;
269 Direction direction;
270 double val = std::stod(attr) / scale_factor;
271 if (type == "min" || type == "max")
272 level = Level::WARNING;
273 else
274 level = Level::CRITICAL;
275 if (type == "min" || type == "lcrit")
276 direction = Direction::LOW;
277 else
278 direction = Direction::HIGH;
279
280 if (DEBUG)
281 std::cout << "Threshold: " << attr_path << ": " << val << "\n";
282
283 threshold_vector.emplace_back(level, direction, val);
284 }
285 // no thresholds is allowed, not an error so return true always
286 return true;
287}
288
289bool HasCriticalInterface(
290 const std::vector<thresholds::Threshold> &threshold_vector)
291{
292 for (auto &threshold : threshold_vector)
293 {
294 if (threshold.level == Level::CRITICAL)
295 return true;
296 }
297 return false;
298}
299
300bool HasWarningInterface(
301 const std::vector<thresholds::Threshold> &threshold_vector)
302{
303 for (auto &threshold : threshold_vector)
304 {
305 if (threshold.level == Level::WARNING)
306 return true;
307 }
308 return false;
309}
310} // namespace thresholds