10
votes

I am having some trouble reading some data from a serial port I opened the following way. I've used this instance of code plenty of times and all worked fine, but now, for some reason that I cant figure out, I am completely unable to read anything from the serial port.

I am able to write and all is correctly received on the other end, but the replies (which are correctly sent) are never received (No, the cables are all ok ;) )

The code I used to open the serial port is the following:

fd = open("/dev/ttyUSB0", O_RDWR | O_NONBLOCK | O_NOCTTY);
if (fd == -1)
{
    Aviso("Unable to open port");
    return (fd);
}
else
{
    //Get the current options for the port...
    bzero(&options, sizeof(options)); /* clear struct for new port settings */
    tcgetattr(fd, &options);

    /*-- Set baud rate -------------------------------------------------------*/
    if (cfsetispeed(&options, SerialBaudInterp(BaudRate))==-1)
        perror("On cfsetispeed:");
    if (cfsetospeed(&options, SerialBaudInterp(BaudRate))==-1)
        perror("On cfsetospeed:");

    //Enable the receiver and set local mode...
    options.c_cflag |= (CLOCAL | CREAD);
    options.c_cflag &= ~PARENB; /* Parity disabled */
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;  /* Mask the character size bits */
    options.c_cflag |= SerialDataBitsInterp(8);           /* CS8 - Selects 8 data bits */
    options.c_cflag &= ~CRTSCTS;                            // disable hardware flow control
    options.c_iflag &= ~(IXON | IXOFF | IXANY);           // disable XON XOFF (for transmit and receive)
    options.c_cflag |= CRTSCTS;                         /* enable hardware flow control */
    
    options.c_cc[VMIN] = 0;     //min carachters to be read
    options.c_cc[VTIME] = 0;    //Time to wait for data (tenths of seconds)

    //Set the new options for the port...
    tcflush(fd, TCIFLUSH);
    if (tcsetattr(fd, TCSANOW, &options)==-1)
    {
        perror("On tcsetattr:");
    }

    PortOpen[ComPort] = fd;
}

return PortOpen[ComPort];

After the port is initializeed I write some stuff to it through simple write command...

int nc = write(hCom, txchar, n);

where hCom is the file descriptor (and it's ok), and (as I said) this works. But... when I do a read afterwards, I get a "Resource Temporarily Unavailable" error from errno.

I tested select to see when the file descriptor had something t read... but it always times out!

I read data like this:

ret = read(hCom, rxchar, n);

and I always get an EAGAIN and I have no idea why.

Update:

The HW is working fine! I can see that there is inbound data on the serial port because I've made a debug cable to read whats going on on another terminal. So...

I know what nonblocking should do. My question is... why isn't anything getting read!. The same setup works fine on windows, so all hardware is working fine...

This is driving me nuts! I'm sure it's something simple as hell! I even tried getting rid of O_NONBLOCK to see when I would receive something... but nothing...

4
I have this same problem. I can transmit but not receive (via USB-RS232 adapter cable). I tried on another linux box that had a RS232 port and it worked just fine. The only change I made was from /dev/ttyUSB0 to /dev/ttyS0. The first computer was Fedora the second is Debian. Other than that, idunno. One other thing. When I close the com program and restart it, the data is read by my program! The data is the input buffer, but my program does not know it. Also, gtkterm works fine, so the h/w is all OK. My program does not see the UART interrupt. This linux h/w abstraction layer is rather bogDon Lawrence

4 Answers

11
votes

Read this.

EAGAIN Non-blocking I/O has been selected using O_NONBLOCK and no data was immediately available for reading.

2
votes

You need to check the serial terminal settings first.

use command - stty -F /dev/ttyUSB0 -a

Check that ctsrts is selected as -ctsrts and do the other required settings with stty utility and you are done.

0
votes

EAGAIN with O_NONBLOCK means there's been no data received on the port. Check that the port and cable are working properly (using minicom or some other known-good program), and that the remote really is sending some data.

0
votes

see my code samples, if EAGAIN, you'd try to read again:

...
options.c_cflag &= ~PARENB; 
options.c_iflag &= ~INPCK; 
...
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // input
options.c_oflag &= ~OPOST; // output
...
fd = open("/dev/ttyUSB0", O_RDWR | O_NDELY | O_NOCTTY);
fcntl(fd, F_SETFL, 0);
...
int nc = write(hCom, txchar, n);
msleep(500); // wait 500ms
fcntl(hCom, F_SETFL, FNDELAY); // don't block serial read
ret = read(hCom, rxchar, n);
if (ret > 0) {
    here had read n bytes or just partial data, read again if partial.
} 
if (ret < 0) {
    if (EAGAIN == errno) {
        not a real error, just read again.
    } else {
        oops, errors.
    }
}
...