gpt4 book ai didi

c++ - 使用 select() 和 fgets() 从串行端口访问信息

转载 作者:塔克拉玛干 更新时间:2023-11-03 06:58:10 25 4
gpt4 key购买 nike

这是这个问题的后续:How to wait for input from the serial port in the middle of a program

我正在编写一个程序来控制 Iridium 调制解调器,该调制解调器需要在程序中间等待串行端口的响应,以验证是否给出了正确的响应。为了实现这一点,一位用户建议我使用 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("\r\n");

//creates a string with the AT command that initiates the SBD session
std::string line2("AT+SBDI");
line2+=std::string("\r\n");

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 读取信号(缓冲区中有数据,但 select 将超时,因为文件句柄上没有可读取的内容)。

底线是这样的:

  • 在循环中使用 FD_SET 来设置/重置您的 fd 集,同时重置您的超时,因为 select 可能会修改它。
  • 使用单个句柄进行读/写/选择,而不是多个句柄,例如。使用 fopen(..., "w+")open(..., O_RDWR)
  • 打开文件
  • 如果仍在使用 fopen,请尝试使用带有 _IONBF 缓冲选项的 setvbuf 禁用缓冲。
  • 否则,使用open/read/write代替fopen

我会注意到 this answer 中提到了其中的一部分对于您之前的问题。

关于c++ - 使用 select() 和 fgets() 从串行端口访问信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6681492/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com