[Resolved] How use select()/poll() with GPIO?
-
Hello all! I'm using libugpio library (libugpio.so) and it has one special function (see listing of
ugpio.h
file below):#!c++ /** * Return the GPIO context's value file descriptor. * * Using this function the application can feed the file descriptor into it's * select/poll... loop to monitor it for events. * * @param ctx a GPIO context * @return the file descriptor of the opened value file of the GPIO */ int ugpio_fd(ugpio_t *ctx);
But I can't find any example to how to use it.
Actually I need make pseudo-interrupts (special waitable
pthread
) because our libraries has no hardware IRQs and user-space library for it. For this we only can useselect()
orpoll()
system functions.I tried code below, but select function returns with timeout, poll function returns immediate. Other the code of mine works correct - I can read real pin state.
#!c++ #include <iostream> #include <ugpio.h> #include <sys/select.h> #include <poll.h> using namespace std; #define DEFAULT_GPIO_TEST_PIN 11 static int test_ugpio_pin(unsigned int pinNum) { int result; // Для функции select() fd_set fd_gpio_in; FD_ZERO(&fd_gpio_in); struct timeval select_timeout; // Переменные для функции poll() struct pollfd fds[1]; fds[0].events = POLLIN; result = gpio_is_requested(pinNum); if (result < 0) { cerr << "Error: Pin #" << pinNum << " is already busy" << endl; return result; } ugpio_t *pMyPin = ugpio_request_one(pinNum, GPIOF_DIR_IN, "myTestPin"); if (pMyPin == NULL) { cerr << "Error: Pin #" << pinNum << " cannot be requested." << endl; return -1; } result = ugpio_open(pMyPin); if (result < 0) { cerr << "Error open file pin in sysfs" << endl; goto err_exit; } result = ugpio_get_activelow(pMyPin); if (result < 0) { cerr << "Error: Pin #" << pinNum << " cannot get active level." << endl; goto err_exit2; } if (result) { cout << "Active level Pin#" << pinNum << "is HIGH" << endl; } else { cout << "Active level Pin#" << pinNum << "is LOW" << endl; } // Проверка работы псевдопрерывания // Using select() select_timeout = { 10, 0 }; FD_SET(ugpio_fd(pMyPin), &fd_gpio_in); result = select(1, &fd_gpio_in, NULL, NULL, &select_timeout); if (result) { cout << "Pseudo-IRQ: Pin has been changed!" << endl; } else { cout << "Timeout: The pin doesn't changed in 10 secs." << endl; } // Using poll() fds[0].fd = ugpio_fd(pMyPin); fds[0].revents = 0; result = poll(fds, 1, 10000); if (result < 0) { cerr << "Error poll() calling!" << endl; } else if (result == 0) { cout << "Timeout: The pin doesn't changed in 10 secs." << endl; } else { cout << "Pseudo-IRQ: It works! The pin has been changed!" << endl; fds[0].revents = 0; } // Чтение состояния result = ugpio_get_value(pMyPin); if (result < 0) { cerr << "Error: Can't read value Pin #" << pinNum << "." << endl; result = -1; goto err_exit2; } else if (result) { cout << "Pin #" << pinNum << " read current state is HIGH" << endl; } else { cout << "Pin #" << pinNum << " read current state is LOW" << endl; } result = 0; err_exit2: ugpio_close(pMyPin); err_exit: ugpio_free(pMyPin); return result; }
Both function normally works with
stdint
file descriptor number 0; May be libugpio with bags?
functionugpio_fd(pMyPin)
return value 3 of file descriptor.
-
Hi @Modest-Polykarpovich,
I am not familiar with libugpio but I am using GPIO interrupts a lot in my own C++ code by directly using the /sys/class/gpio interface.So I can't be sure, but It seems to me that your code misses the step to actually enable GPIO IRQs. To do that, you need to write
rising
,falling
orboth
to the file/sys/class/gpio/gpioX/edge
(withX
being the number of your GPIO).
Maybe there is a function in libugpio to do that...Other than that, your code looks entirely fine to me.
See here for documentation on the sysfs GPIO API
-
@luz said in How use select()/poll() with GPIO?:
Maybe there is a function in libugpio to do that...
Other than that, your code looks entirely fine to me.
This library is very simple, But lib-function
gpio_set_edge()
always return error and value in the file/sys/class/gpio/gpio[N]/edge
is "none".#!bash # cat /sys/class/gpio/gpio11/edge none
But I follow example and manually set value to "rising", but after that it's not works just as well.
@luz said in How use select()/poll() with GPIO?:
So I can't be sure, but It seems to me that your code misses the step to actually enable GPIO IRQs. To do that, you need to write
rising
,falling
orboth
to the file/sys/class/gpio/gpioX/edge
(withX
being the number of your GPIO).
...
See here for documentation on the sysfs GPIO APII saw this document and I can't find my error. I found one example, but this code after compile doesn't work, may be it need special GCC keys - it is doesn't matter. I took this code in my test application and it doesn't works too.
@luz said in How use select()/poll() with GPIO?:
Hi @Modest-Polykarpovich,
I am not familiar with libugpio but I am using GPIO interrupts a lot in my own C++ code by directly using the /sys/class/gpio interface.Could you please send me 100% work your code?
-
I fixed it! The library
libugpio
with bugs. Below is 100% work code GPIO (sysfs) preudo-IRQ + libgpio. See and analyze.!#c++ #include <iostream> #include <ugpio.h> // For gpio (sysfs) test pseudo-IRQs control only #include <stdio.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <poll.h> using namespace std; #define DEFAULT_GPIO_TEST_PIN 11 #define GPIO_EDGE_RISING "rising" #define GPIO_EDGE_FALLING "falling" #define GPIO_EDGE_BOTH "both" /* * The function below copied from project https://github.com/OnionIoT/gpioIrqTrigger/blob/master/gpioIrqTrigger.c * It's correct setting edge in "gpio - sysfs". * WARNING! The libugpio's function equivalent "ugpio_set_edge()" doesn't work (Bug)! */ static int my_gpio_set_edge(const unsigned int gpio, const char *edge) { int fd, len; char buf[255]; memset(buf, 0, sizeof(buf)); len = snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/edge", gpio); fd = open(buf, O_WRONLY | O_NONBLOCK); if (fd < 0) { cerr << "Error open file file " << buf << " result code #" << fd << endl; return fd; } write(fd, edge, strlen(edge) + 1); close(fd); return 0; } static int test_ugpioIrq_pin(unsigned int pinNum, const char * edge) { int result; // Initializations for poll()'function using struct pollfd fds[1]; int length; char buf[255]; char d; /* Запрашиваем номер вывода */ ugpio_t *pMyPin = ugpio_request_one(pinNum, GPIOF_DIR_IN, "MyTestPin"); if (pMyPin == NULL) { cerr << "Error: Pin #" << pinNum << " cannot be requested." << endl; return -1; } /* * Устанавливаем направление - вход * ATTENTION! We are using low-level API of libugpio, because function "ugpio_direction_input()" doesn't work (Bug) and already returns value -1. */ result = gpio_direction_input(pinNum); if (result < 0) { cerr << "Error: Cannot assign direction, function ugpio_direction_input()." << endl; goto err_exit; } /* Устанавливаем триггер срабатывания [ "rising" | "falling" | "both" ] */ if (result = my_gpio_set_edge(pinNum, edge) < 0) { cerr << "Error: set edge fail" << endl; goto err_exit; } /* Открытие вывода для дальнейших операций */ result = ugpio_open(pMyPin); if (result < 0) { cerr << "Error open file pin in sysfs" << endl; goto err_exit; } // Пятикратный опрос poll() for (int i = 0; i < 5; i++) { memset((void*)fds, 0, sizeof(fds)); fds[0].fd = ugpio_fd(pMyPin); // File descriptor number of opened file: /sysfs/class/gpio/gpio[N]/value fds[0].events = POLLPRI; // By official manual from https://www.kernel.org/doc/Documentation/gpio/sysfs.txt if (result = poll(fds, (sizeof(fds) / sizeof(struct pollfd)), 10000) < 0) { // Wait change pin state while 10 seconds. cerr << "Error: Poll function call failed" << endl; goto err_exit2; } /* Event analyze block --begin */ if (fds[0].revents & POLLPRI) { /* * [options] Чтение значения состояния пина */ memset(buf, 0, sizeof(buf)); // Очистка буфера для стабильности lseek(fds[0].fd, 0, SEEK_SET); // Становка указателя в начало length = read(fds[0].fd, buf, sizeof(buf)); // Читаем значение файлового дескриптора cout << "GPIO current state is " << buf << endl; } /* Event analyze block --end */ } result = 0; err_exit2: ugpio_close(pMyPin); err_exit: ugpio_free(pMyPin); return result; }
-
@Modest-Polykarpovich said in [Resolved] How use select()/poll() with GPIO?:
[...] Could you please send me 100% work your code?
I see that you solved the problem already - cool!
Bus just in case - my implementation is this one, which is part of a larger set of utilities handling other peripherals such as i2c, spi, pwm and a lot of other stuff, based on a common mainloop for timers and I/O polling.