Serial port is stuck at wait(4, - c++

I have this implementation in C++ for linux for initializing a serial port:
void setupSerialPort()
{
fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
memset(&tio, 0, sizeof(tio));
tio.c_iflag = 0;
tio.c_oflag = 0;
tio.c_cflag = CS8|CREAD|CLOCAL;
tio.c_lflag = 0;
tio.c_cc[VMIN] = 0;
tio.c_cc[VTIME] = 0;
fd = open(SERIALPORT, O_RDWR | O_NONBLOCK) ;
fcntl(fd , F_SETFL, 0); // read data in the buffer per chunk
cfsetospeed(&tio, B4800); // 4800 baud
cfsetispeed(&tio, B4800); // 4800 baud
tcsetattr(fd , TCSANOW, &tio);
}
Sometimes, the serial port reading is stuck and I use 'strace' to see what is going on. the problem is:
strace -p 9454
Process 9454 attached - interrupt to quit
wait4(-1, ^C <unfinished ...>
Process 9454 detached
How can I avoid the problem (it does not happen all the time)?

The problem occurring randomly indicates that the call to open is failing. So check the return values from open call and other remaining calls.
if (fd < 0) return;
Also ensure clean close of the serial port.

Syscalls involving IO could get stuck specially with network IO. Since you are using NON_BLOCKING mode that shouldnt be the case , The complete code would have been helpful here. Personally i had this situation before and I used timer to generate SIG_USR which used to end the blocking call with an error. Pseudo code for that algo is as follows:
initiateTimer ( timeout)
myfunctionCall(){
someSysCall();
}
if(!signalled){
disableTimer();
}else{
checkState();
if(fatal)
die;
}

My suggestions... Open the device with:
int fd = TEMP_FAILURE_RETRY(open(ttyName, O_RDWR | O_NOCTTY | O_NONBLOCK));
The macro TEMP_FAILURE_RETRY is needed to protect open, close, read and select from signal interruptions. Read about the macro if you use libc. Include O_NOCTTY flag to avoid the device becoming the controlling port of the process. Check return value for valid fd.
C.

Related

linux pseudo terminal (open select read)

I have a following scenario: Someone creates a pseudo terminal via opening /dev/ptmx. New terminal is created and named for example /dev/pts/2. Then, in my program I open /dev/pts/2 for reading. But I also open other devices for reading and use select() function to wait for any incoming data. The select have also some timeout specified for performing other stuff when no data arrives for too long. After successful select i read data using read() function and then print it on the screen.
I encountered an issue if the pseudo terminal is closed by the one who created it. In this case select function ends immediately indicating success as well as read ends indicating "no data" by returning zero. The issue imho is that neither select nor read returns error in such case. How should I handle this to detect that the terminal is no longer existing?
Status processData()
{
fd_set readFileDescriptorSet; // defined somewhere else
int maxFileDescriptor; // defined somewhere else
struct timeval timeout; // defined somewhere else
int ret = select(maxFileDescriptor + 1, &readFileDescriptorSet, nullptr, nullptr, &timeout);
if (!ret) // timeout
return Status::success();
if (ret < 0) // error from select()
return Status::error("select error");
ssize_t rd;
char buff[10];
do {
rd = read(interfaces.serialPort.getFileDescriptor(), buff, sizeof(buff) - 1);
if (rd > 0) { // some data has been read
buff[rd] = '\0';
std::cout << buff;
}
} while (rd > 0);
if (rd < 0) // error from read()
return Status::error("read error");
return Status::success();
}
While the way I open the pseudo terminal is following:
Status internalOpen(std::string fileName)
{
close();
fileDescriptor = ::open(fileName.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fileDescriptor == -1)
return Status::error("Terminal::internalOpen::open('" + fileName + "')");
struct termios attributes;
if (tcgetattr(fileDescriptor, &attributes))
return Status::error("Terminal::internalOpen::tcgetattr()");
setAttributes(attributes);
if (tcsetattr(fileDescriptor, TCSANOW, &attributes))
return Status::error("Terminal::internalOpen::tcsetattr()");
return Status::success();
}
void setAttributes(struct termios &attributes)
{
cfmakeraw(&attributes);
cfsetspeed(&attributes, Config::baudRate);
attributes.c_iflag &= ~(IXOFF | IXANY);
attributes.c_oflag &= ~(ONLCR);
attributes.c_lflag &= ~(ECHOE);
attributes.c_cflag &= ~(CSTOPB | CRTSCTS);
attributes.c_cflag |= CREAD | CLOCAL;
attributes.c_cc[VMIN] = 0;
attributes.c_cc[VTIME] = 0;
}
After select() returns indicating that there's something to be read, the shown code loops repeatedly trying to read() from the non-blocking file descriptor until it is 0:
do {
rd = read( ...
} while (rd > 0);
That's certainly reasonable. Except that the closed connection results in the very first read() returning 0, which the shown logic cannot discriminate.
All that's really needed here is to keep track of whether anything has been read, prior read() returning 0. But if read() returned 0 right off the bat, your goose is cooked.
Additionally, there a few other improvements will make things more robust.
After select() returns, actually check if the file descriptor's bit remains set in the readFileDescriptorSet. The shown logic simply assumes that it is, by checking for all other possibilities. Still, this is somewhat fragile. It's easy to forget this assumption if something tangentially related gets modified (i.e., another fle descriptor gets thrown into the mix).
Use poll() instead of select(), and explicitly check for POLLHUP|POLLRDHUP in revents. The file descriptor closure condition is more explicitly called out, in the poll() interface.

Why epoll is giving data from past events?

I am trying to read uart serial data from Linux.
I have 2 serial device mapped to linux file system , eg : ttys1 and ttys2.
After that open() is used to get FD's :
int fd1 = open("ttys1", O_RDWR | O_NOCTTY);
int fd2 = open("ttys2", O_RDWR | O_NOCTTY);
This calls are in object contructor and application is in idle state for example
On Running state , I want to record uart data from this devices.
I have a thread which is calling a start() method that creates an epoll and add fd1 and fd2 to epoll to monitor:
for(int i = 0 ; i < 2; i++)
{
events[i].events = EPOLLIN | EPOLLERR | EPOLLET ;
events[i].data.fd = (i == 0) ? fd1 : fd2;
if(epoll_ctl(epollFD, EPOLL_CTL_ADD, events[i].data.fd, &events[i]))
{
fprintf(stderr, "Failed to add file descriptor to epoll\n");
close(epollFD);
return;
}
else
{
cout << "Succesfully added File Descriptors to ePoll" << endl;
}
}
After that I have a running thread which is waiting for epoll events and read out data using epoll_wait()
My problem is that first events are with big chunk of data which I want to ignore . If usually i am getting 1-10 bytes from each uart device after each epoll wait , on first shot I get buffered data from those devices but I only want to monitor traffic after fd's were added to epoll. Any Ideas ? Thanks!

Linux C++ reading UART device not working consistently

I am using a BeagleBone Black to read data coming from a microcontroller(s) via a UART port(s). I need the reading of the UART port to be a blocking call. Additionally, for the usage of this software there will be some non-standard baud rates in use (aka not provided by termios). Additionally, the UART should follow 8-N-1 (8 data bits, no parity, 1 stop bit).
The code I have for the opening the UART port is as follows:
int UART::UART_open(unsigned int baudRate)
{
mFd = open(mPath.c_str(), O_RDWR | O_NOCTTY);
if(mFd < 0)
{
return -1;
}
struct termios2 tty;
if(ioctl(mFd, TCGETS2, &tty) == -1)
{
return -1;
}
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 5;
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
tty.c_cflag &= ~CBAUD;
tty.c_cflag |= (BOTHER | CREAD | CLOCAL);
tty.c_ispeed = baudRate;
tty.c_ospeed = baudRate;
if(ioctl(mFd, TCSETS2, &tty) == -1)
{
return -1;
}
return 0;
}
The code I have for reading the UART port is as follows:
int UART::UART_read(unsigned char* buf, int length)
{
if(mFd < 0)
{
return -1;
}
if(read(mFd, buf, length) != length)
{
return -1;
}
return length;
}
There is some odd behavior going on. What happens is, the reading is inconsistent. Sometimes when I test it with an Mbed microcontroller sending data continuously (with small delays in between) via UART to the right port, and a test program to continuously read the UART port on the BeagleBone Black, and print out the data it gets, it works fine, and I am able to print out the data sent and everything works as expected. However, what happens often is the very first read simply blocks forever. No errors occur from the functions, the UART_read function simply hangs. So, to debug the error the first thing I do is I use 'screen' to monitor the /dev/ttyO* port I am trying to read from. What I find is that data is being sent to that port just fine. Then, the odd thing is, after I use screen, if I run my test program to continuously read the UART port, it works fine. This happens consistently too, if I do a quick 'screen' of the port when it is not working, I see data being sent, then my test program works. I have tried changing some of the opening termios2 struct options, to no avail. Any help would be appreciated!
Your termios initialization is obviously incomplete. There's a partial configuration for raw mode, e.g.
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 5;
yet you never actually enable noncanonical mode.
The "blocks forever" behavior of read() is symptomatic of a serial terminal (mis)configured for canonical mode when only binary data is received (i.e. there is no line terminator to "complete" the request).
Another possible cause of "blocks forever" behavior is failure to disable hardware flow-control when it is not used.
The insertion of the following statements would enable noncanonical mode and disable the HW handshake:
cfmakeraw(&tty);
tty.c_cflag &= ~CRTSCTS;
Refer to this answer for a complete example.
if(read(mFd, buf, length) != length)
{
return -1;
}
There is no requirement that a read() of a serial terminal will fill the buffer. Depending on the configuration, a "successful" read can return zero or more bytes up to the number requested.
Therefore a short read is not actually an error condition.

TIOCEXCL in Solaris

I have a little problem. I work with serial port, for example /dev/term/0 and I need to lock multiple access to this device. For that I use this code:
int hComm;
hComm = open(portName, O_RDWR | O_NOCTTY | O_NDELAY);
if(hComm != -1){
ioctl(hComm, TIOCEXCL, NULL);
int flags = fcntl(hComm, F_GETFL, 0);
flags &= ~O_NDELAY;
fcntl(hComm, F_SETFL, flags);
}
All works fine. Then I run another application and try to open this port, I have error EBUSY - and it's OK, but in this moment my first application stop working. I can't read/write and close this port, I always have only one error ENXIO (No such device or address).
I have tested this code in Linux and Mac OS X and all works without any problems, but in Solaris...
I don't know what to do.

Using select() and fgets() to access information from a serial port

This is a followup to this question: How to wait for input from the serial port in the middle of a program
I am writing a program to control an Iridium modem that needs to wait for a response from the serial port in the middle of the program in order to verify that the correct response was given. In order to accomplish this, a user recommended I use the select() command to wait for this input.
However, I have run into some difficulty with this approach. Initially, select() would return the value indicated a timeout on the response every time (even though the modem was sending back the correct responses, which I verified with another program running at the same time). Now, the program stops after one iteration, even with the correct response sent back from the modem.
//setting the file descriptor to the port
int fd = open(portName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
{
/*
* Could not open the port.
*/
perror("open_port: Unable to open /dev/ttyS0 - ");
}
else
fcntl(fd, F_SETFL, 0);
FILE *out = fopen(portName.c_str(), "w");//sets the serial port
FILE *in = fopen(portName.c_str(), "r");
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
struct timeval timeout = { 10, 0 }; /* 10 seconds */
//int ret = select(fd+1, &fds, NULL, NULL, &timeout);
/* ret == 0 means timeout, ret == 1 means descriptor is ready for reading,
ret == -1 means error (check errno) */
char buf[100];
int i =0;
while(i<(sizeof(messageArray)/sizeof(messageArray[0])))
{
//creates a string with the AT command that writes to the module
std::string line1("AT+SBDWT=");
line1+=convertInt( messageArray[i].numChar);
line1+=" ";
line1+=convertInt(messageArray[i].packetNumber);
line1+=" ";
line1+=messageArray[i].data;
line1+=std::string("\r\n");
//creates a string with the AT command that initiates the SBD session
std::string line2("AT+SBDI");
line2+=std::string("\r\n");
fputs(line1.c_str(), out); //sends to serial port
//usleep(7000000);
int ret =select(fd+1, &fds, NULL, NULL, &timeout);
/* ret == 0 means timeout, ret == 1 means descriptor is ready for reading,
ret == -1 means error (check errno) */
if (ret ==1){
fgets (buf ,sizeof(buf), in);
//add code to check if response is correct
}
else if(ret == 0) {
perror("timeout error ");
}
else if (ret ==-1) {
perror("some other error");
}
fputs(line2.c_str(), out); //sends to serial port
//usleep(7000000); //Pauses between the addition of each packet.
int ret2 = select(fd+1, &fds, NULL, NULL, &timeout);
/* ret == 0 means timeout, ret == 1 means descriptor is ready for reading,
ret == -1 means error (check errno) */
if(ret2 == 0) {
perror("timeout error ");
}
else if (ret2 ==-1) {
perror("some other error");
}
i++;
}
You aren't using the same file handle for read/write/select, which is somewhat strange.
You are not resetting your fd_sets, which are modified by select and would have all of your fds unset in the case of a timeout, making the next call timeout by default (as you are asking for no fds).
you are also using buffered IO, which is bound to create headaches in this case. eg. fgets waits for either EOF (which won't occur), or a newline, reading all the while. It will block until it gets its newline, so may keep you hanging indefinitely if that never occurs.
It may also read more than it needs into the buffer, messing up your select read signal (you have data in the buffer, but select will time out, since there's nothing to read on the filehandle).
Bottom line is this:
use FD_SET in the loop to set/reset your fd sets, also reset your timeout, as select may modify it.
use a single handle for read/write/select, instead of multiple handles, eg. open file with fopen(..., "w+") or open(..., O_RDWR)
if still using fopen, try disabling buffering using setvbuf with the _IONBF buffering option.
otherwise, use open/read/write instead of fopen etc.
I will note that part of this was mentioned in this answer to your previous question.
You should perhaps use fflush() on your output file stream.