blob: 7948802fffcd29f08dc320889730c549a62a1514 [file] [log] [blame]
Alexander Hansen8c4b1d92024-11-04 14:06:24 +01001/*
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
16PHOSPHOR_LOG2_USING;
17
18using 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>;
21using ConfigMap = boost::container::flat_map<std::string, VariantType>;
22using ConfigData = boost::container::flat_map<std::string, ConfigMap>;
23
24namespace gpio_presence
25{
26
27ConfigProvider::ConfigProvider(sdbusplus::async::context& ctx,
28 const std::string& interface) :
29 interface(interface), ctx(ctx)
30{}
31
32auto 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
42auto 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
87namespace rules_intf = sdbusplus::bus::match::rules;
88
89const auto senderRule = rules_intf::sender("xyz.openbmc_project.EntityManager");
90
91auto 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 {
101 auto [objPath, intfMap] =
102 co_await addedMatch
103 .next<sdbusplus::message::object_path, ConfigData>();
104
105 debug("Detected interface added on {OBJPATH}", "OBJPATH", objPath);
106
107 if (!std::ranges::contains(std::views::keys(intfMap), interface))
108 {
109 continue;
110 }
111
112 try
113 {
114 addConfig(objPath);
115 }
116 catch (std::exception& e)
117 {
118 error("Incomplete or invalid config found: {ERR}", "ERR", e);
119 }
120 }
121};
122
123auto ConfigProvider::handleInterfacesRemoved(RemovedCallback removeConfig)
124 -> sdbusplus::async::task<void>
125{
126 debug("setting up dbus match for interfaces removed");
127
128 sdbusplus::async::match removedMatch(
129 ctx, rules_intf::interfacesRemoved() + senderRule);
130
131 while (!ctx.stop_requested())
132 {
133 auto [objectPath, interfaces] =
134 co_await removedMatch.next<sdbusplus::message::object_path,
135 std::vector<std::string>>();
136
137 if (!std::ranges::contains(interfaces, interface))
138 {
139 continue;
140 }
141
142 debug("Detected interface {INTF} removed on {OBJPATH}", "INTF",
143 interface, "OBJPATH", objectPath);
144
145 removeConfig(objectPath);
146 }
147};
148
149} // namespace gpio_presence