Parsing a packet using structs

luca 18/01/2018 4

When I was analyzing the source code of an opensource software, I found an interesting technique to parse incoming data in a very efficient way, using a struct.

This technique works if the received data has a fixed length and structure; for example it applies very well to data “packets”.

When receiving, the program normally stores incoming data in a buffer in the RAM memory. For example let’s assume that the packet has a length of 14 bytes:

char rx_buffer[14];

Your specific protocol defines the following fields in the packet:

  • address, 5 bytes
  • temperature value, 3 bytes
  • humidity value, 3 bytes
  • TX counter, 1 bytes
  • checksum, 2 bytes

You can define a struct that represents the structure of the packet:

typedef struct {
  uint8_t address[5];
  uint8_t temperature[3];
  uint8_t humidity[3];
  uint8_t tx;
  uint8_t checksum[2];
} my_packet;

The technique consists in applying, as if it were a template, the struct to the buffer:

mem-struct-001

in this way the received bytes are automatically divided into the different fields:

mem-struct-002

Therefore, to parse the data you only need to cast the buffer:

my_packet* parsed_data = (my_packet*)rx_buffer;

and access the struct fields:

parsed_data->address;
parsed_data->temperature;
[...]

Padding and packed

You still have a problem: to make it more efficient to access the memory, compliers normally align the variables based on their size. This means that – when a compiler allocates memory for your struct – some empty space (named padding) could be added between the different variables:

mem-struct-003

The presence of the padding space causes a misalignment if you apply the struct to the buffer with the received data (which are instead continous). Fortunately, it is possible to ask the compiler not to insert padding using the packed attribute:

typedef struct {
  uint8_t address[5];
  uint8_t temperature[3];
  uint8_t humidity[3];
  uint8_t tx;
  uint8_t checksum[2];
}__attribute__((packed)) my_packet;

If you remember to add this attribute, the technique works perfectly!

4 Comments »

  1. whm 18/01/2018 at 09:01 - Reply

    Isn’t parsed_data a pointer? To access the struct field, shouldn’t you use

    parsed_data->address

    instead of

    parsed_data.address

    • luca 18/01/2018 at 09:24 - Reply

      you’re absolutely right! thanks

  2. francesco 18/01/2018 at 15:42 - Reply

    mi sembra una valida alternativa a json

  3. Federico 05/04/2018 at 14:51 - Reply

    Veramente interessante, grazie!

Leave A Response »

This website uses cookies to ensure you get the best experience on our website maggiori informazioni

Questo sito utilizza i cookie per fonire la migliore esperienza di navigazione possibile. Continuando a utilizzare questo sito senza modificare le impostazioni dei cookie o clicchi su "Accetta" permetti al loro utilizzo.

Chiudi