C – select() doesn’t seem to work with TTY

select() doesn’t seem to work with TTY… here is a solution to the problem.

select() doesn’t seem to work with TTY

I’m currently writing a program that needs to communicate with the AT interface via the UART interface (the operating system is Linux). But I’m having trouble using select() on the file descriptor. For some reason, select doesn’t think the file descriptor is ready to read, but to narrow down the problem, I used the following program.

int main()
{
    char buffer[BSIZE];
    fd_set rfds;
    int ret;
    struct termios cnf;
    struct timeval tv;

fd = open("/dev/ttyO1", O_RDWR);
     Have also tried to set fd = 0 for stdin, as a reference
    signal(SIGINT, sig_handler);
    tcgetattr(fd, &cnf);
    old = cnf;
    cfmakeraw(&cnf);
    tcsetattr(fd, TCSANOW, &cnf);
    while (1) {
        tv.tv_sec = 5;
        tv.tv_usec = 0;
        FD_ZERO(&rfds);
        FD_SET(0, &rfds);
        write(fd, "AT\r", 3);
        ret = select(fd+1, &rfds, NULL, NULL, &tv);
        printf("ret = %d\n", ret);
        if (ret < 0) {
            perror("select()");
        }
        else {
            ret = read(fd, buffer, BSIZE-1);
            buffer[ret] = '\0';
            printf("read: \"%s\"\n", buffer);
        }
    }
    return 0;
}

The run looks like this

    root@linux:~# ./stuff
    ret = 0
    read: "AT
    OK
    "

Indicates that select thinks there is no data, but there is data when reading. This seems strange to me. Also, I tried swapping stdin for tty and it worked great.

The code is running on the Texas Instruments EZSDK PSP kernel, but that shouldn’t be the problem. In addition, the stty settings are as follows

    root@linux:~# stty -aF /dev/ttyO1
    speed 9600 baud; rows 24; columns 80;
    intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
    eol2 = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W;
    lnext = ^V; flush = ^O; min = 1; time = 0;
    -parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts
    -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
    -iuclc -ixany -imaxbel
    opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
    isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
    echoctl echoke

Am I missing the key flag for open()? Or maybe you need to use termios for some setup? This method requires some special hardware

Edit:
I have the same problem when trying to run the program /dev/ttyUSB0, which also happens to be an AT interface. In my opinion, it is related to tty.

Change fd to what I actually use and want to know.

Solution

Do not add file descriptors for serial ports to the FD collection.

Line break:

FD_SET(0, &rfds);

to:

FD_SET(fd, &rfds);

If you need fd zeros in the collection, or add the following line.

FD_SET(fd, &rfds);

Related Problems and Solutions