blob: ac2fb02f75c8b0c249a12098160f97ebe447aa39 [file] [log] [blame]
James Feist03a02ad2019-02-06 12:38:50 -08001/*
2// Copyright (c) 2019 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
James Feistdc7bbdc2019-05-16 15:33:06 -070017#include "callback_manager.hpp"
18
James Feist03a02ad2019-02-06 12:38:50 -080019#include <boost/container/flat_map.hpp>
James Feist03a02ad2019-02-06 12:38:50 -080020#include <sdbusplus/asio/connection.hpp>
21#include <sdbusplus/asio/object_server.hpp>
22#include <variant>
23
24constexpr const char* fatalLedPath =
25 "/xyz/openbmc_project/led/groups/status_critical";
26constexpr const char* criticalLedPath =
27 "/xyz/openbmc_project/led/groups/status_non_critical";
28constexpr const char* warningLedPath =
29 "/xyz/openbmc_project/led/groups/status_degraded";
James Feiste409fc72019-03-05 12:19:43 -080030constexpr const char* okLedPath = "/xyz/openbmc_project/led/groups/status_ok";
James Feist03a02ad2019-02-06 12:38:50 -080031
32constexpr const char* ledIface = "xyz.openbmc_project.Led.Group";
33constexpr const char* ledAssertProp = "Asserted";
34constexpr const char* ledManagerBusname =
35 "xyz.openbmc_project.LED.GroupManager";
36
James Feistdc7bbdc2019-05-16 15:33:06 -070037std::unique_ptr<AssociationManager> associationManager;
38
James Feiste409fc72019-03-05 12:19:43 -080039enum class StatusSetting
40{
41 none,
42 ok,
43 warn,
44 critical,
45 fatal
46};
47
James Feist03a02ad2019-02-06 12:38:50 -080048constexpr const bool debug = false;
49
50// final led state tracking
James Feiste409fc72019-03-05 12:19:43 -080051StatusSetting currentPriority = StatusSetting::none;
James Feist03a02ad2019-02-06 12:38:50 -080052
53// maps of <object-path, <property, asserted>>
54boost::container::flat_map<std::string,
55 boost::container::flat_map<std::string, bool>>
56 fatalAssertMap;
57boost::container::flat_map<std::string,
58 boost::container::flat_map<std::string, bool>>
59 criticalAssertMap;
60boost::container::flat_map<std::string,
61 boost::container::flat_map<std::string, bool>>
62 warningAssertMap;
63
64std::vector<std::string> assertedInMap(
65 const boost::container::flat_map<
66 std::string, boost::container::flat_map<std::string, bool>>& map)
67{
68 std::vector<std::string> ret;
69 // if any of the properties are true, return true
70 for (const auto& pair : map)
71 {
72 for (const auto& item : pair.second)
73 {
74 if (item.second)
75 {
76 ret.push_back(pair.first);
77 }
78 }
79 }
80 return ret;
81}
82
Richard Marian Thomaiyar28161212019-04-13 21:11:23 +053083void updateLedStatus(std::shared_ptr<sdbusplus::asio::connection>& conn,
84 bool forceRefresh = false)
James Feist03a02ad2019-02-06 12:38:50 -080085{
James Feistdc7bbdc2019-05-16 15:33:06 -070086 std::vector<std::string> fatalVector = assertedInMap(fatalAssertMap);
87 bool fatal = fatalVector.size();
James Feist03a02ad2019-02-06 12:38:50 -080088
James Feistdc7bbdc2019-05-16 15:33:06 -070089 std::vector<std::string> criticalVector = assertedInMap(criticalAssertMap);
90 bool critical = criticalVector.size();
James Feist03a02ad2019-02-06 12:38:50 -080091
James Feistdc7bbdc2019-05-16 15:33:06 -070092 std::vector<std::string> warningVector = assertedInMap(warningAssertMap);
93 bool warn = warningVector.size();
James Feist03a02ad2019-02-06 12:38:50 -080094
James Feistdc7bbdc2019-05-16 15:33:06 -070095 associationManager->setLocalAssociations(fatalVector, criticalVector,
96 warningVector);
James Feiste409fc72019-03-05 12:19:43 -080097
98 StatusSetting last = currentPriority;
99
100 if (fatal)
James Feist03a02ad2019-02-06 12:38:50 -0800101 {
James Feiste409fc72019-03-05 12:19:43 -0800102 currentPriority = StatusSetting::fatal;
103 }
104 else if (critical)
105 {
106 currentPriority = StatusSetting::critical;
107 }
108 else if (warn)
109 {
110 currentPriority = StatusSetting::warn;
111 }
112 else
113 {
114 currentPriority = StatusSetting::ok;
115 }
116
117 std::vector<std::pair<std::string, std::variant<bool>>> ledsToSet;
118
Richard Marian Thomaiyar28161212019-04-13 21:11:23 +0530119 if (last != currentPriority || forceRefresh)
James Feiste409fc72019-03-05 12:19:43 -0800120 {
121 switch (currentPriority)
122 {
123 case (StatusSetting::fatal):
124 {
125 ledsToSet.push_back(std::make_pair(fatalLedPath, true));
126 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
127 ledsToSet.push_back(std::make_pair(warningLedPath, false));
128 ledsToSet.push_back(std::make_pair(okLedPath, false));
129 break;
130 }
131 case (StatusSetting::critical):
132 {
133 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
134 ledsToSet.push_back(std::make_pair(criticalLedPath, true));
135 ledsToSet.push_back(std::make_pair(warningLedPath, false));
136 ledsToSet.push_back(std::make_pair(okLedPath, false));
137 break;
138 }
139 case (StatusSetting::warn):
140 {
141 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
142 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
143 ledsToSet.push_back(std::make_pair(warningLedPath, true));
144 ledsToSet.push_back(std::make_pair(okLedPath, false));
145 break;
146 }
147 case (StatusSetting::ok):
148 {
149 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
150 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
151 ledsToSet.push_back(std::make_pair(warningLedPath, false));
152 ledsToSet.push_back(std::make_pair(okLedPath, true));
153 break;
154 }
155 }
James Feist03a02ad2019-02-06 12:38:50 -0800156 }
157
158 for (const auto& ledPair : ledsToSet)
159 {
160 conn->async_method_call(
161 [ledPair](const boost::system::error_code ec) {
162 if (ec)
163 {
164 std::cerr << "Cannot set " << ledPair.first << " to "
165 << std::boolalpha
166 << std::get<bool>(ledPair.second) << "\n";
167 }
168 if constexpr (debug)
169 {
170 std::cerr << "Set " << ledPair.first << " to "
171 << std::boolalpha
172 << std::get<bool>(ledPair.second) << "\n";
173 }
174 },
175 ledManagerBusname, ledPair.first, "org.freedesktop.DBus.Properties",
176 "Set", ledIface, ledAssertProp, ledPair.second);
177 }
178}
179
180void createThresholdMatch(std::shared_ptr<sdbusplus::asio::connection>& conn)
181{
James Feist03a02ad2019-02-06 12:38:50 -0800182
James Feist7b238402019-06-25 11:56:49 -0700183 static sdbusplus::bus::match::match match(
184 static_cast<sdbusplus::bus::bus&>(*conn),
185 "type='signal',interface='org.freedesktop.DBus.Properties',"
186 "path_"
187 "namespace='/xyz/openbmc_project/"
188 "sensors',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
James Feist03a02ad2019-02-06 12:38:50 -0800189 [&conn](sdbusplus::message::message& message) {
190 std::string objectName;
191 boost::container::flat_map<std::string, std::variant<bool>> values;
James Feist03a02ad2019-02-06 12:38:50 -0800192
James Feist7b238402019-06-25 11:56:49 -0700193 try
194 {
195 message.read(objectName, values);
196 }
197 catch (sdbusplus::exception_t&)
198 {
199 return;
200 }
James Feist03a02ad2019-02-06 12:38:50 -0800201 if constexpr (debug)
202 {
203 std::cerr << "Threshold callback " << message.get_path()
204 << "\n";
205 }
206
207 auto findCriticalLow = values.find("CriticalAlarmLow");
208 auto findCriticalHigh = values.find("CriticalAlarmHigh");
209
210 auto findWarnLow = values.find("WarningAlarmLow");
211 auto findWarnHigh = values.find("WarningAlarmHigh");
212
213 if (findCriticalLow != values.end())
214 {
215 criticalAssertMap[message.get_path()]["Low"] =
216 std::get<bool>(findCriticalLow->second);
217 }
218 if (findCriticalHigh != values.end())
219 {
220 criticalAssertMap[message.get_path()]["High"] =
221 std::get<bool>(findCriticalHigh->second);
222 }
223 if (findWarnLow != values.end())
224 {
225 warningAssertMap[message.get_path()]["Low"] =
226 std::get<bool>(findWarnLow->second);
227 }
228 if (findWarnHigh != values.end())
229 {
230 warningAssertMap[message.get_path()]["High"] =
231 std::get<bool>(findWarnHigh->second);
232 }
James Feist03a02ad2019-02-06 12:38:50 -0800233
James Feist7b238402019-06-25 11:56:49 -0700234 associationManager->setSensorAssociations(
235 assertedInMap(criticalAssertMap),
236 assertedInMap(warningAssertMap));
237
238 updateLedStatus(conn);
239 });
240}
241
242void createAssociationMatch(std::shared_ptr<sdbusplus::asio::connection>& conn)
243{
244 static sdbusplus::bus::match::match match(
James Feist03a02ad2019-02-06 12:38:50 -0800245 static_cast<sdbusplus::bus::bus&>(*conn),
James Feiste409fc72019-03-05 12:19:43 -0800246 "type='signal',interface='org.freedesktop.DBus.Properties',"
James Feist7b238402019-06-25 11:56:49 -0700247 "arg0namespace='" +
248 std::string(associationIface) + "'",
249 [&conn](sdbusplus::message::message& message) {
250 if (message.get_path() == rootPath)
251 {
252 return; // it's us
253 }
254 std::string objectName;
255 boost::container::flat_map<std::string,
256 std::variant<std::vector<Association>>>
257 values;
258 try
259 {
260 message.read(objectName, values);
261 }
262 catch (sdbusplus::exception_t&)
263 {
264 return;
265 }
266
267 if constexpr (debug)
268 {
269 std::cerr << "Association callback " << message.get_path()
270 << "\n";
271 }
272
273 auto findAssociations = values.find("associations");
274 if (findAssociations == values.end())
275 {
276 return;
277 }
278 const std::vector<Association>* associations =
279 std::get_if<std::vector<Association>>(
280 &findAssociations->second);
281
282 if (associations == nullptr)
283 {
284 std::cerr << "Illegal Association on " << message.get_path()
285 << "\n";
286 return;
287 }
288
289 bool localWarning = false;
290 bool localCritical = false;
291 bool globalWarning = false;
292 bool globalCritical = false;
293
294 for (const auto& [forward, reverse, path] : *associations)
295 {
296 if (path == rootPath)
297 {
298 globalWarning = globalWarning ? true : reverse == "warning";
299 globalCritical =
300 globalCritical ? true : reverse == "critical";
301
302 if constexpr (1)
303 {
304 std::cerr << "got global ";
305 }
306 }
307 else
308 {
309 localWarning = localWarning ? true : reverse == "warning";
310 localCritical =
311 localCritical ? true : reverse == "critical";
312 }
313 if (globalCritical && localCritical)
314 {
315 break;
316 }
317 }
318
319 bool fatal = globalCritical && localCritical;
320 bool critical = globalWarning && localCritical;
321 bool warning = globalWarning && localWarning;
322
323 fatalAssertMap[message.get_path()]["association"] = fatal;
324 criticalAssertMap[message.get_path()]["association"] = critical;
325 warningAssertMap[message.get_path()]["association"] = warning;
326
327 updateLedStatus(conn);
328 });
James Feist03a02ad2019-02-06 12:38:50 -0800329}
330
331int main(int argc, char** argv)
332{
333 boost::asio::io_service io;
334 auto conn = std::make_shared<sdbusplus::asio::connection>(io);
335 conn->request_name("xyz.openbmc_project.CallbackManager");
336 sdbusplus::asio::object_server objServer(conn);
James Feistdc7bbdc2019-05-16 15:33:06 -0700337 std::shared_ptr<sdbusplus::asio::dbus_interface> rootIface =
338 objServer.add_interface(rootPath,
James Feist03a02ad2019-02-06 12:38:50 -0800339 "xyz.openbmc_project.CallbackManager");
James Feistdc7bbdc2019-05-16 15:33:06 -0700340 rootIface->register_method("RetriggerLEDUpdate",
341 [&conn]() { updateLedStatus(conn, true); });
342 rootIface->initialize();
343
344 std::shared_ptr<sdbusplus::asio::dbus_interface> inventoryIface =
345 objServer.add_interface(rootPath, globalInventoryIface);
346 inventoryIface->initialize();
347
348 associationManager = std::make_unique<AssociationManager>(objServer, conn);
James Feist03a02ad2019-02-06 12:38:50 -0800349
350 createThresholdMatch(conn);
James Feist7b238402019-06-25 11:56:49 -0700351 createAssociationMatch(conn);
James Feiste409fc72019-03-05 12:19:43 -0800352 updateLedStatus(conn);
James Feist03a02ad2019-02-06 12:38:50 -0800353
354 io.run();
355
356 return 0;
357}