xref: /openbmc/s2600wf-misc/callback-manager/src/callback_manager.cpp (revision e409fc703a489ac9527e7424b4d6543a8a55e3cd)
1 /*
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 
17 #include <boost/container/flat_map.hpp>
18 #include <iostream>
19 #include <sdbusplus/asio/connection.hpp>
20 #include <sdbusplus/asio/object_server.hpp>
21 #include <variant>
22 
23 constexpr const char* fatalLedPath =
24     "/xyz/openbmc_project/led/groups/status_critical";
25 constexpr const char* criticalLedPath =
26     "/xyz/openbmc_project/led/groups/status_non_critical";
27 constexpr const char* warningLedPath =
28     "/xyz/openbmc_project/led/groups/status_degraded";
29 constexpr const char* okLedPath = "/xyz/openbmc_project/led/groups/status_ok";
30 
31 constexpr const char* ledIface = "xyz.openbmc_project.Led.Group";
32 constexpr const char* ledAssertProp = "Asserted";
33 constexpr const char* ledManagerBusname =
34     "xyz.openbmc_project.LED.GroupManager";
35 
36 enum class StatusSetting
37 {
38     none,
39     ok,
40     warn,
41     critical,
42     fatal
43 };
44 
45 std::shared_ptr<sdbusplus::asio::dbus_interface> assertedIface = nullptr;
46 
47 constexpr const bool debug = false;
48 
49 // final led state tracking
50 StatusSetting currentPriority = StatusSetting::none;
51 
52 // maps of <object-path, <property, asserted>>
53 boost::container::flat_map<std::string,
54                            boost::container::flat_map<std::string, bool>>
55     fatalAssertMap;
56 boost::container::flat_map<std::string,
57                            boost::container::flat_map<std::string, bool>>
58     criticalAssertMap;
59 boost::container::flat_map<std::string,
60                            boost::container::flat_map<std::string, bool>>
61     warningAssertMap;
62 
63 std::vector<std::string> assertedInMap(
64     const boost::container::flat_map<
65         std::string, boost::container::flat_map<std::string, bool>>& map)
66 {
67     std::vector<std::string> ret;
68     // if any of the properties are true, return true
69     for (const auto& pair : map)
70     {
71         for (const auto& item : pair.second)
72         {
73             if (item.second)
74             {
75                 ret.push_back(pair.first);
76             }
77         }
78     }
79     return ret;
80 }
81 
82 void updateLedStatus(std::shared_ptr<sdbusplus::asio::connection>& conn)
83 {
84     std::vector<std::string> assertedVector = assertedInMap(fatalAssertMap);
85     assertedIface->set_property("Fatal", assertedVector);
86     bool fatal = assertedVector.size();
87 
88     assertedVector = assertedInMap(criticalAssertMap);
89     assertedIface->set_property("Critical", assertedVector);
90     bool critical = assertedVector.size();
91 
92     assertedVector = assertedInMap(warningAssertMap);
93     assertedIface->set_property("Warning", assertedVector);
94 
95     bool warn = assertedVector.size();
96 
97     StatusSetting last = currentPriority;
98 
99     if (fatal)
100     {
101         currentPriority = StatusSetting::fatal;
102     }
103     else if (critical)
104     {
105         currentPriority = StatusSetting::critical;
106     }
107     else if (warn)
108     {
109         currentPriority = StatusSetting::warn;
110     }
111     else
112     {
113         currentPriority = StatusSetting::ok;
114     }
115 
116     std::vector<std::pair<std::string, std::variant<bool>>> ledsToSet;
117 
118     if (last != currentPriority)
119     {
120         switch (currentPriority)
121         {
122             case (StatusSetting::fatal):
123             {
124                 ledsToSet.push_back(std::make_pair(fatalLedPath, true));
125                 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
126                 ledsToSet.push_back(std::make_pair(warningLedPath, false));
127                 ledsToSet.push_back(std::make_pair(okLedPath, false));
128                 break;
129             }
130             case (StatusSetting::critical):
131             {
132                 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
133                 ledsToSet.push_back(std::make_pair(criticalLedPath, true));
134                 ledsToSet.push_back(std::make_pair(warningLedPath, false));
135                 ledsToSet.push_back(std::make_pair(okLedPath, false));
136                 break;
137             }
138             case (StatusSetting::warn):
139             {
140                 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
141                 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
142                 ledsToSet.push_back(std::make_pair(warningLedPath, true));
143                 ledsToSet.push_back(std::make_pair(okLedPath, false));
144                 break;
145             }
146             case (StatusSetting::ok):
147             {
148                 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
149                 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
150                 ledsToSet.push_back(std::make_pair(warningLedPath, false));
151                 ledsToSet.push_back(std::make_pair(okLedPath, true));
152                 break;
153             }
154         }
155     }
156 
157     for (const auto& ledPair : ledsToSet)
158     {
159         conn->async_method_call(
160             [ledPair](const boost::system::error_code ec) {
161                 if (ec)
162                 {
163                     std::cerr << "Cannot set " << ledPair.first << " to "
164                               << std::boolalpha
165                               << std::get<bool>(ledPair.second) << "\n";
166                 }
167                 if constexpr (debug)
168                 {
169                     std::cerr << "Set " << ledPair.first << " to "
170                               << std::boolalpha
171                               << std::get<bool>(ledPair.second) << "\n";
172                 }
173             },
174             ledManagerBusname, ledPair.first, "org.freedesktop.DBus.Properties",
175             "Set", ledIface, ledAssertProp, ledPair.second);
176     }
177 }
178 
179 void createThresholdMatch(std::shared_ptr<sdbusplus::asio::connection>& conn)
180 {
181     static std::unique_ptr<sdbusplus::bus::match::match> match = nullptr;
182 
183     std::function<void(sdbusplus::message::message&)> thresholdCallback =
184         [&conn](sdbusplus::message::message& message) {
185             std::string objectName;
186             boost::container::flat_map<std::string, std::variant<bool>> values;
187             message.read(objectName, values);
188 
189             if constexpr (debug)
190             {
191                 std::cerr << "Threshold callback " << message.get_path()
192                           << "\n";
193             }
194 
195             auto findCriticalLow = values.find("CriticalAlarmLow");
196             auto findCriticalHigh = values.find("CriticalAlarmHigh");
197 
198             auto findWarnLow = values.find("WarningAlarmLow");
199             auto findWarnHigh = values.find("WarningAlarmHigh");
200 
201             if (findCriticalLow != values.end())
202             {
203                 criticalAssertMap[message.get_path()]["Low"] =
204                     std::get<bool>(findCriticalLow->second);
205             }
206             if (findCriticalHigh != values.end())
207             {
208                 criticalAssertMap[message.get_path()]["High"] =
209                     std::get<bool>(findCriticalHigh->second);
210             }
211             if (findWarnLow != values.end())
212             {
213                 warningAssertMap[message.get_path()]["Low"] =
214                     std::get<bool>(findWarnLow->second);
215             }
216             if (findWarnHigh != values.end())
217             {
218                 warningAssertMap[message.get_path()]["High"] =
219                     std::get<bool>(findWarnHigh->second);
220             }
221             updateLedStatus(conn);
222         };
223 
224     match = std::make_unique<sdbusplus::bus::match::match>(
225         static_cast<sdbusplus::bus::bus&>(*conn),
226         "type='signal',interface='org.freedesktop.DBus.Properties',"
227         "path_"
228         "namespace='/xyz/openbmc_project/"
229         "sensors',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
230         thresholdCallback);
231 }
232 
233 int main(int argc, char** argv)
234 {
235     boost::asio::io_service io;
236     auto conn = std::make_shared<sdbusplus::asio::connection>(io);
237     conn->request_name("xyz.openbmc_project.CallbackManager");
238     sdbusplus::asio::object_server objServer(conn);
239     assertedIface =
240         objServer.add_interface("/xyz/openbmc_project/CallbackManager",
241                                 "xyz.openbmc_project.CallbackManager");
242     assertedIface->register_property("Warning", std::vector<std::string>());
243     assertedIface->register_property("Critical", std::vector<std::string>());
244     assertedIface->register_property("Fatal", std::vector<std::string>());
245     assertedIface->initialize();
246 
247     createThresholdMatch(conn);
248     updateLedStatus(conn);
249 
250     io.run();
251 
252     return 0;
253 }
254