tags:

views:

103

answers:

1

I have a select call that doesn't seem to detect characters on the serial port. Is there anything I am missing?

If I remove the read() code that is in the block above the select will return for a while until the existing port buffer is emptied and then nothing more is detected.

I am streaming characters to the port, and running minicom shows the continuous input stream on the port.

Can anybody see anything wrong with this code?

int main(void)

{


  int ret;
  char buf[1280];
  fd_set         m_Inputs;  // fd_set for the select call for com input

  int            m_maxFD;   // max FD for select() call.

  struct timeval tv;



  int fd1;
  fd1 = open("/dev/ttyXR6", O_RDWR | O_NOCTTY | O_NONBLOCK);

  fcntl(fd1, F_SETFL, 0);

  struct termios options;

  tcgetattr(fd1, &options);  // Get the current options for the port...

  // Set the baud rates...
  cfsetispeed(&options, B9600);
  cfsetospeed(&options, B9600);

  // Enable the receiver and set local mode...
  options.c_cflag |= (CLOCAL | CREAD | CS8);
  options.c_cflag &= ~PARENB;  // ignore parity
  options.c_cflag &= ~CSTOPB;  // 1 stop bit (2 if set)
  options.c_cflag &= ~CSIZE;   // clear the size bits
  options.c_cflag &= ~CRTSCTS; //No hard flow control
  options.c_cflag &= ~HUPCL;   //Hang Up on last Close
  options.c_cflag |= CS8;      // reset the size to 8 bits / char
  options.c_cc[VMIN]=1;
  options.c_cc[VTIME] = 1;
  options.c_oflag = 0;
  options.c_lflag = 0;       //ICANON;
  // Set the new options for the port...
  tcsetattr(fd1, TCSANOW, &options);

  // test to make sure the characters are coming in on the port

  for (short i =0; i < 60; i++)
  {
    ret = read(fd1, buf, 32);
    buf[ret] = '\0';
    cout << buf;
    usleep(500);
  }

  fd_set         rfds;  // fd_set for the select call for com input

  FD_ZERO(&rfds);

  FD_SET(fd1, &rfds);


  cout << endl << "FD1 = " << fd1 << endl;

  while (1)
  {
    tv.tv_sec = 0;

    tv.tv_usec = 1000;

    ret = select(fd1 + 1, &rfds, NULL, NULL, &tv);


    if (ret > 0)

    {
      ret = read(fd1, buf, 127);
      buf[ret] = '\0';
      cout << buf;
    }
    usleep(500);
  }

  return 0;

}
+5  A: 

Before it returns, select() modifies rfds to indicate which descriptors have data ready for reading.

In your case, the first time it returns after the 1ms timeout is reached and no data is available on your descriptor, it will remove your descriptor from the rfds set to indicate that no data is available. Then, when you call select() again the next time through the loop, rfds is an empty set, and so after that it will not even bother to check your descriptor anymore.

You need to call FD_SET(fd1, &rfds) before select each time you go through the loop.

Tyler McHenry
...or keep a separate fd_set and memcpy it into a temporary fd_set that you pass to select(). Calling FD_SET each time is expensive if you have lots of sockets. A memcpy is faster in such cases.
Warren Young
Thanks guys. I implemented both suggestions and it works fine now. I have been using this code with a 115200 baud high volume input stream and it obviously never timed out and removed the descriptor. When I went to an intermittent stream it appeared that the code just broke. Thanks again.
David Huff