KFIFO模块

/**********************************************************
*
*  文件名:      kfifo.c
*
*  文件描述:    该文件包含的kfifo的处理函数
*
*  创建人:       GKOSON
*
*   创建日期:     2019年10月8日16:13:06
*
*  版本号:      1.0
*
*  修改记录:    无
*   
*   本文参考博客地址: 
*  https://blog.csdn.net/linyt/article/details/53355355 巧夺天工的kfifo(修订版)
*  https://blog.csdn.net/chen19870707/article/details/39899743 眉目传情之匠心独运的kfifo
*  https://www.cnblogs.com/suozhang/p/6373510.html 参考文章
  *
***********************************************************/


#include "kfifo.h"

#define min(a, b)                (((a) < (b)) ? (a) : (b))


//找出最接近 最大2的指数次幂
uint32_t roundup_pow_of_two(const uint32_t x)
{
    if (x == 0){ return 0; }
    if (x == 1){ return 2; }
    uint32_t ret = 1;
    while (ret < x)
    {
        ret = ret << 1;
    }
    return ret;
}

//数据是否是2的指数次幂
char isPowerOfTwo(uint32_t num) 
{
	return ( num & (num - 1) == 0);
}

/* 
 * 每次调用这个函数都会产生 两个内存块,一个内存块指向struct KFIFO,一个指向 KFIFO.buff
 * 因此 如果这两个内存块不在使用请释放掉!
 */

struct KFIFO *kfifo_alloc(unsigned int size) 
{   
    unsigned char *buffer;
    
    struct KFIFO *ret;
    
    ret=(struct KFIFO *) malloc(sizeof (struct KFIFO));

    /*  
     * round up to the next power of 2, since our 'let the indices  
     * wrap' tachnique works only in this case.  
     */
  
    if (!isPowerOfTwo(size)) 
    {   
            
        //如果你要申请的buffer 不是 2的 次幂圆整,就要把 size 变成 2的次幂圆整 ,方便下面计算
        size = roundup_pow_of_two(size);
    }
        

    buffer = (unsigned char*) malloc(size);
        
    if (!buffer)   //如果返回的值为NULL,这说明分配内存失败
        return 0UL;
  

        
	ret->buffer=buffer;
	ret->size  =size;
	ret->in  = 0;
	ret->out = 0;
        
    if (!ret) //如果ret的值为NULL,这说明分配内存失败
        free(buffer); //释放之前分配的 内存空间
  
    return ret;
        
}


unsigned int __kfifo_put(struct KFIFO *fifo, unsigned char *buffer, unsigned int len)   
{
	unsigned int L;

	//环形缓冲区的剩余容量为fifo->size - fifo->in + fifo->out,让写入的长度取len和剩余容量中较小的,避免写越界;
	len = min( len , fifo->size - fifo->in + fifo->out );

	/*  
	* Ensure that we sample the fifo->out index -before- we  
	* start putting bytes into the kfifo.  
	*/   
	//多处理器 处理内存 的 屏障,STM32不需要这个
	//    smp_mb(); 

	/* first put the data starting from fifo->in to buffer end */
	/* 首先将数据从fifo.in 所在的位置开始写,写之前,首先要看一下fifo->in到 buffer 末尾的大小 是不是 比 len 大*/

	/*
	* 前面讲到fifo->size已经2的次幂圆整,主要是方便这里计算,提升效率
	* 在对10进行求余的时候,我们发现,余数总是整数中的个位上的数字,而不用管其他位是什么;
	* 所以,kfifo->in % kfifo->size 可以转化为 kfifo->in & (kfifo->size – 1),效率会提升
	* 所以fifo->size - (fifo->in & (fifo->size - 1)) 即标识坐标 fifo->in 到 buffer末尾所剩余的长度,
	* L取len和剩余长度的最小值,即为需要拷贝L 字节到fifo->buffer + fifo->in的位置上。
	*/ 
	L = min(len, fifo->size - (fifo->in & (fifo->size - 1)));

	memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, L);   

	/* then put the rest (if any) at the beginning of the buffer */ 

	memcpy(fifo->buffer, buffer + L, len - L);

	/*  
	* Ensure that we add the bytes to the kfifo -before-  
	* we update the fifo->in index.  
	*/   

	// smp_wmb();   //多处理器 处理内存 的 屏障,STM32不需要这个    

	/* 
	* 注意这里 只是用了 fifo->in +=  len而未取模,
	* 这就是kfifo的设计精妙之处,这里用到了unsigned int的溢出性质,
	* 当in 持续增加到溢出时又会被置为0,这样就节省了每次in向前增加都要取模的性能,
	* 锱铢必较,精益求精,让人不得不佩服。
	*/

	fifo->in += len; 

	/*返回值 代表  写入数据的个数 ,这样 就可以根据返回值 判断缓冲区是否写满*/
	return len;   
}  
  
