| #include "tlbmc/hal/gpio/gpio_monitor.h" |
| |
| #include <gpiod.h> |
| |
| #include <memory> |
| #include <utility> |
| |
| #include "absl/log/log.h" |
| #include "absl/memory/memory.h" |
| #include "boost/asio/io_context.hpp" // NOLINT: boost is commonly used in BMC codebase |
| #include "boost/asio/posix/stream_descriptor.hpp" // NOLINT: boost is commonly used in BMC codebase |
| #include "g3/macros.h" |
| #include "gpio_config.pb.h" |
| #include "tlbmc/hal/gpio/gpio.h" |
| |
| namespace milotic_tlbmc { |
| |
| GpioMonitor::GpioMonitor( |
| std::unique_ptr<Gpio> gpio, bool is_one_time_request, |
| std::unique_ptr<boost::asio::posix::stream_descriptor> event_descriptor) |
| : gpio_(std::move(gpio)), |
| is_one_time_request_(is_one_time_request), |
| event_descriptor_(std::move(event_descriptor)) { |
| ScheduleEventHandler(); |
| } |
| |
| GpioMonitor::~GpioMonitor() { |
| if (event_descriptor_->is_open()) { |
| event_descriptor_->close(); |
| } |
| } |
| |
| void GpioMonitor::ScheduleEventHandler() { |
| event_descriptor_->async_wait( |
| boost::asio::posix::stream_descriptor::wait_read, |
| [this](const boost::system::error_code& ec) { |
| if (ec) { |
| LOG(ERROR) << "GPIO event handler error: " << ec.message(); |
| return; |
| } |
| EventHandler(); |
| }); |
| } |
| |
| void GpioMonitor::EventHandler() { |
| // Need to consume the event. Otherwise, the event will be stuck in the queue |
| // and the descriptor will always be ready for read. |
| gpiod_line_event gpio_line_event; |
| if (gpiod_line_event_read_fd(event_descriptor_->native_handle(), |
| &gpio_line_event) < 0) { |
| LOG(ERROR) << ("Failed to read from GPIO event descriptor"); |
| return; |
| } |
| |
| // TODO(alexlai): Implement generic event handler for other modules and |
| // functions. |
| |
| if (is_one_time_request_) { |
| event_descriptor_->close(); |
| } else { |
| ScheduleEventHandler(); |
| } |
| } |
| |
| absl::StatusOr<std::unique_ptr<GpioMonitor>> GpioMonitor::Create( |
| const GpioConfig& gpio_config, |
| std::shared_ptr<boost::asio::io_context> io_context) { |
| ECCLESIA_ASSIGN_OR_RETURN(std::unique_ptr<Gpio> gpio, |
| Gpio::Create(gpio_config)); |
| auto event_descriptor = |
| std::make_unique<boost::asio::posix::stream_descriptor>(*io_context); |
| event_descriptor->assign(gpio->GetGpioLineEventFd()); |
| |
| return absl::WrapUnique(new GpioMonitor( |
| std::move(gpio), gpio_config.gpio_event_config().one_time_request(), |
| std::move(event_descriptor))); |
| } |
| |
| } // namespace milotic_tlbmc |