blob: 97f74f1dfc6a3acca719fb5b9b90647c913543b4 [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
Ed Tanousa2441982023-02-28 13:38:56 -080019#include <boost/asio/io_context.hpp>
Zhikui Ren291d6382020-09-25 15:06:04 -070020#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) {
PavanKumarInteldf992902023-11-29 09:09:06 +0000113 std::ios_base::fmtflags originalFlags = std::cerr.flags();
sunitakx1a9dde92021-06-28 13:42:18 +0000114 if (ec)
115 {
116 std::cerr << "Cannot set " << ledPair.first << " to "
117 << std::boolalpha
118 << std::get<bool>(ledPair.second) << "\n";
PavanKumarIntel8e0b9db2023-10-30 16:50:27 +0000119 std::cerr.flags(originalFlags);
sunitakx1a9dde92021-06-28 13:42:18 +0000120 }
121 if constexpr (debug)
122 {
123 std::cerr << "Set " << ledPair.first << " to "
124 << std::boolalpha
125 << std::get<bool>(ledPair.second) << "\n";
PavanKumarIntel8e0b9db2023-10-30 16:50:27 +0000126 std::cerr.flags(originalFlags);
sunitakx1a9dde92021-06-28 13:42:18 +0000127 }
128 },
129 ledManagerBusname, ledPair.first,
130 "org.freedesktop.DBus.Properties", "Set", ledIface,
131 ledAssertProp, ledPair.second);
132 }
133 }
James Feiste409fc72019-03-05 12:19:43 -0800134 if (fatal)
James Feist03a02ad2019-02-06 12:38:50 -0800135 {
James Feiste409fc72019-03-05 12:19:43 -0800136 currentPriority = StatusSetting::fatal;
137 }
138 else if (critical)
139 {
140 currentPriority = StatusSetting::critical;
141 }
142 else if (warn)
143 {
144 currentPriority = StatusSetting::warn;
145 }
146 else
147 {
148 currentPriority = StatusSetting::ok;
149 }
150
Richard Marian Thomaiyar28161212019-04-13 21:11:23 +0530151 if (last != currentPriority || forceRefresh)
James Feiste409fc72019-03-05 12:19:43 -0800152 {
153 switch (currentPriority)
154 {
155 case (StatusSetting::fatal):
156 {
157 ledsToSet.push_back(std::make_pair(fatalLedPath, true));
158 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
159 ledsToSet.push_back(std::make_pair(warningLedPath, false));
160 ledsToSet.push_back(std::make_pair(okLedPath, false));
161 break;
162 }
163 case (StatusSetting::critical):
164 {
165 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
166 ledsToSet.push_back(std::make_pair(criticalLedPath, true));
167 ledsToSet.push_back(std::make_pair(warningLedPath, false));
168 ledsToSet.push_back(std::make_pair(okLedPath, false));
169 break;
170 }
171 case (StatusSetting::warn):
172 {
173 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
174 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
175 ledsToSet.push_back(std::make_pair(warningLedPath, true));
176 ledsToSet.push_back(std::make_pair(okLedPath, false));
177 break;
178 }
179 case (StatusSetting::ok):
180 {
181 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
182 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
183 ledsToSet.push_back(std::make_pair(warningLedPath, false));
184 ledsToSet.push_back(std::make_pair(okLedPath, true));
185 break;
186 }
187 }
James Feist03a02ad2019-02-06 12:38:50 -0800188 }
189
190 for (const auto& ledPair : ledsToSet)
191 {
192 conn->async_method_call(
193 [ledPair](const boost::system::error_code ec) {
194 if (ec)
195 {
196 std::cerr << "Cannot set " << ledPair.first << " to "
197 << std::boolalpha
198 << std::get<bool>(ledPair.second) << "\n";
199 }
200 if constexpr (debug)
201 {
Jason M. Bills2b973a52025-07-31 11:06:04 -0700202 std::cerr
203 << "Set " << ledPair.first << " to " << std::boolalpha
204 << std::get<bool>(ledPair.second) << "\n";
James Feist03a02ad2019-02-06 12:38:50 -0800205 }
206 },
207 ledManagerBusname, ledPair.first, "org.freedesktop.DBus.Properties",
208 "Set", ledIface, ledAssertProp, ledPair.second);
209 }
210}
211
212void createThresholdMatch(std::shared_ptr<sdbusplus::asio::connection>& conn)
213{
Patrick Williamsff1c36e2022-07-22 19:26:56 -0500214 static sdbusplus::bus::match_t match(
215 static_cast<sdbusplus::bus_t&>(*conn),
Chalapathi Venkataramashettyd0b776e2021-09-30 11:01:52 +0000216 "type='signal',member='ThresholdAsserted'",
Patrick Williamsff1c36e2022-07-22 19:26:56 -0500217 [&conn](sdbusplus::message_t& message) {
Chalapathi Venkataramashettyd0b776e2021-09-30 11:01:52 +0000218 std::string sensorName;
219 std::string thresholdInterface;
220 std::string event;
221 bool assert;
222 double assertValue;
James Feist03a02ad2019-02-06 12:38:50 -0800223
James Feist7b238402019-06-25 11:56:49 -0700224 try
225 {
Chalapathi Venkataramashettyd0b776e2021-09-30 11:01:52 +0000226 message.read(sensorName, thresholdInterface, event, assert,
227 assertValue);
James Feist7b238402019-06-25 11:56:49 -0700228 }
229 catch (sdbusplus::exception_t&)
230 {
231 return;
232 }
James Feist03a02ad2019-02-06 12:38:50 -0800233 if constexpr (debug)
234 {
Chalapathi Venkataramashettyd0b776e2021-09-30 11:01:52 +0000235 std::cerr << "Threshold callback: SensorName = " << sensorName
236 << ", Event = " << event << ", Asserted = " << assert
James Feist03a02ad2019-02-06 12:38:50 -0800237 << "\n";
238 }
239
Chalapathi Venkataramashettyd0b776e2021-09-30 11:01:52 +0000240 if (event == "CriticalAlarmLow")
James Feist03a02ad2019-02-06 12:38:50 -0800241 {
Chalapathi Venkataramashettyd0b776e2021-09-30 11:01:52 +0000242 criticalAssertMap[message.get_path()]["low"] = assert;
James Feist03a02ad2019-02-06 12:38:50 -0800243 }
sunitakxf1a39982021-11-25 14:01:44 +0000244 else if (event == "CriticalAlarmHigh")
James Feist03a02ad2019-02-06 12:38:50 -0800245 {
Chalapathi Venkataramashettyd0b776e2021-09-30 11:01:52 +0000246 criticalAssertMap[message.get_path()]["high"] = assert;
James Feist03a02ad2019-02-06 12:38:50 -0800247 }
Chalapathi Venkataramashettyd0b776e2021-09-30 11:01:52 +0000248 else if (event == "WarningAlarmLow")
James Feist03a02ad2019-02-06 12:38:50 -0800249 {
Chalapathi Venkataramashettyd0b776e2021-09-30 11:01:52 +0000250 warningAssertMap[message.get_path()]["low"] = assert;
James Feist03a02ad2019-02-06 12:38:50 -0800251 }
Chalapathi Venkataramashettyd0b776e2021-09-30 11:01:52 +0000252 else if (event == "WarningAlarmHigh")
James Feist03a02ad2019-02-06 12:38:50 -0800253 {
Chalapathi Venkataramashettyd0b776e2021-09-30 11:01:52 +0000254 warningAssertMap[message.get_path()]["high"] = assert;
James Feist03a02ad2019-02-06 12:38:50 -0800255 }
James Feist03a02ad2019-02-06 12:38:50 -0800256
James Feist7b238402019-06-25 11:56:49 -0700257 associationManager->setSensorAssociations(
258 assertedInMap(criticalAssertMap),
259 assertedInMap(warningAssertMap));
260
261 updateLedStatus(conn);
262 });
263}
264
265void createAssociationMatch(std::shared_ptr<sdbusplus::asio::connection>& conn)
266{
Patrick Williamsff1c36e2022-07-22 19:26:56 -0500267 static sdbusplus::bus::match_t match(
268 static_cast<sdbusplus::bus_t&>(*conn),
James Feiste409fc72019-03-05 12:19:43 -0800269 "type='signal',interface='org.freedesktop.DBus.Properties',"
James Feist7b238402019-06-25 11:56:49 -0700270 "arg0namespace='" +
271 std::string(associationIface) + "'",
Patrick Williamsff1c36e2022-07-22 19:26:56 -0500272 [&conn](sdbusplus::message_t& message) {
James Feist7b238402019-06-25 11:56:49 -0700273 if (message.get_path() == rootPath)
274 {
275 return; // it's us
276 }
277 std::string objectName;
278 boost::container::flat_map<std::string,
279 std::variant<std::vector<Association>>>
280 values;
281 try
282 {
283 message.read(objectName, values);
284 }
285 catch (sdbusplus::exception_t&)
286 {
287 return;
288 }
289
290 if constexpr (debug)
291 {
292 std::cerr << "Association callback " << message.get_path()
293 << "\n";
294 }
295
James Feist56078402019-10-29 16:00:38 -0700296 auto findAssociations = values.find("Associations");
James Feist7b238402019-06-25 11:56:49 -0700297 if (findAssociations == values.end())
298 {
299 return;
300 }
301 const std::vector<Association>* associations =
302 std::get_if<std::vector<Association>>(
303 &findAssociations->second);
304
305 if (associations == nullptr)
306 {
307 std::cerr << "Illegal Association on " << message.get_path()
308 << "\n";
309 return;
310 }
311
312 bool localWarning = false;
313 bool localCritical = false;
314 bool globalWarning = false;
315 bool globalCritical = false;
316
317 for (const auto& [forward, reverse, path] : *associations)
318 {
319 if (path == rootPath)
320 {
321 globalWarning = globalWarning ? true : reverse == "warning";
322 globalCritical =
323 globalCritical ? true : reverse == "critical";
324
325 if constexpr (1)
326 {
327 std::cerr << "got global ";
328 }
329 }
330 else
331 {
332 localWarning = localWarning ? true : reverse == "warning";
333 localCritical =
334 localCritical ? true : reverse == "critical";
335 }
336 if (globalCritical && localCritical)
337 {
338 break;
339 }
340 }
341
342 bool fatal = globalCritical && localCritical;
343 bool critical = globalWarning && localCritical;
James Feist56078402019-10-29 16:00:38 -0700344 bool warning = globalWarning && !critical;
James Feist7b238402019-06-25 11:56:49 -0700345
346 fatalAssertMap[message.get_path()]["association"] = fatal;
347 criticalAssertMap[message.get_path()]["association"] = critical;
348 warningAssertMap[message.get_path()]["association"] = warning;
349
350 updateLedStatus(conn);
351 });
James Feist03a02ad2019-02-06 12:38:50 -0800352}
353
354int main(int argc, char** argv)
355{
Ed Tanousa2441982023-02-28 13:38:56 -0800356 boost::asio::io_context io;
James Feist03a02ad2019-02-06 12:38:50 -0800357 auto conn = std::make_shared<sdbusplus::asio::connection>(io);
358 conn->request_name("xyz.openbmc_project.CallbackManager");
359 sdbusplus::asio::object_server objServer(conn);
James Feistdc7bbdc2019-05-16 15:33:06 -0700360 std::shared_ptr<sdbusplus::asio::dbus_interface> rootIface =
361 objServer.add_interface(rootPath,
James Feist03a02ad2019-02-06 12:38:50 -0800362 "xyz.openbmc_project.CallbackManager");
Jason M. Bills2b973a52025-07-31 11:06:04 -0700363 rootIface->register_method("RetriggerLEDUpdate", [&conn]() {
364 updateLedStatus(conn, true);
365 });
James Feistdc7bbdc2019-05-16 15:33:06 -0700366 rootIface->initialize();
367
368 std::shared_ptr<sdbusplus::asio::dbus_interface> inventoryIface =
369 objServer.add_interface(rootPath, globalInventoryIface);
370 inventoryIface->initialize();
371
372 associationManager = std::make_unique<AssociationManager>(objServer, conn);
James Feist03a02ad2019-02-06 12:38:50 -0800373
374 createThresholdMatch(conn);
James Feist7b238402019-06-25 11:56:49 -0700375 createAssociationMatch(conn);
James Feiste409fc72019-03-05 12:19:43 -0800376 updateLedStatus(conn);
James Feist03a02ad2019-02-06 12:38:50 -0800377
378 io.run();
379
380 return 0;
381}