serial recibir puerto probar leer datos c unix timeout tty

recibir - ¿Cómo puedo implementar el tiempo de espera para leer() al leer desde un puerto serie(C/C++)



probar puerto serial linux (5)

Estoy leyendo bytes desde un puerto serie en C ++ utilizando un descriptor de archivo y la función posix / unix read (). En este ejemplo, estoy leyendo 1 byte desde el puerto serie (las configuraciones de velocidad en baudios y similares se omiten para mayor claridad):

#include <termios.h> #include <fcntl.h> #include <unistd.h> int main(void) { int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY); char buf[1]; int bytesRead = read(fd, buf, 1); close(fd); return 0; }

Si el dispositivo conectado a / dev / ttyS0 no envía ninguna información, el programa se bloqueará. ¿Cómo puedo establecer un tiempo de espera?

He intentado establecer un tiempo de espera como este:

struct termios options; tcgetattr(fd, &options); options.c_cc[VMIN] = 0; options.c_cc[VTIME] = 10; tcsetattr(fd, TCSANOW, &options);

Pensé que se suponía que debía dar un tiempo de espera de 1 segundo, pero no importa. Creo que he entendido mal a VMIN y VTIME. ¿Para qué se utilizan VMIN y VTIME?

Luego busqué en la web y encontré a alguien hablando de la función select (). ¿Es esa la solución y, de ser así, cómo se podría aplicar eso al programa anterior para hacer un tiempo de espera de 1 segundo?

Cualquier ayuda es apreciada. Gracias por adelantado :-)


Hay varios enfoques posibles. Si el programa finalmente sincronizará más de una operación de E / S, select() es la opción más clara.

Sin embargo, si la única entrada es de este i / o, entonces la selección de E / S sin bloqueo y sincronización es un método sencillo. Lo he expandido de un solo carácter de E / S a caracteres múltiples para que sea un ejemplo más general completo:

#include <fcntl.h> #include <termios.h> #include <unistd.h> #include <sys/time.h> int main(void) { int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY); // sometimes "O_NONBLOCK" char buf[10]; int done = 0, inbuf = 0; struct timeval start, now; gettimeofday (&start, NULL); while (!done) { int bytesRead = read(fd, &buf[inbuf], sizeof buf - inbuf); if (bytesRead < 0) { error_processing_here(); continue; } if (bytesRead == 0) // no data read to read { gettimeofday (&now, NULL); if ((now.tv.sec - start.tv_sec) * 1000000 + now.tv.usec - start.tv_usec > timeout_value_in_microsecs) { done = 2; // timeout continue; } sleep(1); // not timed out yet, sleep a second continue; } inbuf += bytesRead; if (we have read all we want) done = 1; } if (done == 2) timeout_condition_handling(); close(fd); return 0; }


Sí, use select(2) . Pase un conjunto de descriptores de archivo que contenga solo su fd en el conjunto de lectura y los conjuntos de escritura / excepción vacíos, y pase un tiempo de espera apropiado. Por ejemplo:

int fd = open(...); // Initialize file descriptor sets fd_set read_fds, write_fds, except_fds; FD_ZERO(&read_fds); FD_ZERO(&write_fds); FD_ZERO(&except_fds); FD_SET(fd, &read_fds); // Set timeout to 1.0 seconds struct timeval timeout; timeout.tv_sec = 1; timeout.tv_usec = 0; // Wait for input to become ready or until the time out; the first parameter is // 1 more than the largest file descriptor in any of the sets if (select(fd + 1, &read_fds, &write_fds, &except_fds, &timeout) == 1) { // fd is ready for reading } else { // timeout or error }



Puede intentar la señal de captura para detener la operación de lectura. use la alarma (1) antes de leer, y si no se devolvió la función de lectura, la alarma enviará la señal SIGALRM, luego puede crear la función de procesamiento de señal para capturar esta señal, como esta:

#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <setjmp.h> static jmp_buf env_alarm; static void sig_alarm(int signo) { longjmp(env_alarm, 1); } int main(void) { int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY); char buf[1]; if (signal(SIGALRM, sig_alarm) == SIG_ERR) { exit(0); } if (setjmp(env_alarm) != 0) { close(fd); printf("Timeout Or Error/n"); exit(0); } alarm(1); int bytesRead = read(fd, buf, 1); alarm(0); close(fd); return 0; }

Pero use select o poll o epoll será mejor si su programa es grande.


¿Para qué se utilizan VMIN y VTIME?

Si MIN> 0 y TIEMPO = 0, MIN establece la cantidad de caracteres que se recibirán antes de que se satisfaga la lectura. Como TIME es cero, el temporizador no se usa.

Si MIN = 0 y TIME> 0, TIME sirve como un valor de tiempo de espera. La lectura se cumplirá si se lee un solo carácter o si se excede el tiempo (t = TIME * 0.1 s). Si se excede el TIEMPO, no se devolverá ningún carácter.

Si MIN> 0 y TIME> 0, TIME sirve como un temporizador entre caracteres. La lectura se cumplirá si se reciben MIN caracteres, o si el tiempo entre dos caracteres excede TIME. El temporizador se reinicia cada vez que se recibe un carácter y solo se activa después de que se haya recibido el primer carácter.

Si MIN = 0 y TIME = 0, la lectura se cumplirá inmediatamente. Se devolverá el número de caracteres disponibles actualmente o el número de caracteres solicitados. De acuerdo con Antonino (ver contribuciones), podrías emitir un fcntl (fd, F_SETFL, FNDELAY); antes de leer para obtener el mismo resultado.

Fuente: http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html