blob: 3eba4b1534904f9342b5190b96c8bbd978327aa4 [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>
Jason M. Bills0d5c0712020-12-08 10:10:47 -080022
James Feist03a02ad2019-02-06 12:38:50 -080023#include <variant>
24
25constexpr const char* fatalLedPath =
26 "/xyz/openbmc_project/led/groups/status_critical";
27constexpr const char* criticalLedPath =
28 "/xyz/openbmc_project/led/groups/status_non_critical";
29constexpr const char* warningLedPath =
30 "/xyz/openbmc_project/led/groups/status_degraded";
James Feiste409fc72019-03-05 12:19:43 -080031constexpr const char* okLedPath = "/xyz/openbmc_project/led/groups/status_ok";
James Feist03a02ad2019-02-06 12:38:50 -080032
33constexpr const char* ledIface = "xyz.openbmc_project.Led.Group";
34constexpr const char* ledAssertProp = "Asserted";
35constexpr const char* ledManagerBusname =
36 "xyz.openbmc_project.LED.GroupManager";
37
James Feistdc7bbdc2019-05-16 15:33:06 -070038std::unique_ptr<AssociationManager> associationManager;
39
James Feiste409fc72019-03-05 12:19:43 -080040enum class StatusSetting
41{
42 none,
43 ok,
44 warn,
45 critical,
46 fatal
47};
48
James Feist03a02ad2019-02-06 12:38:50 -080049constexpr const bool debug = false;
50
51// final led state tracking
James Feiste409fc72019-03-05 12:19:43 -080052StatusSetting currentPriority = StatusSetting::none;
James Feist03a02ad2019-02-06 12:38:50 -080053
54// maps of <object-path, <property, asserted>>
55boost::container::flat_map<std::string,
56 boost::container::flat_map<std::string, bool>>
57 fatalAssertMap;
58boost::container::flat_map<std::string,
59 boost::container::flat_map<std::string, bool>>
60 criticalAssertMap;
61boost::container::flat_map<std::string,
62 boost::container::flat_map<std::string, bool>>
63 warningAssertMap;
64
65std::vector<std::string> assertedInMap(
66 const boost::container::flat_map<
67 std::string, boost::container::flat_map<std::string, bool>>& map)
68{
69 std::vector<std::string> ret;
70 // if any of the properties are true, return true
71 for (const auto& pair : map)
72 {
73 for (const auto& item : pair.second)
74 {
75 if (item.second)
76 {
77 ret.push_back(pair.first);
78 }
79 }
80 }
81 return ret;
82}
83
Richard Marian Thomaiyar28161212019-04-13 21:11:23 +053084void updateLedStatus(std::shared_ptr<sdbusplus::asio::connection>& conn,
85 bool forceRefresh = false)
James Feist03a02ad2019-02-06 12:38:50 -080086{
James Feistdc7bbdc2019-05-16 15:33:06 -070087 std::vector<std::string> fatalVector = assertedInMap(fatalAssertMap);
88 bool fatal = fatalVector.size();
James Feist03a02ad2019-02-06 12:38:50 -080089
James Feistdc7bbdc2019-05-16 15:33:06 -070090 std::vector<std::string> criticalVector = assertedInMap(criticalAssertMap);
91 bool critical = criticalVector.size();
James Feist03a02ad2019-02-06 12:38:50 -080092
James Feistdc7bbdc2019-05-16 15:33:06 -070093 std::vector<std::string> warningVector = assertedInMap(warningAssertMap);
94 bool warn = warningVector.size();
James Feist03a02ad2019-02-06 12:38:50 -080095
James Feistdc7bbdc2019-05-16 15:33:06 -070096 associationManager->setLocalAssociations(fatalVector, criticalVector,
97 warningVector);
James Feiste409fc72019-03-05 12:19:43 -080098
99 StatusSetting last = currentPriority;
100
101 if (fatal)
James Feist03a02ad2019-02-06 12:38:50 -0800102 {
James Feiste409fc72019-03-05 12:19:43 -0800103 currentPriority = StatusSetting::fatal;
104 }
105 else if (critical)
106 {
107 currentPriority = StatusSetting::critical;
108 }
109 else if (warn)
110 {
111 currentPriority = StatusSetting::warn;
112 }
113 else
114 {
115 currentPriority = StatusSetting::ok;
116 }
117
118 std::vector<std::pair<std::string, std::variant<bool>>> ledsToSet;
119
Richard Marian Thomaiyar28161212019-04-13 21:11:23 +0530120 if (last != currentPriority || forceRefresh)
James Feiste409fc72019-03-05 12:19:43 -0800121 {
122 switch (currentPriority)
123 {
124 case (StatusSetting::fatal):
125 {
126 ledsToSet.push_back(std::make_pair(fatalLedPath, true));
127 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
128 ledsToSet.push_back(std::make_pair(warningLedPath, false));
129 ledsToSet.push_back(std::make_pair(okLedPath, false));
130 break;
131 }
132 case (StatusSetting::critical):
133 {
134 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
135 ledsToSet.push_back(std::make_pair(criticalLedPath, true));
136 ledsToSet.push_back(std::make_pair(warningLedPath, false));
137 ledsToSet.push_back(std::make_pair(okLedPath, false));
138 break;
139 }
140 case (StatusSetting::warn):
141 {
142 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
143 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
144 ledsToSet.push_back(std::make_pair(warningLedPath, true));
145 ledsToSet.push_back(std::make_pair(okLedPath, false));
146 break;
147 }
148 case (StatusSetting::ok):
149 {
150 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
151 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
152 ledsToSet.push_back(std::make_pair(warningLedPath, false));
153 ledsToSet.push_back(std::make_pair(okLedPath, true));
154 break;
155 }
156 }
James Feist03a02ad2019-02-06 12:38:50 -0800157 }
158
159 for (const auto& ledPair : ledsToSet)
160 {
161 conn->async_method_call(
162 [ledPair](const boost::system::error_code ec) {
163 if (ec)
164 {
165 std::cerr << "Cannot set " << ledPair.first << " to "
166 << std::boolalpha
167 << std::get<bool>(ledPair.second) << "\n";
168 }
169 if constexpr (debug)
170 {
171 std::cerr << "Set " << ledPair.first << " to "
172 << std::boolalpha
173 << std::get<bool>(ledPair.second) << "\n";
174 }
175 },
176 ledManagerBusname, ledPair.first, "org.freedesktop.DBus.Properties",
177 "Set", ledIface, ledAssertProp, ledPair.second);
178 }
179}
180
181void createThresholdMatch(std::shared_ptr<sdbusplus::asio::connection>& conn)
182{
James Feist03a02ad2019-02-06 12:38:50 -0800183
James Feist7b238402019-06-25 11:56:49 -0700184 static sdbusplus::bus::match::match match(
185 static_cast<sdbusplus::bus::bus&>(*conn),
186 "type='signal',interface='org.freedesktop.DBus.Properties',"
187 "path_"
188 "namespace='/xyz/openbmc_project/"
189 "sensors',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
James Feist03a02ad2019-02-06 12:38:50 -0800190 [&conn](sdbusplus::message::message& message) {
191 std::string objectName;
192 boost::container::flat_map<std::string, std::variant<bool>> values;
James Feist03a02ad2019-02-06 12:38:50 -0800193
James Feist7b238402019-06-25 11:56:49 -0700194 try
195 {
196 message.read(objectName, values);
197 }
198 catch (sdbusplus::exception_t&)
199 {
200 return;
201 }
James Feist03a02ad2019-02-06 12:38:50 -0800202 if constexpr (debug)
203 {
204 std::cerr << "Threshold callback " << message.get_path()
205 << "\n";
206 }
207
208 auto findCriticalLow = values.find("CriticalAlarmLow");
209 auto findCriticalHigh = values.find("CriticalAlarmHigh");
210
211 auto findWarnLow = values.find("WarningAlarmLow");
212 auto findWarnHigh = values.find("WarningAlarmHigh");
213
214 if (findCriticalLow != values.end())
215 {
216 criticalAssertMap[message.get_path()]["Low"] =
217 std::get<bool>(findCriticalLow->second);
218 }
219 if (findCriticalHigh != values.end())
220 {
221 criticalAssertMap[message.get_path()]["High"] =
222 std::get<bool>(findCriticalHigh->second);
223 }
224 if (findWarnLow != values.end())
225 {
226 warningAssertMap[message.get_path()]["Low"] =
227 std::get<bool>(findWarnLow->second);
228 }
229 if (findWarnHigh != values.end())
230 {
231 warningAssertMap[message.get_path()]["High"] =
232 std::get<bool>(findWarnHigh->second);
233 }
James Feist03a02ad2019-02-06 12:38:50 -0800234
James Feist7b238402019-06-25 11:56:49 -0700235 associationManager->setSensorAssociations(
236 assertedInMap(criticalAssertMap),
237 assertedInMap(warningAssertMap));
238
239 updateLedStatus(conn);
240 });
241}
242
243void createAssociationMatch(std::shared_ptr<sdbusplus::asio::connection>& conn)
244{
245 static sdbusplus::bus::match::match match(
James Feist03a02ad2019-02-06 12:38:50 -0800246 static_cast<sdbusplus::bus::bus&>(*conn),
James Feiste409fc72019-03-05 12:19:43 -0800247 "type='signal',interface='org.freedesktop.DBus.Properties',"
James Feist7b238402019-06-25 11:56:49 -0700248 "arg0namespace='" +
249 std::string(associationIface) + "'",
250 [&conn](sdbusplus::message::message& message) {
251 if (message.get_path() == rootPath)
252 {
253 return; // it's us
254 }
255 std::string objectName;
256 boost::container::flat_map<std::string,
257 std::variant<std::vector<Association>>>
258 values;
259 try
260 {
261 message.read(objectName, values);
262 }
263 catch (sdbusplus::exception_t&)
264 {
265 return;
266 }
267
268 if constexpr (debug)
269 {
270 std::cerr << "Association callback " << message.get_path()
271 << "\n";
272 }
273
James Feist56078402019-10-29 16:00:38 -0700274 auto findAssociations = values.find("Associations");
James Feist7b238402019-06-25 11:56:49 -0700275 if (findAssociations == values.end())
276 {
277 return;
278 }
279 const std::vector<Association>* associations =
280 std::get_if<std::vector<Association>>(
281 &findAssociations->second);
282
283 if (associations == nullptr)
284 {
285 std::cerr << "Illegal Association on " << message.get_path()
286 << "\n";
287 return;
288 }
289
290 bool localWarning = false;
291 bool localCritical = false;
292 bool globalWarning = false;
293 bool globalCritical = false;
294
295 for (const auto& [forward, reverse, path] : *associations)
296 {
297 if (path == rootPath)
298 {
299 globalWarning = globalWarning ? true : reverse == "warning";
300 globalCritical =
301 globalCritical ? true : reverse == "critical";
302
303 if constexpr (1)
304 {
305 std::cerr << "got global ";
306 }
307 }
308 else
309 {
310 localWarning = localWarning ? true : reverse == "warning";
311 localCritical =
312 localCritical ? true : reverse == "critical";
313 }
314 if (globalCritical && localCritical)
315 {
316 break;
317 }
318 }
319
320 bool fatal = globalCritical && localCritical;
321 bool critical = globalWarning && localCritical;
James Feist56078402019-10-29 16:00:38 -0700322 bool warning = globalWarning && !critical;
James Feist7b238402019-06-25 11:56:49 -0700323
324 fatalAssertMap[message.get_path()]["association"] = fatal;
325 criticalAssertMap[message.get_path()]["association"] = critical;
326 warningAssertMap[message.get_path()]["association"] = warning;
327
328 updateLedStatus(conn);
329 });
James Feist03a02ad2019-02-06 12:38:50 -0800330}
331
332int main(int argc, char** argv)
333{
334 boost::asio::io_service io;
335 auto conn = std::make_shared<sdbusplus::asio::connection>(io);
336 conn->request_name("xyz.openbmc_project.CallbackManager");
337 sdbusplus::asio::object_server objServer(conn);
James Feistdc7bbdc2019-05-16 15:33:06 -0700338 std::shared_ptr<sdbusplus::asio::dbus_interface> rootIface =
339 objServer.add_interface(rootPath,
James Feist03a02ad2019-02-06 12:38:50 -0800340 "xyz.openbmc_project.CallbackManager");
James Feistdc7bbdc2019-05-16 15:33:06 -0700341 rootIface->register_method("RetriggerLEDUpdate",
342 [&conn]() { updateLedStatus(conn, true); });
343 rootIface->initialize();
344
345 std::shared_ptr<sdbusplus::asio::dbus_interface> inventoryIface =
346 objServer.add_interface(rootPath, globalInventoryIface);
347 inventoryIface->initialize();
348
349 associationManager = std::make_unique<AssociationManager>(objServer, conn);
James Feist03a02ad2019-02-06 12:38:50 -0800350
351 createThresholdMatch(conn);
James Feist7b238402019-06-25 11:56:49 -0700352 createAssociationMatch(conn);
James Feiste409fc72019-03-05 12:19:43 -0800353 updateLedStatus(conn);
James Feist03a02ad2019-02-06 12:38:50 -0800354
355 io.run();
356
357 return 0;
358}