0

I have a serial device connected via a FTDI serial to usb cable. The device sends 78 bytes every 10 msec. I am calling read() every 1 msec, so I expect read() to return 78 bytes every 10 calls (possibly split over 2 calls), and 0 bytes for 8-9 calls in between (my read() call provides a 2k byte buffer). However, what actually happens is read() returns 496 bytes every ~63 msec. I get all the data, but not as soon as it's available. It seems to be buffered somewhere until 496 bytes are accumulated.

Here's my code snippet that sets termios. Everything should be set for raw data. I believe that somehow, the buffering is happening in the linux USB driver, since VMIN and VTIME are both set to 0. Any ideas on how to get the data as soon as it's available? Possibly by tweaking the USB driver settings?

   char *portname = "/dev/ttyUSB0";
   fd = open(portname, O_RDWR | O_NOCTTY | O_NDELAY);
   if (fd < 0)
   {
     printf("Failed to open %s. errno = %d (%s)\n", portname, errno, strerror(errno));
     return -1;
   }
   printf("%s opened successfully\n\n", portname);

   struct termios settings;
   if (tcgetattr(fd, &settings) < 0)
   {
     printf("tcgettattr() failed (%i): %s\n", errno, strerror(errno));
     return -1;
   }

   cfsetispeed(&settings, B460800);   /* set baud rate */
   cfsetospeed(&settings, B460800);

   settings.c_cflag &= ~PARENB;   /* No parity    */
   settings.c_cflag &= ~CSTOPB;   /* 1 stop bit   */
   settings.c_cflag &= ~CSIZE;    /* Clears the mask for setting the data size */
   settings.c_cflag |=  CS8;      /* Set the data bits = 8                     */

   settings.c_cflag &= ~CRTSCTS;       /* No Hardware flow Control                    */
   settings.c_cflag |= CREAD | CLOCAL; /* Enable receiver, Ignore Modem Control lines */

   settings.c_iflag &= ~(IXON | IXOFF | IXANY);  /* Disable XON/XOFF flow control both i/p and o/p */
   settings.c_iflag &= ~(BRKINT | IGNBRK | ICRNL | INLCR | PARMRK | ISTRIP | IGNCR);
   
   settings.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHONL | ISIG | IEXTEN);  /* Non Cannonical mode  */
   settings.c_lflag |= NOFLSH;

   settings.c_oflag &= ~(OPOST | ONLCR);  /* No Output Processing */
   
   settings.c_cc[VMIN]  = 0;
   settings.c_cc[VTIME] = 0;

   if ((tcsetattr(fd, TCSANOW, &settings)) != 0) /* Set the attributes to the termios structure */
   {
     printf("Error setting attributes\n");
     return -1;
   }
gstemp
  • 1
  • 1
    It could be getting buffered in the FTDI chip, since USB uses polling to retrieve data (all communication is initiated by the host in USB). If that's the case, not much you can do about it. I believe you can monitor USB traffic using WireShark, which might shine a light. – pmacfarlane Oct 28 '22 at 22:09
  • 1
    I figured it out shortly after posting the question. I needed to add a udev rules file to set the ftdi usb latency to 1 msec, overriding the default of 16 msec. – gstemp Oct 28 '22 at 22:55
  • "*VMIN and VTIME are both set to 0*" -- Irrelevant since you choose to use nonblocking I/O. "*how to get the data as soon as it's available?*" -- Probably not with nonblocking I/O. You're wasting CPU cycles waiting for data and polling a system buffer. You can get better efficiency and latency using blocking I/O. You're choosing old-fashion polling over an event-driven scheme. – sawdust Oct 28 '22 at 23:55

0 Answers0