I am trying to implement a simple serial port protocol. It goes like this:
0xff
is received0xff
is seen, even when not expected like in the middle of the data, it means a new packet is receivedI can implement this using boost::asio::serial_port
with boost::asio::read()
reading a single byte and processing this byte when it is received. Although this works, I was wondering if there is a more 'boost' like way to do this?
I looked at boost::asio::read_until()
for reading until 0xff
, but then I don't know how to discard the data. Storing the data in a buffer and then not using the buffer seems a bit wasteful.
I can use boost::asio::read_until()
for reading until the end of the packet but then the MatchCondition
needs to have access to (the header of the packet in) the buffer. It seems the MatchCondition
only gets an iterator to the first and last byte recently received.
Also, the data received using boost::asio::read()
ends up in a stream_buf
and I have to parse the received data into a Packet
object. I can do this parsing inside Packet
, in a separate ParsePacket
object or somehow integrate it with boost::asio
(something like boost::asio::read(serial, myPacket);
where myPacket
is a Packet
object)
When 0xff
is seen anywhere in the received data, it means a new packet is starting. So when 0xff
is received, it must forget any previous received data and start receiving a new packet.
I am planning on using asynchronous operations and adding timeouts.
So, my question is: where to implement a protocol like this? Or more generally, where to implement a protocol using boost::asio
. I am not looking for working code but something like advise on where to implement the protocol and which boost::asio
functionality to use.
update:
There is no flow control (hardware or software) used in this case.
First of all, as @Autopulated pointed in comments, I want to warn you about using delimiters (your 0xFF) in binary protocols. It's dangerous technique (brings a lot of ambiguity) and requires complicated implementations. Even if you can guarantee that your data doesn't contain 0xFF bytes you cannot do this about CRC field.
I would recommend to not bother with any delimiters and concentrate on simple and predictable binary protocol: [packet][packet]...
where [packet] = [node address:X][data length:4][data:data length][CRC:1]
Sending such packets can look like:
size_t const data_length_bytes = 4;
std::vector<char> data = ...;
size_t data_length = data.size();
Node_address node_address = ...;
std::vector<boost::asio::const_buffer> bufs;
bufs.push_back(boost::asio::buffer(&node_address, sizeof(node_address)));
bufs.push_back(boost::asio::buffer(&data_length, data_length_bytes));
bufs.push_back(boost::asio::buffer(data));
boost::system::error_code error;
boost::asio::write(socket, boost::asio::buffer(bufs), error);
if (error)
throw boost::system::system_error(error);
Receiving:
size_t data_length;
std::vector<char> data;
Node_address node_address;
char crc;
std::vector<boost::asio::mutable_buffer> bufs;
boost::system::error_code error;
bufs.push_back(boost::asio::buffer(&node_address, sizeof(node_address)));
bufs.push_back(boost::asio::buffer(&data_length, data_length_bytes));
boost::asio::read(serial_port, bufs, error);
if (error)
throw boost::system::system_error(error);
data.resize(data_length);
bufs.clear();
bufs.push_back(boost::asio::buffer(&data.front(), data_length));
bufs.push_back(boost::asio::buffer(&crc, sizeof(crc));
boost::asio::read(serial_port, bufs, error);
if (error)
throw boost::system::system_error(error);
// check CRC
// send response
Please note that this example makes assumption that both peers has the same endianess.
I wrote this code here so don't expect it's correct, use it just as an idea.
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