队列是程序当中最常见的一个组件,特别是在嵌入式软件开发,一个好用的队列既能够保证数据传输的稳定,还能实现代码的适当解耦,本文以单片机为平台,介绍开源microQueue库的原理与使用。
git厂库:https://gitee.com/honrun_he/gd32-w51x_-templates.git
microQueue简介
microQueue是一款环形FIFO,可自由配置每个队列的长度、可设置溢出为锁定模式、覆盖模式。
结构体如下:
typedef enum {
queueModeNormal = 0, /* 覆盖模式 */
queueModeLock, /* 锁定模式 */
}enumQueueMode;
typedef struct{
char *pcName;
uint8_t *pHead;
uint8_t *pTail;
uint8_t *pReadFrom;
uint8_t *pWriteTo;
int32_t length;
enumQueueMode mode;
}QueueType;
结构体成员解释:
pHead:指向列队RAM的第1个字节;
pTail:指向队列的尾部再加1个字节(每当pReadFrom、pWriteTo等于pTail时,把pReadFrom、pWriteTo再指向pHead);
pReadFrom:指向队列当前可以读取的字节(每出队1个字节,值+1);
pWriteTo:指向队列当前可以写入的字节(每入队1个字节,值+1);
length:队列长度;
源码:
/*
* author: Honrun
*/
#include "stdint.h"
#include "stdio.h"
#include "string.h"
#include "DevicesQueue.h"
QueueType g_TypeQueueUart0Read = {0};
static uint8_t st_ucQueueUart0ReadBuff[QUEUE_UART0_READ_LENGTH + 4] = {0};
QueueType g_TypeQueueUart1Read = {0};
static uint8_t st_ucQueueUart1ReadBuff[QUEUE_UART1_READ_LENGTH + 4] = {0};
QueueType g_TypeQueueUart2Read = {0};
static uint8_t st_ucQueueUart2ReadBuff[QUEUE_UART2_READ_LENGTH + 4] = {0};
QueueType g_TypeQueueKeyInput = {0};
static uint8_t st_ucQueueKeyInputBuff[QUEUE_KEY_INPUT_LENGTH + 4] = {0};
enumQueueState enumQueueInit(void)
{
enumQueueState enumState = queueNormal;
int8_t i = 0;
if(enumQueueCreate(&g_TypeQueueUart0Read, "Uart0 Read", st_ucQueueUart0ReadBuff, QUEUE_UART0_READ_LENGTH, queueModeLock) != queueNormal)
enumState = queueError;
if(enumQueueCreate(&g_TypeQueueUart1Read, "Uart1 Read", st_ucQueueUart1ReadBuff, QUEUE_UART1_READ_LENGTH, queueModeLock) != queueNormal)
enumState = queueError;
if(enumQueueCreate(&g_TypeQueueUart2Read, "Uart2 Read", st_ucQueueUart2ReadBuff, QUEUE_UART2_READ_LENGTH, queueModeLock) != queueNormal)
enumState = queueError;
if(enumQueueCreate(&g_TypeQueueKeyInput, "Key Input", st_ucQueueKeyInputBuff, QUEUE_KEY_INPUT_LENGTH, queueModeNormal) != queueNormal)
enumState = queueError;
if(enumState != queueNormal)
printf("enumQueueInit error.\r\n");
return enumState;
}
/*
* Return: 创建是否成功状态值
* Parameters: *pTypeQueue: 队列结构体指针; pucName: 队列名称; iLength: 队列长度
* Description: 初始化队列
*/
enumQueueState enumQueueCreate(QueueType *pTypeQueue, char *pcName, uint8_t *pucBuff, int32_t iLength, enumQueueMode enumMode)
{
if(pTypeQueue == NULL)
return queueNull;
if(iLength < 1)
return queueEmpty;
pTypeQueue->pcName = pcName;
pTypeQueue->pHead = pucBuff;
pTypeQueue->length = iLength + 1;
pTypeQueue->pReadFrom = pTypeQueue->pHead;
pTypeQueue->pWriteTo = pTypeQueue->pHead;
pTypeQueue->pTail = pTypeQueue->pHead + pTypeQueue->length;
pTypeQueue->mode = enumMode;
return queueNormal;
}
/*
* Return: 队列缓存空满状态
* Parameters: *pTypeQueue: 队列结构体指针
* Description: 获取队列缓存空满状态
*/
enumQueueState enumQueueGetState(QueueType *pTypeQueue)
{
uint8_t * pNow = NULL;
if((pTypeQueue == NULL) || (pTypeQueue->pHead == NULL))
return queueNull;
if(pTypeQueue->pReadFrom == pTypeQueue->pWriteTo)
return queueEmpty;
pNow = pTypeQueue->pWriteTo + 1;
pNow = (pNow >= pTypeQueue->pTail) ? pTypeQueue->pHead : pNow;
if(pNow == pTypeQueue->pReadFrom)
return queueFull;
return queueNormal;
}
/*
* Return: void
* Parameters: *pTypeQueue: 队列结构体指针; ucStateFlag: 空满状态
* Description: 设置队列缓存空满状态
*/
enumQueueState enumQueueSetState(QueueType *pTypeQueue, enumQueueState enumState)
{
if((pTypeQueue == NULL) || (pTypeQueue->pHead == NULL))
return queueNull;
switch(enumState)
{
case queueEmpty:
memset(pTypeQueue->pHead, 0, pTypeQueue->length);
pTypeQueue->pReadFrom = pTypeQueue->pWriteTo = pTypeQueue->pHead;
break;
default : break;
}
return queueNormal;
}
/*
* Return: 查找到的数据位置
* Parameters:
* Description: memrchr替代函数
*/
static void *vQueueMemrchr(void *pvHandle, uint8_t ucValue, int32_t iCount)
{
uint8_t *pucCheck = pvHandle;
pucCheck += iCount - 1;
while((iCount--) > 0)
{
if(*pucCheck == ucValue)
return pucCheck;
--pucCheck;
}
return NULL;
}
/*
* Return: 队列缓存中有效数据长度
* Parameters: *pTypeQueue: 队列结构体指针
* Description: 获取队列缓存中有效数据长度
*/
int32_t iQueueGetLengthOfOccupy(QueueType *pTypeQueue)
{
int32_t iLength = 0;
if((pTypeQueue == NULL) || (pTypeQueue->pHead == NULL))
return 0;
if(pTypeQueue->pReadFrom <= pTypeQueue->pWriteTo)
iLength = pTypeQueue->pWriteTo - pTypeQueue->pReadFrom;
else
iLength = pTypeQueue->length - (pTypeQueue->pReadFrom - pTypeQueue->pWriteTo);
return iLength;
}
/*
* Return: 队列缓存中有效数据长度
* Parameters: *pTypeQueue: 队列结构体指针; ucByte: 指定的有效字节
* Description: 获取队列缓存中有效数据长度,需要有指定的有效字节
*/
int32_t iQueueGetLengthOfOccupyNeed(QueueType *pTypeQueue, uint8_t ucByte)
{
int32_t iLength = 0;
uint8_t *pucHead = NULL;
if((pTypeQueue == NULL) || (pTypeQueue->pHead == NULL))
return 0;
/* pHead|-------pReadFrom===============pWriteTo-------------|pTail */
if(pTypeQueue->pReadFrom <= pTypeQueue->pWriteTo)
{
if((pucHead = vQueueMemrchr(pTypeQueue->pReadFrom, ucByte, pTypeQueue->pWriteTo - pTypeQueue->pReadFrom)) != NULL)
iLength = (pucHead - pTypeQueue->pReadFrom) + 1;
}
/* pHead|=======pWriteTo---------------pReadFrom=============|pTail */
else
{
/* pHead|=======|pWriteTo */
if((pucHead = vQueueMemrchr(pTypeQueue->pHead, ucByte, pTypeQueue->pWriteTo - pTypeQueue->pHead)) != NULL)
iLength = (pucHead - pTypeQueue->pHead) + (pTypeQueue->pTail - pTypeQueue->pReadFrom) + 1;
/* pReadFrom|=============|pTail */
else if((pucHead = vQueueMemrchr(pTypeQueue->pReadFrom, ucByte, pTypeQueue->pTail - pTypeQueue->pReadFrom)) != NULL)
iLength = (pucHead - pTypeQueue->pReadFrom) + 1;
}
return iLength;
}
/*
* Return: 队列缓存中到下一个分隔符的有效数据长度
* Parameters: *pTypeQueue: 队列结构体指针
* Description: 获取队列缓存中有效数据长度
*/
int32_t iQueueGetLengthOfSeparetor(QueueType *pTypeQueue, uint8_t ucByte)
{
int32_t iLength = 0;
uint8_t *pucHead = NULL;
if((pTypeQueue == NULL) || (pTypeQueue->pHead == NULL))
return 0;
/* pHead|-------pReadFrom===============pWriteTo-------------|pTail */
if(pTypeQueue->pReadFrom <= pTypeQueue->pWriteTo)
{
if((pucHead = memchr(pTypeQueue->pReadFrom, ucByte, pTypeQueue->pWriteTo - pTypeQueue->pReadFrom)) != NULL)
iLength = (pucHead - pTypeQueue->pReadFrom) + 1;
}
/* pHead|=======pWriteTo---------------pReadFrom=============|pTail */
else
{
/* pReadFrom|=============|pTail */
if((pucHead = memchr(pTypeQueue->pReadFrom, ucByte, pTypeQueue->pTail - pTypeQueue->pReadFrom)) != NULL)
iLength = (pucHead - pTypeQueue->pReadFrom) + 1;
/* pHead|=======|pWriteTo */
else if((pucHead = memchr(pTypeQueue->pHead, ucByte, pTypeQueue->pWriteTo - pTypeQueue->pHead)) != NULL)
iLength = (pucHead - pTypeQueue->pHead) + (pTypeQueue->pTail - pTypeQueue->pReadFrom) + 1;
}
return iLength;
}
/*
* Return: 队列缓存中剩余长度
* Parameters: *pTypeQueue: 队列结构体指针
* Description: 获取队列缓存中剩余长度
*/
int32_t iQueueGetLengthOfRemaining(QueueType *pTypeQueue)
{
int32_t iLength = 0;
if((pTypeQueue == NULL) || (pTypeQueue->pHead == NULL))
return 0;
if(pTypeQueue->pReadFrom <= pTypeQueue->pWriteTo)
iLength = pTypeQueue->length - (pTypeQueue->pWriteTo - pTypeQueue->pReadFrom) - 1;
else
iLength = (pTypeQueue->pReadFrom - pTypeQueue->pWriteTo) - 1;
return iLength;
}
/*
* Return: 是否入队成功状态
* Parameters: *pTypeQueue: 队列结构体指针; ucData: 待入队字节数据
* Description: 入队一个字节数据
*/
enumQueueState enumQueuePushByte(QueueType *pTypeQueue, uint8_t ucData)
{
enumQueueState enumPushState = queueNormal;
if((pTypeQueue == NULL) || (pTypeQueue->pHead == NULL))
return queueNull;
if(enumQueueGetState(pTypeQueue) == queueFull)
{
printf("pTypeQueue %s full!\r\n", pTypeQueue->pcName);
if(pTypeQueue->mode == queueModeLock)
return queueFull;
enumPushState = queueFull;
}
*pTypeQueue->pWriteTo++ = ucData;
pTypeQueue->pWriteTo = ((pTypeQueue->pWriteTo >= pTypeQueue->pTail) ? pTypeQueue->pHead : pTypeQueue->pWriteTo);
/* 在溢出时,需要把read指针指向当前队列新的末尾 */
if(enumPushState == queueFull)
{
pTypeQueue->pReadFrom = pTypeQueue->pWriteTo + 1;
pTypeQueue->pReadFrom = ((pTypeQueue->pReadFrom >= pTypeQueue->pTail) ? pTypeQueue->pHead : pTypeQueue->pReadFrom);
}
return enumPushState;
}
/*
* Return: 是否出队成功状态
* Parameters: *pTypeQueue: 队列结构体指针; *pucData: 待出队字节数据指针
* Description: 出队一个字节数据
*/
enumQueueState enumQueuePopByte(QueueType *pTypeQueue, uint8_t *pucData)
{
if((pTypeQueue == NULL) || (pTypeQueue->pHead == NULL))
return queueNull;
if(pTypeQueue->pReadFrom == pTypeQueue->pWriteTo)
return queueEmpty;
*pucData = *pTypeQueue->pReadFrom++;
pTypeQueue->pReadFrom = ((pTypeQueue->pReadFrom >= pTypeQueue->pTail) ? pTypeQueue->pHead : pTypeQueue->pReadFrom);
return queueNormal;
}
/*
* Return: 是否出队成功状态
* Parameters: *pTypeQueue: 队列结构体指针; *pucData: 待出队字节数据指针
* Description: 出队一个字节数据,并保留队列中的原数据
*/
enumQueueState enumQueueViewByte(QueueType *pTypeQueue, uint8_t *pucData)
{
if((pTypeQueue == NULL) || (pTypeQueue->pHead == NULL))
return queueNull;
if(pTypeQueue->pReadFrom == pTypeQueue->pWriteTo)
return queueEmpty;
*pucData = *pTypeQueue->pReadFrom;
return queueNormal;
}
/*
* Return: 是否入队成功状态
* Parameters: *pTypeQueue: 队列结构体指针; *ppHead: 待入队数据缓存指针; iLength: 缓存长度
* Description: 入队一系列数据
*/
enumQueueState enumQueuePushDatas(QueueType *pTypeQueue, void *pvBuff, int32_t iLength)
{
uint8_t *pucHandle = pvBuff;
enumQueueState enumPushState = queueNormal;
if((pTypeQueue == NULL) || (pTypeQueue->pHead == NULL))
return queueNull;
if(iQueueGetLengthOfRemaining(pTypeQueue) < iLength)
{
printf("pTypeQueue %s full!\r\n", pTypeQueue->pcName);
if(pTypeQueue->mode == queueModeLock)
return queueFull;
enumPushState = queueFull;
}
while((iLength--) > 0)
{
*pTypeQueue->pWriteTo++ = *pucHandle++;
pTypeQueue->pWriteTo = ((pTypeQueue->pWriteTo >= pTypeQueue->pTail) ? pTypeQueue->pHead : pTypeQueue->pWriteTo);
}
/* 在溢出时,需要把read指针指向当前队列新的末尾 */
if(enumPushState == queueFull)
{
pTypeQueue->pReadFrom = pTypeQueue->pWriteTo + 1;
pTypeQueue->pReadFrom = ((pTypeQueue->pReadFrom >= pTypeQueue->pTail) ? pTypeQueue->pHead : pTypeQueue->pReadFrom);
}
return enumPushState;
}
/*
* Return: 是否出队成功状态
* Parameters: *pTypeQueue: 队列结构体指针; *ppHead: 待出队数据缓存指针; iLength: 缓存长度
* Description: 出队一系列数据
*/
enumQueueState enumQueuePopDatas(QueueType *pTypeQueue, void *pvBuff, int32_t iLength)
{
uint8_t *pucHandle = pvBuff;
if((pTypeQueue == NULL) || (pTypeQueue->pHead == NULL))
return queueNull;
if(pvBuff == NULL)
return queueError;
if(iQueueGetLengthOfOccupy(pTypeQueue) < iLength)
return queueError;
while((iLength--) > 0)
{
*pucHandle++ = *pTypeQueue->pReadFrom++;
pTypeQueue->pReadFrom = ((pTypeQueue->pReadFrom >= pTypeQueue->pTail) ? pTypeQueue->pHead : pTypeQueue->pReadFrom);
}
return queueNormal;
}
/*
* Return: 是否出队成功状态
* Parameters: *pTypeQueue: 队列结构体指针; *ppHead: 待出队数据缓存指针; iLength: 缓存长度
* Description: 出队一系列数据,并保留队列中的原数据
*/
enumQueueState enumQueueViewDatas(QueueType *pTypeQueue, void *pvBuff, int32_t iLength)
{
uint8_t *pucHandle = pvBuff, *pucReadFrom = pTypeQueue->pReadFrom;
if((pTypeQueue == NULL) || (pTypeQueue->pHead == NULL))
return queueNull;
if(pvBuff == NULL)
return queueError;
if(iQueueGetLengthOfOccupy(pTypeQueue) < iLength)
return queueError;
while((iLength--) > 0)
{
*pucHandle++ = *pucReadFrom++;
pucReadFrom = ((pucReadFrom >= pTypeQueue->pTail) ? pTypeQueue->pHead : pucReadFrom);
}
return queueNormal;
}
/*
* Return: 是否出队成功状态
* Parameters: *pTypeQueue: 队列结构体指针; *ppHead: 待出队数据缓存指针; iLength: 缓存长度; ucByte: 指定的有效字节
* Description: 出队一系列数据,需要有指定的有效字节
*/
enumQueueState enumQueuePopDatasNeed(QueueType *pTypeQueue, void *pvBuff, int32_t iLength, uint8_t ucByte)
{
uint8_t *pucHandle = pvBuff;
if((pTypeQueue == NULL) || (pTypeQueue->pHead == NULL))
return queueNull;
if(pvBuff == NULL)
return queueError;
if(iQueueGetLengthOfOccupyNeed(pTypeQueue, ucByte) < iLength)
return queueError;
while((iLength--) > 0)
{
*pucHandle++ = *pTypeQueue->pReadFrom++;
pTypeQueue->pReadFrom = ((pTypeQueue->pReadFrom >= pTypeQueue->pTail) ? pTypeQueue->pHead : pTypeQueue->pReadFrom);
}
return queueNormal;
}
/*
* Return: 是否出队成功状态
* Parameters: *pTypeQueue: 队列结构体指针; *ppHead: 待出队数据缓存指针; iLength: 缓存长度; ucByte: 指定的有效字节
* Description: 出队一系列数据,需要有指定的有效字节,并保留队列中的原数据
*/
enumQueueState enumQueueViewDatasNeed(QueueType *pTypeQueue, void *pvBuff, int32_t iLength, uint8_t ucByte)
{
uint8_t *pucHandle = pvBuff, *pucReadFrom = pTypeQueue->pReadFrom;
if((pTypeQueue == NULL) || (pTypeQueue->pHead == NULL))
return queueNull;
if(pvBuff == NULL)
return queueError;
if(iQueueGetLengthOfOccupyNeed(pTypeQueue, ucByte) < iLength)
return queueError;
while((iLength--) > 0)
{
*pucHandle++ = *pucReadFrom++;
pucReadFrom = ((pucReadFrom >= pTypeQueue->pTail) ? pTypeQueue->pHead : pucReadFrom);
}
return queueNormal;
}
头文件:
/*
* Author: Honrun
*/
#ifndef _DevicesQueue_H_
#define _DevicesQueue_H_
#define QUEUE_MAX_LENGTH (2048)
#define QUEUE_UART0_READ_LENGTH (1024)
#define QUEUE_UART1_READ_LENGTH (1024)
#define QUEUE_UART2_READ_LENGTH (1024)
#define QUEUE_KEY_INPUT_LENGTH (256)
#define QUEUE_KEY_TOUCH_LENGTH (64)
/* 使x对n字节对齐 */
#define queueRoundUp(x, n) (((x) + (n) - 1) & (~((n) - 1)))
typedef enum {
queueNormal = 0,
queueError,
queueNull,
queueEmpty,
queueFull,
}enumQueueState;
typedef enum {
queueModeNormal = 0, /* 覆盖模式 */
queueModeLock, /* 锁定模式 */
}enumQueueMode;
typedef struct{
char *pcName;
uint8_t *pHead;
uint8_t *pTail;
uint8_t *pReadFrom;
uint8_t *pWriteTo;
int32_t length;
enumQueueMode mode;
}QueueType;
extern QueueType g_TypeQueueUart0Read;
extern QueueType g_TypeQueueUart1Read;
extern QueueType g_TypeQueueUart2Read;
extern QueueType g_TypeQueueKeyInput;
enumQueueState enumQueueInit(void);
enumQueueState enumQueueCreate(QueueType *pTypeQueue, char *pcName, uint8_t *pucBuff, int32_t iLength, enumQueueMode enumMode);
enumQueueState enumQueueGetState(QueueType *pTypeQueue);
enumQueueState enumQueueSetState(QueueType *pTypeQueue, enumQueueState enumState);
int32_t iQueueGetLengthOfOccupy(QueueType *pTypeQueue);
int32_t iQueueGetLengthOfOccupyNeed(QueueType *pTypeQueue, uint8_t ucByte);
int32_t iQueueGetLengthOfSeparetor(QueueType *pTypeQueue, uint8_t ucByte);
int32_t iQueueGetLengthOfRemaining(QueueType *pTypeQueue);
enumQueueState enumQueuePushByte(QueueType *pTypeQueue, uint8_t ucData);
enumQueueState enumQueuePopByte(QueueType *pTypeQueue, uint8_t *pucData);
enumQueueState enumQueueViewByte(QueueType *pTypeQueue, uint8_t *pucData);
enumQueueState enumQueuePushDatas(QueueType *pTypeQueue, void *pvBuff, int32_t iLength);
enumQueueState enumQueuePopDatas(QueueType *pTypeQueue, void *pvBuff, int32_t iLength);
enumQueueState enumQueueViewDatas(QueueType *pTypeQueue, void *pvBuff, int32_t iLength);
enumQueueState enumQueuePopDatasNeed(QueueType *pTypeQueue, void *pvBuff, int32_t iLength, uint8_t ucByte);
enumQueueState enumQueueViewDatasNeed(QueueType *pTypeQueue, void *pvBuff, int32_t iLength, uint8_t ucByte);
#endif
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)