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