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