常用环形缓冲区

在处理大量通信或者数据传输的应用中,为了减小丢帧率增强通信的健壮性,充当高速与低速设备之间的桥梁,环形FIFO都非常的合适,这里介绍一种用数组实现环形FIFO的方法。此方法可以记录每一帧收到的数据的桢长,便于取出和分析。

#ifndef __RING_BUFFER_H
#define __RING_BUFFER_H

#include "stdbool.h"
#include "stdint.h"
#include "string.h"

/*是(1)否(0)使用环形缓冲区*/
#define IF_USE_RING_BUFFER    1U

/*数据缓冲区长度*/
#define DATA_BUF_LENGTH              250U

/*环形缓冲区相关结构体*/
typedef struct { volatile uint8_t head;/*缓冲区头部*/ volatile uint8_t tail;/*缓冲区尾部*/ volatile uint8_t dataLen;/*缓冲区内数据长度*/ volatile uint8_t readWriteMutexFlag;/*读写互斥标志*/ uint8_t aFrameLen[25];/*存储接收帧的长度*/ volatile uint8_t frameNum;/*缓冲区内桢数*/ uint8_t ringBuf[DATA_BUF_LENGTH];/*缓冲区*/ }ringBufType_t; /*多缓冲*/ typedef struct { ringBufType_t RingBuf_1; ringBufType_t RingBuf_2; }multRingBufType_t; #ifndef COUNTOF #define COUNTOF(__BUFFER__) (sizeof(__BUFFER__) / sizeof(*(__BUFFER__))) #endif 
#if IF_USE_RING_BUFFER /*外部声明*/ extern multRingBufType_t multRingBufDeal; /*写入数据到环形缓冲区*/ bool WriteDataToRingBuffer(ringBufType_t *pRingBuf, uint8_t *pBuf, uint8_t len); /*从环形缓冲区读出数据*/ uint8_t ReadDataFromRingBuffer(ringBufType_t *pRingBuf, uint8_t *pBuf, uint8_t len); #endif/*IF_USE_RING_BUFFER*/ #endif/*__RING_BUFFER_H*/
#include "./UART/ringBuffer.h"

/*定义一个多缓冲结构体*/
multRingBufType_t multRingBufDeal;

