对环形缓冲区的升级

例:

FIFO size = 6;

一:待写入数据 <= FIFO size - tail <= free size

       一次拷贝即可完成

二:FIFO size - tail <= 待写入数据 <= free size

       需要两次拷贝才能完成

      第一次拷贝直到尾部

     第二次从"头"拷贝

存取数据有两种方式,一种通过for();循环的方式,一种通过memcpy();进行拷贝,可以自定义每个通道的缓冲区大小,方法可以记录每一帧收到的数据的桢长,便于取出和分析,写入和读出函数均是以一帧数据为单位。

#ifndef __RING_BUFFER_H
#define __RING_BUFFER_H

#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <stdbool.h>

/*是否打开参数校验*/
#define DEBUG_ASSERT	      0U
/*是(1)否(0)使用环形缓冲区*/
#define IF_USE_RING_BUFFER    1U

/*环形缓冲区相关结构体*/
typedef struct {
	volatile uint32_t r_head;/*缓冲区头部*/
	volatile uint32_t r_tail;/*缓冲区尾部*/
	uint8_t           *pUsrBuf;/*指向用户定义缓冲区的指针*/
	uint32_t          usrLen;/*用户定义缓冲区的长度*/

	volatile uint32_t f_head;
	volatile uint32_t f_tail;
	uint32_t          aFrameLen[32];/*存储收到数据帧的长度*/
}ringBufType_t;

#ifndef COUNTOF
#define COUNTOF(__BUFFER__)   (sizeof(__BUFFER__) / sizeof(*(__BUFFER__)))
#endif

#ifndef MIN
#define MIN(a,b) ((a) > (b)?(b):(a))
#endif

#if IF_USE_RING_BUFFER
/*初始化环形缓冲区*/
uint32_t RingBufInit(ringBufType_t *ringBuf, uint8_t *pBuf, const uint32_t len);
/*写入数据到环形缓冲区*/
uint32_t RingWriteDataToBuffer(ringBufType_t *ringBuf, const uint8_t *pBuf, const uint32_t len);
/*从环形缓冲区读出数据*/
uint32_t RingReadDataFromBuffer(ringBufType_t *ringBuf, uint8_t *pBuf, const uint32_t len);
/*判空*/
uint32_t IfRingEmpty(ringBufType_t *ringBuf);
#endif/*IF_USE_RING_BUFFER*/

#endif/*__RING_BUFFER_H*/
#include "./uart/ringBuffer.h"

bool is_power_of_2(unsigned long n)
{
	return (n != 0 && ((n & (n - 1)) == 0));
}

/**
* @brief	初始化环形缓冲区
* @param	ringBuf:对应 FIFO 句柄
*		pBuf:数据存储缓冲区
*		len:数据存储缓冲区长度
* @retval	执行状态
*/
uint32_t RingBufInit(ringBufType_t *ringBuf, uint8_t *pBuf, const uint32_t len)
{
	#if DEBUG_ASSERT
	if (ringBuf == NULL) { return 0; }
	if (pBuf == NULL) { return 0; }
	if (len == 0) { return 0; }
	#endif

	assert(is_power_of_2(len));

	memset(ringBuf,0,sizeof(ringBufType_t));
	ringBuf->pUsrBuf = pBuf;
	ringBuf->usrLen = len;

	return 1;
}

/**
* @brief	写入数据到环形缓冲区
* @param	ringBuf:对应 FIFO 句柄
*		pBuf:待写入数据缓冲区
*		len:待写入数据长度
* @retval	执行状态
*/
uint32_t RingWriteDataToBuffer(ringBufType_t *ringBuf, const uint8_t *pBuf, const uint32_t len)
{
	#if DEBUG_ASSERT
	if (ringBuf == NULL) { return 0; }
	if (pBuf == NULL) { return 0; }
	if (len == 0) { return 0; }
	#endif
	/*如果不能存下此帧,则舍弃*/
	if (len > ringBuf->usrLen - (ringBuf->r_tail - ringBuf->r_head)) { return 0; }
	if (ringBuf->f_tail - ringBuf->f_head >= COUNTOF(ringBuf->aFrameLen)) { return 0; }

	/*存储桢长*/
	ringBuf->aFrameLen[ringBuf->f_tail & (COUNTOF(ringBuf->aFrameLen) - 1)] = len;
	ringBuf->f_tail++;

	uint32_t off = ringBuf->r_tail & (ringBuf->usrLen - 1);
	/*存储数据*/
	uint32_t min = MIN(len, ringBuf->usrLen - off);
	memcpy(&(ringBuf->pUsrBuf[off]), pBuf, min);
	memcpy(&(ringBuf->pUsrBuf[0]), pBuf + min, len - min);
	ringBuf->r_tail += len;

	return 1;
}
/**
* @brief	从环形缓冲区读出数据
* @param	ringBuf:对应 FIFO 句柄
*		pBuf:存放读出数据缓冲区
*		len:存放读出数据缓冲区长度
* @retval	实际读出数据量
*/
uint32_t RingReadDataFromBuffer(ringBufType_t *ringBuf, uint8_t *pBuf, const uint32_t len)
{
	#if DEBUG_ASSERT
	if (ringBuf == NULL) { return 0; }
	if (pBuf == NULL) { return 0; }
	if (len == 0) { return 0; }
	#endif
	/*判空*/
	if (!IfRingEmpty(ringBuf)) { return 0; }

	/*读取桢长*/
	uint32_t ret = ringBuf->aFrameLen[ringBuf->f_head & (COUNTOF(ringBuf->aFrameLen) - 1)];
	/*如果缓冲区大小不能存储当前帧,则不读取*/
	if (len < ret) { return 0; }
	ringBuf->f_head++;

	uint32_t off = ringBuf->r_head & (ringBuf->usrLen - 1);
	/*读取数据*/
	uint32_t min = MIN(ret, ringBuf->usrLen - off);
	memcpy(pBuf, &(ringBuf->pUsrBuf[off]), min);
	memcpy(pBuf + min, &(ringBuf->pUsrBuf[0]), ret - min);
	ringBuf->r_head += ret;

	return ret;
}
/**
* @brief	判空
* @param	ringBuf:对应 FIFO 句柄
* @retval	状态
*/
uint32_t IfRingEmpty(ringBufType_t *ringBuf)
{
	/*无数据可读*/
	if (ringBuf->r_tail == ringBuf->r_head) { return 0; }
	/*无帧可读*/
	if (ringBuf->f_tail == ringBuf->f_head) { return 0; }
	
	return 1;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值