数据帧分析

原理分析

协议内容:
    1、检验数范围是:不包含数据头和位的所有数据(从设备地址到CRC数据之间的内容)
    2、起始位
    协议头T1=0xAA;
    T2-T2-T3  为0x000000-0xFFFFFF 的连续序列
    3、结束位
    协议头T1=0xEE;
    T2-T2-T3  为0x000000-0xFFFFFF 的连续序列(和数据头一致)
    4、小端序方式LSB


起始位            设备地址        功能码    数据长度    备用数据    CRC检验        数据尾
T1-T2-T3-T4        8Bit          0XA1     16Bit        32Bit      16Bit          T1-T2-T3-T4

测试数据
    1、内部含有前期误导的数据头
    2、有误导的数据尾巴
    3、数据内部含有数据头和尾巴

0xaa,0x00,0xee,0x02,                误导数据头
0xaa,0x01,0x02,0x03,0x0,0x01,
0x05,0x00,0xaa,2,3,4,5,             误导数据头   0x05 0x00 数据长度
0x5f,0xb5,
0x01,0x02,0xee,0xee                 误导数据尾

判定思路:
    1、查找数据头;
    2、找到数据头后,开始查找数据尾巴
    3、尝试找到数据尾巴后,检查数据长度和数据内部长度是否相等
    4、相等后确定找到头和尾
    crc检验

数据帧分析

分析头文件

/*
 * @Author: your name
 * @Date: 2021-08-05 13:59:18
 * @LastEditTime: 2021-08-05 18:00:38
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: /RingBuffer/analysis.h
 */
#ifndef __ANALYSIS_H__
#define __ANALYSIS_H__
#include"ring_buffer.h"



/**
 *协议内容:
    1、检验数范围是:不包含数据头和位的所有数据(从设备地址到CRC数据之间的内容)
    2、起始位
    协议头T1=0xAA;
    T2-T2-T3  为0x000000-0xFFFFFF 的连续序列
    3、结束位 
    协议头T1=0xEE;
    T2-T2-T3  为0x000000-0xFFFFFF 的连续序列(和数据头一致)
    4、小端序方式LSB


起始位	        设备地址	    功能码	数据长度	备用数据	CRC检验	    数据尾
T1-T2-T3-T4	    8Bit	      0XA1	 16Bit	    32Bit	  16Bit	      T1-T2-T3-T4

测试数据
    1、内部含有前期误导的数据头
    2、有误导的数据尾巴
    3、数据内部含有数据头和尾巴

0xaa,0x00,0xee,0x02,                误导数据头
0xaa,0x01,0x02,0x03,0x0,0x01,
0x05,0x00,0xaa,2,3,4,5,             误导数据头   0x05 0x00 数据长度
0x5f,0xb5,
0x01,0x02,0xee,0xee                 误导数据尾

判定思路:
    1、查找数据头;
    2、找到数据头后,开始查找数据尾巴
    3、尝试找到数据尾巴后,检查数据长度和数据内部长度是否相等
    4、相等后确定找到头和尾
    crc检验

 */
/**
 * @description: 
 * @param {*}
 *
 */
typedef struct 
{
    uint8_t addr;
    uint8_t cmd;  
    uint8_t data_len;
    uint32_t ID;
    uint8_t data[32];
}data_frame;

/**
 * @description: 从环形缓冲区获取一帧数据
 * @param {
 * p_ring   :  数据存放的缓冲区
 * frame    :   获取到的数据放在此数据结构内部     
 * 
 * }
 * @return {返回0:没有获取到一帧数据,返回>0 获取到一帧数据的帧长度}
 */

uint32_t analysis_data(RingBuffer *p_ring, data_frame *frame);


void remove_head_tail(data_frame *frame);
#endif

分析实现文件

/*
 * @Author: your name
 * @Date: 2021-08-05 13:59:25
 * @LastEditTime: 2021-08-05 18:09:02
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: /RingBuffer/analysis.c
 */
