1 Osal_start_system(); // No Return from here
1 void osal_start_system( void ) 2 { 3 #if !defined ( ZBIT ) 4 for(;;) // Forever Loop 5 6 #endif 7 { 8 uint8 idx = 0; 9 10 Hal_ProcessPoll(); // This replaces MT_SerialPoll() and osal_check_timer(). 11 12 13 do { 14 if (tasksEvents[idx]) // 最高優先級任務被找到 15 16 { 17 break; 18 } 19 } while (++idx < tasksCnt); //其中tasksCnt為tasksArr數組中元素的個數 20 21 //得到了待處理的具有最高優先級的任務的索引號 idx 22 23 if (idx < tasksCnt) 24 { 25 uint16 events; 26 halIntState_t intState; 27 // 進入/退出臨界區,來提取出需要處理的任務中的事件,其實這和μC/OS-II操作系統中進入臨界區很相似,μC/OS-II中使用OS_ENTER_CRITICAL();OS_EXIT_CRITICAL(); 28 29 HAL_ENTER_CRITICAL_SECTION(intState); 30 events = tasksEvents[idx]; 31 tasksEvents[idx] = 0; // Clear the Events for this task. 32 33 HAL_EXIT_CRITICAL_SECTION(intState);//通過指針調用來執行對應的任務處理函數 34 35 36 events = (tasksArr[idx])( idx, events ); 37 //進入/退出臨界區,保存尚未處理的事件 38 39 HAL_ENTER_CRITICAL_SECTION(intState); 40 tasksEvents[idx] |= events; // Add back unprocessed events to the current task. 41 42 HAL_EXIT_CRITICAL_SECTION(intState); 43 } //本次事件處理結束, 44 45 #if defined( POWER_SAVING ) 46 else // 所有的任務事件都被查詢結束后,沒有任何事件被激活 47 48 { 49 osal_pwrmgr_powerconserve(); // 系統進入休眠狀態。 50 51 } 52 #endif 53 } 54 }
操作系統專門分配了存放所有任務事件的tasksEvents[]數組,每一個單元對應存放着每一個任務的所有事件,在這個函數中首先通過一個do—while循環來遍歷tasksEvents[],找到一個具有待處理事件的優先級最高的任務,序號低的任務優先級高,然后跳出循環,此時,就得到了最高優先級任務的序號idx,然后通過events=tasksEvents[idx]語句,將這個當前具有最高優先級的任務的事件取出,接着就調用(tasksArr[idx])(inx,events)函數來執行具體的處理函數了,taskArr[]是一個函數指針數組,根據不同的idx就可以執行不同的函數。
TI給出了幾個例子來演示Z-Stack協議棧,其實這些例子中的大部分代碼是相同的,只有用戶的應用層,添加了不同的任務及事件處理函數。這里以GeneralApp這個例子來說明。
首先,明確系統中要執行的幾個任務。在GeneralApp這個例子中,幾個任務函數組成了上述的tasksArr函數指針數組,在Osal_GeneralApp.c中定義,osal_start_system()函數通過函數指針(tasksArr[idx])(inx,events)調用。
tasksArr數組如下:
1 const pTaskEventHandlerFn tasksArr[] = { 2 macEventLoop, //MAC層任務處理函數 3 4 nwk_event_loop, //網絡層任務處理函數 5 6 Hal_ProcessEvent, //硬件抽象層任務處理函數 7 8 #if defined( MT_TASK ) 9 10 MT_ProcessEvent, //調試任務處理函數 可選 11 12 #endif 13 14 APS_event_loop, //應用層任務處理函數,用戶不用修改 15 16 ZDApp_event_loop, //設備應用層任務處理函數,用戶可以根據需要修改 17 18 GenericApp_ProcessEvent //用戶應用層任務處理函數,用戶自己生成 19 20 };
如果不算調試任務,操作系統一共要處理6項任務,分別為MAC層,網絡層。硬件抽象層,應用層,ZigBee設備應用層以及完全由用戶處理的應用層,其優先級由高到低。MAC層任務具有最高優先級,用戶層具有最低的優先級。Z-Stack已經編寫了對從MAC層到ZigBee設備應用層這五層任務的事件處理函數,一般情況下不需要修改這些函數,只需要按照自己的需求編寫應用層的任務及事件處理函數就可以。
其它的幾個例子文件中,唯一不同的是最后一個函數其它的函數都是一樣的。一般情況下用戶只需要額外添加三個文件就可以完成一個項目。一個是主文件,存放具體的任務事件處理函數如上述事例中的GenericApp_ProcessEvent,一個是這個主文件的頭文件,另外一個是操作系統的接口文件以Osal開頭,是專門存放任務處理函數數組tasksArr[]的文件。這樣就實現了Z-Stack代碼的公用,用戶只需要添加這幾個文件,編寫自己的任務處理函數就可以了。到現在是不是感覺很簡單,別不想想像的那么復雜,這個操作系統抽象層和實時操作系統中的μC/OS-II有相似之處,唉μC/OS-II中可以分配給64個任務。了解了這個操作系統的話,理解OSAL應該不是很困難,但是,Z-Stack只是基於這個OSAL運行,但重點不在這里,而是ZigBee設備之間的通信的實現,以及組網,組成不同的網絡結構,這些才是整個ZigBee協議中的核心內容,當然也應該遠比我們添加幾個文件來的復雜。
Z-Stack在項目中的目錄結構
在Z-Stack項目中大約有14個目錄文件,目錄文件下面又有很多的子目錄和文件。下面就來看看這14個根目錄,具體是有什么作用:
(1) App:應用層目錄,這個目錄下的文件就是創建一個新項目時自己要添加的文件,
(2) HAL:硬件層目錄,Common目錄下的文件是公用文件,基本上與硬件無關,其中hal_assert.c是斷言文件,用於調用,hal_drivers.c是驅動文件,抽象出與硬件無關的驅動函數,包含有與硬件相關的配置和驅動及操作函數。Include目錄下主要包含各個硬件模塊的頭文件,而Target目錄下的文件是跟硬件平台相關的,可能看到有兩個平台,分別是Cc2430DB平台和一個CC2430EB平台。后面的DB和EB表示的是TI公司開發板的型號,其實還有一種類型是BB的,BB: Battery Board
DB: Development Board EB: Evaluation Board
分別對應TI公司開發的三種板型,其功能按上順序依次變強。可以參看"Z-Stack User's Guide for CC2430"的圖片,可以獲得更直觀的認識。
(3) MAC:MAC層目錄,High Level和Low Level兩個目錄表示MAC層分為了高層和底層兩層,Include目錄下則包含了MAC層的參數配置文件及基MAC的LIB庫函數接口文件,這里的MAC層的協議是不開源的,以庫的形式給出
(4) MT:監制調試層目錄,該目錄下的文件主要用於調試目的,即實現通過串口調試各層,與各層進行直接交互。
(5) NWK:網絡層目錄,含有網絡層配置參數文件及網絡層庫的函數接口文件,及APS層庫的函數接口
(6) OSAL:協議棧的操作系統抽象層目錄
(7) Profile:AF層目錄,Application Farmework 應用框架,包含AF層處理函數接口文件。
(8) Security:安全層目錄,包含安全層處理函數接口文件
(9) Services:ZigBee和802.15.4設備地址處理函數目錄,包括地址模式的定義及地址處理函數
(10) Tools:工作配置目錄,包括空間划分及Z-Stack相關配置信息
(11) ZDO:指ZigBee設備對象,可認為是一種公共的功能集,文件用戶用自定義的對象調用APS子層的服務和NWK層的服務
(12) ZMAC:其中Zmac.c是Z-StackMAC導出層接口文件,zmac_cb.c是ZMAC需要調用的網絡層函數
(13) Zmain:Zmain.c主要包含了整個項目的入口函數main(),在OnBoard.c包含硬件開始平台類外設進行控制的接口函數
(14) Output:輸出文件目錄,這個是EW8051 IDE自動生成的