Using State Machines to Parse UART Variable-Length Protocol Frames

Using State Machines to Parse UART Variable-Length Protocol Frames

In communication design, considering the flexibility of protocols, they are often designed to be “variable length”. An example is shown in the figure below: the communication protocol frame of the Ruimi LoRa terminal.Using State Machines to Parse UART Variable-Length Protocol FramesIf a system receives the above “variable length” protocol frames, there will be a challenge — how to efficiently receive and parse them.To simplify system design, we strongly recommend using a state machine to parse UART data frames, and perform the parsing work in the ISR (interrupt service routine), only submitting the entire data frame to the process for handling when the last byte (0x0D) is received.The principle of this parsing state machine is illustrated in the figure below:Using State Machines to Parse UART Variable-Length Protocol FramesSo can the ISR handle this state machine in time? The answer is: so easy! Because it only has 3 actions, and the computational load is very small:Compare received data -> Update status variable -> Store received data, with only 3 statements in C, translating to no more than 10 machine instructions.

The code listing is as follows:

/**
* @brief  Status of received communication frame
*/
typedef enum
{
    STATUS_IDLE = (uint8_t)0,
    STATUS_HEAD, /* Rx Head=0x3C */
    STATUS_TYPE, /* Rx Type */
    STATUS_DATA, /* Data filed */
    STATUS_TAIL, /* Tail=0x0D */
    STATUS_END, /* End of this frame */
} COMM_TRM_STATUS_TypeDef;

/**
* @brief  Data object for received communication frame
*/
typedef struct
{
    uint8_t    byCnt; /* Count of 1 field */
    uint8_t    byDataLen; /* Length of data field */
    uint8_t    byFrameLen; /* Length of frame */
    COMM_TRM_STATUS_TypeDef    eRxStatus;
    uint8_t    a_byRxBuf[MAX_LEN_COMM_TRM_DATA]; 
} COMM_TRM_DATA;

/**
* @brief  Data object for received communication frame.
* @note  Prevent race condition that accessed by both ISR and process.
*/
static COMM_TRM_DATA    s_stComm2TrmData;

/**
  * @brief  Put a data that received by UART into buffer.
  * @note  Prevent race condition this called by ISR. 
  * @param  uint8_t byData: the data received by UART.
  * @retval  None
  */
void comm2trm_RxUartData(uint8_t byData)
{
    /* Update status according to the received data */
    switch (s_stComm2TrmData.eRxStatus)
    {
        case STATUS_IDLE:
            if (COMM_TRM_HEAD == byData) /* Is Head */
            {
                s_stComm2TrmData.eRxStatus = STATUS_HEAD;
            }
            else
            {
                goto rx_exception;
            }
            break;
        case STATUS_HEAD:
            if (TYPE_INVALID_MIN < byData && byData < TYPE_INVALID_MAX) /* Valid type */
            {
                s_stComm2TrmData.eRxStatus = STATUS_TYPE;
            }
            else
            {
                goto rx_exception;
            }
            break;
        case STATUS_TYPE:
            if (byData <= MAX_LEN_UART_FRAME_DATA) /* Valid data size */
            {
                s_stComm2TrmData.eRxStatus = STATUS_DATA;
                s_stComm2TrmData.byDataLen = byData;
            }
            else
            {
                goto rx_exception;
            }
            break;
        case STATUS_DATA:
            if (s_stComm2TrmData.byCnt < s_stComm2TrmData.byDataLen)
            {
                ++s_stComm2TrmData.byCnt;
            }
            else
            {
                s_stComm2TrmData.eRxStatus = STATUS_TAIL;
            }
            break;
        case STATUS_TAIL:
            if (COMM_TRM_TAIL == byData)
            {
                /* We received a frame of data, now tell process to deal with it! */
                process_poll(&Comm2TrmProcess);
            }
            else
            {
                goto rx_exception;
            }
            break;
        default:
            ASSERT(!"Error: Bad status of comm2trm_RxUartData().\r\n");
            break;
    }

    /* Save the received data */
    s_stComm2TrmData.a_byRxBuf[s_stComm2TrmData.byFrameLen++] = byData;
    return;

rx_exception:
    ClearCommFrame();
    return; 
}

Original text: https://blog.csdn.net/jiangjunjie_2005/article/details/50619884

Source from the internet, copyright belongs to the original author. If there is any infringement, please contact for deletion.

Finally

The author has collected some embedded learning materials, reply with【1024】 in the public account to get the download link~
Recommended good articles Click on the blue text to jump
☞ Collection | Complete Linux Application Programming
☞ Collection | Learn Some Networking Knowledge
☞ Collection | Handwritten C Language
☞ Collection | Handwritten C++ Language
☞ Collection | Experience Sharing
☞ Collection | From Microcontroller to Linux
☞ Collection | Power Control Technology
☞ Collection | Essential Mathematical Knowledge for Embedded Systems
☞ MCU Advanced Collection
☞ Embedded C Language Advanced Collection
☞ Experience Sharing

Leave a Comment