数据循环缓冲区算法

使用方法:

  1. 创建循环缓冲区create_cb
  2. 在获得数据的地方调用write_cb把数据写入缓冲区中
  3. 获得数据帧get_frame,获取符合数据协议帧头和帧尾的数据
/*
 * cycle_buf_frame.h
 *
 *  Created on: 2017年7月31日
 *      Author: C
 */

#ifndef MAIN_CYCLE_BUF_FRAME_H_
#define MAIN_CYCLE_BUF_FRAME_H_

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>

#define u8 unsigned char
#define u16 unsigned short
#define u32 unsigned int

#define CB_OK 0
#define CB_FULL 1
#define CB_MALLOC_FAIL 2
#define CB_DATA_ERR 3
#define CB_NO_VALID 4
#define CB_READ_NOENOUGH 5
#define CB_INVALID 6
#define CB_NO_FRAME 7
#define CB_LACK_SPACE 8
#define CB_READ_POS_ERR 9
#define CB_READ_ERR 10

#define MAX_CB_LEN 65534

/*定义数据头尾长度1个字节*/
#define PTL_HT_LENGTH 1
/*固定数据头,高字节在前*/
#define PTL_HEAD 'a'
/*固定数据尾,高字节在前*/
#define PTL_TAIL 'z'

typedef enum {
    /*请求类型*/
    REQUEST=0,
    /*响应类型*/
    RESPONESE=1,
    /*无响应请求类型*/
    NONE_RESPONESE=2,
}data_types;

typedef enum {
    /*控灯命令*/
    CMD_LED=0X0000,
}data_cmd;


typedef struct {
    /*数据头,指向第一个数据所在的位置*/
    u16 head;
    /*数据类型:请求,响应,P2P。。。。*/
    data_types types;
    /*命令字*/
    data_cmd cmd;
    /*数据内容长度*/
    u16 data_len;
    /*数据内容*/
    void *data;
    /*CRC效验*/
    u16 crc;
    /*数据尾,指向下一个即将写入数据的位置*/
    u16 tail;
}data_packge;

typedef struct {
    /*数据头*/
    u16 head;
    /*数据尾*/
    u16 tail;
    /*数据长度*/
    u16 len;
    /*数据体长度即缓冲区长度*/
    u16 blen;
    /*数据体*/
    u8* data;
}cycle_buffer;

u8 creat_cb(cycle_buffer* cb,u16 len);
u8 get_frame(cycle_buffer* cb,u8* data,u16* len);
u8 read_cb(cycle_buffer* cb,u16 pos,u8* data,u16 len);
u8 write_cb(cycle_buffer* cb,u8* wlen,u8* data,u16 len);
void cb_test(void);



#endif /* MAIN_CYCLE_BUF_FRAME_H_ */


/*
 * cycle_buf_frame.c
 *
 *  Created on: 2017年7月31日
 *      Author: C
 */
#include "cycle_buf_frame.h"