#include "ring_buffer.h"
#include "analysis.h"
#include "crc16.h"
typedef enum
{
    HEAD = 0XAA,
    TAIL = 0XEE,
    HEAD_LEN=8
} DATA_STRUCT;
/*
    获取一帧完整数据

*/
uint32_t analysis_data(RingBuffer *p_ring, data_frame *pframe)
{
    uint16_t ring_len = get_count(p_ring);
    uint8_t u8;
    int16_t head_ofs = -1, tail_ofs = -1;
    uint16_t data_len;
    // do
    // {
    head_ofs = -1;
    tail_ofs = -1;
    for (int16_t i = 0; i < ring_len; i++)
    {
        u8 = read_u8_from_index(p_ring, i);
        if (u8 == HEAD && head_ofs == -1)
        {
            pframe->data[0] = u8;
            head_ofs = i;
            continue;
        }
        if (head_ofs != -1)
        {
            pframe->data[i - head_ofs] = u8;
            if (u8 == TAIL)
            {
                pframe->data_len = i - head_ofs + 1;
                data_len = pframe->data[6] | pframe->data[7] << 8;
                printf("data len =%04x\n", data_len);
                //判定数据计算和长度和实际长度是否一致
                if (pframe->data_len == data_len + 4 + 1 + 1 + 2 + 2 + 4)
                {
                    tail_ofs = i;
                    break;
                }
                
            }
        }
    }
    if (tail_ofs == -1 || head_ofs == -1)
    {
        remove_data(p_ring, head_ofs + 1); //解决有两个头部的情况
        return 0;
    }

    uint16_t crc0 = CRC16(pframe->data + 4, pframe->data_len - 1 - 3 - 6);
    uint16_t crc1 = (pframe->data[pframe->data_len - 5]) << 8 |
                    pframe->data[pframe->data_len - 6];
    printf("crc = %04x  crc1 = %04x \n", crc0, crc1);
    if (crc0 != crc1)
    {
        remove_data(p_ring, head_ofs + 1); //解决有两个头部的情况
        pframe->data_len = 0;
        printf("ERROR : CRC16 fail...\n");
        return 0;
    }
    pframe->addr = pframe->data[4];
    pframe->cmd = pframe->data[5];
    pframe->ID = pframe->data[1]|pframe->data[2]<<8|pframe->data[3]<<16;
    pframe->data_len=data_len;
    remove_head_tail(pframe);
    printf("read : ");
    for (uint16_t i = 0; i < pframe->data_len; i++)
    {
        printf("%02x ", pframe->data[i]);
    }
    printf("\n ");
    // } while (pframe->data_len == 0);
    return pframe->data_len;
}

void remove_head_tail(data_frame *frame)
{
    if(frame->data_len<=0)
    {
        printf("error : data len error\n");
    }
    for(uint16_t i=0;i<frame->data_len;i++)
    {
        frame->data[i]=frame->data[HEAD_LEN+i];
    }
}

环形缓冲区

https://blog.csdn.net/u010261063/article/details/119387023

        头文件

#ifndef __RING_BUFFER_H__
#define __RING_BUFFER_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>

/*
缓冲区示意图:
buffer                  是缓冲区的内存起始地址
read_ofs            读数据的索引
write_ofs           写数据索引
max_len             缓冲区最大数据大小
len                         已经存入数据的大小
-------- -----------------read_ofs---------------------------write_ofs --------------------
            *****************|***************************|***********************
            ********************************************************************
            ********************************************************************
-----buffer ---------------------------------- max---------------------------------------------|

*/
typedef struct
{ 
    uint16_t read_ofs;
    uint16_t write_ofs;
    uint16_t len;
    uint16_t max;
    uint8_t *buffer;
} RingBuffer;

/*

功能:环形缓冲区初始化
参数:
    max_len 预定义缓冲区大小

*/
void InitRingBuff(RingBuffer *p_ring,uint16_t max_len);

/*
环形缓冲区释放
*/
void FreeRingBuff(RingBuffer *p_ring);

/*
 功能:
       从缓冲区读数据 并移除已经读取到的数据
参数
    pBuff       读取数据的存储控制起始地址
    len             希望读取到的数据大小
返回值:
    返回实际读取的数据
*/
int ReadRingBuff(RingBuffer *p_ring,char *pBuff, int len);


