如何在程序执行过程中等待串口输入

4
我正在编写一个程序来控制与卫星通信的 Iridium 调制解调器。每次发送 AT 命令后,调制解调器会回复(根据命令不同)以指示命令是否成功。
目前我已经实现了这样一个程序:在向调制解调器发送每个命令之间,程序只等待 10 秒钟,但这有些冒险,因为它不允许处理错误,以防命令没有成功解释。我唯一知道如何读取串口输入的方法是使用 while(fgets( , ,)),所以我想知道如何让程序在下一个命令发送之前等待来自串口的调制解调器回复并检查它是什么,而不是采用统一的延迟。
我正在使用 Linux 操作系统。
FILE *out = fopen(portName.c_str(), "w");//sets the serial port

for(int i =0; i<(sizeof(messageArray)/sizeof(messageArray[0])); i++)
{
  //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(10000000);     //Pauses  between the addition of each packet.

  fputs(line2.c_str(), out); //sends to serial port

  usleep(10000000); 
}

这不能是一个 expect 脚本的原因是什么? - nmichaels
2个回答

5

使用 selectpoll 函数在串口对应的文件描述符上进行操作,当描述符可读时会返回。

类似这样:

int fd = fileno(stdin);  /* If the serial port is on stdin */
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) */

2
如果串行端口不在标准输入(stdin)上,由于问题指定了Linux操作系统,则使用适当的选项open("/dev/ttyS0",...)可能会解决问题。 - qid
2
“文件描述符”是标识符(int),您的程序实际上将其传递给内核以标识打开的文件(或设备或套接字)。 stdin 是一个“文件流”(或 FILE *),它包装在文件描述符周围。 说实话,对于这个应用程序,@diverscuba23 是正确的,您应该为所有内容使用文件描述符... - Nemo
“select”函数的返回值似乎每次都返回超时值,但调制解调器却发送回了正确的响应。您有什么想法是什么问题吗? - Wandering Sophist
是的,我也很担心这个问题...不幸的是,stdin是有缓存的。这意味着它可以从文件描述符中读取比你要求的更多的内容。尝试使用setvbuf_IONBUF设定stdin为无缓存状态。然后select()和fgets()应该会就是否有数据可读达成一致。 - Nemo
所以 select 返回零,但你可以成功从 fd 中读取?这似乎是个自相矛盾的说法(或可能是竞态条件...)。你可能想要为此打开一个新问题。 - Nemo
显示剩余2条评论

2
为了更好地接近您的模型,您可以采取以下措施:
1)使用纯文件处理程序(通过open())。然后,您将使用read()和write()与串行端口通信。
2)使用上述方法还可以让您使用select,以查看是否有东西可以读取或写入。
这也将使您能够将与调制解调器的通信移动到另一个线程中,如果您的程序还有其他任务需要完成。
我最近做了一些非常相似的事情,只不过是使用了HF无线电调制解调器,并为串行端口通信使用了Boost ASIO库。如果可以的话,这可能会对您有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接