例:
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;
}