/*
 功能:
       向缓冲区写数据
参数
    pBuff       待写入数据的存储控制起始地址
    AddLen             希望写入缓冲区的到的数据大小
返回值:
    返回实际写入的数据大小 返回0 写入失败
*/
int WriteRingBuff(RingBuffer *p_ring,char *pBuff, int AddLen);
/*
 功能:
    读取指定位置的数据 ,
参数:
    index 位置都是处于有数据的位置开始

*/
uint8_t read_u8_from_index(RingBuffer *p_ring,uint16_t index);

/*
 功能:
    获取缓冲区有多少数据
返回值:
    返回缓冲区已经存储的数据大小
*/
uint16_t get_count(RingBuffer *p_ring);

/*
功能:
    从指定位置获取指定长度的数据,并移除其数据
参数:
    p_ring 待操作的缓冲区
    data 存储数据的缓冲区地址
    len 获取数据的长度
返回值:
    返回获取到的数据数量
*/
uint16_t read_data_ofs(RingBuffer *p_ring, uint8_t *data, const uint16_t len, const uint16_t offset);

/**
 * @description 
 *  从环形缓冲区内部移除指定长度的数据
 * @param {RingBuffer} p_ring 待移除的环形缓冲区
 * @param {uint16_t} remove_len 需要移除的长度
 * @return {*}  返回0:移除失败,可能是移除长度参数错误,返回>0 就是实际移除的数据长度
 */
uint16_t remove_data(RingBuffer *p_ring,uint16_t remove_len);

#endif //RING_BUFFER

实现文件

#include "ring_buffer.h"

//环形缓冲区初始化
void InitRingBuff(RingBuffer *p_ring, uint16_t max_len)
{
    p_ring->buffer = (uint8_t *)malloc(max_len);
    memset(p_ring->buffer, 0, max_len);
    p_ring->read_ofs = 0;
    p_ring->write_ofs = 0;
    p_ring->len = 0;
    p_ring->max = max_len;
}

//环形缓冲区释放
void FreeRingBuff(RingBuffer *p_ring)
{
    if (NULL != p_ring->buffer)
    {
        free(p_ring->buffer);
    }
}

//向缓冲区写数据
int WriteRingBuff(RingBuffer *p_ring, char *pBuff, int AddLen)
{
    uint16_t len = 0;
    uint16_t remain = 0;
    if (p_ring->buffer == NULL)
    {
        printf("WriteRingBuff:RingBuff is not Init!\n");
        return 0;
    }
    //计算最多可以写入的数据长度
    if (AddLen >= p_ring->max - p_ring->len)
    {
        AddLen = p_ring->max - p_ring->len;
        printf(" kong jian bu zu %d\n", AddLen);
    }
    for (uint16_t i = 0; i < AddLen; i++)
    {

        p_ring->buffer[p_ring->write_ofs] = pBuff[i];
        p_ring->write_ofs = (++p_ring->write_ofs) % p_ring->max;
    }
    p_ring->len += AddLen;

    printf("write : ");
    for (uint16_t i = 0; i < p_ring->max; i++)
    {
        printf("%02x ", p_ring->buffer[i]);
    }
    printf("\n ");
    printf("read = %d write =  %d  len = %d\n", p_ring->read_ofs, p_ring->write_ofs, p_ring->len);
    return AddLen;
}
/*
    从缓冲区读数据 并移除已经读取到的数据
*/
int ReadRingBuff(RingBuffer *p_ring, char *pBuff, int read_len)
{
    uint16_t len = 0;
    uint16_t alread_read = 0;
    uint16_t remain = 0;
    if (p_ring->buffer == NULL)
    {
        printf("don't init RingBuffer\n");
        return 0;
    }
    if (read_len > p_ring->len)
    {
        read_len = p_ring->len;
        printf("read data only \n");
    }
    for (uint16_t i = 0; i < read_len; i++)
    {
        pBuff[i] = p_ring->buffer[p_ring->read_ofs];
        p_ring->read_ofs = (++p_ring->read_ofs) % p_ring->max;
    }
    p_ring->len -= read_len;

    printf("read : ");
    for (uint16_t i = 0; i < read_len; i++)
    {
        printf("%02x ", pBuff[i]);
    }
    printf("\n ");
    printf("read = %d write =  %d  len = %d\n", p_ring->read_ofs, p_ring->write_ofs, p_ring->len);

    return read_len;
}

