blob: 75c740f44f9366d7d3207e24413e18541aa1c636 [file] [log] [blame]
#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