文档章节

数据循环缓冲区算法

猎人嘻嘻哈哈的
 猎人嘻嘻哈哈的
发布于 2017/05/05 00:21
字数 1255
阅读 62
收藏 0

使用方法:

  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);

    }
}





© 著作权归作者所有

猎人嘻嘻哈哈的
粉丝 4
博文 8
码字总数 4150
作品 0
荆州
程序员
私信 提问
【译】Swift算法俱乐部-环形缓冲区

本文是对 Swift Algorithm Club 翻译的一篇文章。 Swift Algorithm Club是 raywenderlich.com网站出品的用Swift实现算法和数据结构的开源项目,目前在GitHub上有18000+⭐️,我初略统计了一下...

Andy_Ron
07/13
0
0
Ring Buffer 实现原理

简介 消息驱动机制是 GUI 系统的基础,消息驱动的底层基础设施之一是消息队列,它是整个 GUI 系统运转中枢,本文介绍了一个基于环形队列的消息队列实现方法,给出了它的数据结构、主要操作流...

AlphaJay
2011/12/06
12.5K
2
数据压缩算法---LZ77算法 的分析与实现

原文出处:IDreamo LZ77简介 Ziv和Lempel于1977年发表题为“顺序数据压缩的一个通用算法(A Universal Algorithm for Sequential Data Compression )”的论文,论文中描述的算法被后人称为L...

IDreamo
2018/07/17
0
0
为什么 GNU grep 如此之快?

编注:这是GNU grep的原作者Mike Haertel 在FreeBSD邮件列表中对 “GNU grep为什么比BSD grep要快” 所做的回答,下面是邮件正文内容: Gabor 您好, 我是GNU grep的原作者,同时也是一名Fre...

oschina
2013/12/05
5.6K
31
通信(Netty、Mina2)【通信粘包的处理】、【数据协议】、【网络系统的安全性】

Netty、Mina2是非常优秀的javaNIO+ThreadPool线程池通信框架http://www.cnblogs.com/51cto/archive/2010/09/06/1819361.html提到通信就得面临两个问题,一是通信协议的选择,二是数据协议的定...

干死it
2014/06/24
227
0

没有更多内容

加载失败,请刷新页面

加载更多

OpenStack 简介和几种安装方式总结

OpenStack :是一个由NASA和Rackspace合作研发并发起的,以Apache许可证授权的自由软件和开放源代码项目。项目目标是提供实施简单、可大规模扩展、丰富、标准统一的云计算管理平台。OpenSta...

小海bug
昨天
5
0
DDD(五)

1、引言 之前学习了解了DDD中实体这一概念,那么接下来需要了解的就是值对象、唯一标识。值对象,值就是数字1、2、3,字符串“1”,“2”,“3”,值时对象的特征,对象是一个事物的具体描述...

MrYuZixian
昨天
6
0
数据库中间件MyCat

什么是MyCat? 查看官网的介绍是这样说的 一个彻底开源的,面向企业应用开发的大数据库集群 支持事务、ACID、可以替代MySQL的加强版数据库 一个可以视为MySQL集群的企业级数据库,用来替代昂贵...

沉浮_
昨天
6
0
解决Mac下VSCode打开zsh乱码

1.乱码问题 iTerm2终端使用Zsh,并且配置Zsh主题,该主题主题需要安装字体来支持箭头效果,在iTerm2中设置这个字体,但是VSCode里这个箭头还是显示乱码。 iTerm2展示如下: VSCode展示如下: 2...

HelloDeveloper
昨天
7
0
常用物流快递单号查询接口种类及对接方法

目前快递查询接口有两种方式可以对接,一是和顺丰、圆通、中通、天天、韵达、德邦这些快递公司一一对接接口,二是和快递鸟这样第三方集成接口一次性对接多家常用快递。第一种耗费时间长,但是...

程序的小猿
昨天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部