blob: 15e96b04e9fa6b8551845da03fed2aa1876a70a2 [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;
102
103 if (fatal)
James Feist03a02ad2019-02-06 12:38:50 -0800104 {
James Feiste409fc72019-03-05 12:19:43 -0800105 currentPriority = StatusSetting::fatal;
106 }
107 else if (critical)
108 {
109 currentPriority = StatusSetting::critical;
110 }
111 else if (warn)
112 {
113 currentPriority = StatusSetting::warn;
114 }
115 else
116 {
117 currentPriority = StatusSetting::ok;
118 }
119
120 std::vector<std::pair<std::string, std::variant<bool>>> ledsToSet;
121
Richard Marian Thomaiyar28161212019-04-13 21:11:23 +0530122 if (last != currentPriority || forceRefresh)
James Feiste409fc72019-03-05 12:19:43 -0800123 {
124 switch (currentPriority)
125 {
126 case (StatusSetting::fatal):
127 {
128 ledsToSet.push_back(std::make_pair(fatalLedPath, true));
129 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
130 ledsToSet.push_back(std::make_pair(warningLedPath, false));
131 ledsToSet.push_back(std::make_pair(okLedPath, false));
132 break;
133 }
134 case (StatusSetting::critical):
135 {
136 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
137 ledsToSet.push_back(std::make_pair(criticalLedPath, true));
138 ledsToSet.push_back(std::make_pair(warningLedPath, false));
139 ledsToSet.push_back(std::make_pair(okLedPath, false));
140 break;
141 }
142 case (StatusSetting::warn):
143 {
144 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
145 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
146 ledsToSet.push_back(std::make_pair(warningLedPath, true));
147 ledsToSet.push_back(std::make_pair(okLedPath, false));
148 break;
149 }
150 case (StatusSetting::ok):
151 {
152 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
153 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
154 ledsToSet.push_back(std::make_pair(warningLedPath, false));
155 ledsToSet.push_back(std::make_pair(okLedPath, true));
156 break;
157 }
158 }
James Feist03a02ad2019-02-06 12:38:50 -0800159 }
160
161 for (const auto& ledPair : ledsToSet)
162 {
163 conn->async_method_call(
164 [ledPair](const boost::system::error_code ec) {
165 if (ec)
166 {
167 std::cerr << "Cannot set " << ledPair.first << " to "
168 << std::boolalpha
169 << std::get<bool>(ledPair.second) << "\n";
170 }
171 if constexpr (debug)
172 {
173 std::cerr << "Set " << ledPair.first << " to "
174 << std::boolalpha
175 << std::get<bool>(ledPair.second) << "\n";
176 }
177 },
178 ledManagerBusname, ledPair.first, "org.freedesktop.DBus.Properties",
179 "Set", ledIface, ledAssertProp, ledPair.second);
180 }
181}
182
183void createThresholdMatch(std::shared_ptr<sdbusplus::asio::connection>& conn)
184{
James Feist03a02ad2019-02-06 12:38:50 -0800185
James Feist7b238402019-06-25 11:56:49 -0700186 static sdbusplus::bus::match::match match(
187 static_cast<sdbusplus::bus::bus&>(*conn),
188 "type='signal',interface='org.freedesktop.DBus.Properties',"
189 "path_"
190 "namespace='/xyz/openbmc_project/"
191 "sensors',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
James Feist03a02ad2019-02-06 12:38:50 -0800192 [&conn](sdbusplus::message::message& message) {
193 std::string objectName;
194 boost::container::flat_map<std::string, std::variant<bool>> values;
James Feist03a02ad2019-02-06 12:38:50 -0800195
James Feist7b238402019-06-25 11:56:49 -0700196 try
197 {
198 message.read(objectName, values);
199 }
200 catch (sdbusplus::exception_t&)
201 {
202 return;
203 }
James Feist03a02ad2019-02-06 12:38:50 -0800204 if constexpr (debug)
205 {
206 std::cerr << "Threshold callback " << message.get_path()
207 << "\n";
208 }
209
210 auto findCriticalLow = values.find("CriticalAlarmLow");
211 auto findCriticalHigh = values.find("CriticalAlarmHigh");
212
213 auto findWarnLow = values.find("WarningAlarmLow");
214 auto findWarnHigh = values.find("WarningAlarmHigh");
215
216 if (findCriticalLow != values.end())
217 {
218 criticalAssertMap[message.get_path()]["Low"] =
219 std::get<bool>(findCriticalLow->second);
220 }
221 if (findCriticalHigh != values.end())
222 {
223 criticalAssertMap[message.get_path()]["High"] =
224 std::get<bool>(findCriticalHigh->second);
225 }
226 if (findWarnLow != values.end())
227 {
228 warningAssertMap[message.get_path()]["Low"] =
229 std::get<bool>(findWarnLow->second);
230 }
231 if (findWarnHigh != values.end())
232 {
233 warningAssertMap[message.get_path()]["High"] =
234 std::get<bool>(findWarnHigh->second);
235 }
James Feist03a02ad2019-02-06 12:38:50 -0800236
James Feist7b238402019-06-25 11:56:49 -0700237 associationManager->setSensorAssociations(
238 assertedInMap(criticalAssertMap),
239 assertedInMap(warningAssertMap));
240
241 updateLedStatus(conn);
242 });
243}
244
245void createAssociationMatch(std::shared_ptr<sdbusplus::asio::connection>& conn)
246{
247 static sdbusplus::bus::match::match match(
James Feist03a02ad2019-02-06 12:38:50 -0800248 static_cast<sdbusplus::bus::bus&>(*conn),
James Feiste409fc72019-03-05 12:19:43 -0800249 "type='signal',interface='org.freedesktop.DBus.Properties',"
James Feist7b238402019-06-25 11:56:49 -0700250 "arg0namespace='" +
251 std::string(associationIface) + "'",
252 [&conn](sdbusplus::message::message& message) {
253 if (message.get_path() == rootPath)
254 {
255 return; // it's us
256 }
257 std::string objectName;
258 boost::container::flat_map<std::string,
259 std::variant<std::vector<Association>>>
260 values;
261 try
262 {
263 message.read(objectName, values);
264 }
265 catch (sdbusplus::exception_t&)
266 {
267 return;
268 }
269
270 if constexpr (debug)
271 {
272 std::cerr << "Association callback " << message.get_path()
273 << "\n";
274 }
275
James Feist56078402019-10-29 16:00:38 -0700276 auto findAssociations = values.find("Associations");
James Feist7b238402019-06-25 11:56:49 -0700277 if (findAssociations == values.end())
278 {
279 return;
280 }
281 const std::vector<Association>* associations =
282 std::get_if<std::vector<Association>>(
283 &findAssociations->second);
284
285 if (associations == nullptr)
286 {
287 std::cerr << "Illegal Association on " << message.get_path()
288 << "\n";
289 return;
290 }
291
292 bool localWarning = false;
293 bool localCritical = false;
294 bool globalWarning = false;
295 bool globalCritical = false;
296
297 for (const auto& [forward, reverse, path] : *associations)
298 {
299 if (path == rootPath)
300 {
301 globalWarning = globalWarning ? true : reverse == "warning";
302 globalCritical =
303 globalCritical ? true : reverse == "critical";
304
305 if constexpr (1)
306 {
307 std::cerr << "got global ";
308 }
309 }
310 else
311 {
312 localWarning = localWarning ? true : reverse == "warning";
313 localCritical =
314 localCritical ? true : reverse == "critical";
315 }
316 if (globalCritical && localCritical)
317 {
318 break;
319 }
320 }
321
322 bool fatal = globalCritical && localCritical;
323 bool critical = globalWarning && localCritical;
James Feist56078402019-10-29 16:00:38 -0700324 bool warning = globalWarning && !critical;
James Feist7b238402019-06-25 11:56:49 -0700325
326 fatalAssertMap[message.get_path()]["association"] = fatal;
327 criticalAssertMap[message.get_path()]["association"] = critical;
328 warningAssertMap[message.get_path()]["association"] = warning;
329
330 updateLedStatus(conn);
331 });
James Feist03a02ad2019-02-06 12:38:50 -0800332}
333
334int main(int argc, char** argv)
335{
336 boost::asio::io_service io;
337 auto conn = std::make_shared<sdbusplus::asio::connection>(io);
338 conn->request_name("xyz.openbmc_project.CallbackManager");
339 sdbusplus::asio::object_server objServer(conn);
James Feistdc7bbdc2019-05-16 15:33:06 -0700340 std::shared_ptr<sdbusplus::asio::dbus_interface> rootIface =
341 objServer.add_interface(rootPath,
James Feist03a02ad2019-02-06 12:38:50 -0800342 "xyz.openbmc_project.CallbackManager");
James Feistdc7bbdc2019-05-16 15:33:06 -0700343 rootIface->register_method("RetriggerLEDUpdate",
344 [&conn]() { updateLedStatus(conn, true); });
345 rootIface->initialize();
346
347 std::shared_ptr<sdbusplus::asio::dbus_interface> inventoryIface =
348 objServer.add_interface(rootPath, globalInventoryIface);
349 inventoryIface->initialize();
350
351 associationManager = std::make_unique<AssociationManager>(objServer, conn);
James Feist03a02ad2019-02-06 12:38:50 -0800352
353 createThresholdMatch(conn);
James Feist7b238402019-06-25 11:56:49 -0700354 createAssociationMatch(conn);
James Feiste409fc72019-03-05 12:19:43 -0800355 updateLedStatus(conn);
James Feist03a02ad2019-02-06 12:38:50 -0800356
357 io.run();
358
359 return 0;
360}