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