xref: /openbmc/dbus-sensors/src/leakdetector/LeakDetectionManager.cpp (revision 15dde8641baa1cb902d17f9857effb081e384944)
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