Linux 上多线程程序中从串口读取数据

发布于 2024-10-22 00:49:24 字数 384 浏览 2 评论 0原文

我正在Linux 中编写一个程序,通过串行接口与硬件连接。设备以大约 10Hz 的频率发送大约 30-40 字节的数据包。该软件模块将与其他模块交互并通过 IPC 进行通信,因此它必须执行特定的 IPC 睡眠,以允许它在不执行任何有用操作时接收其订阅的消息。

目前我的代码看起来像这样:

while(1){
  IPC_sleep(some_time);
  read_serial();
  process_serial_data();
}

问题是有时会执行读取,而串行端口上只有下一个数据包的一小部分可用,这意味着直到下一次循环时才会全部读取。对于特定应用程序,最好在数据可用时立即读取数据,并且程序在读取时不会阻塞。

这个问题的最佳解决方案是什么?

I'm writing a program in linux to interface, through serial, with a piece of hardware. The device sends packets of approximately 30-40 bytes at about 10Hz. This software module will interface with others and communicate via IPC so it must perform a specific IPC sleep to allow it to receive messages that it's subscribed to when it isn't doing anything useful.

Currently my code looks something like:

while(1){
  IPC_sleep(some_time);
  read_serial();
  process_serial_data();
}

The problem with this is that sometimes the read will be performed while only a fraction of the next packet is available at the serial port, which means that it isn't all read until next time around the loop. For the specific application it is preferable that the data is read as soon as it's available, and that the program doesn't block while reading.

What's the best solution to this problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

忆悲凉 2024-10-29 00:49:24

最好的解决办法就是不睡觉!我的意思是一个好的解决方案可能是混合
IPC 事件和串行事件。 select 是一个很好的工具来做到这一点。然后你必须找到与选择兼容的IPC机制。

  • 基于套接字的 IPC 能够 select()
  • 基于管道的 IPC 能够 select()
  • posix 消息队列也是可选的

然后你的循环看起来像这样

while(1) {
    select(serial_fd | ipc_fd); //of course this is pseudo code
    if(FD_ISSET(fd_set, serial_fd)) {
        parse_serial(serial_fd, serial_context);
        if(complete_serial_message)
            process_serial_data(serial_context)
    }
    if(FD_ISSET(ipc_fd)) {
        do_ipc();
    }
}

read_serial 被替换为 parse_serial,因为如果您花费所有时间等待完整的串行数据包,那么 select 的所有好处都会丢失。但从你的问题来看,你似乎已经在这样做了,因为你提到在两个不同的循环中获取串行数据。
通过建议的架构,您可以在 IPC 和串行端获得良好的反应性。您可以在串行数据可用时立即读取它们,但无需停下来处理 IPC。

当然它假设你可以改变IPC机制。如果不能,也许您可​​以创建一个“桥接进程”,一侧与您所使用的任何 IPC 连接,另一侧使用 select()able IPC 进行通信您的序列号。

The best solution is not to sleep ! What I mean is a good solution is probably to mix
the IPC event and the serial event. select is a good tool to do this. Then you have to find and IPC mechanism that is select compatible.

  • socket based IPC is select() able
  • pipe based IPC is select() able
  • posix message queue are also selectable

And then your loop looks like this

while(1) {
    select(serial_fd | ipc_fd); //of course this is pseudo code
    if(FD_ISSET(fd_set, serial_fd)) {
        parse_serial(serial_fd, serial_context);
        if(complete_serial_message)
            process_serial_data(serial_context)
    }
    if(FD_ISSET(ipc_fd)) {
        do_ipc();
    }
}

read_serial is replaced with parse_serial, because if you spend all your time waiting for complete serial packet, then all the benefit of the select is lost. But from your question, it seems you are already doing that, since you mention getting serial data in two different loop.
With the proposed architecture you have good reactivity on both the IPC and the serial side. You read serial data as soon as they are available, but without stopping to process IPC.

Of course it assumes you can change the IPC mechanism. If you can't, perhaps you can make a "bridge process" that interface on one side with whatever IPC you are stuck with, and on the other side uses a select()able IPC to communicate with your serial code.

春风十里 2024-10-29 00:49:24

将到目前为止收到的消息存储在某种缓冲区中。

如果您不想在等待新数据时阻塞,请使用类似 select 的内容() 在串行端口 上检查是否有更多数据可用。如果没有,您可以继续进行一些处理或任何需要完成的事情,而不是阻塞,直到有数据可供获取。

当其余数据到达时,添加到缓冲区并检查是否有足够的数据来组成完整的消息。如果有,则对其进行处理并将其从缓冲区中删除。

Store away what you got so far of the message in a buffer of some sort.

If you don't want to block while waiting for new data, use something like select() on the serial port to check that more data is available. If not, you can continue doing some processing or whatever needs to be done instead of blocking until there is data to fetch.

When the rest of the data arrives, add to the buffer and check if there is enough to comprise a complete message. If there is, process it and remove it from the buffer.

锦爱 2024-10-29 00:49:24

您必须缓存足够的消息才能知道它是否是完整的消息,或者您是否拥有完整的有效消息。

如果它无效或不在可接受的时间范围内,那么你就扔掉它。否则,您保留并处理它。

这通常称为为设备协议实现解析器。

You must cache enough of a message to know whether or not it is a complete message or if you will have a complete valid message.

If it is not valid or won't be in an acceptable timeframe, then you toss it. Otherwise, you keep it and process it.

This is typically called implementing a parser for the device's protocol.

活雷疯 2024-10-29 00:49:24

这是所需的算法(阻塞):

while(! complete_packet(p) &&  time_taken < timeout)
{
   p += reading_device.read(); //only blocks for t << 1sec. 

   time_taken.update();   
}
//now you have a complete packet or a timeout. 

如果您愿意,您可以散布回调,或者在处理循环中注入相关部分。

This is the algorithm (blocking) that is needed:

while(! complete_packet(p) &&  time_taken < timeout)
{
   p += reading_device.read(); //only blocks for t << 1sec. 

   time_taken.update();   
}
//now you have a complete packet or a timeout. 

You can intersperse a callback if you like, or inject relevant portions in your processing loops.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文