常用环形缓冲区

wei1598025967 2018-08-21 原文

常用环形缓冲区

在处理大量通信或者数据传输的应用中,为了减小丢帧率增强通信的健壮性,充当高速与低速设备之间的桥梁,环形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语言自带库函数,因为效率更高,仅个人使用,如需进一步封装请自行完善。

发表于 2018-08-21 10:37 _白 阅读() 评论() 编辑 收藏

 

版权声明:本文为wei1598025967原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/wei1598025967/p/9509986.html

常用环形缓冲区的更多相关文章

随机推荐

  1. 使用linux mint 安装无线网卡驱动

    linux mint 一次重装无线网卡驱动之旅 新买了个笔记本Thinkpad E440,用了两天发现无线网非 […]...

  2. 一个非侵入的Go事务管理库——如何使用

    在文章“清晰架构(Clean Architecture)的Go微服务: 事物管理”中, […]...

  3. 再见了,我的散装研发管理平台;再见了,4台ECS!

    周末的时候,收到好几个云服务器临近过期的通知短信,准备续个费,居然都要大几千!因为这几个都是以前低价抢购的,掐 […]...

  4. 【小白学PyTorch】21 Keras的API详解(下)池化、Normalization层

    文章来自微信公众号:【机器学习炼丹术】。作者WX:cyx645016617. 参考目录: 目录 1 池化层 1 […]...

  5. oracle数据库视图 – 菜菜小谭

    oracle数据库视图 一.what 视图是一张虚拟表 二.如何创建视图 create view 视图名 as […]...

  6. 经典相位法三维轮廓测量模型

    作者:书涵 Date:2020-04-24 来源:经典相位法三维轮廓测量模型 在结构光三维测量中,之前笔者介绍 […]...

  7. 性能理论——性能测试指标

    TPS  QPS  RT  TOP  RT  吞吐量 一.系统吞吐量要素:   一个系统的吞吐量(承压能力)与 […]...

  8. 通过c#打开pdf文件

    前面我们介绍了如何通过C#打开word文件,但是打开之后如果不允许用户进行编辑,这里我们通常转换成pdf文件, […]...

展开目录

目录导航