1 #include "LeakDetectionManager.hpp"
2
3 #include "LeakGPIODetector.hpp"
4
5 #include <phosphor-logging/lg2.hpp>
6 #include <sdbusplus/async.hpp>
7 #include <sdbusplus/message/native_types.hpp>
8 #include <sdbusplus/server/manager.hpp>
9
10 #include <exception>
11 #include <functional>
12 #include <memory>
13 #include <optional>
14 #include <string>
15
16 PHOSPHOR_LOG2_USING;
17
18 namespace leak
19 {
20
DetectionManager(sdbusplus::async::context & ctx)21 DetectionManager::DetectionManager(sdbusplus::async::context& ctx) :
22 ctx(ctx), leakEvents(ctx),
23 entityManager(
24 ctx, {GPIODetectorConfigIntf::interface},
25 std::bind_front(&DetectionManager::processInventoryAdded, this),
26 std::bind_front(&DetectionManager::processInventoryRemoved, this))
27 {
28 ctx.spawn(entityManager.handleInventoryGet());
29 }
30
processInventoryAdded(const sdbusplus::message::object_path & objectPath,const std::string &)31 auto DetectionManager::processInventoryAdded(
32 const sdbusplus::message::object_path& objectPath,
33 const std::string& /*unused*/) -> void
34 {
35 ctx.spawn(processConfigAddedAsync(objectPath));
36 }
37
processInventoryRemoved(const sdbusplus::message::object_path & objectPath,const std::string &)38 auto DetectionManager::processInventoryRemoved(
39 const sdbusplus::message::object_path& objectPath,
40 const std::string& /*unused*/) -> void
41 {
42 if (!detectors.contains(objectPath.str))
43 {
44 return;
45 }
46 debug("Removed detector {DETECTOR}", "DETECTOR", objectPath);
47 detectors.erase(objectPath.str);
48 }
49
processConfigAddedAsync(sdbusplus::message::object_path objectPath)50 auto DetectionManager::processConfigAddedAsync(
51 sdbusplus::message::object_path objectPath) -> sdbusplus::async::task<>
52 {
53 auto res = co_await getDetectorConfig(objectPath);
54 if (!res)
55 {
56 co_return;
57 }
58 auto config = res.value();
59
60 if (detectors.contains(objectPath.str))
61 {
62 warning("Detector {DETECTOR} already exist", "DETECTOR", config.name);
63 co_return;
64 }
65
66 try
67 {
68 detectors[objectPath.str] =
69 std::make_unique<GPIODetector>(ctx, leakEvents, config);
70 }
71 catch (std::exception& e)
72 {
73 error("Failed to create detector {DETECTOR}: {ERROR}", "DETECTOR",
74 config.name, "ERROR", e.what());
75 }
76
77 co_return;
78 }
79
getDetectorConfig(sdbusplus::message::object_path objectPath)80 auto DetectionManager::getDetectorConfig(
81 sdbusplus::message::object_path objectPath)
82 -> sdbusplus::async::task<std::optional<config::DetectorConfig>>
83 {
84 config::DetectorConfig config = {};
85
86 auto properties =
87 co_await GPIODetectorConfigIntf(ctx)
88 .service(entity_manager::EntityManagerInterface::serviceName)
89 .path(objectPath.str)
90 .properties();
91
92 config.name = properties.name;
93
94 for (const auto& [key, value] : config::validDetectorTypes)
95 {
96 if (properties.type == key)
97 {
98 config.type = value;
99 break;
100 }
101 }
102
103 config.pinName = properties.pin_name;
104
105 for (const auto& [key, value] : config::validPinPolarity)
106 {
107 if (properties.polarity == key)
108 {
109 config.polarity = value;
110 break;
111 }
112 }
113 if (config.polarity == config::PinPolarity::unknown)
114 {
115 error("Invalid polarity {POLARITY} for {NAME}", "POLARITY",
116 properties.polarity, "NAME", config.name);
117 co_return std::nullopt;
118 }
119
120 for (const auto& [key, value] : config::validDetectorLevel)
121 {
122 if (properties.level == key)
123 {
124 config.level = value;
125 break;
126 }
127 }
128 if (config.level == config::DetectorLevel::unknown)
129 {
130 error("Invalid level {LEVEL} for {NAME}", "LEVEL", properties.level,
131 "NAME", config.name);
132 co_return std::nullopt;
133 }
134
135 debug("Detector config: {NAME} {PIN_NAME} {POLARITY} {LEVEL}", "NAME",
136 config.name, "PIN_NAME", config.pinName, "POLARITY", config.polarity,
137 "LEVEL", config.level);
138
139 co_return config;
140 }
141
142 } // namespace leak
143
main()144 int main()
145 {
146 constexpr auto path = leak::DetectorIntf::namespace_path::value;
147 constexpr auto serviceName = "xyz.openbmc_project.leakdetector";
148 sdbusplus::async::context ctx;
149 sdbusplus::server::manager_t manager{ctx, path};
150
151 info("Creating leak detection manager at {PATH}", "PATH", path);
152 leak::DetectionManager leakDetectionManager{ctx};
153
154 ctx.request_name(serviceName);
155
156 ctx.run();
157 return 0;
158 }
159