2012-07-31 6 views
8

Sto lavorando a un progetto in cui ho bisogno di leggere e scrivere dati da una porta seriale, e questo deve essere non bloccante per ragioni a cui non intendo entrare. La funzione select() assomiglia a quello che voglio usare, ma sto lottando per ottenere un'implementazione funzionante.Uso di select() per seriale non bloccante

In open_port() definisco le impostazioni per la porta e che non è bloccante. In otherelect() assegno il descrittore a open_port() e provo a leggere. Ho anche una chiamata di sonno di 1 secondo alla fine della funzione per tentare di evitare che la lettura sia troppo veloce per l'hardware.

Durante l'esecuzione ricevo un messaggio che stampa ogni secondo per "nessun dato disponibile" prima di inviare il messaggio, e dopo aver inviato un messaggio lo stampa, ma di solito è in pezzi con caratteri binari insieme ad esso. Ad esempio, quando si invia la parola "buffer" verrà stampato "ffer" seguito da un carattere binario.

Non ho quasi nessuna esperienza con termios o selezionare, quindi qualsiasi suggerimento sarebbe apprezzato.

#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

come è C++, hai preso in considerazione l'utilizzo di boost :: asio per questo? – moooeeeep

+0

Non avresti bisogno di 'O_NONBLOCK' per la tua chiamata open() per renderlo effettivamente non-blocking? Modifica: IIRC, 'O_NDELAY' salta semplicemente in attesa di DCD, mentre' O_NONBLOCK' in realtà continua senza attendere alcun input. – favoretti

+0

O_NDELAY è impostato uguale a O_NONBLOCK in fcntl.h, sono uguali. Non ho ancora guardato su boost :: asio, e lo farò ora, ma mi piace davvero avere l'opzione su come gestire se ci sono dati con select() –

risposta

1

Quando si utilizzano read() non si ottiene una stringa null terminata, così

cout<<buffer<<endl 

è ovviamente una cattiva idea. Fare un,

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

prima di stamparlo fuori.