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