Обнаружение, если символическое устройство отключилось в Linux с помощью termios api (c ++)

Я использую termios api в Linux для связи с последовательным устройством. Я пытаюсь определить, было ли устройство отключено, поэтому я могу попытаться восстановить соединение через некоторое время. У меня есть следующий пример кода:

while(1)
{
    FD_ZERO(&rfds);
    FD_SET(tty_fd, &rfds);

    // have tried checking fcntl(tty_fd, F_GETFL); too

    // Blocking call to wait until we have data
    select(tty_fd+1, &rfds, NULL, NULL, NULL);

    // While we have data, collect it
    while (read(tty_fd, &c, 1)>0 && bytesRead++<200)
    {
        serialBuffer.push_back(c);
    }

    bytesRead = 0;

    // Try to parse it
    BufferParse();
}

На самом деле я не вижу select () или fcntl возвращают значения ошибки (-1) после физического отключения устройства ttyUSB. Я мог бы, конечно, проверить, существует ли файл в / dev /, но я надеялся, что было более элегантное решение.

Буду признателен за любые советы, спасибо!

 chris1289212 дек. 2015 г., 18:55
Что-то еще: значение errno никогда не меняется независимо от того, подключен он или нет. Остается в 11
 spinkus15 дек. 2015 г., 09:17
@ chris12892 из-за чего? EAGAIN = 11. Можете ли вы обновить код, чтобы показать, как вы тестируете возвращаемое значение select () и добавить набор exclude, пожалуйста?
 chris1289212 дек. 2015 г., 18:36
Ничто в параметре excfds, read не возвращает -1, а fstat () также не возвращает -1.
 chris1289211 дек. 2015 г., 07:38
В данном случае я специально говорю о том, что устройство USB to serial отключено от хост-машины.
 Laszlo Valko11 дек. 2015 г., 18:21
Я думаю, что вы также должны установитьexceptfds (параметр № 4) дляselect(), Вы не получите -1 заselect() пока сам сокет не закрыт (и он может быть закрыт только вашей программой). Вы, вероятнодолжен получить указание наreadfds а такжеexceptfds) и при попыткеread(), вы должны также получить ошибку (EIO или подобное).
 sawdust10 дек. 2015 г., 23:14
С USB-адаптером может быть два уровня отключения. Когда устройство подключено к последовательному порту, это устройство больше не может обмениваться данными. Возможно, отключено само соединение RS232. Сигнал DSR / DTR часто используется для определения локального соединения. Если на рисунке также показано изображение USB, USB-адаптер может быть отключен от хоста. Поэтому вам нужно уточнить, что вы пытаетесь обнаружить. Считывание данных происходит с подключенного последовательного устройства, а не с последовательного порта или USB-адаптера. Если устройство является модемом, то у вас есть другая ссылка для подключения.
 Mathieu11 дек. 2015 г., 09:39
Вы можете использовать libudev для просмотра событий устройства через файловый дескриптор:signal11.us/oss/udev
 Mendes16 дек. 2015 г., 03:58
Как сообщается в опилках, существует много типов отключения. В прошлом у меня был случай, когда я не мог определить, была ли потеряна последовательная связь из-за простых причин, таких как обрыв кабеля. Я заканчиваю тем, что использую последовательное сердцебиение и обнаруживаю его в потоке времени ожидания. Это более безопасное решение, так как могут возникнуть ситуации, когда termios не будет сигнализировать.
 TheCodeArtist12 дек. 2015 г., 17:43
Как насчетfstat()? Вы получаетеEBADF наtty_fd если fstat-ed после удаления устройства? ...

Ответы на вопрос(1)

Решение Вопроса

На USB-устройстве отключение от сети называется

@disconnect: вызывается, когда интерфейс больше недоступен, обычно потому, что его устройство было (или отключается) или модуль драйвера выгружается.

в нашем случае это usb_serial_disconnect (struct usb_interface * interface)

который вызывает usb_serial_console_disconnect (serial), который вызывает tty_hangup ... и так далее.

Вы можете следить за цепочкой, начатой ​​здесь:http://lxr.free-electrons.com/source/drivers/usb/serial/usb-serial.c#L1091

Вкратце это приводит к следующей классической манере:

pselect указывает, что дескриптор файла готов, и ioctl (fd, FIONREAD, & len) возвращает ноль len.

Вот и вы отключили устройство.

Подводя итог (выводится из вашего кода):

while(1)
{
    FD_ZERO(&rfds);
    FD_SET(tty_fd, &rfds);

    // have tried checking fcntl(tty_fd, F_GETFL); too

    // Blocking call to wait until we have data
    int ready = select(tty_fd + 1, &rfds, NULL, NULL, NULL);

    if(ready && FD_ISSET(tty_fd, &rfds)) {
      size_t len = 0;
      ioctl(tty_fd, FIONREAD, &len);
      errsv = errno;

      if(len == 0)
      {
         printf("prog_name: zero read from the device: %s.", strerror(errsv));
         /* close fd and cleanup or reconnect etc...*/
         exit(EXIT_FAILURE);
      }

      // While we have data, collect it
      while (read(tty_fd, &c, 1)>0 && bytesRead++<200)
      {
        serialBuffer.push_back(c);
      }

      bytesRead = 0;

      // Try to parse it
      BufferParse();
    }
}

Жаль, что вы не сказали, какое устройство вы используете.

В случае, если ваше устройство способно управлять потоком данных RTS / CTS, также возможно обнаружить разрыв линии.

 chris1289224 янв. 2016 г., 08:42
Хах! Это прекрасно работает! Спасибо!
 chris1289224 янв. 2016 г., 03:28
Привет, спасибо за подробный комментарий! Устройство представляет собой чип FTDI, подключенный к Raspberry Pi. Raspian Jessie, если дистрибутив имеет значение. Я попробую это немного позже и обновлю, как это получилось.
 Maquefel24 янв. 2016 г., 09:44
Np, фактически нулевое чтение происходит от замены обработчиков операций по умолчанию на фиктивные, которые возвращают ноль при чтении. Это почти то же самое поведение, что и сокеты.

Ваш ответ на вопрос