Move to subproject to enable both projects
Yocto builds need each component to build individually, but meson wants
them to build as a single project. This follows google-misc and moves
to subprojects.
It also enables callback-manager in the build and fixes some build
errors and warnings.
Change-Id: Ie56141bf86b6d9c6b27eb697944fbc392e374c22
Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
diff --git a/subprojects/callback-manager/src/callback_manager.cpp b/subprojects/callback-manager/src/callback_manager.cpp
new file mode 100644
index 0000000..4d54ffe
--- /dev/null
+++ b/subprojects/callback-manager/src/callback_manager.cpp
@@ -0,0 +1,384 @@
+/*
+// 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 <boost/asio/io_context.hpp>
+#include <boost/asio/steady_timer.hpp>
+#include <boost/container/flat_map.hpp>
+#include <sdbusplus/asio/connection.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+
+#include <variant>
+
+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> associationManager;
+
+enum class StatusSetting
+{
+ none,
+ ok,
+ warn,
+ critical,
+ fatal
+};
+
+constexpr const bool debug = false;
+
+// final led state tracking
+StatusSetting currentPriority = StatusSetting::none;
+
+// maps of <object-path, <property, asserted>>
+boost::container::flat_map<std::string,
+ boost::container::flat_map<std::string, bool>>
+ fatalAssertMap;
+boost::container::flat_map<std::string,
+ boost::container::flat_map<std::string, bool>>
+ criticalAssertMap;
+boost::container::flat_map<std::string,
+ boost::container::flat_map<std::string, bool>>
+ warningAssertMap;
+
+std::vector<std::string> assertedInMap(
+ const boost::container::flat_map<
+ std::string, boost::container::flat_map<std::string, bool>>& map)
+{
+ std::vector<std::string> 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<sdbusplus::asio::connection>& conn,
+ bool forceRefresh = false)
+{
+ std::vector<std::string> fatalVector = assertedInMap(fatalAssertMap);
+ bool fatal = fatalVector.size();
+
+ std::vector<std::string> criticalVector = assertedInMap(criticalAssertMap);
+ bool critical = criticalVector.size();
+
+ std::vector<std::string> warningVector = assertedInMap(warningAssertMap);
+ bool warn = warningVector.size();
+
+ associationManager->setLocalAssociations(fatalVector, criticalVector,
+ warningVector);
+
+ StatusSetting last = currentPriority;
+ std::vector<std::pair<std::string, std::variant<bool>>> ledsToSet;
+ if (forceRefresh)
+ {
+ 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, false));
+ for (const auto& ledPair : ledsToSet)
+ {
+ conn->async_method_call(
+ [ledPair](const boost::system::error_code ec) {
+ std::ios_base::fmtflags originalFlags = std::cerr.flags();
+ if (ec)
+ {
+ std::cerr << "Cannot set " << ledPair.first << " to "
+ << std::boolalpha
+ << std::get<bool>(ledPair.second) << "\n";
+ std::cerr.flags(originalFlags);
+ }
+ if constexpr (debug)
+ {
+ std::cerr << "Set " << ledPair.first << " to "
+ << std::boolalpha
+ << std::get<bool>(ledPair.second) << "\n";
+ std::cerr.flags(originalFlags);
+ }
+ },
+ ledManagerBusname, ledPair.first,
+ "org.freedesktop.DBus.Properties", "Set", ledIface,
+ ledAssertProp, ledPair.second);
+ }
+ }
+ if (fatal)
+ {
+ currentPriority = StatusSetting::fatal;
+ }
+ else if (critical)
+ {
+ currentPriority = StatusSetting::critical;
+ }
+ else if (warn)
+ {
+ currentPriority = StatusSetting::warn;
+ }
+ else
+ {
+ currentPriority = StatusSetting::ok;
+ }
+
+ 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;
+ }
+ case (StatusSetting::none):
+ default:
+ 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<bool>(ledPair.second) << "\n";
+ }
+ if constexpr (debug)
+ {
+ std::cerr
+ << "Set " << ledPair.first << " to " << std::boolalpha
+ << std::get<bool>(ledPair.second) << "\n";
+ }
+ },
+ ledManagerBusname, ledPair.first, "org.freedesktop.DBus.Properties",
+ "Set", ledIface, ledAssertProp, ledPair.second);
+ }
+}
+
+void createThresholdMatch(std::shared_ptr<sdbusplus::asio::connection>& conn)
+{
+ static sdbusplus::bus::match_t match(
+ static_cast<sdbusplus::bus_t&>(*conn),
+ "type='signal',member='ThresholdAsserted'",
+ [&conn](sdbusplus::message_t& message) {
+ std::string sensorName;
+ std::string thresholdInterface;
+ std::string event;
+ bool assert;
+ double assertValue;
+
+ try
+ {
+ message.read(sensorName, thresholdInterface, event, assert,
+ assertValue);
+ }
+ catch (sdbusplus::exception_t&)
+ {
+ return;
+ }
+ if constexpr (debug)
+ {
+ std::cerr << "Threshold callback: SensorName = " << sensorName
+ << ", Event = " << event << ", Asserted = " << assert
+ << "\n";
+ }
+
+ if (event == "CriticalAlarmLow")
+ {
+ criticalAssertMap[message.get_path()]["low"] = assert;
+ }
+ else if (event == "CriticalAlarmHigh")
+ {
+ criticalAssertMap[message.get_path()]["high"] = assert;
+ }
+ else if (event == "WarningAlarmLow")
+ {
+ warningAssertMap[message.get_path()]["low"] = assert;
+ }
+ else if (event == "WarningAlarmHigh")
+ {
+ warningAssertMap[message.get_path()]["high"] = assert;
+ }
+
+ associationManager->setSensorAssociations(
+ assertedInMap(criticalAssertMap),
+ assertedInMap(warningAssertMap));
+
+ updateLedStatus(conn);
+ });
+}
+
+void createAssociationMatch(std::shared_ptr<sdbusplus::asio::connection>& conn)
+{
+ static sdbusplus::bus::match_t match(
+ static_cast<sdbusplus::bus_t&>(*conn),
+ "type='signal',interface='org.freedesktop.DBus.Properties',"
+ "arg0namespace='" +
+ std::string(associationIface) + "'",
+ [&conn](sdbusplus::message_t& message) {
+ if (message.get_path() == rootPath)
+ {
+ return; // it's us
+ }
+ std::string objectName;
+ boost::container::flat_map<std::string,
+ std::variant<std::vector<Association>>>
+ 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<Association>* associations =
+ std::get_if<std::vector<Association>>(
+ &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 && !critical;
+
+ 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_context io;
+ auto conn = std::make_shared<sdbusplus::asio::connection>(io);
+ conn->request_name("xyz.openbmc_project.CallbackManager");
+ sdbusplus::asio::object_server objServer(conn);
+ std::shared_ptr<sdbusplus::asio::dbus_interface> rootIface =
+ objServer.add_interface(rootPath,
+ "xyz.openbmc_project.CallbackManager");
+ rootIface->register_method("RetriggerLEDUpdate", [&conn]() {
+ updateLedStatus(conn, true);
+ });
+ rootIface->initialize();
+
+ std::shared_ptr<sdbusplus::asio::dbus_interface> inventoryIface =
+ objServer.add_interface(rootPath, globalInventoryIface);
+ inventoryIface->initialize();
+
+ associationManager = std::make_unique<AssociationManager>(objServer, conn);
+
+ createThresholdMatch(conn);
+ createAssociationMatch(conn);
+ updateLedStatus(conn);
+
+ io.run();
+
+ return 0;
+}