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);