/**
* @brief  写入数据到环形缓冲区
* @param  pBuf: 待写入数据缓冲区
*              len:    待写入数据长度
* @retval 执行状态
*/
bool WriteDataToRingBuffer(ringBufType_t *pRingBuf, uint8_t *pBuf, uint8_t len)
{
    if (pRingBuf == NULL) { return false; }
    if (pBuf == NULL) { return false; }
    /*数据长度不能为 0*/
    if (len <= 0) { return false; }

    /*写入会导致缓冲区溢出*/
    if (len > (COUNTOF(pRingBuf->ringBuf) - pRingBuf->dataLen)) { return false; } /*再写入会导致桢长存储缓冲区溢出*/ if (pRingBuf->frameNum >= COUNTOF(pRingBuf->aFrameLen)) { return false; } /*读写互斥*/ if (pRingBuf->readWriteMutexFlag) { return false; } uint32_t tmp = 0; pRingBuf->readWriteMutexFlag = true;/*打开互斥标志*/ pRingBuf->aFrameLen[pRingBuf->frameNum] = len;/*存储桢长*/ /*如果不满一圈则直接存储*/ if ((COUNTOF(pRingBuf->ringBuf) - pRingBuf->tail) >= pRingBuf->aFrameLen[pRingBuf->frameNum]) { memcpy(&(pRingBuf->ringBuf[pRingBuf->tail]), pBuf, pRingBuf->aFrameLen[pRingBuf->frameNum]); pRingBuf->tail += pRingBuf->aFrameLen[pRingBuf->frameNum]; /*如果满了一圈则回到"头部"*/ if (pRingBuf->tail == COUNTOF(pRingBuf->ringBuf)) { pRingBuf->tail = 0; } } /*满了一圈则分成两部分存储*/ else { memcpy(&(pRingBuf->ringBuf[pRingBuf->tail]), pBuf, COUNTOF(pRingBuf->ringBuf) - pRingBuf->tail); tmp = COUNTOF(pRingBuf->ringBuf) - pRingBuf->tail; pRingBuf->tail = 0; memcpy(&(pRingBuf->ringBuf[pRingBuf->tail]), &pBuf[tmp], pRingBuf->aFrameLen[pRingBuf->frameNum] - tmp); pRingBuf->tail = pRingBuf->aFrameLen[pRingBuf->frameNum] - tmp; } pRingBuf->dataLen += pRingBuf->aFrameLen[pRingBuf->frameNum];/*更新存储数据长度*/ pRingBuf->frameNum++;/*更新帧数*/ pRingBuf->readWriteMutexFlag = false;/*关闭互斥标志*/ return true; } /** * @brief 从环形缓冲区读出数据 * @param pBuf: 存放读出数据缓冲区 * len: 存放读出数据缓冲区长度 * @retval 实际读出数据量 */ uint8_t ReadDataFromRingBuffer(ringBufType_t *pRingBuf, uint8_t *pBuf, uint8_t len) { if (pRingBuf == NULL) { return 0x00; } if (pBuf == NULL) { return 0x00; } /*缓冲区过小*/ if (len < pRingBuf->aFrameLen[0]) { return 0x00; } /*无数据可读*/ if (pRingBuf->dataLen <= 0) { return 0x00; } /*读写互斥*/ if (pRingBuf->readWriteMutexFlag) { return 0x00; } uint32_t ret = 0; uint32_t tmp = 0; pRingBuf->readWriteMutexFlag = true;/*打开互斥标志*/ pRingBuf->dataLen -= pRingBuf->aFrameLen[0];/*更新存储数据长度*/ ret = pRingBuf->aFrameLen[0];/*获取帧长*/ /*如果不满一圈则直接读取*/ if ((COUNTOF(pRingBuf->ringBuf) - pRingBuf->head) >= pRingBuf->aFrameLen[0]) { memcpy(pBuf, &(pRingBuf->ringBuf[pRingBuf->head]), pRingBuf->aFrameLen[0]); pRingBuf->head += pRingBuf->aFrameLen[0]; /*如果满了一圈则回到"尾部"*/ if (pRingBuf->head == COUNTOF(pRingBuf->ringBuf)) { pRingBuf->head = 0; } } /*满了一圈则分成两部分读取*/ else { memcpy(pBuf, &(pRingBuf->ringBuf[pRingBuf->head]), COUNTOF(pRingBuf->ringBuf) - pRingBuf->head); tmp = COUNTOF(pRingBuf->ringBuf) - pRingBuf->head; pRingBuf->head = 0; memcpy(&pBuf[tmp], &(pRingBuf->ringBuf[pRingBuf->head]), pRingBuf->aFrameLen[0] - tmp); pRingBuf->head = pRingBuf->aFrameLen[0] - tmp; } for (uint8_t i = 0; i < (pRingBuf->frameNum - 1); i++) { /*让未读缓冲区桢长始终在最前面*/ pRingBuf->aFrameLen[i] = pRingBuf->aFrameLen[i + 1]; } pRingBuf->aFrameLen[pRingBuf->frameNum - 1] = 0x00;/*帧长缓冲区数据左移后补 0*/ pRingBuf->frameNum--;/*读取后帧数减 1*/ pRingBuf->readWriteMutexFlag = false;/*关闭互斥标志*/ return ret; }

上述代码已用于工程通信中,其中部分采用C语言自带库函数,因为效率更高,仅个人使用,如需进一步封装请自行完善。

猜你喜欢

转载自www.cnblogs.com/wei1598025967/p/9509986.html