Я хочу использовать последовательный COM-порт для коммуникации, и я хочу реализовать тайм-аут каждый раз, когда я называю вызов функции чтения.
int filedesc = open( "dev/ttyS0", O_RDWR );
read( filedesc, buff, len );
Править:
Я использую Linux ОС. Как реализовать вызов функции выбора использования?
select () принимает 5 параметров, сначала наивысший дескриптор файла + 1, затем fd_set для чтения, один для записи и один для исключений. Последний параметр - это структура timeval, используемая для тайм-аута. Он возвращает -1 при ошибке, 0 при тайм-ауте или количество файловых дескрипторов в установленных наборах.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
int main(void)
{
fd_set set;
struct timeval timeout;
int rv;
char buff[100];
int len = 100;
int filedesc = open( "dev/ttyS0", O_RDWR );
FD_ZERO(&set); /* clear the set */
FD_SET(filedesc, &set); /* add our file descriptor to the set */
timeout.tv_sec = 0;
timeout.tv_usec = 10000;
rv = select(filedesc + 1, &set, NULL, NULL, &timeout);
if(rv == -1)
perror("select"); /* an error accured */
else if(rv == 0)
printf("timeout"); /* a timeout occured */
else
read( filedesc, buff, len ); /* there was data to read */
}
В качестве альтернативы select ()
для В конкретном случае последовательного порта (терминала) вы можете использовать tcsetattr ()
, чтобы перевести файловый дескриптор в неканонический режим с тайм-аутом чтения.
Для этого снимите флаг ICANON
и установите управляющий символ VTIME
:
struct termios termios;
tcgetattr(filedesc, &termios);
termios.c_lflag &= ~ICANON; /* Set non-canonical mode */
termios.c_cc[VTIME] = 100; /* Set timeout of 10.0 seconds */
tcsetattr(filedesc, TCSANOW, &termios);
Примечание VTIME
измеряется в десятых долях секунды, и что для него обычно используется тип unsigned char
, что означает, что максимальный тайм-аут составляет 25,5 секунды.
Если вы установили, что сокет действительно работает в неблокирующем режиме, каждый вызов для чтения будет читать только данные, доступные в данный момент (если есть). Таким образом, это фактически эквивалентно немедленному таймауту.
Вы можете установить неблокирующий режим для сокета с помощью такой функции:
int setnonblock(int sock) {
int flags;
flags = fcntl(sock, F_GETFL, 0);
if (-1 == flags)
return -1;
return fcntl(sock, F_SETFL, flags | O_NONBLOCK);
}
(Для получения дополнительной информации о чтении из неблокирующих сокетов см. читать
страницу руководства)
Вы не говорите, что такое ОС, но если вы работаете под Linux, вы можете использовать вызов select. Он возвращается, если в файловом дескрипторе есть что читать, или вы можете настроить его так, чтобы он истекал по таймауту, если читать нечего. Код возврата указывает, какой именно.