RING BUFFER

发布时间:2023年12月30日

在嵌入式系统设计开发中ring buffer具有非常广泛的用途,高效的ringbuffer可以避免频繁的数据对齐操作,在被队列给弄的七窍生烟之后,我绝对手搓一个ringbuffer,用于LWIP udp数据包缓存,ringbuffer满则直接丢弃进入的数据,ringbuffer不为空则允许用户读取特定长度的数据,并采用memcpy方式提升存取效率。

ringbuffer.h:

注意为了区分ringbuffer的满与空状态,我们申请buffer时需要额外定义一个字节。

/****************************************************************************/
/**
* @file RingBuffer.h
*****************************************************************************/

#ifndef _RING_BUFFER_H_      
#define _RING_BUFFER_H_

/***************************** Include Files ********************************/
//#include "common_def.h"
#include <stdint.h>
/************************** Constant Definitions *****************************/

/* do note that we should reserve 1 byte data to avoid mistake of data full and empty 
 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
 * | 7 | 8 |   |   |   |   |   |   | 1 | 2 | 3 | 4 | 5 | 6 |
 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
 * so if we want a 1024 buffer, we should define size as 1024+1		                                    
 */
#define RING_BUFFER_SIZE    (100+1)
#define RING_BUFFER_ELEM_TYPE  uint8_t

#define USE_MEMCPY_PERF   1
/**************************** Type Definitions *******************************/
typedef struct{    
    uint8_t*   writePtr;         //buffer pointer to be added.
    uint8_t*   readPtr;          //buffer pointer to be read and store into flash.
    uint8_t*   endPtr;           //constant var to store buffer end pointer.
    uint8_t    bufferData[RING_BUFFER_SIZE];
} RING_BUFFER_T;

/************************** Functions Definitions******************************/
int ringBuffer_int(RING_BUFFER_T* pbuffer);
/*****************************************************************************/
/**
*
* get Ring buffer used data size,
* 
* 
* @param    pbuffer  RING_BUFFER_T*    Ring buffer struct pointer.
* @return   int    Ring buffer used data size.
*
* @note     None.
*
******************************************************************************/
int ringBuffer_get_used_size(RING_BUFFER_T* pbuffer);
/*****************************************************************************/
/**
*
* get Ring buffer available to use(unused) data size,
* 
* 
* @param    pbuffer  RING_BUFFER_T*    Ring buffer struct pointer.
* @return   int    Ring buffer unused data size.
*
* @note     None.
*
******************************************************************************/
int ringBuffer_get_unused_size(RING_BUFFER_T* pbuffer);
/*****************************************************************************/
/**
*
*  push a data into Ring buffer,
* 
* 
* @param    pbuffer     RING_BUFFER_T*    Ring buffer struct pointer.
* @param    pdata       uint8_t*          data to be added into Ring buffer.
* @param    data_size   int               data to be added into Ring buffer.
* @return   int         data size actuality pushed into Ring buffer from pdata.
*
* @note     None.
*
******************************************************************************/
int ringBuffer_push_data(RING_BUFFER_T* pbuffer, uint8_t* pdata, int data_size);  //push into a data.
/*****************************************************************************/
/**
*
*  pop data from Ring buffer,
* 
* 
* @param    pbuffer     RING_BUFFER_T*    Ring buffer struct pointer.
* @param    pdata       uint8_t*          data buffer to be popped from Ring buffer.
* @param    data_size   int               data to be popped from Ring buffer.
* @return   int         data size actuality popped from Ring buffer to pdata.
*
* @note     None.
*
******************************************************************************/
int ringBuffer_pop_data(RING_BUFFER_T* pbuffer, uint8_t* pdata, int data_size);  //pop out a data

#endif
ringbuffer.c?
/******************************************************************************/
/*****************************************************************************/
/**
*
* @file RingBuffer.c
*
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver   Who  Date     Changes
* ----- ---- -------- --------------------------------------------------------
* 1.00  kahn.qiao  25/06/2023 Fisrt edit.
* 2.00  kahn.qiao  29/12/2023 to support memcpy performance.
* </pre>
*
******************************************************************************/

/***************************** Include Files *********************************/
#include "RingBuffer.h"
#include <stdlib.h>

/************************** Constant Definitions *****************************/


/**************************** Type Definitions *******************************/

/***************** Macros (Inline Functions) Definitions *********************/

/************************** Variable Definitions *****************************/


