韓新風,高智中
(1.安徽科技學院電氣與電子工程學院,安徽鳳陽 233100;2.安徽科技學院信息與網絡學院,安徽鳳陽 233100)
Z-Stack協(xié)議棧軟件是TI公司開發(fā)的Zigbee協(xié)議棧,適用于其公司的CC2430、CC2530和CC2538等射頻芯片。Z-Stack協(xié)議棧是在IEEE 802.15.4標準基礎上建立的,具有物理層、介質訪問控制層、網絡層、安全層、應用程序接口、應用層,其中物理層、介質訪問控制層是根據IEEE 802.15.4標準定義的,而網絡層、安全層和應用程序接口是由ZigBee聯(lián)盟制定的。Z-Stack協(xié)議棧采用的是一個名為操作系統(tǒng)抽象層(Operating System Abstraction Layer,OSAL)的協(xié)議棧調度程序。對用戶來說,除了能夠看到這個調度程序外,其他任何協(xié)議棧操作的具體實現(xiàn)細節(jié)都封裝在庫代碼中,用戶在開發(fā)具體應用時,只能通過調用API(Application Programming Interface)接口,而無權知道ZigBee協(xié)議棧實現(xiàn)的具體細節(jié)[1],因此稱Z-Stack協(xié)議棧為半開源的協(xié)議棧。用戶主要利用應用層來完成具體的應用系統(tǒng)的設計。Z-Stack協(xié)議棧定義了三種ZigBee設備類型:協(xié)調器、路由器和終端設備[2]。本文以TI公司的CC2530用于設計無線溫濕度測量系統(tǒng)來說明應用系統(tǒng)設計的一般步驟,其中終端設備負責測量溫度和濕度,路由器負責轉發(fā)數(shù)據,協(xié)調器負責接收數(shù)據、進行數(shù)據處理顯示或者將數(shù)據上傳至上位機。
基于Z-Stack協(xié)議棧的新項目的創(chuàng)建與一般軟件不同,因為它是一個半開源的協(xié)議棧,有很多代碼(如介質訪問控制層、網絡層的部分代碼)對用戶來講是非開源的,即對用戶不可見,但這些代碼卻是必備的,因此新項目的創(chuàng)建一般會采用在原有項目基礎上進行修改的方法來完成。用戶計算機上需要安裝IAR Embeded Workbench IDE軟件。一般需要四個步驟:項目文件的建立(重命名)、項目文件修改、修改APP目錄及源文件、編譯選項的設置。
第一步,在Texas Instrument/ZStack-2.2.2-1.3.0/Projects/zstack/Samples文件夾下建立用戶自己的文件夾,將其命名為HumandTemApp。在此文件夾下,創(chuàng)建兩個子文件夾:CC2530和Source,其中CC2530文件負責項目平臺的創(chuàng)建,Source文件負責源代碼的實現(xiàn)。第二步,將TI官網提供的示例項目中用于創(chuàng)建項目平臺的文件復制一份到用戶文件夾,具體操作如下:選擇Texas nstrument/ZStack-2.2.2-1.3.0/Projects/zstack/Samples/GenericApp/CC2530DB文件夾中的GenericApp.ewd、GenericApp.ewp、GenericApp.eww這三個文件復制一份粘貼在HumandTemAPP/CC2530文件夾下,并將這些文件的名稱改為HumandTemApp.ewd、HumandTemApp.ewp、HumandTemApp.eww。需要注意的是,只修改文件名,文件類型(即文件后綴名)保持不變。
使用記事本方式分別打開HumandTemApp.ewd、HumandTemApp.ewp、HumandTemApp.eww三個文件,采用查找替換的方法,將這三個文件中的“GenericApp”全部替換為“HumandTemApp”。
至此,將實例系統(tǒng)中用于創(chuàng)建項目平臺的非開源代碼,成功移植到了用戶的項目中,用戶項目平臺創(chuàng)建完成。
使用IAR軟件打開HumandTemAPP/CC2530目錄下HumandTemApp.eww文件,可以看到名為HumandTemApp的項目。第一步,將HumandTemApp項目下App目錄下的所有源文件刪除(實例項目的源文件),操作方法是:選中HumandTemApp項目下App目錄下的任一源文件,鼠標左鍵點擊選中該源文件,然后點擊右鍵選中下拉列表中的Remove選項,即可將該文件刪除。第二步,創(chuàng)建用戶自己的源文件,并完成協(xié)調器、路由器或終端源程序。在TI官網提供的實例GenericApp中,協(xié)調器、路由器或終端源程序都寫在了同一個文件中。程序運行時是借助于條件編譯來實現(xiàn)不同功能的。為了使源代碼讀寫更加清晰,用戶可以選擇將協(xié)調器、路由器或終端源程序分開編寫[3]。具體操作如下:在HumandTemApp項目下,點擊選中App目錄,然后點擊IAR軟件的菜單欄Project/Add Group,在App目錄添加文件夾,如協(xié)調器的源文件Coordinator、路由器的源文件Router或終端設備EndDevice。
用戶需要根據自己項目的結構,選擇協(xié)議棧默認網狀拓撲結構。項目內含有協(xié)調器節(jié)點CoordinatorEB、路由節(jié)點Router和終端節(jié)點EndDevice。用戶打開IAR軟件的Project/Edit Configuration進行Workspace選項的設置。首先用戶可通過刪除功能(Remove)將原有GenericApp例程中Workspace各選項刪除,然后通過新建功能(New)建立用戶自己的Workspace各選項CoordinatorEB、Router和EndDevice。
當用戶選擇編譯協(xié)調器選項時,將路由器和終端節(jié)點的編譯選項屏蔽掉。具體操作方法如下:第一步,在Workspace中選擇CoordinatorEB;第二步,在HumandTemApp項目下,點擊選中App目錄下用戶創(chuàng)建的Router;第三步,點擊鼠標右鍵,選擇下拉列表選項中的Options中的Options for node“HumandTemApp”,打開對話框后,選中Exclude from build,采用相同方法對EndDevice進行編譯設置。這樣就保證在編譯Coordinator時,不會對Router和EndDevice進行編譯。
當然,用戶在Workspace中選擇EndDevice時,也可以用相同方法屏蔽協(xié)調器和路由器。
在文件nwk_globals.h中的三種宏定義對應ZigBee網絡的三種網絡拓撲結構。每一種協(xié)議規(guī)范都有自己缺省的網絡拓撲結構及相關網絡設置。例如,在ZIGBEEPRO_PROFILE協(xié)議規(guī)范下,將網絡默認設置為網狀拓撲。
在Z-Stack-CC2530-2.5.0中,存在三種邏輯設備的類型:Coordinator(協(xié)調器)、Router(路由器)和End-Device(終端設備)。在編譯時也可以通過編譯選項確定邏輯設備具體屬于哪種類型。
Z-Stack協(xié)議棧的核心是事件的產生與事件的處理。協(xié)調器源代碼主要分為兩部分:一是任務的初始化;二是用戶事件的處理。
任務的初始化借助于任務初始化函數(shù)完成。該函數(shù)的編寫可以參考TI官網提供的GenericApp中的OSAL_GenericApp.c文件。
需要修改的主要有兩部分:
(1)將任務初始化函數(shù)osalInitTasks()的最后一個任務修改為用戶自定義的任務初始化,如HumandTemApp_Init(TaskID),并參照官網實例GenericApp_Init(TaskID)修改用戶的HumandTemApp_Init(TaskID)函數(shù)。
ZigBee協(xié)議棧采用的OSAL是一種支持多任務運行的系統(tǒng)資源分配機制,它是一種基于事件驅動的輪詢式實時操作系統(tǒng)[4]。OSAL專門分配了存放所有任務事件的tasksEvents[]數(shù)組,每一個單元對應存放著每一個任務的所有事件。當某一個任務有事件發(fā)生時,程序會通過osal_set_event()或者osal_msg_event()函數(shù)觸發(fā)事件[5],將tasksEvents[]數(shù)組中對應單元設置為1。因此當tasksEvents[]數(shù)組某個單元不為零時,說明相應的任務有事件發(fā)生。也有可能同時發(fā)生多個事件,即tasksEvents[]數(shù)組有多個元素為1。
(2)把用戶自定義的事件處理函數(shù)如HumandTemApp_ProcessEvent()添加到事件處理函數(shù)數(shù)組tasksArr[],作為該數(shù)組的最后一個元素。
OSAL輪詢系統(tǒng)查詢到某一層有事件發(fā)生時,將通過do-while循環(huán)來遍歷tasksEvents[],找到一個具有待處理事件的優(yōu)先級最高的任務,序號低的任務優(yōu)先級高,然后跳出循環(huán),此時就得到了最高優(yōu)先級任務的序號idx,然后通過events=tasksEvents[idx]語句將當前具有最高優(yōu)先級的任務事件取出,接著調用(tasksArr[idx])(idx,events)函數(shù)來執(zhí)行具體的處理[6],即調用對應層的事件處理函數(shù)來完成對該事件的處理。處理完該事件后,該事件會被清除。如果所有事件全都被處理完成,該層的事件處理函數(shù)將返回零。
用戶只需要編寫用戶自定義的事件處理函數(shù),如HumandTemApp_ProcessEvent(),其余層的事件處理函數(shù)ZigBee協(xié)議棧已經寫好,用戶一般無需編寫或修改。
用戶事件的處理,可以參考TI官網提供的GenericApp中的GenericApp.c。
(1)首先對所使用的端點、簇等進行定義,并參考GenericApp.c中的GenericApp_Init()函數(shù)編寫用戶的任務初始化函數(shù),如HumandTemApp_Init()。
一般情況下,一個設備如果同時存在多個應用(例如,一個終端設備既要連接一個濕度傳感器,又要連接溫度傳感器),可以為每個應用建立一個端點(端點號可以由用戶從1~240中任意選定),并且要為每個端點關聯(lián)一個taskID。需要注意的是,一個taskID是可以同時關聯(lián)多個端點的,但是某個特定端點只能關聯(lián)一個taskID。例如,在HumandTemApp_Init()函數(shù)中,可以用如下代碼,將端點和應用層任務HumandTemApp_TaskID掛鉤。
//Fill out the endpoint description
HumandTemApp_epDesc.endPoint=10;//HumandTemApp_ENDPOINT;此端點編號為10
HumandTemApp_epDesc.task_id=&HumandTemApp_TaskID;和應用層任務掛鉤
//Register the endpoint description with the AF
afRegister(&HumandTemApp_epDesc);//注冊端點,調用該函數(shù)才能完成整個掛鉤操作
(2)所有用戶事件的處理都是經過用戶事件處理函數(shù)來完成的。用戶可以參考GenericApp.c中的GenericApp_ProcessEvent()編寫協(xié)調器的事件處理函數(shù)HumandTemApp_ProcessEvent()。
ZigBee事件分為兩類:一類為系統(tǒng)事件(協(xié)議棧已經定義好);另一類為用戶事件(用戶可以自己定義)。不同事件按照事件類號進行區(qū)分。事件類號采用one-hot code(獨熱碼)進行編碼,即只有一個bit為1,其余全為0。協(xié)議棧已經通過宏定義系統(tǒng)事件SYS_EVENT_MSG為0x8000,自定義的用戶事件可以從0x4000~0x0001(共15個)中由用戶任選1個(只要不與現(xiàn)有的事件沖突即可),例如,用戶發(fā)送事件可以定義為#define SENT_MSG 0x0004。
事件處理函數(shù)GenericApp_ProcessEvent(byte task_id,UNINT events)(調用此函數(shù)需要傳遞的task_id為任務號,events為事件類號),該函數(shù)內部可以調用若干個不同函數(shù)對不同類型的事件進行處理。第一步,根據事件類號events來判定何種事件發(fā)生。提取系統(tǒng)事件的方法是判定(events&SYS_EVENT_MSG)是否為真,如果是,那么該事件即為系統(tǒng)事件。通過任務號task_id接收消息,獲取消息指針MSGpkt,然后根據消息中的事件號MSGpkt->event來處理具體事件。處理完系統(tǒng)事件后,將用return(events^SYS_EVENT_MSG)將該事件清除。第二步,若要提取某個用戶事件,例如判斷SENT_MSG是否發(fā)生,則可以通過判定(events&SENT_MSG)是否為真,如果是,則調用用戶的相應函數(shù)進行處理。處理完成該事件后,采用return(events^SYS_EVENT_MSG)將該事件清除。
路由器或終端設備源代碼的編寫步驟與協(xié)調器源代碼結構編寫步驟類似。由于路由器與協(xié)調器在網絡中的功能不同,發(fā)生的事件和處理方式可能不同,主要區(qū)別在于用戶事件的處理函數(shù)HumandTemApp_ProcessEvent()可能不同。
需要注意的是,在編寫源代碼時,協(xié)調器與路由器或終端節(jié)點之間數(shù)據的發(fā)送或接收,前后要清晰一致。如在無線溫濕度測量系統(tǒng)中,測量的終端節(jié)點可以通過osal_start_timerEx()函數(shù)定期觸發(fā)事件,在事件處理函數(shù)中可以通過AF_DataRequest()函數(shù)完成數(shù)據的發(fā)送。協(xié)調器接收到數(shù)據后會觸發(fā)AF_INCOMING_MSG_CMD事件,當OSAL檢測到該事件發(fā)生會調用用戶編寫的HumandTemApp_ProcessMSGCmd()進行處理,以便接收數(shù)據進行顯示或者將數(shù)據傳送至上位機。
Z-Stack協(xié)議棧學習的關鍵是理解基于輪詢及優(yōu)先級控制的任務管理方式。由于Z-Stack是一個半開源的協(xié)議棧,有很大一部分源代碼對用戶并不開放,使初學者在理解上可能存在障礙。針對Z-Stack半開源的協(xié)議棧的特點,新的項目并不需要用戶獨立創(chuàng)建,通過移植的方法將用戶不可見的那些源代碼融入用戶自己的項目中。這對用戶來講既省時又省力,用戶只需要將精力集中在如何寫應用層的源代碼即可。