Невозможно прочитать с последовательного устройства после отсоединения и повторного подключения соединителя

У меня есть приложение Linux, которое предполагается читать с последовательного устройства /dev/ttyS0 . Последовательное устройство открывается следующим образом:

 // Open the serial port if((serial_device = open("/dev/ttyS0", O_RDWR | O_NOCTTY)) < 0){ fprintf(stderr, "ERROR: Open\n"); exit(EXIT_FAILURE); } // Get serial device attributes if(tcgetattr(serial_device,&options)){ fprintf(stderr, "ERROR: Terminal Get Attributes\n"); exit(EXIT_FAILURE); } cfsetspeed(&options,speed); // Set I/O baud rates cfmakeraw(&options); // Set options to transceive raw data options.c_cflag |= (CLOCAL | CREAD); // Enable the receiver and set local mode options.c_cflag &= ~CSTOPB; // 1 stop bit options.c_cflag &= ~CRTSCTS; // Disable hardware flow control options.c_cc[VMIN] = 1; // Minimum number of characters to read options.c_cc[VTIME] = 10; // One second timeout // Set the new serial device attributes if(tcsetattr(serial_device, TCSANOW, &options)){ fprintf(stderr, "ERROR: Terminal Set Attributes\n"); exit(EXIT_FAILURE); } 

Затем я использую функцию select для чтения и чтения с последовательного устройства:

 // Flush I/O Bffer if(tcflush(serial_device,TCIOFLUSH)){ fprintf(stderr, "ERROR: I/O Flush\n"); exit(EXIT_FAILURE); } // Write message to board if(write(serial_device,msg, strlen(msg)) != (int)strlen(msg)){ fprintf(stderr, "ERROR: Write\n"); exit(EXIT_FAILURE); } switch(select(serial_device+1, &set, NULL, NULL, &timeout)){ // Error case -1: fprintf(stderr, "ERROR: Select\n"); exit(EXIT_FAILURE); // Timeout case 0: success = false; break; // Input ready default: // Try to read a character switch(read(serial_device, &c, 1)){ // Error (miss) case -1: success = false; break; // Got a character default: msg[i++] = c; break; } break; } // Set 200ms timeout this->timeout.tv_sec = 0; this->timeout.tv_usec = 200000; } 

Я попытался открыть порт, установив, что чтение не было успешным:

 if(!success) close(serial_device); openPort(); // Same as above } 

Тем не менее, действие физического отсоединения последовательного разъема приведет к тому, что приложение не сможет прочитать что-либо еще, и выберите не будет ничего, кроме тайм-аута. Повторное подключение соединителя во время работы приложения не устранит проблему, и выбор будет продолжать ничего не обнаруживать.

Единственным способом успешного чтения из последовательного порта является перезапуск приложения. Мне интересно, почему это так, и как я могу восстановить после отсоединения последовательного разъема во время выполнения.

Использование select() только с одним файловым дескриптором необычно. Это также добавляет уровень сложности.
Поскольку serial port настроен для неканонического ввода, при правильном выборе VMIN и VTIME , вы можете выполнить чтение символа за раз с более простым кодом. EG попробуйте VMIN = 1 и VTIME = 10*timeout.tv_sec

Однако, как вы поняли, и если вы готовы обрабатывать (или хотите) тайм-аут, а не ждать, пока, по крайней мере, один персонаж не VMIN = 0 , тогда VMIN = 0 будет эмулировать ваш исходный код с помощью select() .

VMIN = 0 и VTIME> 0
Это чистое чтение времени. Если данные доступны во входной очереди, они переносятся в буфер вызывающего абонента максимум до nbytes и немедленно возвращаются вызывающему. В противном случае драйвер блокируется до тех пор, пока данные не поступят, или когда десятые десятки VTIME не истекут с начала вызова. Если таймер истекает без данных, возвращается ноль. Один байт достаточен для удовлетворения этого запроса на чтение, но если в входной очереди доступно больше, оно возвращается вызывающему. Обратите внимание, что это общий таймер, а не межсимвольный.

Однако (например, OP) я сбив с толку, почему подключение соединителя порта должно прерывать любые чтения или выбирать мониторинг и никогда не сталкивалось с такой проблемой.