I'm working with a serial device RFID reader (caenrfid lepton7). It has a mode where it can send data forever each time it sees a new RFID tag. The problem with the nature of the serial line is that if my program crashes while reading a frame the device will continue to send data until I stop it using either a physical switch (it has a pin dedicated for that) or a push button on the device. For the moment, during my tests I use the physical user button. Then, because it has sent more data that I haven't read the Linux kernel enqueue the incoming buffer into the tty line but since it may contain a partial frame I need to discard that because it's not recoverable. To my understanding the way to go is to use tcflush. So after opening the device this is what I try:
int
etrp_open(const char *path)
{
assert(self);
assert(path);
int fd;
struct termios tty;
if ((fd = open(path, O_RDWR | O_NOCTTY)) < 0)
return -1;
if (tcgetattr(fd, &tty) < 0) {
close(fd);
return -1;
}
tty.c_cflag &= ~(PARENB | CSIZE);
tty.c_cflag |= CLOCAL | CS8 | CREAD;
tty.c_lflag &= ~(ECHO | ECHOE | ECHOK | ICANON | IEXTEN | ISIG);
tty.c_iflag &= ~(IGNBRK | BRKINT | ICRNL | INLCR | PARMRK | INPCK | ISTRIP | IXON);
tty.c_oflag &= ~(OPOST);
if (cfsetispeed(&tty, B921600) < 0 ||
cfsetospeed(&tty, B921600) < 0 ||
tcsetattr(fd, TCSAFLUSH, &tty) < 0) {
close(fd);
return -1;
}
if (tcflush(fd, TCIOFLUSH) < 0) {
close(fd);
return -1;
}
return 0;
}
But after the tcflush call, even though the device stopped sending data if I call read
on fd it will actually read! Why is that?
[... as before ...]
if (tcflush(fd, TCIOFLUSH) < 0) {
close(fd);
return -1;
}
char buf[1024];
ssize_t nr;
nr = read(fd, buf, sizeof (buf));
printf("read = %zd\n", nr);
When running the application and after have started the non-stop arrival of data, closing my app, waiting a few seconds, pressing the kill switch. Then the read actually reads:
./scanner
read = 128
I have found in another thread that I need to call usleep before tcflush but I don't get why, I've tried and it seems to work most of the time but I don't really like having to do some sleep code to re-initialize correctly a device.
My questions:
- Why is that usleep call necessary?
- What is usually the proper way to completely discard not read data AND incoming data from a partial frame? (imagine a device that will continue to send its data even after a reset).