xref: /openbmc/dbus-sensors/src/GPIOInterface.cpp (revision 15dde8641baa1cb902d17f9857effb081e384944)
1 #include "GPIOInterface.hpp"
2 
3 #include <gpiod.hpp>
4 #include <phosphor-logging/lg2.hpp>
5 #include <sdbusplus/async.hpp>
6 
7 #include <exception>
8 #include <memory>
9 #include <stdexcept>
10 #include <string>
11 #include <utility>
12 
13 namespace gpio
14 {
15 
16 PHOSPHOR_LOG2_USING;
17 
GPIOInterface(sdbusplus::async::context & ctx,const std::string & consumerName,const std::string & pinName,bool activeLow,Callback_t updateStateCallback)18 GPIOInterface::GPIOInterface(sdbusplus::async::context& ctx,
19                              const std::string& consumerName,
20                              const std::string& pinName, bool activeLow,
21                              Callback_t updateStateCallback) :
22     ctx(ctx), pinName(pinName),
23     updateStateCallback(std::move(updateStateCallback))
24 {
25     if (!this->updateStateCallback)
26     {
27         throw std::runtime_error("updateStateCallback is not set");
28     }
29     line = gpiod::find_line(pinName);
30     if (!line)
31     {
32         throw std::runtime_error("Failed to find GPIO line for " + pinName);
33     }
34     try
35     {
36         line.request({consumerName, gpiod::line_request::EVENT_BOTH_EDGES,
37                       activeLow ? gpiod::line_request::FLAG_ACTIVE_LOW : 0});
38     }
39     catch (std::exception& e)
40     {
41         throw std::runtime_error("Failed to request line for " + pinName +
42                                  " with error " + e.what());
43     }
44 
45     int lineFd = line.event_get_fd();
46     if (lineFd < 0)
47     {
48         throw std::runtime_error(
49             "Failed to get event fd for GPIO line " + pinName);
50     }
51 
52     fdioInstance = std::make_unique<sdbusplus::async::fdio>(ctx, lineFd);
53 }
54 
start()55 auto GPIOInterface::start() -> sdbusplus::async::task<>
56 {
57     // Start the async read for the GPIO line
58     ctx.spawn(readGPIOAsyncEvent());
59 
60     // Read the initial GPIO value
61     co_await readGPIOAsync();
62 }
63 
readGPIOAsync()64 auto GPIOInterface::readGPIOAsync() -> sdbusplus::async::task<>
65 {
66     auto lineValue = line.get_value();
67     if (lineValue < 0)
68     {
69         error("Failed to read GPIO line {LINENAME}", "LINENAME", pinName);
70         co_return;
71     }
72     co_await updateStateCallback(lineValue == gpiod::line_event::RISING_EDGE);
73 
74     co_return;
75 }
76 
readGPIOAsyncEvent()77 auto GPIOInterface::readGPIOAsyncEvent() -> sdbusplus::async::task<>
78 {
79     while (!ctx.stop_requested())
80     {
81         // Wait for the fd event for the line to change
82         co_await fdioInstance->next();
83 
84         line.event_read();
85         auto lineValue = line.get_value();
86 
87         co_await updateStateCallback(
88             lineValue == gpiod::line_event::RISING_EDGE);
89     }
90 
91     co_return;
92 }
93 
94 } // namespace gpio
95