更新時(shí)間:2021-11-01 11:15:42 來(lái)源:動(dòng)力節(jié)點(diǎn) 瀏覽1421次
數(shù)據(jù)隊(duì)列用于將數(shù)據(jù)包從 RF 內(nèi)核傳輸?shù)街?CPU,反之亦然。它們被實(shí)現(xiàn)為隊(duì)列條目的鏈表。本文檔描述了可用的隊(duì)列條目類(lèi)型,并提供了用于創(chuàng)建隊(duì)列并與之交互的代碼片段。
RF 內(nèi)核支持 4 種不同類(lèi)型的隊(duì)列條目:
姓名 |
數(shù)據(jù)類(lèi)型 |
描述 |
---|---|---|
單包入口 |
rfc_dataEntryGeneral_t |
每個(gè)條目一包;標(biāo)頭后的數(shù)據(jù)。 |
多包入口 |
rfc_dataEntryMulti_t |
同一條目中有多個(gè)數(shù)據(jù)包,數(shù)據(jù)在頭部之后。 |
指針入口 |
rfc_dataEntryPointer_t |
每包一個(gè)條目;另一個(gè)內(nèi)存位置的數(shù)據(jù)。 |
部分入場(chǎng) |
rfc_dataEntryPartial_t |
存儲(chǔ)未知或無(wú)限長(zhǎng)度的數(shù)據(jù)包;標(biāo)頭后的數(shù)據(jù)。 |
只有部分條目可用于傳輸數(shù)據(jù)。所有其他類(lèi)型都專(zhuān)門(mén)與 RX 命令一起使用。
所有隊(duì)列條目都以一個(gè)公共頭部分開(kāi)始,包含一個(gè)指向下一個(gè)條目的指針、一個(gè)配置字段和條目的長(zhǎng)度(以字節(jié)為單位)。
每個(gè)隊(duì)列條目與 4 字節(jié)邊界對(duì)齊非常重要。否則 RF 核心將無(wú)法訪問(wèn)隊(duì)列條目。
單個(gè)數(shù)據(jù)包條目每個(gè)條目包含一個(gè)數(shù)據(jù)包,并將數(shù)據(jù)直接存儲(chǔ)在標(biāo)頭后面,以便可以將整個(gè)隊(duì)列分配在線性存儲(chǔ)部分中。它們是最簡(jiǎn)單的條目類(lèi)型,足以滿(mǎn)足許多應(yīng)用程序的需求。數(shù)據(jù)部分可能包含由 配置的數(shù)據(jù)包長(zhǎng)度、 config.lenSz有效載荷和可選的附加元數(shù)據(jù),如 RX 時(shí)間戳或 CRC。
當(dāng)可以另外確定分組大小時(shí),可以省略數(shù)據(jù)段開(kāi)頭的長(zhǎng)度指示符。對(duì)于可變長(zhǎng)度的數(shù)據(jù)包,這是必要的。
指針條目類(lèi)似于單個(gè)數(shù)據(jù)包條目,但不包含標(biāo)頭之后的數(shù)據(jù)。相反,它持有一個(gè)指向包含數(shù)據(jù)的另一個(gè)內(nèi)存位置的指針。當(dāng)您想執(zhí)行以下操作時(shí),此隊(duì)列類(lèi)型很有用:
將數(shù)據(jù)存儲(chǔ)與隊(duì)列條目分開(kāi)
在不同隊(duì)列之間共享相同的緩沖區(qū),而無(wú)需重新創(chuàng)建隊(duì)列結(jié)構(gòu)
將緩沖區(qū)移動(dòng)到另一個(gè)隊(duì)列(例如自定義隊(duì)列實(shí)現(xiàn))而不復(fù)制內(nèi)容
專(zhuān)有 PHY 支持一種入口類(lèi)型,在通過(guò)空中接收整個(gè)數(shù)據(jù)包之前可以訪問(wèn)數(shù)據(jù)。它可用于以下目的:
在接收整個(gè)數(shù)據(jù)包之前必須讀取數(shù)據(jù)時(shí)。例如,當(dāng)數(shù)據(jù)包包含與支持的數(shù)據(jù)包格式不兼容的長(zhǎng)度字段時(shí) 。
當(dāng)在數(shù)據(jù)包的開(kāi)頭不知道數(shù)據(jù)包的長(zhǎng)度時(shí)。
當(dāng)數(shù)據(jù)包的長(zhǎng)度對(duì)于單個(gè)數(shù)據(jù)包條目太長(zhǎng)或使用無(wú)限數(shù)據(jù)包長(zhǎng)度時(shí)。
部分條目可能包含多個(gè)數(shù)據(jù)包。在這種情況下,數(shù)據(jù)部分中的每個(gè)數(shù)據(jù)包都以大小為lenSz的長(zhǎng)度字段開(kāi)始,該字段可用于計(jì)算同一條目中下一個(gè)數(shù)據(jù)包的開(kāi)始。該字段nextIndex包含條目中寫(xiě)入的總字節(jié)數(shù)。
為了創(chuàng)建數(shù)據(jù)隊(duì)列,需要執(zhí)行以下步驟:
1.為所有隊(duì)列條目分配足夠的內(nèi)存。
2.初始化每個(gè)隊(duì)列條目頭。
3.創(chuàng)建隊(duì)列對(duì)象
該類(lèi)型的對(duì)象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;
它持有一個(gè)指向第一個(gè)和最后一個(gè)條目的指針,并且可以具有固定或無(wú)限大小。在前一種情況下pLastEntry指向最后一個(gè)條目。在循環(huán)隊(duì)列中,pLastEntry是一個(gè)空指針。
下面的例子解釋了如何創(chuàng)建一個(gè)包含 4 個(gè)單包條目的循環(huán)隊(duì)列,最多可以存儲(chǔ) 32 個(gè)字節(jié)。
1.第一步,我們需要為所有隊(duì)列條目分配足夠的內(nèi)存:
#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)));
所有隊(duì)列條目都需要字對(duì)齊。當(dāng)預(yù)期的負(fù)載大小不是 4 的倍數(shù)時(shí),選擇下一個(gè)更大的字對(duì)齊值作為 DATA_SECTION_SIZE。
2.準(zhǔn)備條目標(biāo)題并關(guān)閉環(huán):
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.創(chuàng)建一個(gè)循環(huán)隊(duì)列對(duì)象:
dataQueue_t queue = {
.pCurrEntry = &buffer[0];
.pLastEntry = NULL;
};
每當(dāng) RF 內(nèi)核完成一個(gè)數(shù)據(jù)包時(shí),它就會(huì)引發(fā)中斷IRQ_RX_ENTRY_DONE,該中斷 映射到 RF 驅(qū)動(dòng)程序中的事件RF_EventRxEntryDone。在處理中斷和執(zhí)行回調(diào)時(shí),數(shù)據(jù)包數(shù)據(jù)從入口讀取,status必須重新設(shè)置該字段 DATA_ENTRY_PENDING,RF 內(nèi)核才能重新使用它。
將當(dāng)前條目保存在變量中:
// 初始化為第一個(gè)條目
rfc_dataEntryGeneral_t * rxEntry = ( rfc_dataEntryGeneral_t * ) queue . pCurrEntry ;
從 RX 隊(duì)列中的單個(gè)數(shù)據(jù)包條目中讀取數(shù)據(jù)包。這可以在 RF 驅(qū)動(dòng)程序回調(diào)中或在 RX 任務(wù)中完成:
// 要讀取的當(dāng)前條目。
rfc_dataEntryGeneral_t * rxEntry ;
// 數(shù)據(jù)包以 1 字節(jié)長(zhǎng)度信息開(kāi)始 (lenSz = 1)
uint8_t packetLength = * ( uint8_t * )( & rxEntry -> data );
// 有效載荷如下。
uint8_t * packetDataPointer = ( uint8_t * )( & rxEntry -> data + sizeof ( packetLength ));
// 正確:使用 memcpy 從緩沖區(qū)讀取負(fù)載。
uint32_t myValue;
memcpy ( & myValue , packetDataPointer , sizeof ( myValue ));
// 危險(xiǎn):取消引用數(shù)據(jù)包有效載荷中可能未對(duì)齊的指針:
// myValue = *((uint32_t*)packetDataPointer);
設(shè)置rxEntry為下一次迭代的下一個(gè)隊(duì)列項(xiàng):
// 將條目標(biāo)記為正在讀取
(( volatile rfc_dataEntryGeneral_t * ) rxEntry ) -> status = DATA_ENTRY_PENDING ;
// 獲取下一個(gè)條目
rfc_dataEntryGeneral_t * rxEntry = (( rfc_dataEntryGeneral_t * ) rxEntry -> pNextEntry );
以上就是關(guān)于“數(shù)據(jù)隊(duì)列的使用方法”的介紹,大家如果想了解更多相關(guān)知識(shí),不妨來(lái)關(guān)注一下動(dòng)力節(jié)點(diǎn)的Java在線學(xué)習(xí),里面有更豐富的知識(shí)在等著大家,里面的內(nèi)容全面,通俗易懂,適合小白學(xué)習(xí),希望對(duì)大家能夠有所幫助。
相關(guān)閱讀
0基礎(chǔ) 0學(xué)費(fèi) 15天面授
有基礎(chǔ) 直達(dá)就業(yè)
業(yè)余時(shí)間 高薪轉(zhuǎn)行
工作1~3年,加薪神器
工作3~5年,晉升架構(gòu)
提交申請(qǐng)后,顧問(wèn)老師會(huì)電話與您溝通安排學(xué)習(xí)
初級(jí) 202925
初級(jí) 203221
初級(jí) 202629
初級(jí) 203743