Clearing the serial port's buffer

64,007

Solution 1

I think I figured it out. For some reason, I need to add a delay before flushing. These two lines added before returning fd seem to have done the trick:

  sleep(2); //required to make flush work, for some reason
  tcflush(fd,TCIOFLUSH);

Solution 2

The cause of this problem lies in using a USB serial port. If you use a regular serial port, you will not have this problem.

Most USB serial port drivers don't support flushing properly, probably because there's no way of knowing if there's still data in the internal shift register, FIFO or in the USB subsystem.

See also Greg's reply to a similar problem reported earlier here.

Your sleep may cure the problem, but it's only a work-around. Unfortunately there is no solution other than using a regular serial port.

Solution 3

I have been experiencing similar symptoms with an Arduino Uno board that resets on open(). I was receiving data after the open() call that was generated before the Arduino board had been reset and thus before open() had been called.

Tracking down the issue with ioctl() calls I learned that the data had simply not yet arrived in the input buffer by the time tcflush() was called. So the tcflush() did work but there was no data to flush. A sleep of 1000 us after the open() call seemed to solve the issue. This is becasue the delay allowed the data to arrive before tcflush() was called and therefore tcflush() did indeed flush the input buffer.

You might be experiencing the same issue.

Share:
64,007
capcom
Author by

capcom

I like to learn, teach, and share. I ask a lot of questions because I am curious. I hope to apply what I learn from my fellow humans in my quest to make the world a better place. Be kind to all, stay true to yourself. Personal success is secondary.

Updated on July 09, 2022

Comments

  • capcom
    capcom almost 2 years

    This is what my function looks like to open the serial port (using Ubuntu 12.04):

    int open_port(void)
    {
      int fd; /* File descriptor for the port */
    
      fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
    
      if (fd == -1)
      {
       // Could not open the port.          
       perror("open_port: Unable to open /dev/ttyUSB0 - ");
      }
      else
        fcntl(fd, F_SETFL, 0);
    
      struct termios options;
    
      tcgetattr(fd, &options); 
      //setting baud rates and stuff
      cfsetispeed(&options, B19200);
      cfsetospeed(&options, B19200);
      options.c_cflag |= (CLOCAL | CREAD);
      tcsetattr(fd, TCSANOW, &options);
    
      tcsetattr(fd, TCSAFLUSH, &options);
    
      options.c_cflag &= ~PARENB;//next 4 lines setting 8N1
      options.c_cflag &= ~CSTOPB;
      options.c_cflag &= ~CSIZE;
      options.c_cflag |= CS8;
    
      //options.c_cflag &= ~CNEW_RTSCTS;
    
      options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); //raw input
    
      options.c_iflag &= ~(IXON | IXOFF | IXANY); //disable software flow control
    
      return (fd);
    }
    

    What the problem is, is that when I run this program and if my serial device was already plugged in, the buffer has content in it. I need a way to clear the buffer before I start reading from it. I thought using tcsetattr(fd, TCSAFLUSH, &options); would fix this problem, by flushing the IO buffers before initializing the port, but no such luck. Any insight?

  • Étienne
    Étienne about 10 years
    I think it was this bug in Linux Kernel: see lkml.iu.edu//hypermail/linux/kernel/0707.3/1776.html
  • Dmitry
    Dmitry almost 7 years
    Linux 4.8.0, ubuntu 16.04x64, cp210x USB UART driver (USB VID/PID: 10c4:ea60) -- got the same issue with this setup. Solution: put usleep(10000); after open(). Two seconds is too long, but 1000us suggested by @areslagae was too short. 10ms is just right in my case.
  • Oscar
    Oscar almost 6 years
    Finally, I am not the only one.