当前位置:网站首页>Design and implementation of communication protocol

Design and implementation of communication protocol

2022-07-07 12:47:00 Gudong Mengxi

Communication protocol classification

Hardware protocol

During data transmission at the physical layer , The corresponding hardware protocol should be followed between the sender and the receiver , For example, we passed IO Collect a voltage signal , When the input voltage is higher than 2V When , The hardware will think that a high level has been collected , lower than 2V It is considered as a low level . Common optical fibers , A serial port ,CAN Bus we divide it into hardware protocols , They are the carriers of data transmission .

Software protocol

According to the physical characteristics of the bus , On this basis, various software protocols can be designed , The explanation of the agreement involved here is the software agreement , Hereinafter referred to as the agreement . For example, through IO You can design SPI Communication protocol and IIC agreement , adopt CAN The bus can be designed CANOpen agreement , Through serial port, we can design Modbus agreement .

The frame format

When data transmission is based on hardware, a frame format needs to be designed , For example, the data transmitted by serial port is usually in bytes , Then the smallest unit of transmission in protocol design must also be bytes , Communication frames are usually divided into two categories , One is fixed length frame , One is the indefinite length frame .

Fixed length frame

All frames have the same length , The receiver receives the specified length characters first , Then do further processing according to the message type , This kind of agreement has low scalability , Suitable for simple data transmission .

Indefinite frame

The first one is : Communication parties are divided according to functions , It is divided into different message types , The length of each type is different , But the receiver and sender agree on the length of each type of data in advance , The transmission data does not contain length information .

The second kind : The frame length is not fixed , Each frame can be divided into three parts , Frame head , data , check , The length of frame header and check is fixed , The length of the data is variable , The frame header contains length information , Analyze after receiving a complete frame header , The length of the remaining data is obtained by reading the length information , Then continue to receive , Until the verification is received , One frame data reception is completed , Then check the data , Check successfully and proceed to the next step , In this case, the receiving end does not know the length of data to be received before sending , Compared with the first protocol, it is more scalable , It can be used to transfer super long information such as files .

Communication frame design

Starting mark Frame head data check End identification
1 byte16 bytesn bytes1 byte1 byte

The communication message is mainly divided into two parts :

  • The user layer contains frame headers and data , This part defines the type of message and the content of transmission
  • In order to ensure the accuracy and integrity of data , Add the starting mark , Checksum End ID

Start and end marks

In order to avoid the occurrence of start identification and end identification in the data , Therefore, when this character appears in the data, it needs to be escaped .

Starting mark End identification 0xdb
0x550x560xdb
0xdb 0xdc0xdb 0xdd0xdb 0xde

Frame head

type Instructions Frame number Total length Data length
2 byte2 byte2 bytes4 bytes4 bytes
  • Types and instructions are used to tell the receiver how to process data
  • Frame number and total length are used to transmit big data , Such as files
  • The data length represents the number of bytes in the data area

data

Data
n bytes

Data length is not fixed , Is variable , The receiving end will receive data according to the length information contained in the frame header , If there is no data, the end of the frame is directly received

check

CRC
1 bytes

The end of the frame contains 1 byte CRC, Used to verify the whole data , If the TCP This reliable communication , Can be removed CRC,CRC To prevent errors during transmission

Frame data structure

typedef struct
{
    
    uint16_t type;
    uint16_t cmd;
    uint16_t index;
    uint32_t total;
    uint32_t len;
} msg_header_t;

typedef struct
{
    
    msg_header_t header;
    uint8_t payload[];
} msg_t;
  • according to C The default boundary alignment of the language , Frame header size is 16 byte .
  • The data length is not fixed, and a pointer is used here to represent .
  • msg_t The size is 20 byte .

Communication frame transmission

Send message

uint32_t msg_data_convert(uint8_t *in, uint32_t in_len, uint8_t *out, uint32_t out_len)
{
    
    int i = 0;
    int j = 0;
    uint8_t *p = in;

    for (; (i < in_len) && (j < (out_len - 1)); i++, p++)
    {
    
        if (MSG_BEGIN_FLAG == *p)
        {
    
            out[j++] = 0xdb;
            out[j++] = 0xdc;
        }
        else if (MSG_END_FLAG == *p)
        {
    
            out[j++] = 0xdb;
            out[j++] = 0xdd;
        }
        else
        {
    
            out[j++] = *p;
            if (0xdb == *p)
            {
    
                out[j++] = 0xde;
            }
        }
    }

    DEBUG_ASSERT(j < (out_len - 1));

    return j;
}

