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...
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,
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 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.
Good Luck!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With