2012-07-31 16 views
8

Pracuję nad projektem, w którym potrzebuję czytać i zapisywać dane z portu szeregowego, a to nie może być blokowane z powodów, dla których nie wejdę. Funkcja select() wygląda na to, co chcę użyć, ale mam problem z uzyskaniem działającej implementacji.Używanie select() do niezablokowania numeru seryjnego

W open_port() określam ustawienia dla portu i to, że nie jest blokowany. W otherselect() przypisuję deskryptor do open_port() i próbuję odczytać. Mam też 1 sekundę połączenia w stan uśpienia na końcu funkcji, aby uniknąć zbyt szybkiego czytania sprzętu.

Po uruchomieniu otrzymuję wiadomość, która drukuje co sekundę dla "brak dostępnych danych", zanim wyślę wiadomość, a po wysłaniu wiadomości ją wydrukuje, ale zazwyczaj jest w kawałkach z postaciami binarnymi. Na przykład, wysyłając słowo "bufor", wydrukuje "ffer", po którym następuje znak binarny.

Nie mam prawie żadnego doświadczenia z termios lub wybierz, więc wszelkie sugestie będą mile widziane.

#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

jak to jest C++, czy rozważałeś użycie boost :: asio do tego? – moooeeeep

+0

Czy nie potrzebujesz 'O_NONBLOCK' do wywołania open(), aby uniemożliwić blokowanie? Edycja: IIRC, 'O_NDELAY' po prostu przeskakuje czekając na DCD, podczas gdy' O_NONBLOCK' po prostu przechodzi dalej bez czekania na jakiekolwiek wejście. – favoretti

+0

O_NDELAY jest ustawione na równe O_NONBLOCK w fcntl.h, są one równe. Nie szukałem jeszcze boost :: asio, i zrobię to teraz, ale bardzo lubię, gdy dano mi opcję obsługi, jeśli są dane z select() –

Odpowiedz

1

Kiedy używać read() nie dostaniesz null zakończone ciąg, więc

cout<<buffer<<endl 

jest oczywiście zły pomysł. Wykonaj,

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

przed wydrukowaniem.

Powiązane problemy