u8 creat_cb(cycle_buffer* cb,u16 len){
    cb->data=malloc(len);
    if(cb->data==NULL)
        return CB_MALLOC_FAIL;
    cb->head=0;
    cb->head=0;
    cb->tail=0;
    cb->len=0;
    cb->blen=len;
  return CB_OK;
}
/****************************************************************************
//--函数名称:write_cb
//--函数功能:写数据到缓冲区
//--函数参数:cb   目标缓冲区
                            :wlen 已写入数数据长度
                            :data 将要写入的数据
                            :len  将要写入的数据长度
//--返回数据:返回写状态
****************************************************************************/
u8 write_cb(cycle_buffer* cb,u8* wlen,u8* data,u16 len){
    u16 i;

    /*写缓冲区*/
    for(i=0;i<len;i++)
    {
        /*判断缓冲区的数据是否超出缓冲区长度*/
        if(cb->len<=cb->blen)
        {
            cb->data[cb->tail]=data[i];
            cb->len++;
            cb->tail++;
            /*判断是否已写到数据数组尾*/
            if(cb->tail>=cb->blen)
            {
                cb->tail=0;
            }
        }
        else
        {
            *wlen=i;
            return CB_FULL;
        }
    }
    *wlen=len;
    return CB_OK;
}
/****************************************************************************
//--函数名称:read_cb
//--函数功能:从缓冲区中读取数据
//--函数参数:cb   目标缓冲区
                            :pos  开始读取的位置,相对于缓冲区基地址的位置
                            :data 读取数据保存位置
                            :len  读取数据长度
//--返回数据:返回读状态
****************************************************************************/
u8 read_cb(cycle_buffer* cb,u16 pos,u8* data,u16 len){
    u16 i,temp=pos;
    /*判断缓冲区是否未分配空间*/
    if(cb->data==NULL)
        return CB_INVALID;
    /*判断pos位置是否处于head到尾之间*/
    if(cb->tail>=cb->head)
    {
        if(pos<cb->head||pos>=cb->tail)
            return CB_READ_POS_ERR;
    }
    else
    {
        if(pos>=cb->tail&&pos<cb->head)
            return CB_READ_POS_ERR;
    }
    /*判断读长度是否大于pos位置到数据尾的数据长度*/
    if(cb->tail>=pos)
    {
        if(len>(cb->tail-pos))
            return CB_READ_NOENOUGH;
    }
    if(cb->tail<pos)
    {
        if(len>(cb->blen-pos+cb->tail))
        return CB_READ_NOENOUGH;
    }

    for(i=0;i<len;i++)
    {
        data[i]=cb->data[temp];
        if(temp>cb->blen-1)
            temp=0;
        else
            temp++;
    }
    /*将指针赋值给data*/
    //data=&cb->data[pos];
    return CB_OK;
}
/****************************************************************************
//--函数名称:get_frame
//--函数功能:根据数据协议中的帧头和帧尾获取有效帧,并删除帧前的无效数据
//--函数参数:cb   目标缓冲区
                            len  读取到帧的长度
//--返回数据:返回读状态
****************************************************************************/
u8 get_frame(cycle_buffer* cb,u8* data,u16* len)
{
    u16 i,head_pos,tail_pos,temp_pos=cb->head;
    u8 temp_data[PTL_HT_LENGTH];
    u8 find_head=0;
    u32 temp_num=0;
    signed char m;

    for(i=0;i<cb->len-PTL_HT_LENGTH+1;i++)
    {
        /*读两个字节*/
        if(CB_OK!=read_cb(cb,temp_pos,temp_data,PTL_HT_LENGTH))
            return CB_READ_ERR;
        /*把宏定义的数据头转换成字符数组*/
        temp_num=0;
        for(m=PTL_HT_LENGTH-1;m>=0;m--)
        {
            temp_num=temp_num+(temp_data[PTL_HT_LENGTH-1-m]<<(8*m));
        }

        /*判断是否为数据头*/
        if(PTL_HEAD==temp_num)
        {
            /*记录数据头的位置/更新数据头位置*/
            head_pos=temp_pos;
            find_head++;
        }
        /*已找到数据头,再找数据尾*/
        if(find_head>0)
        {
            /*判断是否为数据尾*/
            if(PTL_TAIL==temp_num)
            {
                /*找到了数据头,也找到了数据尾*/
                /*记录数据尾的位置*/
                tail_pos=temp_pos;
                /*计算帧数据长度*/
                if(head_pos<tail_pos)
                {
                     *len=tail_pos-head_pos+PTL_HT_LENGTH;
                     /*copy数据*/
                     memcpy(data,&cb->data[head_pos],*len);
                }
                else
                {
                    *len=cb->blen-head_pos+tail_pos+PTL_HT_LENGTH;
                    /*copy数据*/
                    memcpy(data,&cb->data[head_pos],cb->blen-head_pos);
                    memcpy((data+cb->blen-head_pos),&cb->data[0],tail_pos+PTL_HT_LENGTH);
                }


                /*计算剩余数据长度*/
                if(cb->head<=head_pos)
                {
                    /*剩余数据=初始数据-头前无用数据-读走数据*/
                    cb->len=cb->len-(head_pos-cb->head)-*len;
                }
                else
                {
                    /*剩余数据=初始数据-头前无用数据-读走数据*/
                    cb->len=cb->len-(cb->blen-cb->head+head_pos)-*len;
                }
                /*数据取出后,重置数据头位置*/
                if(tail_pos+PTL_HT_LENGTH>=cb->blen)
                    cb->head=cb->blen-(tail_pos+PTL_HT_LENGTH);
                else
                    cb->head=tail_pos+PTL_HT_LENGTH;
                return CB_OK;
            }
        }
        /*数据读取位置后移*/
        if(temp_pos==cb->blen-1)
            temp_pos=0;
        else
            temp_pos++;
    }
    /*读完整个缓冲区未获得完整帧*/
    if(find_head>0)
    {
        /*重置缓冲区头*/
        cb->head=head_pos;
        /*计算剩余数据长度*/
        cb->len=cb->len-(head_pos-cb->head);
    }
    else
    {
        /*重置整个缓冲区*/
        cb->head=cb->tail=cb->len=0;
    }
    *len=0;
    return CB_NO_FRAME;
}

void cb_test()
{
    u8 wlen,data1[50],data[50]="rzrabceddzccab";
    u16 len;
    cycle_buffer cb;
    creat_cb(&cb,50);
    write_cb(&cb,&wlen,data,14);
    while(1)
    {

        while(get_frame(&cb,data1,&len)==CB_OK)
        {

            printf("frame data len %d is:%.*s\n\n",len,len, data1);
            Sleep(100);

        }
        write_cb(&cb,&wlen,data,14);

    }
}





猜你喜欢

转载自my.oschina.net/u/2345008/blog/892817