C++ 使用 Boost Asio 从串口读取

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2807055/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 11:08:51  来源:igfitidea点击:

Reading from serial port with Boost Asio

c++serial-portboost-asiostreambuf

提问by HelloGoodbye

I'm want to check for incoming data packages on the serial port, using boost.asio. Each data packet will start with a header that is one byte long, and will specify what type of the message has been sent. Each different type of message has its own length. The function I want to write should listen for new incoming messages continually, and when it finds one it should read it, and call some other function to parse it. My current code is as follows:

我想检查串行端口上的传入数据包,使用boost.asio. 每个数据包都以一个字节长的报头开始,并指定已发送的消息类型。每种不同类型的消息都有自己的长度。我想写的函数应该不断地监听新的传入消息,当它找到一个时,它应该读取它,并调用其他函数来解析它。我目前的代码如下:

void check_for_incoming_messages()
{
    boost::asio::streambuf response;
    boost::system::error_code error;
    std::string s1, s2;
    if (boost::asio::read(port, response, boost::asio::transfer_at_least(0), error)) {
        s1 = streambuf_to_string(response);
        int msg_code = s1[0];
        if (msg_code < 0 || msg_code >= NUM_MESSAGES) {
            // Handle error, invalid message header
        }
        if (boost::asio::read(port, response, boost::asio::transfer_at_least(message_lengths[msg_code]-s1.length()), error)) {
            s2 = streambuf_to_string(response);
            // Handle the content of s1 and s2
        }
        else if (error != boost::asio::error::eof) {
            throw boost::system::system_error(error);
        }
    }
    else if (error != boost::asio::error::eof) {
        throw boost::system::system_error(error);
    }
}

Is boost::asio::streambufthe right tool to use? And how do I extract the data from it so I can parse the message? I also want to know if I need to have a separate thread which only calls this function, so that it gets called more often. Should I be worried about losing data between two calls to the function because of high traffic and serial port's buffer running out? I'm using Qt's libraries for GUI and I don't really know how much time it takes to process all the events.

是否boost::asio::streambuf使用正确的工具?以及如何从中提取数据以便解析消息?我还想知道是否需要一个单独的线程来只调用这个函数,以便更频繁地调用它。由于高流量和串行端口缓冲区耗尽,我是否应该担心在两次调用该函数之间丢失数据?我正在使用 Qt 的 GUI 库,但我真的不知道处理所有事件需要多少时间。

Edit:The interesting question is: how can I check if there is any incoming data at the serial port? If there is no incoming data, I don't want the function to block...

编辑:有趣的问题是:如何检查串行端口是否有任何传入数据?如果没有传入数据,我不希望该函数阻塞...

回答by kaliatech

This article is helpful in understanding how ASIO can be used asynchronously with serial ports:

这篇文章有助于理解如何与串行端口异步使用 ASIO:

UPDATE (2019-03):

更新(2019-03)

The original article I had linked to is no longer available and is difficult to find even in Internet Archive. (Here is a snapshot.). There are now newer articles on using ASIO for serial I/O found easily by searching, but this older article is still very useful. I'm putting it in a public gist so that it doesn't get lost:

我链接到的原始文章不再可用,即使在 Internet Archive 中也很难找到。(这是一个快照。)。现在可以通过搜索轻松找到有关使用 ASIO 进行串行 I/O 的较新文章,但是这篇较旧的文章仍然非常有用。我将它放在公共要点中,以免丢失:

The code described in the article appears to have been copied here:

文章中描述的代码似乎已复制到此处:

The author seems to have updated it for C++11. I believe the article was originally written by fede.tft.

作者似乎已经为 C++11 更新了它。我相信这篇文章最初是由fede.tft写的。

回答by OcularProgrammer

Jason,

杰森,

If it is suitable for your application, I'd highly recommend implementing a callback-based asynchronous serial RX. How do I perform a nonblocking read using asio?has a great little example of how to implement asynch serial with a timeout. As you recognised, it will require a multi-threaded implementation to get the performance advantages, so you will need to put some thought where your recieved data will be buffered to make sure you aren't doing a lot of copying.

如果它适合您的应用程序,我强烈建议您实现基于回调的异步串行 RX。如何使用 asio 执行非阻塞读取?有一个很好的小例子,说明如何使用超时实现异步串行。正如您所认识到的,它将需要多线程实现才能获得性能优势,因此您需要考虑将接收到的数据缓冲到何处,以确保不会进行大量复制。

As far as the boost::streambuffstuff goes, I personally prefer just to block out some memory as a char array - char m_RXBuffer[m_RXBuffSize]and use boost::asio::buffer(m_RXBuffer, m_RXBuffSize)to pass the target buffer into async_read_some. In particular for RS232, I have always found the fact that the underlying data is a stream of bytes naturally maps a lot better onto a simple char array than any of the more complex data structures.

就这些boost::streambuff东西而言,我个人更喜欢将一些内存作为字符数组阻塞 - char m_RXBuffer[m_RXBuffSize]并用于boost::asio::buffer(m_RXBuffer, m_RXBuffSize)将目标缓冲区传递到async_read_some. 特别是对于 RS232,我一直发现这样一个事实,即底层数据是字节流,与任何更复杂的数据结构相比,它自然地映射到简单的 char 数组上要好得多。

Good Luck!

祝你好运!