/************************** Function Prototypes ******************************/
int ringBuffer_int(RING_BUFFER_T* pbuffer)
{
    pbuffer->writePtr = pbuffer->bufferData;
    pbuffer->readPtr =  pbuffer->bufferData;
    pbuffer->endPtr =  pbuffer->bufferData + RING_BUFFER_SIZE;
    return 0;
}
/*****************************************************************************/
/**
*
* get Ring buffer used data size,
* 
* 
* @param    pbuffer  RING_BUFFER_T*    Ring buffer struct pointer.
* @return   int    Ring buffer used data size.
*
* @note     None.
*
******************************************************************************/
int ringBuffer_get_used_size(RING_BUFFER_T* pbuffer)
{
    if(pbuffer->writePtr>=pbuffer->readPtr)
    {
        return pbuffer->writePtr - pbuffer->readPtr;
    }else
    {
        return pbuffer->endPtr - pbuffer->readPtr + pbuffer->writePtr - pbuffer->bufferData;
    }
}
/*****************************************************************************/
/**
*
* get Ring buffer available to use(unused) data size,
* 
* 
* @param    pbuffer  RING_BUFFER_T*    Ring buffer struct pointer.
* @return   int    Ring buffer unused data size.
*
* @note     None.
*
******************************************************************************/
int ringBuffer_get_unused_size(RING_BUFFER_T* pbuffer)
{
    return RING_BUFFER_SIZE - ringBuffer_get_used_size(pbuffer)-1;
}
/*****************************************************************************/
/**
*
*  push a data into Ring buffer,
* 
* 
* @param    pbuffer     RING_BUFFER_T*    Ring buffer struct pointer.
* @param    pdata       uint8_t*          data to be added into Ring buffer.
* @param    data_size   int               data to be added into Ring buffer.
* @return   int         data size actuality pushed into Ring buffer from pdata.
*
* @note     None.
*
******************************************************************************/
int ringBuffer_push_data(RING_BUFFER_T* pbuffer, uint8_t* pdata, int data_size)  //push into a data.
{
    int i,avail_len,index,write_len;
    avail_len = ringBuffer_get_unused_size(pbuffer);
    if(avail_len < data_size)  // to be write data size > buffer availiale size.
    {
        return 0;
    }else
    {
#if USE_MEMCPY_PERF		
		if(data_size <= (pbuffer->endPtr - pbuffer->writePtr))
		{
			/* write data to ring buffer 
			 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
			 * |   |   |   | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |   |   |   |
			 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
			 *			                                    
			 */
			memcpy(pbuffer->writePtr,
			   pdata,
			   data_size);
		}else
		{
			/* write data to ring buffer
			 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
			 * | 7 | 8 |   |   |   |   |   |   | 1 | 2 | 3 | 4 | 5 | 6 |
			 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
			 *			                                    
			 */
			write_len = pbuffer->endPtr - pbuffer->writePtr;
			memcpy(pbuffer->writePtr,  //from the write position.
			   pdata,
			   write_len);
			memcpy(pbuffer->bufferData, //from the start of buffer.
			   pdata+write_len,
			   data_size - write_len);   
		}		
#else		
        index = pbuffer->writePtr - pbuffer->bufferData;
        for(i=0;i<data_size;i++)
        {
            pbuffer->bufferData[index] = (uint8_t)(pdata[i]);
            index = (index +1) %RING_BUFFER_SIZE;
        }
#endif
        pbuffer->writePtr += data_size;
        if(pbuffer->writePtr>=pbuffer->endPtr) //out of buffer
        {
            pbuffer->writePtr -= RING_BUFFER_SIZE;
        }
		
        return data_size;
    }
}
/*****************************************************************************/
/**
*
*  pop data from Ring buffer,
* 
* 
* @param    pbuffer     RING_BUFFER_T*    Ring buffer struct pointer.
* @param    pdata       uint8_t*          data buffer to be popped from Ring buffer.
* @param    data_size   int               data to be popped from Ring buffer.
* @return   int         data size actuality popped from Ring buffer to pdata.
*
* @note     None.
*
******************************************************************************/
int ringBuffer_pop_data(RING_BUFFER_T* pbuffer, uint8_t* pdata, int data_size)  //pop out a data
{
    int i,avail_len,index,read_len;
    avail_len = ringBuffer_get_used_size(pbuffer);
	
	avail_len = (avail_len<data_size)?avail_len:data_size;
	if(avail_len>0)
    {
        
#if USE_MEMCPY_PERF			
		if(avail_len <= (pbuffer->endPtr - pbuffer->readPtr))
		{
			/* read data from ring buffer 
			 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
			 * |   |   |   | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |   |   |   |
			 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
			 *			                                    
			 */
			memcpy(pdata,
			   pbuffer->readPtr,
			   avail_len);
		}else
		{
			/* read data from ring buffer 
			 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
			 * | 7 | 8 |   |   |   |   |   |   | 1 | 2 | 3 | 4 | 5 | 6 |
			 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
			 *			                                    
			 */
			read_len = pbuffer->endPtr - pbuffer->readPtr;
			memcpy(pdata,  //from the read position.
			   pbuffer->readPtr,
			   read_len);
			memcpy(pdata+read_len, //from the start of buffer.
			   pbuffer->bufferData,
			   avail_len - read_len);   
		}
#else
		index = pbuffer->readPtr - pbuffer->bufferData;
        for(i=0;i<avail_len;i++)
        {
            pdata[i] = pbuffer->bufferData[index];
            index = (index +1) %RING_BUFFER_SIZE;
        }	
#endif	
        pbuffer->readPtr += avail_len;
        if(pbuffer->readPtr>=pbuffer->endPtr) //out of buffer
        {
            pbuffer->readPtr -= RING_BUFFER_SIZE;
        }
        return avail_len;
    }
}

gitee 路径:

?ringbuffer: C 实现的ringbuffericon-default.png?t=N7T8https://gitee.com/kahnqiao/ringbuffer.git

文章来源:https://blog.csdn.net/wofeboy/article/details/135305868
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。