unsigned int __kfifo_get(struct KFIFO *fifo, unsigned char *buffer, unsigned int len)   
{
	unsigned int L;   

	len = min(len, fifo->in - fifo->out);   //in out 一样的话 那就是0!后面的L也是0 两次拷贝也是废话

	/*  
	* Ensure that we sample the fifo->in index -before- we  
	* start removing bytes from the kfifo.  
	*/   

	//smp_rmb();    //多处理器 处理内存 的 屏障,STM32不需要这个

	/* first get the data from fifo->out until the end of the buffer */   
	L = min(len, fifo->size - (fifo->out & (fifo->size - 1)));   
	memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), L);   

	/* then get the rest (if any) from the beginning of the buffer */   
	memcpy(buffer + L, fifo->buffer, len - L);   

	/*  
	* Ensure that we remove the bytes from the kfifo -before-  
	* we update the fifo->out index.  
	*/   

	//smp_mb();   //多处理器 处理内存 的 屏障,STM32不需要这个

	/*
	* 注意这里 只是用了 fifo->out +=  len 也未取模运算,
	* 同样unsigned int的溢出性质,当out 持续增加到溢出时又会被置为0,
	* 如果in先溢出,出现 in  < out 的情况,那么 in – out 为负数(又将溢出),
	* in – out 的值还是为buffer中数据的长度。
	*/

	fifo->out += len;

	return len;  
}
#ifndef _KFIFO_H_
#define _KFIFO_H_
#include "gunit.h"

//声明 一个 结构体 kfifo

struct KFIFO
{   
	unsigned char *buffer;    /* the buffer holding the data */   
	unsigned int size;            /* the size of the allocated buffer */   
	unsigned int in;                /* data is added at offset (in % size) */   
	unsigned int out;                /* data is extracted from off. (out % size) */   
	/*STM32 只有一个核心,同一时刻只能写或者读,因此不需要*/
	//    volatile unsigned int *lock; /* protects concurrent modifications */  
};

char isPowerOfTwo(uint32_t num) ;

unsigned int roundup_pow_of_two( unsigned int date_roundup_pow_of_two );

struct KFIFO *kfifo_alloc(unsigned int size);

unsigned int __kfifo_put(struct KFIFO *fifo, unsigned char *buffer, unsigned int len);

unsigned int __kfifo_get(struct KFIFO *fifo, unsigned char *buffer, unsigned int len);

#endif

 

 

测试:

#include "kfifo.h"

struct KFIFO * kfifo;

void KFIFOInit(void) 
{
    kfifo = kfifo_alloc(128);
}

void KFIFOPut(uint8_t ch) 
{
   __kfifo_put(kfifo,&ch,1);
}

void KFIFOGet(void) 
{
    unsigned int tempLength = 0;
    uint8_t tempData;
    
    tempLength = __kfifo_get(kfifo, (uint8_t *)&tempData,1);
    if (tempLength == 1)
        {
                printf("\r\n#------\r\n");
                G_printHEX(&tempData,tempLength);
                printf("\r\n#------\r\n");
        }
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值