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 bool forceRefresh = false) 84 { 85 std::vector<std::string> assertedVector = assertedInMap(fatalAssertMap); 86 assertedIface->set_property("Fatal", assertedVector); 87 bool fatal = assertedVector.size(); 88 89 assertedVector = assertedInMap(criticalAssertMap); 90 assertedIface->set_property("Critical", assertedVector); 91 bool critical = assertedVector.size(); 92 93 assertedVector = assertedInMap(warningAssertMap); 94 assertedIface->set_property("Warning", assertedVector); 95 96 bool warn = assertedVector.size(); 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 assertedIface = 241 objServer.add_interface("/xyz/openbmc_project/CallbackManager", 242 "xyz.openbmc_project.CallbackManager"); 243 assertedIface->register_property("Warning", std::vector<std::string>()); 244 assertedIface->register_property("Critical", std::vector<std::string>()); 245 assertedIface->register_property("Fatal", std::vector<std::string>()); 246 assertedIface->register_method("RetriggerLEDUpdate", 247 [&conn]() { updateLedStatus(conn, true); }); 248 assertedIface->initialize(); 249 250 createThresholdMatch(conn); 251 updateLedStatus(conn); 252 253 io.run(); 254 255 return 0; 256 } 257