专注Java教育14年 全国咨询/投诉热线:444-1124-454
星辉LOGO图
始于2009,口口相传的Java黄埔军校
首页 hot资讯 数据队列的使用方法

数据队列的使用方法

更新时间:2021-11-01 11:15:42 来源:星辉 浏览975次

使用数据队列

数据队列用于将数据包从 RF 内核传输到主 CPU,反之亦然。它们被实现为队列条目的链表。本文档描述了可用的队列条目类型,并提供了用于创建队列并与之交互的代码片段。

队列条目类型

RF 内核支持 4 种不同类型的队列条目:

姓名

数据类型

描述

单包入口

rfc_dataEntryGeneral_t

每个条目一包;标头后的数据。

多包入口

rfc_dataEntryMulti_t

同一条目中有多个数据包,数据在头部之后。

指针入口

rfc_dataEntryPointer_t

每包一个条目;另一个内存位置的数据。

部分入场

rfc_dataEntryPartial_t

存储未知或无限长度的数据包;标头后的数据。

只有部分条目可用于传输数据。所有其他类型都专门与 RX 命令一起使用。

所有队列条目都以一个公共头部分开始,包含一个指向下一个条目的指针、一个配置字段和条目的长度(以字节为单位)。

每个队列条目与 4 字节边界对齐非常重要。否则 RF 核心将无法访问队列条目。

单包条目 rfc_dataEntryGeneral_t

单个数据包条目每个条目包含一个数据包,并将数据直接存储在标头后面,以便可以将整个队列分配在线性存储部分中。它们是最简单的条目类型,足以满足许多应用程序的需求。数据部分可能包含由 配置的数据包长度、 config.lenSz有效载荷和可选的附加元数据,如 RX 时间戳或 CRC。

当可以另外确定分组大小时,可以省略数据段开头的长度指示符。对于可变长度的数据包,这是必要的。

指针条目 rfc_dataEntryPointer_t

指针条目类似于单个数据包条目,但不包含标头之后的数据。相反,它持有一个指向包含数据的另一个内存位置的指针。当您想执行以下操作时,此队列类型很有用:

将数据存储与队列条目分开

在不同队列之间共享相同的缓冲区,而无需重新创建队列结构

将缓冲区移动到另一个队列(例如自定义队列实现)而不复制内容

部分条目 rfc_dataEntryPartial

专有 PHY 支持一种入口类型,在通过空中接收整个数据包之前可以访问数据。它可用于以下目的:

在接收整个数据包之前必须读取数据时。例如,当数据包包含与支持的数据包格式不兼容的长度字段时 。

当在数据包的开头不知道数据包的长度时。

当数据包的长度对于单个数据包条目太长或使用无限数据包长度时。

部分条目可能包含多个数据包。在这种情况下,数据部分中的每个数据包都以大小为lenSz的长度字段开始,该字段可用于计算同一条目中下一个数据包的开始。该字段nextIndex包含条目中写入的总字节数。

创建队列

为了创建数据队列,需要执行以下步骤:

1.为所有队列条目分配足够的内存。

2.初始化每个队列条目头。

3.创建队列对象

该类型的对象dataQueue_t在头文件中定义<ti/devices/${DEVICE_FAMILY}/driverlib/rf_mailbox.h>;

// The queue structure
typedef struct {
   uint8_t *pCurrEntry;   // Points to the first entry, NULL for an empty queue
   uint8_t *pLastEntry;   // Pointer to the last entry, NULL for a circular queue
} dataQueue_t;

它持有一个指向第一个和最后一个条目的指针,并且可以具有固定或无限大小。在前一种情况下pLastEntry指向最后一个条目。在循环队列中,pLastEntry是一个空指针。

下面的例子解释了如何创建一个包含 4 个单包条目的循环队列,最多可以存储 32 个字节。

1.第一步,我们需要为所有队列条目分配足够的内存:

