2

I am trying to read a GPIO value using whenever it changes the state.

/sys/class/gpio/gpio499/value

I have set /sys/class/gpio/gpio499/edge to be both

I am trying to monitor the change in value using poll command in one separate thread. Here is the code snippet :

void PIN_gpio_poll(size_t gpio)     //GPIO 499
{
        char path[30];
        char cValue;
        int fd;
        int ret_poll;
        int ret_read;
        struct pollfd pollfd;
        int i;

        pollfd.events = POLLPRI | POLLERR; /* look for GPIO status change. */


        snprintf(path, 30, PHDRIVER_LINUX_CFG_DIR "/gpio%u/value", gpio);
        fd = open(path, O_RDONLY);
        if (fd == -1)
        {
                printf("Gpio_poll _ERROR\r\n");
        }

        pollfd.fd = fd;

        ret_read = read(pollfd.fd, &cValue, 1);    // Dummy Read to clear

        while (1)
        {
                lseek(fd, 0, SEEK_SET);
                ret_read = read(fd, &cValue, 1);
                printf("Value=%c, RET READ=%d\n",cValue,ret_read);
//              ret_poll = poll( &pollfd, 1, -1 );
                ret_poll = poll( &pollfd, 1, 10000 );  //10sec timeout

                printf("******REVENTS=%x\n",pollfd.revents);
                if( ret_poll == -1 )
                {
                        printf("Gpio_poll poll failed\r\n");
                        close(fd);
                }else{
//                      if (pollfd.revents & POLLPRI )
                        {
                                lseek(fd, 0, SEEK_SET);
                                ret_read = read(pollfd.fd, &cValue, 1);
                                if(ret_read > 0)
                                {
                                    printf("Cvalue = %c\n",cValue);
                                }
                        }

                }
        }
}

The problem I am facing is if I set events as POLLIN, poll returns immediately. This is understood because there is always data to be read in value (0 or 1) GPIO. I referred https://www.kernel.org/doc/Documentation/gpio/sysfs.txt and set events as POLLPRI | POLLERR . But in this method the poll returns only after timeout. It doesn't return when value of the GPIO is changed. Is there anything I am missing the trick here?? I have also set /sys/class/gpio/gpio499/edge to rising, falling, but nothing seems to be working.

EDIT: Here is the output of grep -r . /sys/class/gpio/gpio499

/sys/class/gpio/gpio499/edge:both
/sys/class/gpio/gpio499/power/control:auto
/sys/class/gpio/gpio499/power/runtime_active_time:0
grep: /sys/class/gpio/gpio499/power/autosuspend_delay_ms: Input/output error
/sys/class/gpio/gpio499/power/runtime_status:unsupported
/sys/class/gpio/gpio499/power/runtime_suspended_time:0
/sys/class/gpio/gpio499/value:1
/sys/class/gpio/gpio499/active_low:0
/sys/class/gpio/gpio499/direction:in

Note: I want to detect value from 1 to 0.

Kumara
  • 301
  • 1
  • 3
  • 10
  • Did you make sure, that the pin is configured as input? (`cat /sys/class/gpio/gpio499/direction` says _in_?) – Ctx Oct 19 '17 at 08:13
  • Maybe the output of `grep -r . /sys/class/gpio/gpio499` (edited into your question) can help – Ctx Oct 19 '17 at 08:16
  • 1
    Possible duplicate of [how to detect a pin change of a GPIO on Linux board](https://stackoverflow.com/questions/25962574/how-to-detect-a-pin-change-of-a-gpio-on-linux-board) – Jackson Oct 19 '17 at 08:33
  • yes @Ctx . direction set to _in_ – Kumara Oct 19 '17 at 08:34
  • @KeshavaKumar Did you make sure, that the content of /sys/class/gpio/gpio499/value indeed changes? – Ctx Oct 19 '17 at 09:01
  • @Ctx yes. It indeed changes. I have read fd in while(1) and it changes to 0,1 perfectly as intended. But _poll_ doesn't seems to be working for me. – Kumara Oct 19 '17 at 09:14
  • 1
    Ok, the rest looks fine, which gpio-driver is working here? Maybe it has a bug or the behaviour is unimplemented? – Ctx Oct 19 '17 at 09:37
  • @Ctx . I am working with IO Expander PCAL6416AHF,128 . https://www.nxp.com/docs/en/data-sheet/PCAL6416A.pdf where pin configured as GPIO. – Kumara Oct 19 '17 at 09:52
  • Consider to use new ABI for GPIO, i.e. character device and corresponding IOCTLs. An example is under *tools/gpio* – 0andriy Oct 19 '17 at 17:33
  • What is `PHDRIVER_LINUX_CFG_DIR` ? maybe `char path[30];` is a bit undersized... How about PATH_MAX ?Also: a `size_t` needs a`%s`or`%zu` format specifier. – wildplasser Oct 19 '17 at 21:18

1 Answers1

0

the function: poll() does not work as the posted code is expecting.

Suggest: 1) read the file to get the current input value. 2) execute a spin loop, reading the value, until the value changes, similar to:

readbytes = read( fd, &cValue, 1 );  
while( readbytes > 0 )
{  
    if( (off_t)-1 == lseek(fd, 0, SEEK_SET) )
    { // then lseek failed
        perror( "lseek failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, lseek successful

    readbytes = read(fd, &new_cValue, 1);
    if( 0 >= readbytes )
    { 
        perror( "read failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, read successful

    if( cValue != new_cValue )
    { // then state changed
        cValue = new_cValue;
        break;
    }
}

This loop does burn more CPU cycles, but should work

user3629249
  • 16,402
  • 1
  • 16
  • 17