I'm facing an issue with the libgpiod, I guess there is a solution but it's not clear for me. I want to create sometimes a worker that will listen some gpio chip lines events and be able to stop it.
I spawn the worker thread in something like that:
std::jthread([this]() {
gpiod_line_event event;
while (is_running) {
gpiod_line_event_wait(line, NULL);
gpiod_line_event_read(line, &event);
if (event.event_type == GPIOD_LINE_EVENT_RISING_EDGE) {
std::cout << "GPIOD_LINE_EVENT_RISING_EDGE\n";
} else if (event.event_type == GPIOD_LINE_EVENT_FALLING_EDGE) {
std::cout << "GPIOD_LINE_EVENT_FALLING_EDGE\n";
}
}
});
That let me stuck in gpiod_line_event_wait. Is there a good way to cancel it and continue properly?
I tried to close the chip and release the line. I also tried to set the line value but nothing worked. I've seen that constant GPIOD_CTXLESS_EVENT_POLL_RET_STOP but I don't really understand if it can help me and how I should use it.
Edit: of course I could also use the timeout parameter and check if I should quit the execution sometimes but I'm looking for something else.
Edit:
Actually there is a pretty simple solution. libgpiod provides the gpiod_line_request_get_fd that return a file descriptor for the line.
Once you've that, you can create 2 pollfd structures, the line-request will have events POLLIN and POLLPRI and the second will be a simple channel with the event you want. Then we can just call ppoll with these arguments and trigger the channel whenever we want to stop the worker.
An implementation could be:
int wait_until(int fd, int channel, int64_t timeout_ns)
{
struct pollfd pfds[2];
int ret;
memset(&pfds, 0, sizeof(pfds));
pfds[0].fd = fd;
pfds[0].events = POLLIN | POLLPRI;
pfds[1].fd = channel;
pfds[1].events = POLLIN | POLLERR;
ret = poll_fds(pfds, 2, timeout_ns);
if (ret >= 1 && pfds[1].revents != 0)
return 2;
return ret;
}
static int
poll_fds(struct pollfd *pfds, uint8_t len, int64_t timeout_ns)
{
struct timespec ts;
int ret;
if (timeout_ns >= 0) {
ts.tv_sec = timeout_ns / 1000000000ULL;
ts.tv_nsec = timeout_ns % 1000000000ULL;
}
ret = ppoll(pfds, len, timeout_ns < 0 ? NULL : &ts, NULL);
if (ret < 0)
return -1;
else if (ret == 0)
return 0;
return 1;
}