/*
    获取缓冲区有多少数据
*/
uint16_t get_count(RingBuffer *p_ring)
{
    return p_ring->len;
}

/*
    读取指定位置的数据 ,位置都是处于有数据的位置开始

*/
uint8_t read_u8_from_index(RingBuffer *p_ring, uint16_t index)
{
    uint16_t real_index = 0;
    if (index > p_ring->len - 1)
    {
        printf("index error\n");
    }
    real_index = (p_ring->read_ofs + index) % p_ring->max;
    return p_ring->buffer[real_index];
}
/*
功能:
    从指定位置获取指定长度的数据,并移除其数据
参数:
    p_ring 待操作的缓冲区
    data 存储数据的缓冲区地址
    len 获取数据的长度
返回值:
    返回获取到的数据数量
*/
uint16_t read_data_ofs(RingBuffer *p_ring, uint8_t *data, const uint16_t len, const uint16_t offset)
{

    if ((len + offset) > p_ring->len)
    {
        printf("%s %d get data fail...", __FILE__, __LINE__);
    }
    p_ring->read_ofs +=offset; 
    for (uint32_t i = 0; i < len; i++)
    {
        
        data[i]= p_ring->buffer[p_ring->read_ofs];
        p_ring->read_ofs = (++p_ring->read_ofs)%p_ring->max;
    }
    p_ring->len -= (len+offset);
    printf("read = %d write =  %d  len = %d\n", p_ring->read_ofs, p_ring->write_ofs, p_ring->len);
    return len;
}

uint16_t remove_data(RingBuffer *p_ring,uint16_t remove_len)
{
    if(remove_len >p_ring->len )
    {
        printf("%s %dparam error ",__FILE__,__LINE__);
        return 0;
    }
    p_ring->read_ofs= (p_ring->read_ofs+remove_len)%p_ring->max;
    p_ring->len-=remove_len; 

    printf("remove later : ");
    for (uint16_t i = 0; i < p_ring->max; i++)
    {
        printf("%02x ", p_ring->buffer[i]);
    }
    printf("\n ");
    printf("read = %d write =  %d  len = %d\n", p_ring->read_ofs, p_ring->write_ofs, p_ring->len);
}

crc16校验


#include "crc16.h"
 static  unsigned char  const TabH[] = { //CRC 高位字节值表
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
        0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
        0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
        0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
        0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
        0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
        0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
        0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
    } ;
    static unsigned char const  TabL[] = { //CRC 低位字节值表
        0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
        0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
        0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
        0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
        0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
        0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
        0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
        0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
        0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
        0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
        0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
        0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
        0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
        0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
        0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
        0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
        0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
        0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
        0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
        0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
        0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
        0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
        0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
        0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
        0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
        0x43, 0x83, 0x41, 0x81, 0x80, 0x40
    } ;
/* CRC16 计算函数,ptr-数据指针,len-数据长度,返回值-计算出的 CRC16 数值 */
unsigned short CRC16(unsigned char *ptr, unsigned char len)
{
    unsigned int index;
    unsigned char crch = 0xFF; //高 CRC 字节
    unsigned char crcl = 0xFF; //低 CRC 字节
   printf("crc data:");
   for(uint16_t i=0;i<len;i++)
   {
       printf("%02x ",ptr[i]);
   }
   printf("\n");
    while (len--){ //计算指定长度的 CRC
        index = crch ^ *ptr++;
        crch = crcl ^ TabH[index];
        crcl = TabL[index];
    }
    return ((crch<<8) | crcl);
}

Guess you like

Origin blog.csdn.net/u010261063/article/details/119424169