oli
oli

Reputation: 35

Strategy for protocol frame decoding

I have the following issue: I'm programming micro controllers (ATmega 8bit, 8051, etc...) in C and receive a custom bus-protocol over the UART interface. I put the received bytes into an buffer and process them later.

Now the question: Are there any design patterns or strategies to decode the received frames? How is the best way to do this? Are there any books/tutorials?

this is my first question here, so please don't hit me, if the question is not well formed :)

Upvotes: 2

Views: 2339

Answers (2)

peter_mcc
peter_mcc

Reputation: 836

I've found it is important to design the protocol so that it is easy to decode. My current one has specific start & end bytes. So when the UART receives things it knows where the packet starts (setting the buffer index to zero) and where it ends (so it can be processed).

If you do this you then need to "escape" the start/end bytes in your data, adding another byte in. ie 0x7F -> 0x7D, 0x5F where 0x7D means "next byte is escaped" and the 0x5F represents an escaped 0x7F.

This has made things heaps easier for me. The IRQ is simple, unescaping/checking the packet is simple and then it is easy to get the data from the packet bytes.

IRQ

If (received byte == start flag)
    set receive buffer index to zero
else
    if (space left in buffer)
        store character in buffer
        if (received byte == end flag)
            process buffer

Process Buffer

Unescape the packet data
Check length
Check checksum
Analyse data

Upvotes: 0

Lundin
Lundin

Reputation: 214300

Since all such protocols are custom, there is no standard way to approach them as such. The only thing resembling a ADT (or "design pattern" if you will) is the actual reception of data, which is typically done through a ring buffer.

What you typically do to parse the actual protocol is nothing fancy, but it is always done in the same manner. You will end up with something like this:

(I'm using the prefix XYZ in the below code to indicate that the code is meant to decode the fictional "XYZ" protocol. Replace it with the custom protocol's name.)

// xyz.h
#ifndef XYZ_H
#define XYZ_H

typedef enum
{
  XYZ_OK,
  XYZ_ERR_SYNC,        // various error codes for things that can go wrong
  XYZ_ERR_LENGTH,
  XYZ_ERR_CHECKSUM,
  ...

} xyz_result_t;


xyz_result_t  xyz_decode (const uint8_t* buf, size_t n);

#endif /* XYZ_H */



// xyz.c
#include "xyz.h"

xyz_result_t  xyz_decode (const uint8_t* buf, size_t n)
{
  // various protocol-specific checks:

  if(buf[0] != SOME_SYNC_CHARACTER)
  {
    return XYZ_ERR_SYNC;
  }

  if(buf[something] < expected_min_length ||
     buf[something] > expected_max_length)
  {
    return XYZ_ERR_LENGTH;
  }

  ...

  return XYZ_OK;
}

Upvotes: 2

Related Questions