2012-07-31 23 views
8

Estoy trabajando en un proyecto en el que necesito leer y escribir datos desde un puerto en serie, y esto debe ser no bloqueante por razones que no entraré. La función select() se parece a lo que quiero usar, pero estoy luchando para obtener una implementación que funcione.Uso de select() para serie sin bloqueo

En open_port() defino las configuraciones para el puerto y que es no-bloqueante. En otherselect() asigno el descriptor a open_port() e intento leer. También tengo una llamada de espera de 1 segundo al final de la función para intentar evitar que la lectura sea demasiado rápida para el hardware.

Al ejecutar recibo un mensaje imprimiendo cada segundo para "sin datos disponibles" antes de enviar el mensaje, y después de enviar un mensaje lo imprime, pero generalmente está en pedazos con caracteres binarios junto con él. Por ejemplo, al enviar la palabra "buffer" se imprimirá "ffer" seguido de un carácter binario.

Casi no tengo experiencia con termios o seleccione, por lo que cualquier sugerencia sería apreciada.

#include <iostream> 
#include "stdio.h" 
#include "termios.h" 
#include "errno.h" 
#include "fcntl.h" 
#include "string.h" 
#include "time.h" 
#include "sys/select.h" 

using namespace std; 

int open_port(){ 
struct termios oldtio,newtio; 
int serial_fd; 
if ((serial_fd = open("/dev/ttyS0", O_RDWR | O_EXCL | O_NDELAY)) == -1) { 
    cout << "unable to open" << endl; 
    return -1; 
} 
if (tcgetattr(serial_fd, &oldtio) == -1) { 
    cout << "tcgetattr failed" << endl; 
    return -1; 
} 
cfmakeraw(&newtio); // Clean all settings 
newtio.c_cflag = (newtio.c_cflag & ~CSIZE) | CS8 | B115200; // 8 databits 
newtio.c_cflag |= (CLOCAL | CREAD); 
newtio.c_cflag &= ~(PARENB | PARODD); // No parity 
newtio.c_cflag &= ~CRTSCTS; // No hardware handshake 
newtio.c_cflag &= ~CSTOPB; // 1 stopbit 
newtio.c_iflag = IGNBRK; 
newtio.c_iflag &= ~(IXON | IXOFF | IXANY); // No software handshake 
newtio.c_lflag = 0; 
newtio.c_oflag = 0; 
newtio.c_cc[VTIME] = 1; 
newtio.c_cc[VMIN] = 60; 
if (tcsetattr(serial_fd, TCSANOW, &newtio) == -1) { 
    cout << "tcsetattr failed" << endl; 
    return -1; 
} 
tcflush(serial_fd, TCIOFLUSH); // Clear IO buffer 
return serial_fd; 
} 

void otherselect(){ 
fd_set readfs; 
timeval tv; 
tv.tv_sec = 1; 
tv.tv_usec = 0; 
char * buffer = new char[15]; 
int _fd = open_port(); 
FD_ZERO(&readfs); 
FD_SET(_fd, &readfs); 
select(_fd+1, &readfs, NULL, NULL, &tv /* no timeout */); 
if (FD_ISSET(_fd, &readfs)) 
{ 
    int r = read(_fd, buffer, 15); 
    if(r == -1){ 
     cout << strerror(errno) << endl; 
    } 
    cout << buffer << endl; 
} 
else{ 
    cout << "data not available" << endl; 
} 
close(_fd); 
sleep(1); 
} 

int main() { 
    while(1){ 
     otherselect(); 
    } 
} 
+0

como es C++, ¿ha considerado usar boost :: asio para esto? – moooeeeep

+0

¿No necesitarías 'O_NONBLOCK' para tu llamada a open() para que no bloqueara? Editar: IIRC, 'O_NDELAY' simplemente se salta la espera de DCD, mientras que' O_NONBLOCK' realmente continúa sin esperar ninguna entrada. – favoretti

+0

O_NDELAY se establece igual a O_NONBLOCK en fcntl.h, son iguales. No he investigado boost :: asio todavía, y lo haré ahora, pero realmente me gusta que me den la opción de cómo manejarlo si hay datos con select() –

Respuesta

1

Cuando se utiliza leer() no obtiene una cadena terminada en nulo, por lo

cout<<buffer<<endl 

es, evidentemente, una mala idea. Haga una,

buffer[r]='\0' #(provided r<15) 

antes de que se imprima.