#include <ti/devices/${DEVICE_FAMILY}/driverlib/rfc_data_entry.h>
#include <ti/devices/${DEVICE_FAMILY}/driverlib/rfc_mailbox.h>
#define BUFFER_ENTRIES      4
// Must be word-aligned
#define DATA_SECTION_SIZE   32
// -1: Do not count the dummy data byte in the entry
#define ENTRY_HEADER_SIZE   (sizeof(rfc_dataEntryGeneral_t) - 1)
#define BUFFER_SIZE_BYTES   (BUFFER_ENTRIES * (ENTRY_HEADER_SIZE + DATA_SECTION_SIZE))
// Align the buffer to word boundaries. Example for GCC.
uint8_t buffer[BUFFER_SIZE_BYTES] __attribute__ ((aligned (4)));

所有队列条目都需要字对齐。当预期的负载大小不是 4 的倍数时,选择下一个更大的字对齐值作为 DATA_SECTION_SIZE。

2.准备条目标题并关闭环:

rfc_dataEntryGeneral_t item = (rfc_dataEntryGeneral_t*)&buffer[0];
for (uint8_t i = 0; i < BUFFER_ENTRIES; i++)
{
    item->config.type = DATA_ENTRY_TYPE_GEN;
    item->length = DATA_SECTION_SIZE; // Note: When creating partial items, add 4                                      
                                     // bytes for the additional header fields.
    item->status = DATA_ENTRY_PENDING;
    item->pNextEntry = ((uint8_t*)item) + ENTRY_HEADER_SIZE + DATA_SECTION_SIZE;
    if (i == (elements - 1))
    {
        // Close the circle for the last item
        item->pNextEntry = buffer;
    }
    item = (rfc_dataEntryGeneral_t*)item->pNextEntry;
}

3.创建一个循环队列对象:

dataQueue_t queue = {
    .pCurrEntry = &buffer[0];
    .pLastEntry = NULL;
};

从队列中读取数据

每当 RF 内核完成一个数据包时,它就会引发中断IRQ_RX_ENTRY_DONE,该中断 映射到 RF 驱动程序中的事件RF_EventRxEntryDone。在处理中断和执行回调时,数据包数据从入口读取,status必须重新设置该字段 DATA_ENTRY_PENDING,RF 内核才能重新使用它。

将当前条目保存在变量中:

// 初始化为第一个条目
rfc_dataEntryGeneral_t *  rxEntry  =  ( rfc_dataEntryGeneral_t * ) queue . pCurrEntry ;

从 RX 队列中的单个数据包条目中读取数据包。这可以在 RF 驱动程序回调中或在 RX 任务中完成:

// 要读取的当前条目。
rfc_dataEntryGeneral_t *  rxEntry ; 
// 数据包以 1 字节长度信息开始 (lenSz = 1) 
uint8_t  packetLength       =  * ( uint8_t * )( & rxEntry -> data ); 
// 有效载荷如下。
uint8_t *  packetDataPointer  =  ( uint8_t * )( & rxEntry -> data  +  sizeof ( packetLength )); 
// 正确:使用 memcpy 从缓冲区读取负载。
uint32_t  myValue; 
memcpy ( & myValue ,  packetDataPointer ,  sizeof ( myValue )); 
// 危险:取消引用数据包有效载荷中可能未对齐的指针:
// myValue = *((uint32_t*)packetDataPointer);

设置rxEntry为下一次迭代的下一个队列项:

// 将条目标记为正在读取
(( volatile  rfc_dataEntryGeneral_t * ) rxEntry ) -> status  =  DATA_ENTRY_PENDING ; 
// 获取下一个条目
rfc_dataEntryGeneral_t *  rxEntry  =   (( rfc_dataEntryGeneral_t * ) rxEntry -> pNextEntry );

以上就是关于“数据队列的使用方法”的介绍,大家如果想了解更多相关知识,不妨来关注一下星辉的Java星辉在线学习,里面有更丰富的知识在等着大家,里面的内容全面,通俗易懂,适合小白学习,希望对大家能够有所帮助。

提交申请后,顾问老师会电话与您沟通安排学习

免费课程推荐 >>
技术文档推荐 >>