I'm working on a project in which I need to read and write data from a serial port, and this needs to be non-blocking for reasons I won't go into. The select() function looks like what I want to use, but I'm struggling with getting a working implementation.
In open_port() I define the settings for the port and that it is non-blocking. In otherselect() I assign the descriptor to the open_port() and attempt to read. I also have a 1 second sleep call at the end of the function to attempt to avoid the reading being too fast for hardware.
When running I get a message printing out every second for "no data available" before I send the message, and after I send a message it prints it out, but it is usually in pieces with binary characters along with it. For example, when sending the word "buffer" it will print "ffer" followed by a binary character.
I have almost no experience with termios or select, so any suggestions would be appreciated.
#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();
}
}
When you return to select() it blocks, waiting for more data. However your peer on the other side of the connection is waiting for a response to the data already sent. Your program ends up blocking forever. You could work around it with timeouts and such, but the whole point is to make non-blocking I/O efficient.
To configure the Serial Port for your device, on your computer go to Control Panel - Device Manager, select “High-Speed USB Serial Port (Com X)”, right click and select Properties. Click the Features tab. This tab is used to change the COM port number and configure the port.
Serial refers to the transfer of data one bit at a time. Serial communications include most network devices, keyboards, mice, MODEMs, and terminals. When doing serial communications each word (i.e. byte or character) of data you send or receive is sent one bit at a time. Each bit is either on or off.
When you use read() you don't get a null terminated string, so
cout<<buffer<<endl
is obviously a bad idea. Do a,
buffer[r]='\0' #(provided r<15)
before you print it out.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With