嵌入式DTU实际用到的数组队列形式共享内存实现结果

本文介绍了一种用于嵌入式系统的队列管理方案,包括数据队列与长度队列的实现方法。通过自定义队列结构,实现了数据的高效存取及长度信息的维护,适用于有限资源的嵌入式环境。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#define __DTU_INNER_FUNC__
#ifdef __DTU_INNER_FUNC__
#define MAX_UART_SIZE       (32*1024)
// 用户共享内存
kal_mutexid dtu_mutex;
#define MUTEX_BEGIN         kal_take_mutex(dtu_mutex)
#define MUTEX_END           kal_give_mutex(dtu_mutex)


#define MAX_SIZE            (1024*1024-1024*1024/56 -2*MAX_UART_SIZE)                           // 1MB-MAX_L_SIZE

struct arrQueue                             // 声明队列的头和尾节点,数据存储元素
{
    unsigned char       data[MAX_SIZE+1];   // 定义数组队列元素,能容纳MAX_SIZE字节
    unsigned int        front;              // 含有数据的第一个下标
    unsigned int        rear;               // 含有数据的最后一个元素下标,rear所在的元素不存数据
}queue;

void initQueue()
{
    memset(queue.data, '\0', sizeof(queue.data));
    queue.front = 0;
    queue.rear  = 0;
}


void enQueue(unsigned char *pElement, unsigned int *len)//向queue中存入长度为len字节数据,len返回长度实际存入的长度
{
    // 如果rear在front前面一位,则表明缓冲区已经满,无法存入数据
    // 当rear在最后一位,front在最前一位,也是没有空间
    if ((queue.rear+1)%(MAX_SIZE+1) == queue.front)
    {
        *len = 0;
        return;
    }

    // 如果rear在front前面一位以上,则rear与front之间就是空闲区域,长度为front-rear-1
    if (queue.rear+1<queue.front)
    {
        // 存入数据位len与剩余空间较小者
        *len = *len <= (queue.front-queue.rear-1) ? *len : queue.front-queue.rear-1;
        
        memcpy(&queue.data[queue.rear], pElement, *len);
        queue.rear += *len;
    }
    else    // 如果 rear在front后面,或者相等时,并且有空间
    {
        // 剩余空间大小为 MAX_SIZE-(rear-front), 可写入的数据位长度与剩余空间较小者
        *len = *len <= (MAX_SIZE-(queue.rear-queue.front)) ? *len : MAX_SIZE-(queue.rear-queue.front);
        // 如果front为0,则rear就在小于等于MAX_SIZE的位置,只需要队列尾部保存数据
        if (queue.front==0)
        {
            memcpy(&queue.data[queue.rear], pElement, *len);
            queue.rear += *len;
        }
        else // 如果front不为0,则 队列尾保存了数据,队列头部有可能需要保存数据
        {
            // 如果尾部可以保存数据,则直接保存数据
            if ((MAX_SIZE+1-queue.rear) >= *len)
            {
                memcpy(&queue.data[queue.rear], pElement, *len);
                queue.rear = (queue.rear + *len)%(MAX_SIZE+1);
            }
            else // 如果尾部保存不了数据,头部还需要保存数据,尾部保存的数据长度为:MAX_SIZE+1-queue.rear
            {
                memcpy(&queue.data[queue.rear], pElement, MAX_SIZE+1-queue.rear);
                queue.rear = *len-(MAX_SIZE+1-queue.rear);
                memcpy(&queue.data[0], pElement+(*len-queue.rear), queue.rear);
            }
        }
    }
}

void deQueue(unsigned char *pElement, unsigned int *len)//向queue中取出长度为len字节数据,len返回长度实际取出的长度
{
    // 如果为空数据
    if ((*len==0) || (queue.rear==queue.front))
    {
        *len = 0;
        return;
    }

    // 如果 rear在front后面,则直接取出数据
    if (queue.rear > queue.front)
    {
        *len = *len <= (queue.rear-queue.front) ? *len : (queue.rear-queue.front);
        memcpy(pElement, &queue.data[queue.front], *len);
        queue.front += *len;
    }
    else    // 如果rear在front前面
    {
        // 队列中数据长度为 rear+(MAX_SIZE+1-front)
        *len = *len <= queue.rear+(MAX_SIZE+1-queue.front) ? *len : queue.rear+(MAX_SIZE+1-queue.front);
        
        // 如果尾部可以取出*len的数据则直接取,尾部数据大小为MAX_SIZE+1-queue.front
        if (*len <= MAX_SIZE+1-queue.front)
        {
            memcpy(pElement, &queue.data[queue.front], *len);
            queue.front = (queue.front + *len) % (MAX_SIZE+1);
        }
        else    // 如果尾部取完,还需要取数据,则取头部数据
        {
            memcpy(pElement, &queue.data[queue.front], (MAX_SIZE+1-queue.front));
            queue.front = *len-(MAX_SIZE+1-queue.front);
            memcpy(&pElement[*len-queue.front], &queue.data[0], queue.front);
        }
    }
}

