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