使用 Boost Asio 从串口读取
我想使用 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);
}
}
boost::asio::streambuf
是正确使用的工具吗?如何从中提取数据以便解析消息?我还想知道是否需要有一个仅调用此函数的单独线程,以便更频繁地调用它。我是否应该担心由于高流量和串行端口缓冲区耗尽而在两次调用该函数之间丢失数据?我正在使用 Qt 的 GUI 库,但我真的不知道处理所有事件需要多少时间。
编辑:有趣的问题是:如何检查串口是否有传入数据?如果没有传入数据,我不希望该函数被阻止......
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:
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::streambuf
the 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.
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...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
本文有助于理解如何将 ASIO 与串口异步使用:
更新(2019-03):
我链接到的原始文章不再可用,即使在互联网档案馆中也很难找到。 (这是快照。)。现在有关于使用 ASIO 进行串行 I/O 的较新文章,可以通过搜索轻松找到,但这篇旧文章仍然非常有用。我将其放在公共要点中,以免丢失:
文章中描述的代码似乎已复制到此处:
作者似乎已将其更新为 C++11。我相信这篇文章是
最初由 fede.tft 编写。
This article is helpful in understanding how ASIO can be used asynchronously with serial ports:
UPDATE (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:
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.
Jason,
如果它适合您的应用程序,我强烈建议您实现基于回调的异步串行 RX。 How do I Perform a nonblocking read using asio? 有一个很好的小例子,说明如何实现带超时的异步串行。正如您所认识到的,它将需要多线程实现来获得性能优势,因此您需要考虑一下接收到的数据将被缓冲在哪里,以确保您不会进行大量复制。
就
boost::streambuff
的内容而言,我个人更喜欢将一些内存作为 char 数组 -char m_RXBuffer[m_RXBuffSize]
并使用boost ::asio::buffer(m_RXBuffer, m_RXBuffSize)
将目标缓冲区传递到async_read_some
中。特别是对于 RS232,我一直发现底层数据是字节流,与任何更复杂的数据结构相比,自然能更好地映射到简单的 char 数组。祝你好运!
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.
As far as the
boost::streambuff
stuff goes, I personally prefer just to block out some memory as a char array -char m_RXBuffer[m_RXBuffSize]
and useboost::asio::buffer(m_RXBuffer, m_RXBuffSize)
to pass the target buffer intoasync_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.Good Luck!