更新時間:2021-11-01 11:15:42 來源:動力節點 瀏覽1340次
數據隊列用于將數據包從 RF 內核傳輸到主 CPU,反之亦然。它們被實現為隊列條目的鏈表。本文檔描述了可用的隊列條目類型,并提供了用于創建隊列并與之交互的代碼片段。
RF 內核支持 4 種不同類型的隊列條目:
姓名 |
數據類型 |
描述 |
---|---|---|
單包入口 |
rfc_dataEntryGeneral_t |
每個條目一包;標頭后的數據。 |
多包入口 |
rfc_dataEntryMulti_t |
同一條目中有多個數據包,數據在頭部之后。 |
指針入口 |
rfc_dataEntryPointer_t |
每包一個條目;另一個內存位置的數據。 |
部分入場 |
rfc_dataEntryPartial_t |
存儲未知或無限長度的數據包;標頭后的數據。 |
只有部分條目可用于傳輸數據。所有其他類型都專門與 RX 命令一起使用。
所有隊列條目都以一個公共頭部分開始,包含一個指向下一個條目的指針、一個配置字段和條目的長度(以字節為單位)。
每個隊列條目與 4 字節邊界對齊非常重要。否則 RF 核心將無法訪問隊列條目。
單個數據包條目每個條目包含一個數據包,并將數據直接存儲在標頭后面,以便可以將整個隊列分配在線性存儲部分中。它們是最簡單的條目類型,足以滿足許多應用程序的需求。數據部分可能包含由 配置的數據包長度、 config.lenSz有效載荷和可選的附加元數據,如 RX 時間戳或 CRC。
當可以另外確定分組大小時,可以省略數據段開頭的長度指示符。對于可變長度的數據包,這是必要的。
指針條目類似于單個數據包條目,但不包含標頭之后的數據。相反,它持有一個指向包含數據的另一個內存位置的指針。當您想執行以下操作時,此隊列類型很有用:
將數據存儲與隊列條目分開
在不同隊列之間共享相同的緩沖區,而無需重新創建隊列結構
將緩沖區移動到另一個隊列(例如自定義隊列實現)而不復制內容
專有 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在線學習,里面有更豐富的知識在等著大家,里面的內容全面,通俗易懂,適合小白學習,希望對大家能夠有所幫助。
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習