45 static constexpr size_t EVENT_BUFFER_CAPACITY = 64;
53 LinuxGPIO(
const std::string& chip_path,
unsigned int line_offset)
54 : chip_path_(chip_path),
55 line_offset_(line_offset),
56 chip_(gpiod_chip_open(chip_path.c_str()))
60 XR_LOG_ERROR(
"Failed to open GPIO chip: %s", chip_path.c_str());
65 settings_ = gpiod_line_settings_new();
68 XR_LOG_ERROR(
"Failed to create GPIO line settings");
73 line_cfg_ = gpiod_line_config_new();
76 XR_LOG_ERROR(
"Failed to create GPIO line config");
81 req_cfg_ = gpiod_request_config_new();
84 XR_LOG_ERROR(
"Failed to create GPIO request config");
89 gpiod_request_config_set_consumer(req_cfg_,
"LinuxGPIO");
90 gpiod_request_config_set_event_buffer_size(req_cfg_, EVENT_BUFFER_CAPACITY);
92 event_buffer_ = gpiod_edge_event_buffer_new(EVENT_BUFFER_CAPACITY);
95 XR_LOG_ERROR(
"Failed to allocate GPIO edge event buffer");
115 enum gpiod_line_value value = gpiod_line_request_get_value(request_, line_offset_);
116 if (value == GPIOD_LINE_VALUE_ERROR)
118 XR_LOG_ERROR(
"Failed to read GPIO value: %s", std::strerror(errno));
122 return value == GPIOD_LINE_VALUE_ACTIVE;
136 enum gpiod_line_value line_value =
137 value ? GPIOD_LINE_VALUE_ACTIVE : GPIOD_LINE_VALUE_INACTIVE;
139 if (gpiod_line_request_set_value(request_, line_offset_, line_value) < 0)
141 XR_LOG_WARN(
"Failed to write GPIO value: %s", std::strerror(errno));
151 if (!has_config_ || !request_)
153 return ErrorCode::STATE_ERR;
158 return ErrorCode::ARG_ERR;
161 interrupt_enabled_ =
true;
162 return ErrorCode::OK;
171 interrupt_enabled_ =
false;
172 return ErrorCode::OK;
187 return gpiod_line_request_get_fd(request_);
201 if (READY != ErrorCode::OK)
206 bool handled =
false;
209 int ready = gpiod_line_request_wait_edge_events(request_, 0);
212 XR_LOG_ERROR(
"Failed to poll GPIO edge events: %s", std::strerror(errno));
213 return ErrorCode::FAILED;
221 int read = gpiod_line_request_read_edge_events(request_,
event_buffer_,
222 EVENT_BUFFER_CAPACITY);
225 XR_LOG_ERROR(
"Failed to read GPIO edge events: %s", std::strerror(errno));
226 return ErrorCode::FAILED;
237 for (
int i = 0; i < read; ++i)
244 return handled ? ErrorCode::OK : ErrorCode::EMPTY;
255 if (READY_STATUS != ErrorCode::OK)
260 int ready = gpiod_line_request_wait_edge_events(request_, 0);
263 XR_LOG_ERROR(
"Failed to poll GPIO edge events: %s", std::strerror(errno));
264 return ErrorCode::FAILED;
269 return ErrorCode::EMPTY;
272 int ret = gpiod_line_request_read_edge_events(request_,
event_buffer_, 1);
276 XR_LOG_ERROR(
"Failed to read GPIO edge event: %s", std::strerror(errno));
277 return ErrorCode::FAILED;
282 return ErrorCode::EMPTY;
285 struct gpiod_edge_event* edge_event =
289 XR_LOG_ERROR(
"Failed to access GPIO edge event from buffer");
290 return ErrorCode::FAILED;
293 const uint64_t TIMESTAMP_NS = gpiod_edge_event_get_timestamp_ns(edge_event);
294 if (TIMESTAMP_NS >
static_cast<uint64_t
>(std::numeric_limits<int64_t>::max()))
296 XR_LOG_ERROR(
"GPIO edge event timestamp out of int64 range");
297 return ErrorCode::OUT_OF_RANGE;
300 event.timestamp =
static_cast<int64_t
>(TIMESTAMP_NS);
302 (gpiod_edge_event_get_event_type(edge_event) == GPIOD_EDGE_EVENT_RISING_EDGE)
306 return ErrorCode::OK;
316 if (!settings_ || !line_cfg_ || !req_cfg_ || !chip_)
318 return ErrorCode::INIT_ERR;
321 interrupt_enabled_ =
false;
323 gpiod_line_settings_reset(settings_);
324 gpiod_line_config_reset(line_cfg_);
328 return ErrorCode::ARG_ERR;
333 return ErrorCode::ARG_ERR;
336 if (gpiod_line_config_add_line_settings(line_cfg_, &line_offset_, 1, settings_) < 0)
338 return ErrorCode::FAILED;
343 request_ = gpiod_chip_request_lines(chip_, req_cfg_, line_cfg_);
346 return ErrorCode::FAILED;
351 if (gpiod_line_request_reconfigure_lines(request_, line_cfg_) < 0)
353 return ErrorCode::FAILED;
357 current_config_ = config;
360 return ErrorCode::OK;
364 std::string chip_path_;
365 unsigned int line_offset_;
366 gpiod_chip* chip_ =
nullptr;
369 gpiod_line_settings* settings_ =
nullptr;
370 gpiod_request_config* req_cfg_ =
nullptr;
371 gpiod_line_config* line_cfg_ =
nullptr;
372 gpiod_line_request* request_ =
nullptr;
374 bool has_config_ =
false;
375 bool interrupt_enabled_ =
false;
386 return ErrorCode::FAILED;
392 if (gpiod_line_settings_set_direction(settings_, GPIOD_LINE_DIRECTION_INPUT) < 0)
394 return ErrorCode::FAILED;
396 if (gpiod_line_settings_set_edge_detection(settings_, GPIOD_LINE_EDGE_NONE) < 0)
398 return ErrorCode::FAILED;
403 if (gpiod_line_settings_set_direction(settings_, GPIOD_LINE_DIRECTION_OUTPUT) < 0)
405 return ErrorCode::FAILED;
407 if (gpiod_line_settings_set_drive(settings_, GPIOD_LINE_DRIVE_PUSH_PULL) < 0)
409 return ErrorCode::FAILED;
411 if (gpiod_line_settings_set_edge_detection(settings_, GPIOD_LINE_EDGE_NONE) < 0)
413 return ErrorCode::FAILED;
418 if (gpiod_line_settings_set_direction(settings_, GPIOD_LINE_DIRECTION_OUTPUT) < 0)
420 return ErrorCode::FAILED;
422 if (gpiod_line_settings_set_drive(settings_, GPIOD_LINE_DRIVE_OPEN_DRAIN) < 0)
424 return ErrorCode::FAILED;
426 if (gpiod_line_settings_set_edge_detection(settings_, GPIOD_LINE_EDGE_NONE) < 0)
428 return ErrorCode::FAILED;
433 if (gpiod_line_settings_set_direction(settings_, GPIOD_LINE_DIRECTION_INPUT) < 0)
435 return ErrorCode::FAILED;
437 if (gpiod_line_settings_set_edge_detection(settings_, GPIOD_LINE_EDGE_RISING) < 0)
439 return ErrorCode::FAILED;
444 if (gpiod_line_settings_set_direction(settings_, GPIOD_LINE_DIRECTION_INPUT) < 0)
446 return ErrorCode::FAILED;
448 if (gpiod_line_settings_set_edge_detection(settings_, GPIOD_LINE_EDGE_FALLING) <
451 return ErrorCode::FAILED;
456 if (gpiod_line_settings_set_direction(settings_, GPIOD_LINE_DIRECTION_INPUT) < 0)
458 return ErrorCode::FAILED;
460 if (gpiod_line_settings_set_edge_detection(settings_, GPIOD_LINE_EDGE_BOTH) < 0)
462 return ErrorCode::FAILED;
467 return ErrorCode::OK;
479 return ErrorCode::FAILED;
486 ret = gpiod_line_settings_set_bias(settings_, GPIOD_LINE_BIAS_DISABLED);
489 ret = gpiod_line_settings_set_bias(settings_, GPIOD_LINE_BIAS_PULL_UP);
492 ret = gpiod_line_settings_set_bias(settings_, GPIOD_LINE_BIAS_PULL_DOWN);
496 return ret < 0 ? ErrorCode::FAILED : ErrorCode::OK;
515 if (!has_config_ || !request_)
517 XR_LOG_ERROR(
"GPIO is not configured");
532 return ErrorCode::STATE_ERR;
537 XR_LOG_ERROR(
"GPIO is not configured for interrupt mode");
539 return ErrorCode::ARG_ERR;
542 if (!interrupt_enabled_)
544 XR_LOG_ERROR(
"GPIO interrupt is not enabled");
545 return ErrorCode::STATE_ERR;
548 return ErrorCode::OK;
void Run(bool in_isr, PassArgs &&... args) const
执行回调函数并传递参数 / Execute the callback with arguments
bool Empty() const
检查回调是否为空 / Check whether the callback is empty
通用输入输出(GPIO)接口类。General Purpose Input/Output (GPIO) interface class.
Callback callback_
GPIO 事件的回调函数。Callback function for GPIO events.
Direction
定义 GPIO 引脚的方向类型。Defines the direction types for GPIO pins.
@ OUTPUT_PUSH_PULL
推挽输出模式。Push-pull output mode.
@ RISING_INTERRUPT
上升沿中断模式。Rising edge interrupt mode.
@ FALL_RISING_INTERRUPT
双沿触发中断模式。Both edge interrupt mode.
@ OUTPUT_OPEN_DRAIN
开漏输出模式。Open-drain output mode.
@ FALL_INTERRUPT
下降沿中断模式。Falling edge interrupt mode.
Pull
定义 GPIO 引脚的上拉/下拉模式。Defines the pull-up/pull-down configurations for GPIO pins.
@ NONE
无上拉或下拉。No pull-up or pull-down.
@ DOWN
下拉模式。Pull-down mode.
基于 libgpiod v2.x 的 Linux GPIO 实现 Linux GPIO implementation using libgpiod v2.x
ErrorCode EnableInterrupt() override
使能 GPIO 中断处理状态。Enables GPIO interrupt handling state.
static bool IsInterruptDirection(Direction direction)
判断 direction 是否为中断方向。Checks whether direction is interrupt mode.
ErrorCode ApplyDirection(Direction direction)
根据 GPIO 方向配置 line settings。 Applies line settings according to GPIO direction.
ErrorCode ApplyPull(Pull pull)
根据 GPIO 上拉/下拉配置 line settings。 Applies line settings according to GPIO pull mode.
gpiod_edge_event_buffer * event_buffer_
持久化事件缓冲区。Persistent edge event buffer.
LinuxGPIO(const std::string &chip_path, unsigned int line_offset)
构造 LinuxGPIO 对象。Constructs a LinuxGPIO instance.
void Write(bool value) override
写入 GPIO 引脚状态。Writes a level to the GPIO line.
ErrorCode ReadEvent(GPIOEvent &event)
读取单个中断事件。Reads a single interrupt edge event.
bool Read() override
读取 GPIO 引脚状态。Reads the GPIO line level.
ErrorCode SetConfig(Configuration config) override
配置 GPIO 引脚参数。Configures GPIO line settings.
ErrorCode EnsureInterruptReady() const
确保中断路径已启用。Ensures interrupt path is enabled and ready.
ErrorCode DisableInterrupt() override
禁用 GPIO 中断处理状态。Disables GPIO interrupt handling state.
int GetFd() const
获取 GPIO request 对应的文件描述符,用于 epoll/poll 注册。 Gets the request file descriptor for epoll/poll registrati...
ErrorCode HandleInterrupt()
非阻塞处理中断事件,排空队列并触发回调。 Handles GPIO interrupt events in non-blocking mode, drains queued events and dis...
bool EnsureConfigured() const
确保 GPIO 已配置。Ensures GPIO has been configured.
GPIOEventType
GPIO 事件类型。GPIO event type.
@ FALLING_EDGE
下降沿事件。Falling edge event.
@ RISING_EDGE
上升沿事件。Rising edge event.
存储 GPIO 配置参数的结构体。Structure storing GPIO configuration parameters.
Pull pull
GPIO 上拉/下拉配置。GPIO pull-up/pull-down configuration.
Direction direction
GPIO 引脚方向。GPIO pin direction.
GPIO 事件结构体。GPIO event structure.
int64_t timestamp
事件时间戳(纳秒)。Event timestamp in nanoseconds.
GPIOEventType type
事件类型。Event type.