1、说明
缓冲区 cache 机制对于处理通信上,多包粘包的问题很有帮助,下面是使用数组实现环形队列 cache 机制的源码
2、源码
.h文件
#ifndef CACHE_QUE_H
#define CACHE_QUE_H
#include <stdint.h>
#include <stdbool.h>
#define CACHE_QUE_MAXLEN 65535
typedef struct{
uint8_t *pArray; //指向数组
uint16_t quefront; //队头下标
uint16_t queRear; //队尾下标
uint16_t maxlen; //总长度
}CacheQue_st;
typedef enum{
E_UINT8 = 0,
E_UINT16,
E_UINT32
}E_DATA_VALUE_TYPE;
bool cacheQueInit(CacheQue_st *que, uint8_t *array, uint16_t len);
bool cacheQueRst(CacheQue_st *que);
bool cacheQueClear(CacheQue_st *que);
uint16_t cacheQuePush(CacheQue_st *que, uint8_t *data, uint16_t len);
uint16_t cacheQuePop(CacheQue_st *que, uint8_t *buff, uint16_t len);
void addData(uint8_t *buff, uint32_t value, E_DATA_VALUE_TYPE type);
void addData_string(uint8_t *buff, const uint8_t *data, uint16_t len);
#endif
.c文件
#include "cacheQue.h"
#include <string.h>
#include "task_debug.h"
static const char *TAG_ERROR = "[QUE_ERROR]";
//cache queue 初始化
bool cacheQueInit(CacheQue_st *que, uint8_t *array, uint16_t len)
{
if(que == NULL || array == NULL || len > CACHE_QUE_MAXLEN || len <= 0)
{
debug_level_printf(LOG_LEVEL_INFO, "%s cacheQueInit wrong, que:%08x, array:%08x, len:%d, maxlen:%d\r\n", TAG_ERROR, que, array, len, CACHE_QUE_MAXLEN);
return false;
}
que->pArray = array;
que->quefront = 0;
que->queRear = 0;
que->maxlen = len;
return true;
}
//cache queue 重置
//注意:重置后,若再次使用队列,需调用cacheQueInit 重新初始化
bool cacheQueRst(CacheQue_st *que)
{
if(que == NULL)
{
debug_level_printf(LOG_LEVEL_INFO, "%s cacheQueRst wrong, que:%08x\r\n", TAG_ERROR, que);
return false;
}
memset(que->pArray, 0, que->maxlen);
memset(que, 0, sizeof(CacheQue_st));
return true;
}
//cache queue 清空数据缓冲区
bool cacheQueClear(CacheQue_st *que)
{
if(que == NULL)
{
debug_level_printf(LOG_LEVEL_INFO, "%s cacheQueClear wrong, que:%08x\r\n", TAG_ERROR, que);
return false;
}
memset(que->pArray, 0, que->maxlen);
que->quefront = 0;
que->queRear = 0;
return true;
}
// 判断队列是否已满
static bool isFull(CacheQue_st *que)
{
return (que->queRear + 1) % que->maxlen == que->quefront;
}
// 入队操作
static bool enqueue(CacheQue_st *que, uint8_t value)
{
if(isFull(que))
{
return false;
}
que->pArray[que->queRear] = value;
que->queRear = (que->queRear + 1) % que->maxlen; // 循环后移
return true;
}
//入队
uint16_t cacheQuePush(CacheQue_st *que, uint8_t *data, uint16_t length)
{
uint16_t len = length;
while(len > 0)
{
if(!enqueue(que, *data))
{
debug_level_printf(LOG_LEVEL_INFO, "%s enQueue wrong for full, all:%d, success:%d\r\n", TAG_ERROR, length, length-len);
return length-len;
}
data++;
len--;
}
return length;
}
// 判断队列是否为空
static bool isEmpty(CacheQue_st *que)
{
return que->quefront == que->queRear;
}
// 出队操作
static bool dequeue(CacheQue_st *que, uint8_t *value)
{
if(isEmpty(que))
{
return false;
}
*value = que->pArray[que->quefront];
que->quefront = (que->quefront + 1) % que->maxlen; // 循环后移
return true;
}
uint16_t cacheQuePop(CacheQue_st *que, uint8_t *buff, uint16_t length)
{
uint16_t len = length;
while(len > 0)
{
if(!dequeue(que, buff))
{
return length-len;
}
buff++;
len--;
}
return length;
}
//非队列的普通数据打包,常用在发送打包
void addData(uint8_t *buff, uint32_t value, E_DATA_VALUE_TYPE type)
{
if(buff == NULL)
{
return;
}
switch(type)
{
case E_UINT8:
{
*buff = (uint8_t)(value & 0x000000FF);
}break;
case E_UINT16:
{
buff[0] = (uint8_t)(value & 0x000000FF);
buff[1] = (uint8_t)((value >> 8) & 0x000000FF);
}break;
case E_UINT32:
{
buff[0] = (uint8_t)(value & 0x000000FF);
buff[1] = (uint8_t)((value >> 8) & 0x000000FF);
buff[2] = (uint8_t)((value >> 16) & 0x000000FF);
buff[3] = (uint8_t)((value >> 24) & 0x000000FF);
}break;
default:
break;
}
}
void addData_string(uint8_t *buff, const uint8_t *data, uint16_t len)
{
if(buff == NULL || data == NULL)
{
return;
}
//be careful the buff overflow
memcpy(buff, data, len);
}
3、附带发送时数据打包源码
.c文件
//非队列的普通数据打包,常用在发送打包
void addData(uint8_t *buff, uint32_t value, E_DATA_VALUE_TYPE type)
{
if(buff == NULL)
{
return;
}
switch(type)
{
case E_UINT8:
{
*buff = (uint8_t)(value & 0x000000FF);
}break;
case E_UINT16:
{
buff[0] = (uint8_t)(value & 0x000000FF);
buff[1] = (uint8_t)((value >> 8) & 0x000000FF);
}break;
case E_UINT32:
{
buff[0] = (uint8_t)(value & 0x000000FF);
buff[1] = (uint8_t)((value >> 8) & 0x000000FF);
buff[2] = (uint8_t)((value >> 16) & 0x000000FF);
buff[3] = (uint8_t)((value >> 24) & 0x000000FF);
}break;
default:
break;
}
}
void addData_string(uint8_t *buff, const uint8_t *data, uint16_t len)
{
if(buff == NULL || data == NULL)
{
return;
}
//be careful the buff overflow
memcpy(buff, data, len);
}
.h文件
typedef enum{
E_UINT8 = 0,
E_UINT16,
E_UINT32
}E_DATA_VALUE_TYPE;
void addData(uint8_t *buff, uint32_t value, E_DATA_VALUE_TYPE type);
void addData_string(uint8_t *buff, uint8_t *data, uint16_t len);
用法举例
比如以下某条发送指令,需要打包一个数据帧的时候,按不同数据格式填充
static void currentDemandRes(uint8_t resCode, uint8_t duty)
{
uint16_t index = 0;
uint8_t padding[3] = {0};
addData(&txMsgbuff[index++], (uint32_t)resCode, E_UINT8);
addData_string(&txMsgbuff[index], padding, 3); index += 3;
addData(&txMsgbuff[index++], (uint32_t)duty, E_UINT8);
addData_string(&txMsgbuff[index], padding, 3); index += 3;
addData(&txMsgbuff[index], getTxChecksum(index-8), E_UINT32); index += 4;
}