| /* |
| * SPDX-FileCopyrightText: Copyright (c) 2022-2024. All rights |
| * reserved. SPDX-License-Identifier: Apache-2.0 |
| */ |
| #include "config_provider.hpp" |
| |
| #include <boost/container/flat_map.hpp> |
| #include <phosphor-logging/lg2.hpp> |
| #include <sdbusplus/async/match.hpp> |
| #include <sdbusplus/bus/match.hpp> |
| #include <xyz/openbmc_project/ObjectMapper/client.hpp> |
| |
| #include <ranges> |
| #include <string> |
| |
| PHOSPHOR_LOG2_USING; |
| |
| using VariantType = |
| std::variant<std::vector<std::string>, std::string, int64_t, uint64_t, |
| double, int32_t, uint32_t, int16_t, uint16_t, uint8_t, bool>; |
| using ConfigMap = boost::container::flat_map<std::string, VariantType>; |
| using ConfigData = boost::container::flat_map<std::string, ConfigMap>; |
| |
| namespace gpio_presence |
| { |
| |
| ConfigProvider::ConfigProvider(sdbusplus::async::context& ctx, |
| const std::string& interface) : |
| interface(interface), ctx(ctx) |
| {} |
| |
| auto ConfigProvider::initialize(AddedCallback addConfig, |
| RemovedCallback removeConfig) |
| -> sdbusplus::async::task<void> |
| { |
| ctx.spawn(handleInterfacesAdded(addConfig)); |
| ctx.spawn(handleInterfacesRemoved(removeConfig)); |
| |
| co_await getConfig(addConfig); |
| } |
| |
| auto ConfigProvider::getConfig(AddedCallback addConfig) |
| -> sdbusplus::async::task<void> |
| { |
| auto client = sdbusplus::client::xyz::openbmc_project::ObjectMapper<>(ctx) |
| .service("xyz.openbmc_project.ObjectMapper") |
| .path("/xyz/openbmc_project/object_mapper"); |
| |
| debug("calling 'GetSubTree' to find instances of {INTF}", "INTF", |
| interface); |
| |
| using SubTreeType = |
| std::map<std::string, std::map<std::string, std::vector<std::string>>>; |
| SubTreeType res = {}; |
| |
| try |
| { |
| std::vector<std::string> interfaces = {interface}; |
| res = co_await client.get_sub_tree("/xyz/openbmc_project/inventory", 0, |
| interfaces); |
| } |
| catch (std::exception& e) |
| { |
| error("Failed GetSubTree call for configuration interface: {ERR}", |
| "ERR", e); |
| } |
| |
| if (res.empty()) |
| { |
| co_return; |
| } |
| |
| // call the user callback for all the device that is already available |
| for (auto& [path, serviceInterfaceMap] : res) |
| { |
| for (const auto& service : |
| std::ranges::views::keys(serviceInterfaceMap)) |
| { |
| debug("found configuration interface at {SERVICE} {PATH} {INTF}", |
| "SERVICE", service, "PATH", path, "INTF", interface); |
| |
| addConfig(path); |
| } |
| } |
| } |
| |
| namespace rules_intf = sdbusplus::bus::match::rules; |
| |
| const auto senderRule = rules_intf::sender("xyz.openbmc_project.EntityManager"); |
| |
| auto ConfigProvider::handleInterfacesAdded(AddedCallback addConfig) |
| -> sdbusplus::async::task<void> |
| { |
| debug("setting up dbus match for interfaces added"); |
| |
| sdbusplus::async::match addedMatch( |
| ctx, rules_intf::interfacesAdded() + senderRule); |
| |
| while (!ctx.stop_requested()) |
| { |
| auto [objPath, intfMap] = |
| co_await addedMatch |
| .next<sdbusplus::message::object_path, ConfigData>(); |
| |
| debug("Detected interface added on {OBJPATH}", "OBJPATH", objPath); |
| |
| if (!std::ranges::contains(std::views::keys(intfMap), interface)) |
| { |
| continue; |
| } |
| |
| try |
| { |
| addConfig(objPath); |
| } |
| catch (std::exception& e) |
| { |
| error("Incomplete or invalid config found: {ERR}", "ERR", e); |
| } |
| } |
| }; |
| |
| auto ConfigProvider::handleInterfacesRemoved(RemovedCallback removeConfig) |
| -> sdbusplus::async::task<void> |
| { |
| debug("setting up dbus match for interfaces removed"); |
| |
| sdbusplus::async::match removedMatch( |
| ctx, rules_intf::interfacesRemoved() + senderRule); |
| |
| while (!ctx.stop_requested()) |
| { |
| auto [objectPath, interfaces] = |
| co_await removedMatch.next<sdbusplus::message::object_path, |
| std::vector<std::string>>(); |
| |
| if (!std::ranges::contains(interfaces, interface)) |
| { |
| continue; |
| } |
| |
| debug("Detected interface {INTF} removed on {OBJPATH}", "INTF", |
| interface, "OBJPATH", objectPath); |
| |
| removeConfig(objectPath); |
| } |
| }; |
| |
| } // namespace gpio_presence |