| Alexander Hansen | 8c4b1d9 | 2024-11-04 14:06:24 +0100 | [diff] [blame] | 1 | /* | 
 | 2 |  * SPDX-FileCopyrightText: Copyright (c) 2022-2024. All rights | 
 | 3 |  * reserved. SPDX-License-Identifier: Apache-2.0 | 
 | 4 |  */ | 
 | 5 | #include "config_provider.hpp" | 
 | 6 |  | 
 | 7 | #include <boost/container/flat_map.hpp> | 
 | 8 | #include <phosphor-logging/lg2.hpp> | 
 | 9 | #include <sdbusplus/async/match.hpp> | 
 | 10 | #include <sdbusplus/bus/match.hpp> | 
 | 11 | #include <xyz/openbmc_project/ObjectMapper/client.hpp> | 
 | 12 |  | 
 | 13 | #include <ranges> | 
 | 14 | #include <string> | 
 | 15 |  | 
 | 16 | PHOSPHOR_LOG2_USING; | 
 | 17 |  | 
 | 18 | using VariantType = | 
 | 19 |     std::variant<std::vector<std::string>, std::string, int64_t, uint64_t, | 
 | 20 |                  double, int32_t, uint32_t, int16_t, uint16_t, uint8_t, bool>; | 
 | 21 | using ConfigMap = boost::container::flat_map<std::string, VariantType>; | 
 | 22 | using ConfigData = boost::container::flat_map<std::string, ConfigMap>; | 
 | 23 |  | 
 | 24 | namespace gpio_presence | 
 | 25 | { | 
 | 26 |  | 
 | 27 | ConfigProvider::ConfigProvider(sdbusplus::async::context& ctx, | 
 | 28 |                                const std::string& interface) : | 
 | 29 |     interface(interface), ctx(ctx) | 
 | 30 | {} | 
 | 31 |  | 
 | 32 | auto ConfigProvider::initialize(AddedCallback addConfig, | 
 | 33 |                                 RemovedCallback removeConfig) | 
 | 34 |     -> sdbusplus::async::task<void> | 
 | 35 | { | 
 | 36 |     ctx.spawn(handleInterfacesAdded(addConfig)); | 
 | 37 |     ctx.spawn(handleInterfacesRemoved(removeConfig)); | 
 | 38 |  | 
 | 39 |     co_await getConfig(addConfig); | 
 | 40 | } | 
 | 41 |  | 
 | 42 | auto ConfigProvider::getConfig(AddedCallback addConfig) | 
 | 43 |     -> sdbusplus::async::task<void> | 
 | 44 | { | 
 | 45 |     auto client = sdbusplus::client::xyz::openbmc_project::ObjectMapper<>(ctx) | 
 | 46 |                       .service("xyz.openbmc_project.ObjectMapper") | 
 | 47 |                       .path("/xyz/openbmc_project/object_mapper"); | 
 | 48 |  | 
 | 49 |     debug("calling 'GetSubTree' to find instances of {INTF}", "INTF", | 
 | 50 |           interface); | 
 | 51 |  | 
 | 52 |     using SubTreeType = | 
 | 53 |         std::map<std::string, std::map<std::string, std::vector<std::string>>>; | 
 | 54 |     SubTreeType res = {}; | 
 | 55 |  | 
 | 56 |     try | 
 | 57 |     { | 
 | 58 |         std::vector<std::string> interfaces = {interface}; | 
 | 59 |         res = co_await client.get_sub_tree("/xyz/openbmc_project/inventory", 0, | 
 | 60 |                                            interfaces); | 
 | 61 |     } | 
 | 62 |     catch (std::exception& e) | 
 | 63 |     { | 
 | 64 |         error("Failed GetSubTree call for configuration interface: {ERR}", | 
 | 65 |               "ERR", e); | 
 | 66 |     } | 
 | 67 |  | 
 | 68 |     if (res.empty()) | 
 | 69 |     { | 
 | 70 |         co_return; | 
 | 71 |     } | 
 | 72 |  | 
 | 73 |     // call the user callback for all the device that is already available | 
 | 74 |     for (auto& [path, serviceInterfaceMap] : res) | 
 | 75 |     { | 
 | 76 |         for (const auto& service : | 
 | 77 |              std::ranges::views::keys(serviceInterfaceMap)) | 
 | 78 |         { | 
 | 79 |             debug("found configuration interface at {SERVICE} {PATH} {INTF}", | 
 | 80 |                   "SERVICE", service, "PATH", path, "INTF", interface); | 
 | 81 |  | 
 | 82 |             addConfig(path); | 
 | 83 |         } | 
 | 84 |     } | 
 | 85 | } | 
 | 86 |  | 
 | 87 | namespace rules_intf = sdbusplus::bus::match::rules; | 
 | 88 |  | 
 | 89 | const auto senderRule = rules_intf::sender("xyz.openbmc_project.EntityManager"); | 
 | 90 |  | 
 | 91 | auto ConfigProvider::handleInterfacesAdded(AddedCallback addConfig) | 
 | 92 |     -> sdbusplus::async::task<void> | 
 | 93 | { | 
 | 94 |     debug("setting up dbus match for interfaces added"); | 
 | 95 |  | 
 | 96 |     sdbusplus::async::match addedMatch( | 
 | 97 |         ctx, rules_intf::interfacesAdded() + senderRule); | 
 | 98 |  | 
 | 99 |     while (!ctx.stop_requested()) | 
 | 100 |     { | 
| Alexander Hansen | 6483200 | 2025-07-24 15:52:16 +0200 | [diff] [blame] | 101 |         auto tmp = co_await addedMatch | 
 | 102 |                        .next<sdbusplus::message::object_path, ConfigData>(); | 
 | 103 |  | 
 | 104 |         auto [objPath, intfMap] = std::move(tmp); | 
| Alexander Hansen | 8c4b1d9 | 2024-11-04 14:06:24 +0100 | [diff] [blame] | 105 |  | 
 | 106 |         debug("Detected interface added on {OBJPATH}", "OBJPATH", objPath); | 
 | 107 |  | 
 | 108 |         if (!std::ranges::contains(std::views::keys(intfMap), interface)) | 
 | 109 |         { | 
 | 110 |             continue; | 
 | 111 |         } | 
 | 112 |  | 
 | 113 |         try | 
 | 114 |         { | 
 | 115 |             addConfig(objPath); | 
 | 116 |         } | 
 | 117 |         catch (std::exception& e) | 
 | 118 |         { | 
 | 119 |             error("Incomplete or invalid config found: {ERR}", "ERR", e); | 
 | 120 |         } | 
 | 121 |     } | 
 | 122 | }; | 
 | 123 |  | 
 | 124 | auto ConfigProvider::handleInterfacesRemoved(RemovedCallback removeConfig) | 
 | 125 |     -> sdbusplus::async::task<void> | 
 | 126 | { | 
 | 127 |     debug("setting up dbus match for interfaces removed"); | 
 | 128 |  | 
 | 129 |     sdbusplus::async::match removedMatch( | 
 | 130 |         ctx, rules_intf::interfacesRemoved() + senderRule); | 
 | 131 |  | 
 | 132 |     while (!ctx.stop_requested()) | 
 | 133 |     { | 
| Alexander Hansen | 6483200 | 2025-07-24 15:52:16 +0200 | [diff] [blame] | 134 |         auto tmp = co_await removedMatch.next<sdbusplus::message::object_path, | 
 | 135 |                                               std::vector<std::string>>(); | 
 | 136 |         auto [objectPath, interfaces] = std::move(tmp); | 
| Alexander Hansen | 8c4b1d9 | 2024-11-04 14:06:24 +0100 | [diff] [blame] | 137 |  | 
 | 138 |         if (!std::ranges::contains(interfaces, interface)) | 
 | 139 |         { | 
 | 140 |             continue; | 
 | 141 |         } | 
 | 142 |  | 
 | 143 |         debug("Detected interface {INTF} removed on {OBJPATH}", "INTF", | 
 | 144 |               interface, "OBJPATH", objectPath); | 
 | 145 |  | 
 | 146 |         removeConfig(objectPath); | 
 | 147 |     } | 
 | 148 | }; | 
 | 149 |  | 
 | 150 | } // namespace gpio_presence |