数据结构2之环形队列

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;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值