Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where to implement a protocol using boost::asio?

I am trying to implement a simple serial port protocol. It goes like this:

  1. discard all data until 0xff is received
  2. read header (node address and data length, 4 bytes)
  3. read data (max. 64 bytes)
  4. read crc
  5. process the received packet
  6. send response
  7. when 0xff is seen, even when not expected like in the middle of the data, it means a new packet is received

I 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.

like image 259
rve Avatar asked Nov 18 '11 06:11

rve


1 Answers

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.

like image 97
Andriy Tylychko Avatar answered Sep 26 '22 18:09

Andriy Tylychko