views:

196

answers:

2

I have the following C program:

#include <fcntl.h>
#include <termios.h>
#include <stdio.h>

int main()
{
    int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NONBLOCK);
    if(fd < 0)
    {
        perror("Could not open device");
    }
    printf("Device opened\n");

    struct termios options;
    tcgetattr(fd, &options);
    cfmakeraw(&options);
    cfsetispeed(&options, B19200);
    cfsetospeed(&options, B19200);
    tcsetattr(fd, TCSANOW, &options);

    char txpacket[] = {0x23, 0x06, 0x00, 0x00, 0xdd, 0xf9};
    ssize_t written = write(fd, txpacket, sizeof(txpacket));
    printf("Written %d bytes\n", written);

    printf("Starting to wait for target to respond\n");
    while(1)
    {
        fd_set readset;
        FD_ZERO(&readset);
        FD_SET(fd, &readset);
        int nCount = select(fd + 1, &readset, NULL, NULL, NULL);
        if(nCount > 0)
        {
            if(FD_ISSET(fd, &readset))
            {
                int i;
                char buffer[128];
                ssize_t bytesread = read(fd, buffer, sizeof(buffer));
                printf("Received %d bytes\n", bytesread);
                for(i = 0; i < bytesread; i++)
                {
                    printf("  %02x", buffer[i]);
                }
            }
        }
    }
}

This program opens the serial device /dev/ttyS0, writes a sequence of data to it and starts listening for a response. I get the following output:

Device opened
Written 6 bytes
Starting to wait for target to respond
Received 0 bytes
Received 0 bytes
Received 0 bytes
Received 0 bytes
Received 0 bytes
Received 0 bytes
...

And the application consumes 100% CPU. I'm not able to receive any data, even though the target hardware actually transmits it.

What is wrong?

+3  A: 

read() returning 0 indicates the end-of-file condition. You should check for that and break out of the loop if it occurs.

As to what's causing that - end-of-file on a serial port indicates it has detected a hangup, meaning that the DCD line has been dropped.

You can set the CLOCAL flag in options.c_cflag to ignore the modem control lines, if your device doesn't set them properly.

caf
Thanks! That was indeed what was causing the problem.
Dr. Sbaitso
Damn, did not see the CLOCAL thing !
shodanex
Had the same problem, thanks for the tip. Didn't realize cfmakeraw dind't see those two obvious flags.
RishiD
A: 

You should try without the O_NONBLOCK flag. in raw mode, if the settings of c_cc[VMIN] and c_cc[VTIME] is 0, the serial port behave like this (according to man cfmakeraw) :

If data is available, read returns immediately, with the lesser of the number of bytes available, or the number of bytes requested. If no data is available, read returns 0

So what you should try is :

options->c_cc[VMIN]=1;
shodanex