I currently work on Raspberry PI 3. In order to loop serial port communication I connected TXD with RXD in GPIO port. So I receive the bytes that I've just sent. In my program I need to use the timeout limitation for reading the port. To do so I used following command select(fd + 1, &read_fds, NULL, NULL, &timeout)
. If the timeout is met with first byte (i.e. I've sent nothing), I can't read next byte - the state of reading is still "Timeout".
My question is: how can I clear tthis state or what do I have to set to port parameters to recive second byte which was send after reaching timeout during previous port reading. My code bellow:
#include <stdio.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>
int main ()
{
struct termios RSopt;
char byte = 0;
char str[2] = {0,0};
int fd;
fd = open( "/dev/ttyS0", O_RDWR| O_NOCTTY );
// Parameters setting for serial communication
tcgetattr(fd, &RSopt);
cfsetospeed (&RSopt, (speed_t)B300);
cfsetispeed (&RSopt, (speed_t)B300);
RSopt.c_cflag &= ~CSIZE; // Mask out size
RSopt.c_cflag |= CS8; // Or in 7-bits
RSopt.c_cflag |= PARODD; // Enable Parity - even by default
tcsetattr (fd, TCSANOW, &RSopt); // Set new options
// Timeout setting
struct timeval timeout;
timeout.tv_sec = 2;
timeout.tv_usec = 0;
// File descriptor initialization
fd_set read_fds;
//-----------------------------------------------------------------
FD_ZERO(&read_fds);
FD_SET(fd, &read_fds);
str[0] = 0xFA;
//write(fd, str, 1);
//printf("Send.\n");
//printf("Wait...\n");
if (select(fd + 1, &read_fds, NULL, NULL, &timeout) == 1) {
read(fd, &byte, 1);
printf("Recive: %x\n", byte);
} else {
printf("Timeout.\n");
}
//-----------------------------------------------------------------
FD_ZERO(&read_fds);
FD_SET(fd, &read_fds);
str[0] = 0xFB;
write(fd, str, 1);
printf("Send.\n");
printf("Wait...\n");
if (select(fd + 1, &read_fds, NULL, NULL, &timeout) == 1) {
read(fd, &byte, 1);
printf("Recive: %x\n", byte);
} else {
printf("Timeout.\n");
}
}
You need to set
timeout.tv_sec = 2;
timeout.tv_usec = 0;
before each select
since some kernels will reduce your timeout
with the time spent in the select
, leaving you with a zero timeout value if you've already timed out once.
Edit: You can confirm that this is what is happening to you by printing the timeout
values before the select
that times out directly.