xref: /openbmc/dbus-sensors/src/leakdetector/LeakGPIODetector.cpp (revision e6b1731fe95eb7d2c195929edf64ea42a110f1f1)
1 #include "LeakGPIODetector.hpp"
2 
3 #include "LeakEvents.hpp"
4 #include "SystemdInterface.hpp"
5 
6 #include <sdbusplus/async.hpp>
7 #include <sdbusplus/message/native_types.hpp>
8 
9 #include <array>
10 #include <functional>
11 #include <string>
12 #include <string_view>
13 #include <tuple>
14 
15 namespace leak
16 {
17 
18 namespace config
19 {
20 
21 /** @brief Leak level to systemd target service map */
22 static constexpr std::array<
23     std::tuple<config::DetectorLevel, std::string_view, std::string_view>, 4>
24     leakActionTargets = {
25         {{config::DetectorLevel::warning, "assert",
26           "xyz.openbmc_project.leakdetector.warning.assert@"},
27          {config::DetectorLevel::warning, "deassert",
28           "xyz.openbmc_project.leakdetector.warning.deassert@"},
29          {config::DetectorLevel::critical, "assert",
30           "xyz.openbmc_project.leakdetector.critical.assert@"},
31          {config::DetectorLevel::critical, "deassert",
32           "xyz.openbmc_project.leakdetector.critical.deassert@"}}};
33 } // namespace config
34 
getObjectPath(const std::string & detectorName)35 static auto getObjectPath(const std::string& detectorName)
36     -> sdbusplus::message::object_path
37 {
38     return (
39         sdbusplus::message::object_path(DetectorIntf::namespace_path::value) /
40         DetectorIntf::namespace_path::detector / detectorName);
41 }
42 
GPIODetector(sdbusplus::async::context & ctx,Events & leakEvents,const config::DetectorConfig & config)43 GPIODetector::GPIODetector(sdbusplus::async::context& ctx, Events& leakEvents,
44                            const config::DetectorConfig& config) :
45     DetectorIntf(ctx, getObjectPath(config.name).str.c_str()), ctx(ctx),
46     leakEvents(leakEvents), config(config),
47     gpioInterface(ctx, config.name, config.pinName,
48                   (config.polarity == config::PinPolarity::activeLow),
49                   std::bind_front(&GPIODetector::updateGPIOStateAsync, this))
50 {
51     pretty_name<false>(config.name);
52     type<false>(config.type);
53 
54     ctx.spawn(gpioInterface.start());
55 
56     debug("Created leak detector {NAME}", "NAME", config.name);
57 }
58 
updateGPIOStateAsync(bool gpioState)59 auto GPIODetector::updateGPIOStateAsync(bool gpioState)
60     -> sdbusplus::async::task<>
61 {
62     auto newState = gpioState ? DetectorIntf::DetectorState::Abnormal
63                               : DetectorIntf::DetectorState::Normal;
64 
65     debug("Updating detector {DETECTOR} state to {STATE}", "DETECTOR",
66           config.name, "STATE", newState);
67 
68     if (newState != state_)
69     {
70         state(newState);
71 
72         co_await leakEvents.generateLeakEvent(getObjectPath(config.name),
73                                               state_, config.level);
74         std::string action = (state_ == DetectorIntf::DetectorState::Normal)
75                                  ? "deassert"
76                                  : "assert";
77 
78         for (const auto& [level, action_str, serviceSuffix] :
79              config::leakActionTargets)
80         {
81             if (config.level == level && action_str == action)
82             {
83                 auto target = std::string(serviceSuffix) + config.name +
84                               ".service";
85                 debug("Starting systemd target {TARGET}", "TARGET", target);
86                 co_await systemd::SystemdInterface::startUnit(ctx, target);
87                 break;
88             }
89         }
90     }
91 
92     co_return;
93 }
94 
95 } // namespace leak
96