「星标公众号」,一起进步!
来源:https://github.com/54zorb/Zorb-Framework
Zorb Framework是一个基于面向对象的思想来搭建一个轻量级的嵌入式框架。
本次分享的是Zorb Framework的环形缓冲区功能zf_buffer。
环形缓冲区主要应用在字节数据流传输上,如串口、网口的收发都可以通过环形缓冲区进行缓存。
例如我要通过串口发送命令“LED ON”来控制开发板的led灯亮起来,但开发板串口接收不是一次把“LED ON”同时接收,而是一个字节一个字节地接收,因此需要使用缓冲区来缓存数据,然后解析器来解析缓冲区的数据。
我们先来看看要实现的缓冲区长什么样子,提供什么功能,这样方便我们设计。
初步要提供的功能如下:
1、要有可以缓存数据的空间
2、可以知道总空间的大小
3、可以知道已用空间的数量
4、可以压入数据
5、可以弹出数据
6、我也可以在不弹出数据的情况下,读到特定长度的数据
因此,初步设计的数据结构如下:
/* 环形缓冲区数据结构 */
typedef struct _RingBuffer
{
bool IsExternBuffer; /* 是否外部缓冲区,是则销毁时不释放 */
uint8_t *pBuf; /* 缓冲区指针 */
uint32_t Head; /* 缓冲区头地址 */
uint32_t Trail; /* 缓冲区尾地址 */
uint32_t Size; /* 缓冲区大小 */
uint32_t Count; /* 数据字节数 */
/* 缓冲器是否已满 */
bool (*IsFull)(struct _RingBuffer * const pRb);
/* 缓冲器是否空 */
bool (*IsEmpty)(struct _RingBuffer * const pRb);
/* 压入一个字节 */
bool (*SaveByte)(struct _RingBuffer * const pRb, uint8_t byte);
/* 取出一个字节 */
bool (*GetByte)(struct _RingBuffer * const pRb, uint8_t *pByte);
/* 读取缓冲器已使用字节个数 */
uint32_t (*GetCount)(struct _RingBuffer * const pRb);
/* 读取n个字节(n超过最大数据数时全部读出) */
bool (*ReadBytes)(struct _RingBuffer * const pRb, uint8_t *pArray,
uint32_t n);
/* 丢弃n个字节(n超过最大数据数时全部丢弃) */
bool (*DropBytes)(struct _RingBuffer * const pRb, uint32_t n);
/* 清空缓冲器 */
bool (*Clear)(struct _RingBuffer * const pRb);
/* 释放缓冲器(不释放外部创建的缓冲区) */
bool (*Dispose)(struct _RingBuffer * const pRb);
} RingBuffer;
其实按实际需要,可能远不止上面提到的6种情况,例如我可以丢弃特定数量的字节数据,也可以直接清空掉缓冲区数据,甚至可以设想提供动态缓冲区的功能,也就是说可以释放缓冲器自己。
/******************************************************************************
* 描述 :创建环形缓冲器(内部分配空间,size=0表示使用外部数据)
* 参数 :(out)-ppRb 环形缓冲器结构体指针的指针
* (in)-size 缓冲器大小
* (out)-ppBuf 缓冲器空间指针的指针
* 返回 :无
******************************************************************************/
bool RB_create(RingBuffer **ppRb, uint32_t size)
{
RingBuffer *pRb;
uint8_t *pBuf;
ZF_ASSERT(ppRb != (RingBuffer **)0)
pRb = (RingBuffer *)ZF_MALLOC(sizeof(RingBuffer));
if (pRb == NULL)
{
ZF_DEBUG(LOG_E, "malloc ringbuffer space error\r\n");
return false;
}
pRb->Head = (uint32_t)0;
pRb->Trail = (uint32_t)0;
pRb->Count = 0;
if (size > 0)
{
pBuf = (void *)ZF_MALLOC(size);
if (pBuf == NULL)
{
ZF_DEBUG(LOG_E, "malloc ringbuffer buffer space error\r\n");
return false;
}
pRb->pBuf = pBuf;
pRb->Size = size;
pRb->IsExternBuffer = false;
}
else
{
pRb->pBuf = NULL;
pRb->Size = 0;
pRb->IsExternBuffer = true;
}
/* 初始化方法 */
pRb->IsFull = RB_isFull;
pRb->IsEmpty = RB_isEmpty;
pRb->SaveByte = RB_saveByte;
pRb->SaveRange = RB_saveRange;
pRb->GetByte = RB_getByte;
pRb->GetCount = RB_getCount;
pRb->ReadBytes = RB_readBytes;
pRb->DropBytes = RB_dropBytes;
pRb->Clear = RB_clear;
pRb->Dispose = RB_dispose;
/* 输出 */
*ppRb = pRb;
return true;
}
/******************************************************************************
* 描述 :释放缓冲器(不释放外部创建的缓冲区)
* 参数 :(in)-pRb 环形缓冲器结构体指针
* 返回 :-true 成功
* -false 失败
******************************************************************************/
bool RB_dispose(RingBuffer * const pRb)
{
ZF_ASSERT(pRb != (RingBuffer *)0)
/* 外部创建的缓冲区不释放 */
if (!pRb->IsExternBuffer)
{
ZF_FREE(pRb->pBuf);
}
ZF_FREE(pRb);
return true;
}
/******************************************************************************
* 描述 :压入一个字节
* 参数 :(in)-pRb 环形缓冲器结构体指针
* (in)-byte 要压入的字节
* 返回 :-true 成功
* -false 失败
******************************************************************************/
bool RB_saveByte(RingBuffer * const pRb, uint8_t byte)
{
bool res = false;
ZF_ASSERT(pRb != (RingBuffer *)0)
ZF_ASSERT(pRb->pBuf != (uint8_t *)0)
if (!RB_isFull(pRb))
{
pRb->pBuf[pRb->Trail++] = byte;
pRb->Trail %= pRb->Size;
pRb->Count++;
res = true;
}
return res;
}
/******************************************************************************
* 描述 :取出一个字节
* 参数 :(in)-pRb 环形缓冲器结构体指针
* (out)-pByte 存放取出字节的地址
* 返回 :-true 成功
* -false 失败
******************************************************************************/
bool RB_getByte(RingBuffer * const pRb, uint8_t *pByte)
{
bool res = false;
ZF_ASSERT(pRb != (RingBuffer *)0)
ZF_ASSERT(pRb->pBuf != (uint8_t *)0)
ZF_ASSERT(pByte != (uint8_t *)0)
if (!RB_isEmpty(pRb))
{
*pByte = pRb->pBuf[pRb->Head++];
pRb->Head %= pRb->Size;
pRb->Count--;
res = true;
}
return res;
}
/**
*****************************************************************************
* @file app_buffer.c
* @author Zorb
* @version V1.0.0
* @date 2018-06-28
* @brief 环形缓冲区测试的实现
*****************************************************************************
* @history
*
* 1. Date:2018-06-28
* Author:Zorb
* Modification:建立文件
*
*****************************************************************************
*/
#include "app_buffer.h"
#include "zf_includes.h"
/* 环形缓冲区指针 */
RingBuffer *rb;
/******************************************************************************
* 描述 :任务初始化
* 参数 :无
* 返回 :无
******************************************************************************/
void App_Buffer_init(void)
{
/* 创建500字节的缓冲区 */
RB_create(&rb, 500);
}
/******************************************************************************
* 描述 :任务程序
* 参数 :无
* 返回 :无
******************************************************************************/
void App_Buffer_process(void)
{
uint32_t i;
uint8_t buf[11];
uint8_t byte;
ZF_DEBUG(LOG_D, "rb count before adding data is %d\r\n", rb->Count);
/* 填充10个字节数据(0-9) */
for (i = 0; i < 10; i++)
{
rb->SaveByte(rb, i);
}
ZF_DEBUG(LOG_D, "rb count after adding data is %d\r\n", rb->Count);
/* 读出数据看是否正确 */
rb->ReadBytes(rb, buf, 10);
ZF_DEBUG(LOG_D, "rb data is ");
for (i = 0; i < 10; i++)
{
ZF_DEBUG(LOG_D, "%d ", buf[i]);
}
ZF_DEBUG(LOG_D, "\r\n\r\n");
/* 弹出数据 */
for (i = 0; i < 10; i++)
{
rb->GetByte(rb, &byte);
ZF_DEBUG(LOG_D, "byte %d is %d\r\n", i, byte);
ZF_DEBUG(LOG_D, "rb count is %d\r\n", rb->Count);
}
while(1);
}
/******************************** END OF FILE ********************************/
结果:
本文来源网络,免费传达知识,版权归原作者所有。如涉及作品版权问题,请联系我进行删除。
《嵌入式Linux驱动大全》
如何高效阅读嵌入式项目代码?