unsigned int lenQueue()     // 队列存了多少数据
{
    return (queue.rear+MAX_SIZE+1-queue.front)%(MAX_SIZE+1);
}


/////////////////////////////////长度数组队列///////////////////////////////////
#define MAX_L_SIZE      1024*1024/56    //1024*1024/56+1
struct LQueue
{
    unsigned int data[MAX_L_SIZE];
    unsigned int front;
    unsigned int rear;
}lqueue;

void initLQueue()
{
    memset(lqueue.data, '\0', sizeof(lqueue.data));
    lqueue.front = 0;
    lqueue.rear = 0;
}

void enLQueue(unsigned int *len)    // 插入长度len, len不能为0,插入正确len不改变,插入错误len为0
{
    if ((lqueue.rear+1)%MAX_L_SIZE == lqueue.front)     // 队列已满
    {
        *len = 0;
    }
    else
    {
        lqueue.data[lqueue.rear] = *len;
        lqueue.rear = (lqueue.rear+1)%MAX_L_SIZE;
    }

}

void deLQueue(unsigned int *len)    // 返回一个长度len数值,len为0则队列为空
{
    if (lqueue.rear == lqueue.front)    // 队列为空
    {
        *len = 0;
    }
    else
    {
        *len = lqueue.data[lqueue.front];
        lqueue.data[lqueue.front] = 0;  // 还原数据为0
        lqueue.front = (lqueue.front+1)%MAX_L_SIZE;
    }
}

unsigned int lenLQueue()            // 获取队列存入多少len数值
{
    return (lqueue.rear+MAX_L_SIZE-lqueue.front)%MAX_L_SIZE;
}
/////////////////////////////////长度队列///////////////////////////////////
#endif
#undef __DTU_INNER_FUNC__


// 缓冲区对外两个接口函数
//////////////////////////////////////////////////////////////////////
// 写入数据到缓冲区,若缓冲区存不下需要放入的数据,则删除前面存入的数据
unsigned char dtu_buffer_add_data(const unsigned char *pbuf, unsigned int len)
{
    unsigned int len_t = 0;
    int i = 0;
    if ((pbuf==NULL) || (len==0))
    {
        return 0;
    }
    MUTEX_BEGIN;
    while (MAX_SIZE-lenQueue() < len)   // 如果缓冲区满了,则删除以前的的数据
    {
        deLQueue(&len_t);
        deQueue((unsigned char*)g_dtu_buffer, &len_t);
        trace_print("add_data deQueue【%d-%s】\r\n", len_t, g_dtu_buffer);
    }
    if (MAX_L_SIZE==lenLQueue()+1)      // 如果长度队列满了,则删除一个长度队列
    {
        deLQueue(&len_t);
        deQueue((unsigned char*)g_dtu_buffer, &len_t);
        trace_print("add_data deQueue【%d-%s】\r\n", len_t, g_dtu_buffer);
    }

    for (i=len-DTU_DATA_LEN; i>=0; i-=DTU_DATA_LEN) // i为剩余存储一组数据的剩余长度,如果小于0,表示不足一组数据,等于0表示刚好一组数据
    {
        len_t = DTU_DATA_LEN;
        trace_print("lenQueue=%d,%d,%d\r\n", lenQueue(), len_t, len-i-DTU_DATA_LEN);
        enLQueue(&len_t);
        enQueue((unsigned char*)&pbuf[len-i-DTU_DATA_LEN], &len_t);
    }
    // 存储不足一组数据的数据
    len_t = len%DTU_DATA_LEN;
    if (len_t)
    {
        enLQueue(&len_t);
        enQueue((unsigned char*)&pbuf[len-len_t], &len_t);
        trace_print("lenQueue=%d,%d\r\n", lenQueue(), len_t);
    }
    MUTEX_END;
    return 1;
}

// 从缓冲区获取内容
unsigned char dtu_buffer_get_data(unsigned char* pbuf, unsigned int* len)
{
    unsigned char result = 0;
    if (pbuf==NULL)
        return result;
    MUTEX_BEGIN;

    deLQueue((unsigned int*)len);
    deQueue((unsigned char*)pbuf, (unsigned int*)len);
    if (*len)   // 如果有数据,返回1
    {
        result = 1;
    }

    MUTEX_END;
    return result;
}

/////////////////////////////////////////////////////////////////////////
 
 
// 使用时需要先初始化
    ///////////////////////////// 初始化队列
    initQueue();
    initLQueue();
    ///////////////////////////// 初始化队列完毕

 

// 然后调用两个函数进行存取数据,上面数组队列对外接口只有两个函数和初始化函数而已

// 存入数据
dtu_buffer_add_data((unsigned char*)uart_buffer2, len);     // 添加数据到发送队列

// 取出数据
if (KAL_TRUE==dtu_buffer_get_data((unsigned char*)g_send_data_buffer, (unsigned int*)&len)) // 取数据
{
    g_send_data_buffer[len] = '\0';
    u8_heartbeat_times = 0;
}

 

 数据队列测试原型见http://blog.youkuaiyun.com/zeroboundary/article/details/9295979

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值