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();
}
}
come è C++, hai preso in considerazione l'utilizzo di boost :: asio per questo? – moooeeeep
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
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() –