这是这个问题的后续问题:如何在程序中间等待串口的输入
我正在编写一个程序来控制一个铱调制解调器,该调制解调器需要在程序中间等待串行端口的响应,以验证是否给出了正确的响应。为了完成这个任务,一个用户建议我使用select()
命令来等待这个输入。
然而,我在使用这种方法时遇到了一些困难。最初,select()
每次都会返回响应超时的值(即使调制解调器发送回正确的响应,我用同时运行的另一个程序验证了这一点)。现在,程序在一次迭代后停止,即使从调制解调器发回了正确的响应。
//setting the file descriptor to the port
int fd = open(portName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
{
/*
* Could not open the port.
*/
perror("open_port: Unable to open /dev/ttyS0 - ");
}
else
fcntl(fd, F_SETFL, 0);
FILE *out = fopen(portName.c_str(), "w");//sets the serial port
FILE *in = fopen(portName.c_str(), "r");
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
struct timeval timeout = { 10, 0 }; /* 10 seconds */
//int ret = select(fd+1, &fds, NULL, NULL, &timeout);
/* ret == 0 means timeout, ret == 1 means descriptor is ready for reading,
ret == -1 means error (check errno) */
char buf[100];
int i =0;
while(i<(sizeof(messageArray)/sizeof(messageArray[0])))
{
//creates a string with the AT command that writes to the module
std::string line1("AT+SBDWT=");
line1+=convertInt( messageArray[i].numChar);
line1+=" ";
line1+=convertInt(messageArray[i].packetNumber);
line1+=" ";
line1+=messageArray[i].data;
line1+=std::string("rn");
//creates a string with the AT command that initiates the SBD session
std::string line2("AT+SBDI");
line2+=std::string("rn");
fputs(line1.c_str(), out); //sends to serial port
//usleep(7000000);
int ret =select(fd+1, &fds, NULL, NULL, &timeout);
/* ret == 0 means timeout, ret == 1 means descriptor is ready for reading,
ret == -1 means error (check errno) */
if (ret ==1){
fgets (buf ,sizeof(buf), in);
//add code to check if response is correct
}
else if(ret == 0) {
perror("timeout error ");
}
else if (ret ==-1) {
perror("some other error");
}
fputs(line2.c_str(), out); //sends to serial port
//usleep(7000000); //Pauses between the addition of each packet.
int ret2 = select(fd+1, &fds, NULL, NULL, &timeout);
/* ret == 0 means timeout, ret == 1 means descriptor is ready for reading,
ret == -1 means error (check errno) */
if(ret2 == 0) {
perror("timeout error ");
}
else if (ret2 ==-1) {
perror("some other error");
}
i++;
}
读/写/选择没有使用相同的文件句柄,这有点奇怪。
你没有重置你的fd_sets,这是由select
修改的,并且会在超时的情况下取消所有的fds,默认情况下使下一次调用超时(因为你要求没有fds)。
您还使用了缓冲IO,这在这种情况下必然会造成麻烦。如。fgets
等待EOF
(它不会发生),或者一个换行符,一直读取。它将阻塞,直到它得到它的换行符,所以可能会让你无限期挂起,如果它从来没有发生。它也可能读取比它需要的更多的数据到缓冲区,扰乱你的select
读信号(你有数据在缓冲区中,但选择将超时,因为没有什么可读的文件句柄)。
底线是:
- 在循环中使用
FD_SET
来设置/重置你的fd设置,也重置你的超时,因为select
可能会修改它。 - 使用单个句柄进行读/写/选择,而不是多个句柄。打开
fopen(..., "w+")
或open(..., O_RDWR)
文件 - 如果仍然使用
fopen
,尝试使用setvbuf
和_IONBF
缓冲选项禁用缓冲。 - 否则,使用
open
/read
/write
代替fopen
等。
我注意到在对你上一个问题的回答中提到了这一点。
您可能应该在输出文件流上使用fflush()。