帶大家來一起快速的看懂ZigBee的協議棧的運行流程。
1.讀任何程序都需要從main函數入手,那我們先來看Zmain.c中的main函數。
問題:在main中我們會看到很多的函數,我們究竟要看哪個函數呢?
回答:這么多的函數中其實我們只需要關注osal_init_system()和osal_start_system()兩個函數就可以了。我們在編程的時候其實也只會關系到這兩個函數。
2.我們跟蹤(把光標放在這個函數上點右鍵,再點擊go to define)osal_init_system()這個函數,發現它在OSAL.c文件中。
問題:在這個函數中有遇到了很多函數,那我們又要關注那些函數呢?
回答:這個函數中我們只需要關注osalInitTasks()函數就可以了,這其實就是把每個事件作為每個任務。
3.我們跟蹤osalInitTasks()這個函數,發現在OSAL_SampleApp.c中。其他的函數先不管。
在這個函數我們可以看到我們的任務編號是從0開始的,然后每添加一個任務任務編號(taskID++)就加一,并且為任務分配內存。如下:
uint8 taskID = 0;
tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));
在這個函數中需要我們特別關注的是SampleApp_Init(taskID)這個函數,因為我們在編程的時候這個函數是需要我們程序員去編寫的,這個事協議棧提供的編程接口。
4.同樣我們跟蹤這個函數SampleApp_Init(taskID),發現它在SampleApp.c中(這個函數很重要)。在這個函數中我們看到需要我們去配置一些信息,如串口波特率、流控等等。
uartConfig.callBackFunc = Serial_CallBack;
這需要我們來定義串口回調函數來無線發送數據。
5.現在系統的初始化已經做好了,遇到SampleApp_Init()函數的return后一步一步的返回。
6.返回到main函數后,我們再來看osal_start_system()函數,注意這個函數一但進去之后,此函數就不會再返回。我們跟蹤這個函數,發現它在OSAL.c中。
do {
if (tasksEvents[idx]) // Task is highest priority that is ready.
{
break;
}
} while (++idx < tasksCnt);
注意這段邏輯,這是把任務中優先級高的選出來。
events = tasksEvents[idx];//把優先級高的選出來賦值給事件來處理。
這里我們需要來看一個數組:
const pTaskEventHandlerFn tasksArr[] = {
macEventLoop,
nwk_event_loop,
Hal_ProcessEvent,
#if defined( MT_TASK )
MT_ProcessEvent,
#endif
APS_event_loop,
#if defined ( ZIGBEE_FRAGMENTATION )
APSF_ProcessEvent,
#endif
ZDApp_event_loop,
#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
ZDNwkMgr_event_loop,
#endif
SampleApp_ProcessEvent
};
我們知道這些都是事件處理函數。問題又來了,這么多我們應該看和用哪一個呢?
協議棧給用戶提供的函數編程接口是SampleApp_ProcessEvent這個函數。
然而怎么調用到這個函數呢?看下面的代碼。
events = (tasksArr[idx])( idx, events );//這是是一個函數指針的應用。自己補C語言,這里不贅述。
7.既然是這樣我們就要跟蹤SampleApp_ProcessEvent()這個函數,發現它在SampleApp.c中。
case AF_INCOMING_MSG_CMD:
SampleApp_MessageMSGCB( MSGpkt );
break;
這是我們需要關注的case,這個就是接受到數據的時候讀出無線發過來的數據。SampleApp_MessageMSGCB( MSGpkt );這個函數就需要程序員進行編寫。所以這個函數也非常的重要。
這就是協議棧的大體運行過程,當然這些還很淺顯,還沒有討論一些深層次的內容,并且有些地方寫得不合適的地方,希望大家指正,這里我表示萬分的感激。