bool msg_create(msg_parser_t *obj, msg_type_def type, msg_cmd_def cmd, uint32_t index, uint32_t total, uint8_t *payload, uint32_t len)
{
    
    uint8_t crc = 0;
    bool ret = false;
    msg_t msg = {
    0};
    uint32_t offset = 0;

    if ((payload && (len > 0)) || (!payload && (len == 0)))
    {
    
        ret = true;
    }

    msg.header.type = (uint16_t)type;
    msg.header.cmd = (uint16_t)cmd;
    msg.header.index = index;
    msg.header.total = total;
    msg.header.len = len;
    msg.payload = payload;
    crc = msg_parser_calculate_crc(0, (uint8_t *)&msg, sizeof(msg_header_t));
    crc = msg_parser_calculate_crc(crc, msg.payload, msg.header.len);

    obj->msg_send_buffer[offset++] = MSG_BEGIN_FLAG;
    /*  Escape the frame header and tail in the data  */
    offset += msg_data_convert((uint8_t *)&msg, sizeof(msg_header_t), &obj->msg_send_buffer[offset], sizeof(obj->msg_send_buffer) - offset);
    offset += msg_data_convert(msg.payload, msg.header.len, &obj->msg_send_buffer[offset], sizeof(obj->msg_send_buffer) - offset);
    offset += msg_data_convert(&crc, sizeof(crc), &obj->msg_send_buffer[offset], sizeof(obj->msg_send_buffer) - offset);
    obj->msg_send_buffer[offset++] = MSG_END_FLAG;
    /*  Send message through serial port  */
    com_write(obj->com_drv, obj->msg_send_buffer, offset);

    return ret;
}

Receive message

msg_t *msg_parser_recv(msg_parser_t *obj)
{
    
    uint8_t temp = 0;
    uint32_t crc = 0;
    uint8_t recv_crc = 0;
    uint32_t recv_cnt = 0;
    msg_t *ret = &obj->recv_msg;

    /*  Receive frame header  */
    do
    {
    
        com_read_byte(obj->com_drv, &temp, osWaitForever);
    } while (MSG_BEGIN_FLAG != temp);

    /*  Receive remaining data  */
    do
    {
    
        com_read_byte(obj->com_drv, &temp, osWaitForever);

        if (temp == 0xdb)
        {
    
            com_read_byte(obj->com_drv, &temp, osWaitForever);
            if (0xdc == temp)
                obj->msg_recv_buffer[recv_cnt++] = MSG_BEGIN_FLAG;
            else if (0xdd == temp)
                obj->msg_recv_buffer[recv_cnt++] = MSG_END_FLAG;
            else if (0xde == temp)
                obj->msg_recv_buffer[recv_cnt++] = 0xdb;
        }
        else
        {
    
            obj->msg_recv_buffer[recv_cnt++] = temp;
        }
    } while ((MSG_END_FLAG != temp) && (recv_cnt < sizeof(obj->msg_recv_buffer)));

    if (recv_cnt < sizeof(obj->msg_recv_buffer))
    {
    
        /*  Get frame header  */
        memcpy(&ret->header, obj->msg_recv_buffer, sizeof(msg_header_t));

        if (recv_cnt == (sizeof(msg_header_t) + 2 + ret->header.len))
        {
    
            /*  get data  */
            ret->payload = obj->msg_recv_buffer + sizeof(msg_header_t);
            /*  Get verification  */
            recv_crc = obj->msg_recv_buffer[recv_cnt - 2];
            /*  Calculation check  */
            crc = msg_parser_calculate_crc(0, (uint8_t *)ret, sizeof(msg_header_t));
            crc = msg_parser_calculate_crc(crc, ret->payload, ret->header.len);

            if (recv_crc != crc)
            {
    
                ret = NULL;
            }
        }
        else
        {
    
            ret = NULL;
        }
    }
    else
    {
    
        ret = NULL;
    }

    return ret;
}
原网站

版权声明
本文为[Gudong Mengxi]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/188/202207071030536450.html