Estoy desarrollando un receptor para un pequeño proyecto de hardware. Estoy trabajando en una placa pequeña que usa UART para transferir datos.
El código del receptor se muestra en su totalidad a continuación, explicaré los bits problemáticos por separado en breve.
#define TTY "/dev/ttys002" #include <stdio.h> #include <string.h> #include <unistd.h> //Unix standard functions #include <fcntl.h> //File controls #include <errno.h> //Error numbers #include <assert.h> #include <termios.h> //Posix terminal int open_port(const char * tty) { int fd; fd = open(tty, (O_RDWR | O_NOCTTY | O_NDELAY)); assert("__failed to open port__" && fd != -1); //Block until read fcntl(fd, F_SETFL, 0); return fd; } void configure_port(int fd) { struct termios options; //Get current options tcgetattr(fd, &options); //9600 Baud cfsetispeed(&options, B9600); cfsetospeed(&options, B9600); //Receive & local mode options.c_cflag |= (CLOCAL | CREAD); //Raw output options.c_oflag &= ~OPOST; //No hardware flow control options.c_cflag &= ~CRTSCTS; //No parity, 1 stop bit options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; //8 data bits options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; //Write options back, set them immediately tcsetattr(fd, TCSANOW, &options); } int main(int argc, const char * argv[]) { int fd = open_port(TTY); const size_t count = 8; char buf[count + 1]; ssize_t n; configure_port(fd); while (1) { n = read(fd, buf, count); buf[count] = '\0'; if (n > 0) { printf("%s\n", buf); } } return 0; } Como actualmente no tengo mi hardware a mano, decidí probar mi receptor en un tty regular ( #define TTY "/dev/ttys002" ). Para probarlo, simplemente compilé y ejecuté el código anterior y luego abrí una terminal separada y:
echo "text" >> /dev/ttys002Todo esto funciona muy bien y obtengo todos los datos que estoy haciendo eco en el tty.
Sin embargo, el problema surge cuando ingreso un mensaje largo en el tty:
echo "this is a longer test message" >> /dev/ttys002 Recibo el mensaje completo como una sola cadena en la salida de mi programa. ¿Por qué esto es tan? Hubiera esperado que el texto se dividiera en bloques de 8 caracteres ( const size_t count = 8; ).
Si es importante, estoy usando esta guía como referencia para la configuración.
Editar: consulte los comentarios para obtener más información sobre el tema.
En mi humilde opinión, su mensaje se divide en bloques de ocho caracteres: n = read(fd, buf, count); no puede dar más que contar bytes a la vez.
Pero como no configura la línea tty en modo RAW, todavía está en modo de búfer de línea. Entonces, el controlador subyacente bloquea la primera lectura hasta que tiene una línea completa terminada con \n (o excede la capacidad del búfer).
Luego, la lectura regresa con los primeros 8 bytes, y las siguientes lecturas también regresan inmediatamente con 8 bytes, ya que los datos están disponibles en el búfer del controlador.
Debería mirar el modo no canónico en man termios , si desea usar el modo de entrada sin procesar:
options.c_cflags &= ~ICANON; /* optionally if defaults are not appropriates */ options.c_cc[VMIN] = vmin; /* default is 1 */ options.c_cc[VTIME] = vtime; /* default is 0 */Pero de todos modos, lee los caracteres y nunca agrega el nulo de terminación, por lo que buf no tiene ninguna razón para terminar en nulo. Solo debe imprimir la cantidad de caracteres que realmente se leen:
const size_t count = 8; char buf[count]; ssize_t n; configure_port(fd); while (1) { n = read(fd, buf, count); if (n > 0) { printf("%.*s\n", n, buf); /* only print the n characters */ } }Parece que tu problema tiene el mismo nombre que este sitio :)
Está asignando 8 bytes de datos en la pila para su variable buf . Luego, en la función de read , está escribiendo la cadena "este es un mensaje de prueba más largo", cuya longitud es mucho más de 8 bytes. Cuando usa la función printf con "%s", printf dejará de imprimir cuando llegue a un carácter nulo ( \0 ) porque espera que su cadena termine en nulo. En su caso, debe verificar si su variable buf está terminada en nulo. Si no es así, debe hacer que el último byte del buf sea un carácter nulo
Lo que está buscando es un pseudo tty (PTY).
Una forma sencilla de crear un PTY es usar socat(1) así:
socat pty,link=/tmp/testpty stdioEsto creará un PTY y adjuntará el stdio de la terminal actual a su lado maestro. Cualquier dato que ingrese aquí se enviará al lado esclavo del PTY.
Ahora conéctese al lado esclavo desde su programa y debería funcionar como espera:
#define TTY "/tmp/testpty"