[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 use select() or poll() 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?
    function ugpio_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 or both to the file /sys/class/gpio/gpioX/edge (with X 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 or both to the file /sys/class/gpio/gpioX/edge (with X being the number of your GPIO).
    ...
    See here for documentation on the sysfs GPIO API

    I 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.



Looks like your connection to Community was lost, please wait while we try to reconnect.