/* // Copyright (c) 2019 Intel Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ #include "callback_manager.hpp" #include #include #include #include constexpr const char* fatalLedPath = "/xyz/openbmc_project/led/groups/status_critical"; constexpr const char* criticalLedPath = "/xyz/openbmc_project/led/groups/status_non_critical"; constexpr const char* warningLedPath = "/xyz/openbmc_project/led/groups/status_degraded"; constexpr const char* okLedPath = "/xyz/openbmc_project/led/groups/status_ok"; constexpr const char* ledIface = "xyz.openbmc_project.Led.Group"; constexpr const char* ledAssertProp = "Asserted"; constexpr const char* ledManagerBusname = "xyz.openbmc_project.LED.GroupManager"; std::unique_ptr associationManager; enum class StatusSetting { none, ok, warn, critical, fatal }; constexpr const bool debug = false; // final led state tracking StatusSetting currentPriority = StatusSetting::none; // maps of > boost::container::flat_map> fatalAssertMap; boost::container::flat_map> criticalAssertMap; boost::container::flat_map> warningAssertMap; std::vector assertedInMap( const boost::container::flat_map< std::string, boost::container::flat_map>& map) { std::vector ret; // if any of the properties are true, return true for (const auto& pair : map) { for (const auto& item : pair.second) { if (item.second) { ret.push_back(pair.first); } } } return ret; } void updateLedStatus(std::shared_ptr& conn, bool forceRefresh = false) { std::vector fatalVector = assertedInMap(fatalAssertMap); bool fatal = fatalVector.size(); std::vector criticalVector = assertedInMap(criticalAssertMap); bool critical = criticalVector.size(); std::vector warningVector = assertedInMap(warningAssertMap); bool warn = warningVector.size(); associationManager->setLocalAssociations(fatalVector, criticalVector, warningVector); StatusSetting last = currentPriority; if (fatal) { currentPriority = StatusSetting::fatal; } else if (critical) { currentPriority = StatusSetting::critical; } else if (warn) { currentPriority = StatusSetting::warn; } else { currentPriority = StatusSetting::ok; } std::vector>> ledsToSet; if (last != currentPriority || forceRefresh) { switch (currentPriority) { case (StatusSetting::fatal): { ledsToSet.push_back(std::make_pair(fatalLedPath, true)); ledsToSet.push_back(std::make_pair(criticalLedPath, false)); ledsToSet.push_back(std::make_pair(warningLedPath, false)); ledsToSet.push_back(std::make_pair(okLedPath, false)); break; } case (StatusSetting::critical): { ledsToSet.push_back(std::make_pair(fatalLedPath, false)); ledsToSet.push_back(std::make_pair(criticalLedPath, true)); ledsToSet.push_back(std::make_pair(warningLedPath, false)); ledsToSet.push_back(std::make_pair(okLedPath, false)); break; } case (StatusSetting::warn): { ledsToSet.push_back(std::make_pair(fatalLedPath, false)); ledsToSet.push_back(std::make_pair(criticalLedPath, false)); ledsToSet.push_back(std::make_pair(warningLedPath, true)); ledsToSet.push_back(std::make_pair(okLedPath, false)); break; } case (StatusSetting::ok): { ledsToSet.push_back(std::make_pair(fatalLedPath, false)); ledsToSet.push_back(std::make_pair(criticalLedPath, false)); ledsToSet.push_back(std::make_pair(warningLedPath, false)); ledsToSet.push_back(std::make_pair(okLedPath, true)); break; } } } for (const auto& ledPair : ledsToSet) { conn->async_method_call( [ledPair](const boost::system::error_code ec) { if (ec) { std::cerr << "Cannot set " << ledPair.first << " to " << std::boolalpha << std::get(ledPair.second) << "\n"; } if constexpr (debug) { std::cerr << "Set " << ledPair.first << " to " << std::boolalpha << std::get(ledPair.second) << "\n"; } }, ledManagerBusname, ledPair.first, "org.freedesktop.DBus.Properties", "Set", ledIface, ledAssertProp, ledPair.second); } } void createThresholdMatch(std::shared_ptr& conn) { static sdbusplus::bus::match::match match( static_cast(*conn), "type='signal',interface='org.freedesktop.DBus.Properties'," "path_" "namespace='/xyz/openbmc_project/" "sensors',arg0namespace='xyz.openbmc_project.Sensor.Threshold'", [&conn](sdbusplus::message::message& message) { std::string objectName; boost::container::flat_map> values; try { message.read(objectName, values); } catch (sdbusplus::exception_t&) { return; } if constexpr (debug) { std::cerr << "Threshold callback " << message.get_path() << "\n"; } auto findCriticalLow = values.find("CriticalAlarmLow"); auto findCriticalHigh = values.find("CriticalAlarmHigh"); auto findWarnLow = values.find("WarningAlarmLow"); auto findWarnHigh = values.find("WarningAlarmHigh"); if (findCriticalLow != values.end()) { criticalAssertMap[message.get_path()]["Low"] = std::get(findCriticalLow->second); } if (findCriticalHigh != values.end()) { criticalAssertMap[message.get_path()]["High"] = std::get(findCriticalHigh->second); } if (findWarnLow != values.end()) { warningAssertMap[message.get_path()]["Low"] = std::get(findWarnLow->second); } if (findWarnHigh != values.end()) { warningAssertMap[message.get_path()]["High"] = std::get(findWarnHigh->second); } associationManager->setSensorAssociations( assertedInMap(criticalAssertMap), assertedInMap(warningAssertMap)); updateLedStatus(conn); }); } void createAssociationMatch(std::shared_ptr& conn) { static sdbusplus::bus::match::match match( static_cast(*conn), "type='signal',interface='org.freedesktop.DBus.Properties'," "arg0namespace='" + std::string(associationIface) + "'", [&conn](sdbusplus::message::message& message) { if (message.get_path() == rootPath) { return; // it's us } std::string objectName; boost::container::flat_map>> values; try { message.read(objectName, values); } catch (sdbusplus::exception_t&) { return; } if constexpr (debug) { std::cerr << "Association callback " << message.get_path() << "\n"; } auto findAssociations = values.find("associations"); if (findAssociations == values.end()) { return; } const std::vector* associations = std::get_if>( &findAssociations->second); if (associations == nullptr) { std::cerr << "Illegal Association on " << message.get_path() << "\n"; return; } bool localWarning = false; bool localCritical = false; bool globalWarning = false; bool globalCritical = false; for (const auto& [forward, reverse, path] : *associations) { if (path == rootPath) { globalWarning = globalWarning ? true : reverse == "warning"; globalCritical = globalCritical ? true : reverse == "critical"; if constexpr (1) { std::cerr << "got global "; } } else { localWarning = localWarning ? true : reverse == "warning"; localCritical = localCritical ? true : reverse == "critical"; } if (globalCritical && localCritical) { break; } } bool fatal = globalCritical && localCritical; bool critical = globalWarning && localCritical; bool warning = globalWarning && localWarning; fatalAssertMap[message.get_path()]["association"] = fatal; criticalAssertMap[message.get_path()]["association"] = critical; warningAssertMap[message.get_path()]["association"] = warning; updateLedStatus(conn); }); } int main(int argc, char** argv) { boost::asio::io_service io; auto conn = std::make_shared(io); conn->request_name("xyz.openbmc_project.CallbackManager"); sdbusplus::asio::object_server objServer(conn); std::shared_ptr rootIface = objServer.add_interface(rootPath, "xyz.openbmc_project.CallbackManager"); rootIface->register_method("RetriggerLEDUpdate", [&conn]() { updateLedStatus(conn, true); }); rootIface->initialize(); std::shared_ptr inventoryIface = objServer.add_interface(rootPath, globalInventoryIface); inventoryIface->initialize(); associationManager = std::make_unique(objServer, conn); createThresholdMatch(conn); createAssociationMatch(conn); updateLedStatus(conn); io.run(); return 0; }