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