2016-06-03 10 views
0

Я пытаюсь поймать прерывание на GPIO через sysfs, используя poll(). У меня есть -1 в третьей позиции, поэтому он может блокироваться, но, похоже, он всегда возвращается. Я проверил некоторые подобные сообщения на SO. В частности, this (1), this (2) и this (3).poll() не блокируется, сразу возвращается

В (1), было решено путем размещения манекена read() перед вызовом poll(). Если я это сделаю (см. Комментарий read() в коде). Мой код проходит через цикл один раз и блокирует навсегда на poll() во второй раз.

В (2) это может быть объяснение, но на самом деле не является решением моей проблемы.

В (3), у меня уже есть lseek() перед моим read()

Как я могу получить эту poll() блокировать и возвращать только как в прерывании, когда изменился линии GPIO value?

Вот фрагмент кода:

int read_gpio(char *path, void (*callback)(int)){ 
    int fd; 
    char buf[11]; 
    int res = 0; 
    char c; 
    int off; 
    struct pollfd gpio_poll_fd = { 
     .fd = fd, 
     .events = POLLPRI, 
     .revents = 0 
    }; 
    for(;;){ 

     gpio_poll_fd.fd = open(path, O_RDONLY); 
     if(fd == -1){ 
      perror("error opening file"); 
      return -1; 
     } 
//  char c; 
//  read(fd,&c,1); 
     LOGD("for begins"); 
     res = poll(&gpio_poll_fd,1,-1); 
     LOGD("polling ended"); 
     if(res == -1){ 
      perror("error polling"); 
      break; 
     } 

     if((gpio_poll_fd.revents & POLLPRI) == POLLPRI){ 
      LOGD("POLLPRI"); 
      off = lseek(fd, 0, SEEK_SET); 
      if(off == -1) break; 
      memset(&buf[0], 0, 11); 
      size_t num = read(fd, &buf[0], 10*sizeof(char)); 
      LOGD("Before callback"); 
      callback(atoi(buf)); 
      LOGD("After Callback"); 
     } 
     if((gpio_poll_fd.revents & POLLERR) == POLLERR) { 
      //seems always to be true .. 
      //LOGD("POLLERR"); 
     } 
     close(fd); 
     LOGD("for ends"); 

    } 
    LOGD("for exits"); 

    return 0; 
} 

Примечание: Как я это делаю на Android JNI, я получал информацию для отладки из LOGD()

Update: После совет в комментарии jxh Я устроил структуру, как это, хотя теперь он блокирует на poll() бесконечно. Когда содержание значения изменяются от внешнего приложенного напряжения, POLLPRI не идет высоко, и опрос() не возвращает:

int read_gpio(char *path, void (*callback)(int)){ 
    int fd = open(path, O_RDONLY); 
    if(fd == -1){ 
     perror("error opening file"); 
     return -1; 
    } 
    char buf[11]; 
    int res, off; 
    char c; 
    struct pollfd pfd = { 
      .fd = fd, 
      .events = POLLPRI, 
      .revents = 0 
    }; 
    for(;;){ 
     LOGD("for begins"); 
//  dummy read causes poll never to run 
//  lseek() alone here cause poll never to run 
//  read(fd, &buf[],1); 
//  lseek(fd, 0, SEEK_SET); 
     res = poll(&pfd,1,-1); 
     LOGD("polling ended"); 
     if(res == -1){ 
      perror("error polling"); 
      break; 
     } 

     if((pfd.revents & POLLPRI) == POLLPRI){ 
      LOGD("POLLPRI"); 
      off = lseek(fd, 0, SEEK_SET); 
      if(off == -1) break; 
      memset(&buf[0], 0, 11); 
      read(fd, &buf[0], 10*sizeof(char)); 
//   These two lines will cause it to poll constantly 
//   close(fd); 
//   fd = open(path, O_RDONLY); 
      LOGD("Before callback"); 
      callback(atoi(buf)); 
      LOGD("After Callback"); 
     } 
     LOGD("for ends"); 
    } 
    close(fd); 
    LOGD("for exits"); 

    return 0; 
} 
+1

Вы уверены, что ваш 'open()' преуспевает? Ваш код, который, как представляется, предназначен для проверки, который смотрит на неправильную переменную. –

+0

@JohnBollinger Определенно, я получаю правильное значение. Спасибо, что подняли голову на тест. –

+0

Непонятно, почему вы полагаете, что ответ, указанный в вашей ссылке (1), можно игнорировать. Кажется, это объясняет поведение, которое вы сообщаете для представленного случая, в котором вы не читаете файл между его открытием и опросом. Возможно, вы действительно хотите спросить, почему 'poll()' блокирует бесконечно, когда выполняется после этого начального чтения? –

ответ

4

В коде fd не инициализирован.

При открытии файла вы назначаете gpio_poll_fd.fd напрямую, без использования fd, поэтому fd остается неинициализированным.

Try:

gpio_poll_fd.fd = fd = open(path, O_RDONLY); 

Как было отмечено в комментариях, в соответствии с GPIO manual (который я не читал, пока после прохождения через эти замечания более тщательно), интерфейс GPIO sysfs немного особенным:

Если вывод может быть сконфигурирован как прерывание генерирующей прерывание , и если он был сконфигурирован для генерации прерываний (см описания «край»), вы можете poll(2) в этом файле и poll(2) будет возвращаться при каждом запуске прерывания. Если вы используете poll(2), задайте события POLLPRI и POLLERR. Если вы используете , используйте select(2), установите дескриптор файла в exceptfds. После poll(2) возвращает lseek(2) в начало sysfs файл и прочитайте новое значение или закройте файл и откройте его , чтобы прочитать значение.

Итак, хотя это не типичная идиома poll(), ваша конструкция закрытия и повторного открытия правильная. Однако я бы предпочел оставить дескриптор файла открытым. Итак, вот как я бы структурировал ваш код:

int read_gpio(char *path, void (*callback)(int)){ 
    char buf[11]; 
    int fd, res, off; 
    struct pollfd pfd; 
    if((pfd.fd = fd = open(path, O_RDONLY)) == -1){ 
     perror("path"); 
     return -1; 
    } 
    LOGD("First read"); 
    res = read(fd, buf, 10); 
    assert(res == 10); 
    LOGD("Before callback"); 
    callback(atoi(buf)); 
    LOGD("After Callback"); 
    pfd.events = POLLPRI|POLLERR; // poll(2) says setting POLLERR is 
            // unnecessary, but GPIO may be 
            // special. 
    for(;;){ 
     LOGD("for begins"); 
     if((res = poll(&pfd,1,-1)) == -1){ 
      perror("poll"); 
      break; 
     } 
     LOGD("polling ended"); 
     if((pfd.revents & POLLPRI) == POLLPRI){ 
      LOGD("POLLPRI"); 
      off = lseek(fd, 0, SEEK_SET); 
      if(off == -1) break; 
      memset(buf, 0, 11); 
      res = read(fd, buf, 10); 
      assert(res == 10); 
      LOGD("Before callback"); 
      callback(atoi(buf)); 
      LOGD("After Callback"); 
     } else { 
      // POLLERR, POLLHUP, or POLLNVAL 
      break; 
     } 
     LOGD("for ends"); 
    } 
    close(fd); 
    LOGD("for exits"); 

    return 0; 
} 
+0

Я сделал это в for 'for (;;)'. Должно ли это быть сделано снаружи? –

+0

Поскольку вы закрываете (fd) 'на каждой итерации внутри' for'. – jxh

+0

Да, это полностью объясняет проблему. Sysfs FD является одним опросом, но в значительной степени во всем мире используется неинициализированный 'fd'. –