blob: f57a722a398c8199924e457abfda18acac5df02e [file] [log] [blame]
Jagpal Singh Gillca8c7e92024-11-02 16:51:48 -07001#include "CableMonitor.hpp"
2
3#include "CableConfig.hpp"
4
5#include <phosphor-logging/lg2.hpp>
6#include <sdbusplus/async.hpp>
7#include <sdbusplus/async/stdexec/__detail/__then.hpp>
8#include <sdbusplus/message/native_types.hpp>
9#include <sdbusplus/server/manager.hpp>
10
11#include <chrono>
12#include <cstring>
13#include <filesystem>
14#include <functional>
15#include <string>
16
17PHOSPHOR_LOG2_USING;
18
19namespace cable
20{
21
22Monitor::Monitor(sdbusplus::async::context& ctx) :
23 ctx(ctx), cableEvents(ctx),
24 entityManager(ctx, {CableInventoryIntf::interface},
25 std::bind_front(&Monitor::inventoryAddedHandler, this),
26 std::bind_front(&Monitor::inventoryRemovedHandler, this)),
27 notifyWatch(ctx, Config::configFileDir,
28 std::bind_front(&Monitor::configUpdateHandler, this))
29{
30 ctx.spawn(start());
31}
32
33auto Monitor::inventoryAddedHandler(
34 const sdbusplus::message::object_path& objectPath,
35 const std::string& /*unused*/) -> void
36{
37 debug("Received cable added for {NAME}", "NAME", objectPath);
38 ctx.spawn(processCableAddedAsync(objectPath));
39}
40
41auto Monitor::inventoryRemovedHandler(
42 const sdbusplus::message::object_path& objectPath,
43 const std::string& /*unused*/) -> void
44{
45 debug("Received cable removed for {NAME}", "NAME", objectPath);
46 ctx.spawn(processCableRemovedAsync(objectPath));
47}
48
49auto Monitor::configUpdateHandler(std::string configFileName)
50 -> sdbusplus::async::task<>
51{
52 if (strcmp(Config::configFileName, configFileName.c_str()) != 0)
53 {
54 error("Update config file name {NAME} is not expected", "NAME",
55 configFileName);
56 co_return;
57 }
58 auto configFilePath =
59 std::string(Config::configFileDir) + "/" + configFileName;
60 if (!std::filesystem::exists(configFilePath))
61 {
62 error("Config file {NAME} does not exist", "NAME", configFilePath);
63 co_return;
64 }
65 expectedCables = co_await Config::processConfig(configFilePath);
66 if (expectedCables.empty())
67 {
68 error("No expected cables found in config file {NAME}", "NAME",
69 configFileName);
70 co_return;
71 }
72 co_await entityManager.handleInventoryGet();
73 ctx.spawn(sdbusplus::async::sleep_for(ctx, std::chrono::seconds(5)) |
74 stdexec::then([&]() { reconcileCableData(); }));
75}
76
77auto Monitor::start() -> sdbusplus::async::task<>
78{
79 info("Start cable monitor");
80
81 // Start async handler for cable config update
82 ctx.spawn(notifyWatch.readNotifyAsync());
83
84 // Process the cable config if it already exists
85 auto configFilePath =
86 std::string(Config::configFileDir) + "/" + Config::configFileName;
87 if (std::filesystem::exists(configFilePath))
88 {
89 co_await configUpdateHandler(Config::configFileName);
90 }
91
92 co_return;
93}
94
95auto Monitor::processCableAddedAsync(sdbusplus::message::object_path objectPath)
96 -> sdbusplus::async::task<>
97{
98 auto cableName = objectPath.filename();
99
100 debug("Received cable added for {NAME}", "NAME", cableName);
101
102 if (connectedCables.contains(cableName))
103 {
104 debug("Cable {NAME} is already connected, so skip it", "NAME",
105 cableName);
106 co_return;
107 }
108 else if (expectedCables.empty())
109 {
110 debug("No expected cables yet, so skip cable add for {NAME}", "NAME",
111 cableName);
112 co_return;
113 }
114 else if (!expectedCables.contains(cableName))
115 {
116 debug(
117 "Cable {NAME} is not in expected cables, skip connected event generation",
118 "NAME", cableName);
119 co_return;
120 }
121
122 connectedCables.insert(cableName);
123 co_await cableEvents.generateCableEvent(Events::Type::connected, cableName);
124 debug("New cable {NAME} added", "NAME", cableName);
125
126 co_return;
127}
128
129auto Monitor::processCableRemovedAsync(
130 sdbusplus::message::object_path objectPath) -> sdbusplus::async::task<>
131{
132 auto cableName = objectPath.filename();
133
134 debug("Received cable removed for {NAME}", "NAME", cableName);
135
136 if (expectedCables.empty())
137 {
138 debug("No expected cables yet, so skip cable add for {NAME}", "NAME",
139 cableName);
140 co_return;
141 }
142 else if (!expectedCables.contains(cableName))
143 {
144 debug(
145 "Cable {NAME} is not in expected cables, so skip disconnected event generation",
146 "NAME", cableName);
147 co_return;
148 }
149 else if (!connectedCables.contains(cableName))
150 {
151 debug(
152 "Cable {NAME} is not connected, so skip disconnected event generation",
153 "NAME", cableName);
154 co_return;
155 }
156
157 connectedCables.erase(cableName);
158 co_await cableEvents.generateCableEvent(Events::Type::disconnected,
159 cableName);
160 debug("Removed cable {NAME}", "NAME", cableName);
161
162 co_return;
163}
164
165auto Monitor::reconcileCableData() -> void
166{
167 for (const auto& cableName : expectedCables)
168 {
169 if (connectedCables.contains(cableName))
170 {
171 continue;
172 }
173 ctx.spawn(cableEvents.generateCableEvent(Events::Type::disconnected,
174 cableName));
175 }
176}
177
178} // namespace cable
179
180int main()
181{
182 constexpr auto path = "/xyz/openbmc_project/cable_monitor";
183 constexpr auto serviceName = "xyz.openbmc_project.cablemonitor";
184 sdbusplus::async::context ctx;
185 sdbusplus::server::manager_t manager{ctx, path};
186
187 info("Creating cable monitor");
188 cable::Monitor cableMonitor{ctx};
189 ctx.request_name(serviceName);
190
191 ctx.run();
192 return 0;
193}