xref: /openbmc/s2600wf-misc/callback-manager/src/callback_manager.cpp (revision df992906de8d4f4cf8cc4fccf6fa18ac06dca36c)
103a02ad0SJames Feist /*
203a02ad0SJames Feist // Copyright (c) 2019 Intel Corporation
303a02ad0SJames Feist //
403a02ad0SJames Feist // Licensed under the Apache License, Version 2.0 (the "License");
503a02ad0SJames Feist // you may not use this file except in compliance with the License.
603a02ad0SJames Feist // You may obtain a copy of the License at
703a02ad0SJames Feist //
803a02ad0SJames Feist //      http://www.apache.org/licenses/LICENSE-2.0
903a02ad0SJames Feist //
1003a02ad0SJames Feist // Unless required by applicable law or agreed to in writing, software
1103a02ad0SJames Feist // distributed under the License is distributed on an "AS IS" BASIS,
1203a02ad0SJames Feist // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1303a02ad0SJames Feist // See the License for the specific language governing permissions and
1403a02ad0SJames Feist // limitations under the License.
1503a02ad0SJames Feist */
1603a02ad0SJames Feist 
17dc7bbdcbSJames Feist #include "callback_manager.hpp"
18dc7bbdcbSJames Feist 
19a244198fSEd Tanous #include <boost/asio/io_context.hpp>
20291d6388SZhikui Ren #include <boost/asio/steady_timer.hpp>
2103a02ad0SJames Feist #include <boost/container/flat_map.hpp>
2203a02ad0SJames Feist #include <sdbusplus/asio/connection.hpp>
2303a02ad0SJames Feist #include <sdbusplus/asio/object_server.hpp>
240d5c0713SJason M. Bills 
2503a02ad0SJames Feist #include <variant>
2603a02ad0SJames Feist 
2703a02ad0SJames Feist constexpr const char* fatalLedPath =
2803a02ad0SJames Feist     "/xyz/openbmc_project/led/groups/status_critical";
2903a02ad0SJames Feist constexpr const char* criticalLedPath =
3003a02ad0SJames Feist     "/xyz/openbmc_project/led/groups/status_non_critical";
3103a02ad0SJames Feist constexpr const char* warningLedPath =
3203a02ad0SJames Feist     "/xyz/openbmc_project/led/groups/status_degraded";
33e409fc70SJames Feist constexpr const char* okLedPath = "/xyz/openbmc_project/led/groups/status_ok";
3403a02ad0SJames Feist 
3503a02ad0SJames Feist constexpr const char* ledIface = "xyz.openbmc_project.Led.Group";
3603a02ad0SJames Feist constexpr const char* ledAssertProp = "Asserted";
3703a02ad0SJames Feist constexpr const char* ledManagerBusname =
3803a02ad0SJames Feist     "xyz.openbmc_project.LED.GroupManager";
3903a02ad0SJames Feist 
40dc7bbdcbSJames Feist std::unique_ptr<AssociationManager> associationManager;
41dc7bbdcbSJames Feist 
42e409fc70SJames Feist enum class StatusSetting
43e409fc70SJames Feist {
44e409fc70SJames Feist     none,
45e409fc70SJames Feist     ok,
46e409fc70SJames Feist     warn,
47e409fc70SJames Feist     critical,
48e409fc70SJames Feist     fatal
49e409fc70SJames Feist };
50e409fc70SJames Feist 
5103a02ad0SJames Feist constexpr const bool debug = false;
5203a02ad0SJames Feist 
5303a02ad0SJames Feist // final led state tracking
54e409fc70SJames Feist StatusSetting currentPriority = StatusSetting::none;
5503a02ad0SJames Feist 
5603a02ad0SJames Feist // maps of <object-path, <property, asserted>>
5703a02ad0SJames Feist boost::container::flat_map<std::string,
5803a02ad0SJames Feist                            boost::container::flat_map<std::string, bool>>
5903a02ad0SJames Feist     fatalAssertMap;
6003a02ad0SJames Feist boost::container::flat_map<std::string,
6103a02ad0SJames Feist                            boost::container::flat_map<std::string, bool>>
6203a02ad0SJames Feist     criticalAssertMap;
6303a02ad0SJames Feist boost::container::flat_map<std::string,
6403a02ad0SJames Feist                            boost::container::flat_map<std::string, bool>>
6503a02ad0SJames Feist     warningAssertMap;
6603a02ad0SJames Feist 
assertedInMap(const boost::container::flat_map<std::string,boost::container::flat_map<std::string,bool>> & map)6703a02ad0SJames Feist std::vector<std::string> assertedInMap(
6803a02ad0SJames Feist     const boost::container::flat_map<
6903a02ad0SJames Feist         std::string, boost::container::flat_map<std::string, bool>>& map)
7003a02ad0SJames Feist {
7103a02ad0SJames Feist     std::vector<std::string> ret;
7203a02ad0SJames Feist     // if any of the properties are true, return true
7303a02ad0SJames Feist     for (const auto& pair : map)
7403a02ad0SJames Feist     {
7503a02ad0SJames Feist         for (const auto& item : pair.second)
7603a02ad0SJames Feist         {
7703a02ad0SJames Feist             if (item.second)
7803a02ad0SJames Feist             {
7903a02ad0SJames Feist                 ret.push_back(pair.first);
8003a02ad0SJames Feist             }
8103a02ad0SJames Feist         }
8203a02ad0SJames Feist     }
8303a02ad0SJames Feist     return ret;
8403a02ad0SJames Feist }
8503a02ad0SJames Feist 
updateLedStatus(std::shared_ptr<sdbusplus::asio::connection> & conn,bool forceRefresh=false)862816121fSRichard Marian Thomaiyar void updateLedStatus(std::shared_ptr<sdbusplus::asio::connection>& conn,
872816121fSRichard Marian Thomaiyar                      bool forceRefresh = false)
8803a02ad0SJames Feist {
89dc7bbdcbSJames Feist     std::vector<std::string> fatalVector = assertedInMap(fatalAssertMap);
90dc7bbdcbSJames Feist     bool fatal = fatalVector.size();
9103a02ad0SJames Feist 
92dc7bbdcbSJames Feist     std::vector<std::string> criticalVector = assertedInMap(criticalAssertMap);
93dc7bbdcbSJames Feist     bool critical = criticalVector.size();
9403a02ad0SJames Feist 
95dc7bbdcbSJames Feist     std::vector<std::string> warningVector = assertedInMap(warningAssertMap);
96dc7bbdcbSJames Feist     bool warn = warningVector.size();
9703a02ad0SJames Feist 
98dc7bbdcbSJames Feist     associationManager->setLocalAssociations(fatalVector, criticalVector,
99dc7bbdcbSJames Feist                                              warningVector);
100e409fc70SJames Feist 
101e409fc70SJames Feist     StatusSetting last = currentPriority;
1021a9dde9bSsunitakx     std::vector<std::pair<std::string, std::variant<bool>>> ledsToSet;
1031a9dde9bSsunitakx     if (forceRefresh)
1041a9dde9bSsunitakx     {
1051a9dde9bSsunitakx         ledsToSet.push_back(std::make_pair(fatalLedPath, false));
1061a9dde9bSsunitakx         ledsToSet.push_back(std::make_pair(criticalLedPath, false));
1071a9dde9bSsunitakx         ledsToSet.push_back(std::make_pair(warningLedPath, false));
1081a9dde9bSsunitakx         ledsToSet.push_back(std::make_pair(okLedPath, false));
1091a9dde9bSsunitakx         for (const auto& ledPair : ledsToSet)
1101a9dde9bSsunitakx         {
1111a9dde9bSsunitakx             conn->async_method_call(
1121a9dde9bSsunitakx                 [ledPair](const boost::system::error_code ec) {
113*df992906SPavanKumarIntel                     std::ios_base::fmtflags originalFlags = std::cerr.flags();
1141a9dde9bSsunitakx                     if (ec)
1151a9dde9bSsunitakx                     {
1161a9dde9bSsunitakx                         std::cerr << "Cannot set " << ledPair.first << " to "
1171a9dde9bSsunitakx                                   << std::boolalpha
1181a9dde9bSsunitakx                                   << std::get<bool>(ledPair.second) << "\n";
1198e0b9db6SPavanKumarIntel                         std::cerr.flags(originalFlags);
1201a9dde9bSsunitakx                     }
1211a9dde9bSsunitakx                     if constexpr (debug)
1221a9dde9bSsunitakx                     {
1231a9dde9bSsunitakx                         std::cerr << "Set " << ledPair.first << " to "
1241a9dde9bSsunitakx                                   << std::boolalpha
1251a9dde9bSsunitakx                                   << std::get<bool>(ledPair.second) << "\n";
1268e0b9db6SPavanKumarIntel                         std::cerr.flags(originalFlags);
1271a9dde9bSsunitakx                     }
1281a9dde9bSsunitakx                 },
1291a9dde9bSsunitakx                 ledManagerBusname, ledPair.first,
1301a9dde9bSsunitakx                 "org.freedesktop.DBus.Properties", "Set", ledIface,
1311a9dde9bSsunitakx                 ledAssertProp, ledPair.second);
1321a9dde9bSsunitakx         }
1331a9dde9bSsunitakx     }
134e409fc70SJames Feist     if (fatal)
13503a02ad0SJames Feist     {
136e409fc70SJames Feist         currentPriority = StatusSetting::fatal;
137e409fc70SJames Feist     }
138e409fc70SJames Feist     else if (critical)
139e409fc70SJames Feist     {
140e409fc70SJames Feist         currentPriority = StatusSetting::critical;
141e409fc70SJames Feist     }
142e409fc70SJames Feist     else if (warn)
143e409fc70SJames Feist     {
144e409fc70SJames Feist         currentPriority = StatusSetting::warn;
145e409fc70SJames Feist     }
146e409fc70SJames Feist     else
147e409fc70SJames Feist     {
148e409fc70SJames Feist         currentPriority = StatusSetting::ok;
149e409fc70SJames Feist     }
150e409fc70SJames Feist 
1512816121fSRichard Marian Thomaiyar     if (last != currentPriority || forceRefresh)
152e409fc70SJames Feist     {
153e409fc70SJames Feist         switch (currentPriority)
154e409fc70SJames Feist         {
155e409fc70SJames Feist             case (StatusSetting::fatal):
156e409fc70SJames Feist             {
157e409fc70SJames Feist                 ledsToSet.push_back(std::make_pair(fatalLedPath, true));
158e409fc70SJames Feist                 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
159e409fc70SJames Feist                 ledsToSet.push_back(std::make_pair(warningLedPath, false));
160e409fc70SJames Feist                 ledsToSet.push_back(std::make_pair(okLedPath, false));
161e409fc70SJames Feist                 break;
162e409fc70SJames Feist             }
163e409fc70SJames Feist             case (StatusSetting::critical):
164e409fc70SJames Feist             {
165e409fc70SJames Feist                 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
166e409fc70SJames Feist                 ledsToSet.push_back(std::make_pair(criticalLedPath, true));
167e409fc70SJames Feist                 ledsToSet.push_back(std::make_pair(warningLedPath, false));
168e409fc70SJames Feist                 ledsToSet.push_back(std::make_pair(okLedPath, false));
169e409fc70SJames Feist                 break;
170e409fc70SJames Feist             }
171e409fc70SJames Feist             case (StatusSetting::warn):
172e409fc70SJames Feist             {
173e409fc70SJames Feist                 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
174e409fc70SJames Feist                 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
175e409fc70SJames Feist                 ledsToSet.push_back(std::make_pair(warningLedPath, true));
176e409fc70SJames Feist                 ledsToSet.push_back(std::make_pair(okLedPath, false));
177e409fc70SJames Feist                 break;
178e409fc70SJames Feist             }
179e409fc70SJames Feist             case (StatusSetting::ok):
180e409fc70SJames Feist             {
181e409fc70SJames Feist                 ledsToSet.push_back(std::make_pair(fatalLedPath, false));
182e409fc70SJames Feist                 ledsToSet.push_back(std::make_pair(criticalLedPath, false));
183e409fc70SJames Feist                 ledsToSet.push_back(std::make_pair(warningLedPath, false));
184e409fc70SJames Feist                 ledsToSet.push_back(std::make_pair(okLedPath, true));
185e409fc70SJames Feist                 break;
186e409fc70SJames Feist             }
187e409fc70SJames Feist         }
18803a02ad0SJames Feist     }
18903a02ad0SJames Feist 
19003a02ad0SJames Feist     for (const auto& ledPair : ledsToSet)
19103a02ad0SJames Feist     {
19203a02ad0SJames Feist         conn->async_method_call(
19303a02ad0SJames Feist             [ledPair](const boost::system::error_code ec) {
19403a02ad0SJames Feist                 if (ec)
19503a02ad0SJames Feist                 {
19603a02ad0SJames Feist                     std::cerr << "Cannot set " << ledPair.first << " to "
19703a02ad0SJames Feist                               << std::boolalpha
19803a02ad0SJames Feist                               << std::get<bool>(ledPair.second) << "\n";
19903a02ad0SJames Feist                 }
20003a02ad0SJames Feist                 if constexpr (debug)
20103a02ad0SJames Feist                 {
20203a02ad0SJames Feist                     std::cerr << "Set " << ledPair.first << " to "
20303a02ad0SJames Feist                               << std::boolalpha
20403a02ad0SJames Feist                               << std::get<bool>(ledPair.second) << "\n";
20503a02ad0SJames Feist                 }
20603a02ad0SJames Feist             },
20703a02ad0SJames Feist             ledManagerBusname, ledPair.first, "org.freedesktop.DBus.Properties",
20803a02ad0SJames Feist             "Set", ledIface, ledAssertProp, ledPair.second);
20903a02ad0SJames Feist     }
21003a02ad0SJames Feist }
21103a02ad0SJames Feist 
createThresholdMatch(std::shared_ptr<sdbusplus::asio::connection> & conn)21203a02ad0SJames Feist void createThresholdMatch(std::shared_ptr<sdbusplus::asio::connection>& conn)
21303a02ad0SJames Feist {
21403a02ad0SJames Feist 
215ff1c36e5SPatrick Williams     static sdbusplus::bus::match_t match(
216ff1c36e5SPatrick Williams         static_cast<sdbusplus::bus_t&>(*conn),
217d0b776e3SChalapathi Venkataramashetty         "type='signal',member='ThresholdAsserted'",
218ff1c36e5SPatrick Williams         [&conn](sdbusplus::message_t& message) {
219d0b776e3SChalapathi Venkataramashetty             std::string sensorName;
220d0b776e3SChalapathi Venkataramashetty             std::string thresholdInterface;
221d0b776e3SChalapathi Venkataramashetty             std::string event;
222d0b776e3SChalapathi Venkataramashetty             bool assert;
223d0b776e3SChalapathi Venkataramashetty             double assertValue;
22403a02ad0SJames Feist 
2257b238401SJames Feist             try
2267b238401SJames Feist             {
227d0b776e3SChalapathi Venkataramashetty                 message.read(sensorName, thresholdInterface, event, assert,
228d0b776e3SChalapathi Venkataramashetty                              assertValue);
2297b238401SJames Feist             }
2307b238401SJames Feist             catch (sdbusplus::exception_t&)
2317b238401SJames Feist             {
2327b238401SJames Feist                 return;
2337b238401SJames Feist             }
23403a02ad0SJames Feist             if constexpr (debug)
23503a02ad0SJames Feist             {
236d0b776e3SChalapathi Venkataramashetty                 std::cerr << "Threshold callback: SensorName = " << sensorName
237d0b776e3SChalapathi Venkataramashetty                           << ", Event = " << event << ", Asserted = " << assert
23803a02ad0SJames Feist                           << "\n";
23903a02ad0SJames Feist             }
24003a02ad0SJames Feist 
241d0b776e3SChalapathi Venkataramashetty             if (event == "CriticalAlarmLow")
24203a02ad0SJames Feist             {
243d0b776e3SChalapathi Venkataramashetty                 criticalAssertMap[message.get_path()]["low"] = assert;
24403a02ad0SJames Feist             }
245f1a39984Ssunitakx             else if (event == "CriticalAlarmHigh")
24603a02ad0SJames Feist             {
247d0b776e3SChalapathi Venkataramashetty                 criticalAssertMap[message.get_path()]["high"] = assert;
24803a02ad0SJames Feist             }
249d0b776e3SChalapathi Venkataramashetty             else if (event == "WarningAlarmLow")
25003a02ad0SJames Feist             {
251d0b776e3SChalapathi Venkataramashetty                 warningAssertMap[message.get_path()]["low"] = assert;
25203a02ad0SJames Feist             }
253d0b776e3SChalapathi Venkataramashetty             else if (event == "WarningAlarmHigh")
25403a02ad0SJames Feist             {
255d0b776e3SChalapathi Venkataramashetty                 warningAssertMap[message.get_path()]["high"] = assert;
25603a02ad0SJames Feist             }
25703a02ad0SJames Feist 
2587b238401SJames Feist             associationManager->setSensorAssociations(
2597b238401SJames Feist                 assertedInMap(criticalAssertMap),
2607b238401SJames Feist                 assertedInMap(warningAssertMap));
2617b238401SJames Feist 
2627b238401SJames Feist             updateLedStatus(conn);
2637b238401SJames Feist         });
2647b238401SJames Feist }
2657b238401SJames Feist 
createAssociationMatch(std::shared_ptr<sdbusplus::asio::connection> & conn)2667b238401SJames Feist void createAssociationMatch(std::shared_ptr<sdbusplus::asio::connection>& conn)
2677b238401SJames Feist {
268ff1c36e5SPatrick Williams     static sdbusplus::bus::match_t match(
269ff1c36e5SPatrick Williams         static_cast<sdbusplus::bus_t&>(*conn),
270e409fc70SJames Feist         "type='signal',interface='org.freedesktop.DBus.Properties',"
2717b238401SJames Feist         "arg0namespace='" +
2727b238401SJames Feist             std::string(associationIface) + "'",
273ff1c36e5SPatrick Williams         [&conn](sdbusplus::message_t& message) {
2747b238401SJames Feist             if (message.get_path() == rootPath)
2757b238401SJames Feist             {
2767b238401SJames Feist                 return; // it's us
2777b238401SJames Feist             }
2787b238401SJames Feist             std::string objectName;
2797b238401SJames Feist             boost::container::flat_map<std::string,
2807b238401SJames Feist                                        std::variant<std::vector<Association>>>
2817b238401SJames Feist                 values;
2827b238401SJames Feist             try
2837b238401SJames Feist             {
2847b238401SJames Feist                 message.read(objectName, values);
2857b238401SJames Feist             }
2867b238401SJames Feist             catch (sdbusplus::exception_t&)
2877b238401SJames Feist             {
2887b238401SJames Feist                 return;
2897b238401SJames Feist             }
2907b238401SJames Feist 
2917b238401SJames Feist             if constexpr (debug)
2927b238401SJames Feist             {
2937b238401SJames Feist                 std::cerr << "Association callback " << message.get_path()
2947b238401SJames Feist                           << "\n";
2957b238401SJames Feist             }
2967b238401SJames Feist 
29756078401SJames Feist             auto findAssociations = values.find("Associations");
2987b238401SJames Feist             if (findAssociations == values.end())
2997b238401SJames Feist             {
3007b238401SJames Feist                 return;
3017b238401SJames Feist             }
3027b238401SJames Feist             const std::vector<Association>* associations =
3037b238401SJames Feist                 std::get_if<std::vector<Association>>(
3047b238401SJames Feist                     &findAssociations->second);
3057b238401SJames Feist 
3067b238401SJames Feist             if (associations == nullptr)
3077b238401SJames Feist             {
3087b238401SJames Feist                 std::cerr << "Illegal Association on " << message.get_path()
3097b238401SJames Feist                           << "\n";
3107b238401SJames Feist                 return;
3117b238401SJames Feist             }
3127b238401SJames Feist 
3137b238401SJames Feist             bool localWarning = false;
3147b238401SJames Feist             bool localCritical = false;
3157b238401SJames Feist             bool globalWarning = false;
3167b238401SJames Feist             bool globalCritical = false;
3177b238401SJames Feist 
3187b238401SJames Feist             for (const auto& [forward, reverse, path] : *associations)
3197b238401SJames Feist             {
3207b238401SJames Feist                 if (path == rootPath)
3217b238401SJames Feist                 {
3227b238401SJames Feist                     globalWarning = globalWarning ? true : reverse == "warning";
3237b238401SJames Feist                     globalCritical =
3247b238401SJames Feist                         globalCritical ? true : reverse == "critical";
3257b238401SJames Feist 
3267b238401SJames Feist                     if constexpr (1)
3277b238401SJames Feist                     {
3287b238401SJames Feist                         std::cerr << "got global ";
3297b238401SJames Feist                     }
3307b238401SJames Feist                 }
3317b238401SJames Feist                 else
3327b238401SJames Feist                 {
3337b238401SJames Feist                     localWarning = localWarning ? true : reverse == "warning";
3347b238401SJames Feist                     localCritical =
3357b238401SJames Feist                         localCritical ? true : reverse == "critical";
3367b238401SJames Feist                 }
3377b238401SJames Feist                 if (globalCritical && localCritical)
3387b238401SJames Feist                 {
3397b238401SJames Feist                     break;
3407b238401SJames Feist                 }
3417b238401SJames Feist             }
3427b238401SJames Feist 
3437b238401SJames Feist             bool fatal = globalCritical && localCritical;
3447b238401SJames Feist             bool critical = globalWarning && localCritical;
34556078401SJames Feist             bool warning = globalWarning && !critical;
3467b238401SJames Feist 
3477b238401SJames Feist             fatalAssertMap[message.get_path()]["association"] = fatal;
3487b238401SJames Feist             criticalAssertMap[message.get_path()]["association"] = critical;
3497b238401SJames Feist             warningAssertMap[message.get_path()]["association"] = warning;
3507b238401SJames Feist 
3517b238401SJames Feist             updateLedStatus(conn);
3527b238401SJames Feist         });
35303a02ad0SJames Feist }
35403a02ad0SJames Feist 
main(int argc,char ** argv)35503a02ad0SJames Feist int main(int argc, char** argv)
35603a02ad0SJames Feist {
357a244198fSEd Tanous     boost::asio::io_context io;
35803a02ad0SJames Feist     auto conn = std::make_shared<sdbusplus::asio::connection>(io);
35903a02ad0SJames Feist     conn->request_name("xyz.openbmc_project.CallbackManager");
36003a02ad0SJames Feist     sdbusplus::asio::object_server objServer(conn);
361dc7bbdcbSJames Feist     std::shared_ptr<sdbusplus::asio::dbus_interface> rootIface =
362dc7bbdcbSJames Feist         objServer.add_interface(rootPath,
36303a02ad0SJames Feist                                 "xyz.openbmc_project.CallbackManager");
364dc7bbdcbSJames Feist     rootIface->register_method("RetriggerLEDUpdate",
3652816121fSRichard Marian Thomaiyar                                [&conn]() { updateLedStatus(conn, true); });
366dc7bbdcbSJames Feist     rootIface->initialize();
367dc7bbdcbSJames Feist 
368dc7bbdcbSJames Feist     std::shared_ptr<sdbusplus::asio::dbus_interface> inventoryIface =
369dc7bbdcbSJames Feist         objServer.add_interface(rootPath, globalInventoryIface);
370dc7bbdcbSJames Feist     inventoryIface->initialize();
371dc7bbdcbSJames Feist 
372dc7bbdcbSJames Feist     associationManager = std::make_unique<AssociationManager>(objServer, conn);
37303a02ad0SJames Feist 
37403a02ad0SJames Feist     createThresholdMatch(conn);
3757b238401SJames Feist     createAssociationMatch(conn);
376e409fc70SJames Feist     updateLedStatus(conn);
37703a02ad0SJames Feist 
37803a02ad0SJames Feist     io.run();
37903a02ad0SJames Feist 
38003a02ad0SJames Feist     return 0;
38103a02ad0SJames Feist }
382