blob: fbac1909d4fb59638c2b03bd9263d257da98f4bd [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
Zhikui Ren291d6382020-09-25 15:06:04 -070019#include <boost/asio/io_service.hpp>
20#include <boost/asio/steady_timer.hpp>
James Feist03a02ad2019-02-06 12:38:50 -080021#include <boost/container/flat_map.hpp>
James Feist03a02ad2019-02-06 12:38:50 -080022#include <sdbusplus/asio/connection.hpp>
23#include <sdbusplus/asio/object_server.hpp>
Jason M. Bills0d5c0712020-12-08 10:10:47 -080024
James Feist03a02ad2019-02-06 12:38:50 -080025#include <variant>
26
27constexpr const char* fatalLedPath =
28 "/xyz/openbmc_project/led/groups/status_critical";
29constexpr const char* criticalLedPath =
30 "/xyz/openbmc_project/led/groups/status_non_critical";
31constexpr const char* warningLedPath =
32 "/xyz/openbmc_project/led/groups/status_degraded";
James Feiste409fc72019-03-05 12:19:43 -080033constexpr const char* okLedPath = "/xyz/openbmc_project/led/groups/status_ok";
James Feist03a02ad2019-02-06 12:38:50 -080034
35constexpr const char* ledIface = "xyz.openbmc_project.Led.Group";
36constexpr const char* ledAssertProp = "Asserted";
37constexpr const char* ledManagerBusname =
38 "xyz.openbmc_project.LED.GroupManager";
39
James Feistdc7bbdc2019-05-16 15:33:06 -070040std::unique_ptr<AssociationManager> associationManager;
41
James Feiste409fc72019-03-05 12:19:43 -080042enum class StatusSetting
43{
44 none,
45 ok,
46 warn,
47 critical,
48 fatal
49};
50
James Feist03a02ad2019-02-06 12:38:50 -080051constexpr const bool debug = false;
52
53// final led state tracking
James Feiste409fc72019-03-05 12:19:43 -080054StatusSetting currentPriority = StatusSetting::none;
James Feist03a02ad2019-02-06 12:38:50 -080055
56// maps of <object-path, <property, asserted>>
57boost::container::flat_map<std::string,
58 boost::container::flat_map<std::string, bool>>
59 fatalAssertMap;
60boost::container::flat_map<std::string,
61 boost::container::flat_map<std::string, bool>>
62 criticalAssertMap;
63boost::container::flat_map<std::string,
64 boost::container::flat_map<std::string, bool>>
65 warningAssertMap;
66
67std::vector<std::string> assertedInMap(
68 const boost::container::flat_map<
69 std::string, boost::container::flat_map<std::string, bool>>& map)
70{
71 std::vector<std::string> ret;
72 // if any of the properties are true, return true
73 for (const auto& pair : map)
74 {
75 for (const auto& item : pair.second)
76 {
77 if (item.second)
78 {
79 ret.push_back(pair.first);
80 }
81 }
82 }
83 return ret;
84}
85
Richard Marian Thomaiyar28161212019-04-13 21:11:23 +053086void updateLedStatus(std::shared_ptr<sdbusplus::asio::connection>& conn,
87 bool forceRefresh = false)
James Feist03a02ad2019-02-06 12:38:50 -080088{
James Feistdc7bbdc2019-05-16 15:33:06 -070089 std::vector<std::string> fatalVector = assertedInMap(fatalAssertMap);
90 bool fatal = fatalVector.size();
James Feist03a02ad2019-02-06 12:38:50 -080091
James Feistdc7bbdc2019-05-16 15:33:06 -070092 std::vector<std::string> criticalVector = assertedInMap(criticalAssertMap);
93 bool critical = criticalVector.size();
James Feist03a02ad2019-02-06 12:38:50 -080094
James Feistdc7bbdc2019-05-16 15:33:06 -070095 std::vector<std::string> warningVector = assertedInMap(warningAssertMap);
96 bool warn = warningVector.size();
James Feist03a02ad2019-02-06 12:38:50 -080097
James Feistdc7bbdc2019-05-16 15:33:06 -070098 associationManager->setLocalAssociations(fatalVector, criticalVector,
99 warningVector);
James Feiste409fc72019-03-05 12:19:43 -0800100
101 StatusSetting last = currentPriority;
sunitakx1a9dde92021-06-28 13:42:18 +0000102 std::vector<std::pair<std::string, std::variant<bool>>> ledsToSet;
103 if (forceRefresh)
104 {
105 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
106 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
107 ledsToSet.push_back(std::make_pair(warningLedPath, false));
108 ledsToSet.push_back(std::make_pair(okLedPath, false));
109 for (const auto& ledPair : ledsToSet)
110 {
111 conn->async_method_call(
112 [ledPair](const boost::system::error_code ec) {
113 if (ec)
114 {
115 std::cerr << "Cannot set " << ledPair.first << " to "
116 << std::boolalpha
117 << std::get<bool>(ledPair.second) << "\n";
118 }
119 if constexpr (debug)
120 {
121 std::cerr << "Set " << ledPair.first << " to "
122 << std::boolalpha
123 << std::get<bool>(ledPair.second) << "\n";
124 }
125 },
126 ledManagerBusname, ledPair.first,
127 "org.freedesktop.DBus.Properties", "Set", ledIface,
128 ledAssertProp, ledPair.second);
129 }
130 }
James Feiste409fc72019-03-05 12:19:43 -0800131 if (fatal)
James Feist03a02ad2019-02-06 12:38:50 -0800132 {
James Feiste409fc72019-03-05 12:19:43 -0800133 currentPriority = StatusSetting::fatal;
134 }
135 else if (critical)
136 {
137 currentPriority = StatusSetting::critical;
138 }
139 else if (warn)
140 {
141 currentPriority = StatusSetting::warn;
142 }
143 else
144 {
145 currentPriority = StatusSetting::ok;
146 }
147
Richard Marian Thomaiyar28161212019-04-13 21:11:23 +0530148 if (last != currentPriority || forceRefresh)
James Feiste409fc72019-03-05 12:19:43 -0800149 {
150 switch (currentPriority)
151 {
152 case (StatusSetting::fatal):
153 {
154 ledsToSet.push_back(std::make_pair(fatalLedPath, true));
155 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
156 ledsToSet.push_back(std::make_pair(warningLedPath, false));
157 ledsToSet.push_back(std::make_pair(okLedPath, false));
158 break;
159 }
160 case (StatusSetting::critical):
161 {
162 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
163 ledsToSet.push_back(std::make_pair(criticalLedPath, true));
164 ledsToSet.push_back(std::make_pair(warningLedPath, false));
165 ledsToSet.push_back(std::make_pair(okLedPath, false));
166 break;
167 }
168 case (StatusSetting::warn):
169 {
170 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
171 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
172 ledsToSet.push_back(std::make_pair(warningLedPath, true));
173 ledsToSet.push_back(std::make_pair(okLedPath, false));
174 break;
175 }
176 case (StatusSetting::ok):
177 {
178 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
179 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
180 ledsToSet.push_back(std::make_pair(warningLedPath, false));
181 ledsToSet.push_back(std::make_pair(okLedPath, true));
182 break;
183 }
184 }
James Feist03a02ad2019-02-06 12:38:50 -0800185 }
186
187 for (const auto& ledPair : ledsToSet)
188 {
189 conn->async_method_call(
190 [ledPair](const boost::system::error_code ec) {
191 if (ec)
192 {
193 std::cerr << "Cannot set " << ledPair.first << " to "
194 << std::boolalpha
195 << std::get<bool>(ledPair.second) << "\n";
196 }
197 if constexpr (debug)
198 {
199 std::cerr << "Set " << ledPair.first << " to "
200 << std::boolalpha
201 << std::get<bool>(ledPair.second) << "\n";
202 }
203 },
204 ledManagerBusname, ledPair.first, "org.freedesktop.DBus.Properties",
205 "Set", ledIface, ledAssertProp, ledPair.second);
206 }
207}
208
209void createThresholdMatch(std::shared_ptr<sdbusplus::asio::connection>& conn)
210{
James Feist03a02ad2019-02-06 12:38:50 -0800211
James Feist7b238402019-06-25 11:56:49 -0700212 static sdbusplus::bus::match::match match(
213 static_cast<sdbusplus::bus::bus&>(*conn),
214 "type='signal',interface='org.freedesktop.DBus.Properties',"
215 "path_"
216 "namespace='/xyz/openbmc_project/"
217 "sensors',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
James Feist03a02ad2019-02-06 12:38:50 -0800218 [&conn](sdbusplus::message::message& message) {
219 std::string objectName;
220 boost::container::flat_map<std::string, std::variant<bool>> values;
James Feist03a02ad2019-02-06 12:38:50 -0800221
James Feist7b238402019-06-25 11:56:49 -0700222 try
223 {
224 message.read(objectName, values);
225 }
226 catch (sdbusplus::exception_t&)
227 {
228 return;
229 }
James Feist03a02ad2019-02-06 12:38:50 -0800230 if constexpr (debug)
231 {
232 std::cerr << "Threshold callback " << message.get_path()
233 << "\n";
234 }
235
236 auto findCriticalLow = values.find("CriticalAlarmLow");
237 auto findCriticalHigh = values.find("CriticalAlarmHigh");
238
239 auto findWarnLow = values.find("WarningAlarmLow");
240 auto findWarnHigh = values.find("WarningAlarmHigh");
241
242 if (findCriticalLow != values.end())
243 {
244 criticalAssertMap[message.get_path()]["Low"] =
245 std::get<bool>(findCriticalLow->second);
246 }
247 if (findCriticalHigh != values.end())
248 {
249 criticalAssertMap[message.get_path()]["High"] =
250 std::get<bool>(findCriticalHigh->second);
251 }
252 if (findWarnLow != values.end())
253 {
254 warningAssertMap[message.get_path()]["Low"] =
255 std::get<bool>(findWarnLow->second);
256 }
257 if (findWarnHigh != values.end())
258 {
259 warningAssertMap[message.get_path()]["High"] =
260 std::get<bool>(findWarnHigh->second);
261 }
James Feist03a02ad2019-02-06 12:38:50 -0800262
James Feist7b238402019-06-25 11:56:49 -0700263 associationManager->setSensorAssociations(
264 assertedInMap(criticalAssertMap),
265 assertedInMap(warningAssertMap));
266
267 updateLedStatus(conn);
268 });
269}
270
271void createAssociationMatch(std::shared_ptr<sdbusplus::asio::connection>& conn)
272{
273 static sdbusplus::bus::match::match match(
James Feist03a02ad2019-02-06 12:38:50 -0800274 static_cast<sdbusplus::bus::bus&>(*conn),
James Feiste409fc72019-03-05 12:19:43 -0800275 "type='signal',interface='org.freedesktop.DBus.Properties',"
James Feist7b238402019-06-25 11:56:49 -0700276 "arg0namespace='" +
277 std::string(associationIface) + "'",
278 [&conn](sdbusplus::message::message& message) {
279 if (message.get_path() == rootPath)
280 {
281 return; // it's us
282 }
283 std::string objectName;
284 boost::container::flat_map<std::string,
285 std::variant<std::vector<Association>>>
286 values;
287 try
288 {
289 message.read(objectName, values);
290 }
291 catch (sdbusplus::exception_t&)
292 {
293 return;
294 }
295
296 if constexpr (debug)
297 {
298 std::cerr << "Association callback " << message.get_path()
299 << "\n";
300 }
301
James Feist56078402019-10-29 16:00:38 -0700302 auto findAssociations = values.find("Associations");
James Feist7b238402019-06-25 11:56:49 -0700303 if (findAssociations == values.end())
304 {
305 return;
306 }
307 const std::vector<Association>* associations =
308 std::get_if<std::vector<Association>>(
309 &findAssociations->second);
310
311 if (associations == nullptr)
312 {
313 std::cerr << "Illegal Association on " << message.get_path()
314 << "\n";
315 return;
316 }
317
318 bool localWarning = false;
319 bool localCritical = false;
320 bool globalWarning = false;
321 bool globalCritical = false;
322
323 for (const auto& [forward, reverse, path] : *associations)
324 {
325 if (path == rootPath)
326 {
327 globalWarning = globalWarning ? true : reverse == "warning";
328 globalCritical =
329 globalCritical ? true : reverse == "critical";
330
331 if constexpr (1)
332 {
333 std::cerr << "got global ";
334 }
335 }
336 else
337 {
338 localWarning = localWarning ? true : reverse == "warning";
339 localCritical =
340 localCritical ? true : reverse == "critical";
341 }
342 if (globalCritical && localCritical)
343 {
344 break;
345 }
346 }
347
348 bool fatal = globalCritical && localCritical;
349 bool critical = globalWarning && localCritical;
James Feist56078402019-10-29 16:00:38 -0700350 bool warning = globalWarning && !critical;
James Feist7b238402019-06-25 11:56:49 -0700351
352 fatalAssertMap[message.get_path()]["association"] = fatal;
353 criticalAssertMap[message.get_path()]["association"] = critical;
354 warningAssertMap[message.get_path()]["association"] = warning;
355
356 updateLedStatus(conn);
357 });
James Feist03a02ad2019-02-06 12:38:50 -0800358}
359
360int main(int argc, char** argv)
361{
362 boost::asio::io_service io;
363 auto conn = std::make_shared<sdbusplus::asio::connection>(io);
364 conn->request_name("xyz.openbmc_project.CallbackManager");
365 sdbusplus::asio::object_server objServer(conn);
James Feistdc7bbdc2019-05-16 15:33:06 -0700366 std::shared_ptr<sdbusplus::asio::dbus_interface> rootIface =
367 objServer.add_interface(rootPath,
James Feist03a02ad2019-02-06 12:38:50 -0800368 "xyz.openbmc_project.CallbackManager");
James Feistdc7bbdc2019-05-16 15:33:06 -0700369 rootIface->register_method("RetriggerLEDUpdate",
370 [&conn]() { updateLedStatus(conn, true); });
371 rootIface->initialize();
372
373 std::shared_ptr<sdbusplus::asio::dbus_interface> inventoryIface =
374 objServer.add_interface(rootPath, globalInventoryIface);
375 inventoryIface->initialize();
376
377 associationManager = std::make_unique<AssociationManager>(objServer, conn);
James Feist03a02ad2019-02-06 12:38:50 -0800378
379 createThresholdMatch(conn);
James Feist7b238402019-06-25 11:56:49 -0700380 createAssociationMatch(conn);
James Feiste409fc72019-03-05 12:19:43 -0800381 updateLedStatus(conn);
James Feist03a02ad2019-02-06 12:38:50 -0800382
383 io.run();
384
385 return 0;
386}