zigbee协议栈 任务、事件与轮询机制
typedef unsigned char uint8?? 只占一個字節,即二進制的8位,0b00000000,16進制的兩位0x00;
typedef unsigned short uint16 只占兩個字節,即二進制的16位,0b0000000000000000,16進制的四位 0x0000
?
協議棧中有三個變量至關重要:
l? tasksCnt保存了任務的總個數
uint8 tasksCnt????
l? tasksEvents這是一個指針(可以看做數組),作為事件表,數組的索引是任務ID號,每一元素對應了該任務下的所有事件,這個事件可以拆分為小事件;
uint16 *tasksEvents?
l? tasksArr——這是一個數組,數組中的每一項都是一個函數指針,指向了任務事件的處理函數。數組的索引是任務的ID號,該ID號下的元素就是對應任務的事件處理函數,事件處理函數利用switch將該任務下的所有事件處理;
pTaskEventHandlerFntasksArr[] ,pTaskEventHandlerFn 是函數指針
typedef unsignedshort (*pTaskEventHandlerFn) (unsigned char task_id, unsigned short event)
表明,pTaskEventHandlerFn是一個指向返回值為(unsigned short)形參為(unsigned char task_id ,unsigned short event)的函數的指針
?
tasksEvents中的元素為一個16位二進制數,zigbee協議棧用一位二進制來定義事件,為1表示有事件,為0表示無事件,如任務ZDAppTaskID下的事件為
| 事件 | 十六進制 | 二進制 |
| ZDO_NETWORK_INIT | 0x0001 | 0b0000000000000001 |
| ZDO_NETWORK_START | 0x0002 | 0b0000000000000010 |
| ZDO_DEVIEC_RESET | 0x0004 | 0b0000000000000100 |
| ZDO_COMMAND_CNF | 0x0008 | 0b0000000000001000 |
| ZDO_START_CHANGE_EVT | 0x0010 | 0b0000000000010000 |
| ZDO_ROUTER_START | 0x0020 | 0b0000000000100000 |
| ZDO_NEW_DEVICE | 0x0040 | 0b0000000001000000 |
| ZDO_DEVICE_AUTH | 0x0080 | 0b0000000010000000 |
| ZDO_SCEMGR_EVENT | 0x0100 | 0b0000000100000000 |
| ZDO_NWK_UPDATE_NV | 0x0200 | 0b0000001000000000 |
| ZDO_FRAMECOUNTER_CHANGE | 0x0400 | 0b0000010000000000 |
如上圖,這樣二進制的每一位的1可以定義為一個事件,理論上一個任務下可以定義16個事件。這樣的好處是,事件與事件之間可以用二進制加法處理即異或算法相加。
比如:tasksEvents[ZDAppTaskID]=0x0003 ,由于 0x0003=0x0001^0x0002,所以可以看做ZDO_NETWORK_INT+ZDO_NETWORK_START,所以此時該任務下的事件有兩個,即ZDO_NETWORK_INT和ZDO_NETWORK_START。提取的時候可以利用與運算來提取。 “與”運算能用來判斷二進制數的某一位是否為1。由于二進制的減法運算與加法運算相同,所以也可以通過加法異或運算來清零某一已經處理過的事件。
?
全zigbee協議棧最重要的就是? void osal_start_system( void )函數,整個輪詢機制也在這個函數中被完成
第5行,定義了一個變量idx,用來標識任務,(如任務0),用來在事件表和函數表中索引;
第6、7行,更新系統時鐘,同時查看硬件方面是否有事件發生,如串口是否接收到數據、是否有按鍵按下等信息,這部分內容在此暫不考慮;
第9~15行,idx從零增大到tasksCnt,依次遍歷事件表,查看哪個任務idx對應的事件不為空,當找到任務idx的事件不為空時停止遍歷,轉而去調用該任務的事件處理函數,不妨設此時的idx = 8;
第19~22行,將該任務8的事件取出來放到events變量中,由于事件值被取出來了,所以對應事件表中的元素值要清零,即tasksEvents[8] = 0;
第25行,由于任務事件處理函數表的元素索引與任務事件表的索引一一對應,所以直接將8作為索引帶入任務事件處理函數表就可以調用任務8的事件處理函數(tasksArr[8])(8,events),而且由于函數表中的事件處理函數是以函數指針的形式給出的,所以還需要填寫形參,分別是任務id號8,和從任務8的事件events。形參中有events天經地義,因為需要分辨events中含有哪些具體事件,形參中為什么有任務id號呢?是因為,在處理任務的時候可能需要調用其他與任務綁定的函數。同時,任務處理函數的返回值也是任務值,UINT16,返回的是未被處理的具體事件。
第32行,將任務8未被處理的具體事件放回事件表中任務8對應的事件元素中。
?
然而,以上的機制可以解釋Zigbee是怎樣處理一個任務下面的事件的,但處理后的事件表是被清零的,那是誰來給任務的這些事件來置一呢?
osal_set_event(uint8 task_id , uint16 event_flag ) ;由它來給事件表中的元素賦值。
函數原型為:
uint8osal_set_event( uint8 task_id , uint16 event_flag )
{
?if( task_id < tasksCnt)
{
??halIntState_t?? intState ;
??HAL_ENTER_CRITICALL_SECTION( inState ) ;?? //關中斷
??tasksEvents[task_id] |= event_falg ;?????????? //給任務task_id設置事件event_flag
?? HAL_EXTI_CRITICALL_SECTION(inState ) ;???? //開中斷
?? return( SUCCESS )
}
else
{
??return( INVALID_TASK )
}
?
}
?
如,原來的tasksEvents[ZDAppTaskID] = 0x0000,即此任務下無事件可以處理,當我調用
osal_set_event(uint8 ZDAppTaskID , ZDO_NETWORK_INIT )后?tasksEvents[ZDAppTaskID] = 0x0001,這樣當進入輪詢時就會調用事件處理函數處理該事件。
?
?
知道了任務下的事件是如何被設置、處理的,我們知道任務ID是將事件表和事件處理函數聯系起來的關鍵,那么任務本身是怎樣被設置的呢?
添加任務的關鍵是
l? 新任務的初始化函數
l? 新任務的事件處理函數
如要添加任務GenericApp則其初始化函數GenericApp_Init( taskID ),事件處理函數GenericApp_ProcessEvent應該分別放在osalInitTasks函數、事件處理函數表tasksArr[]的最后,而tasksEvent[]的大小會隨著tasksArr[]的大小一起變化,即當在tasksArr[]最后一位加入GenericApp_ProcessEvent時,tasksEvent[]也隨著增加一個元素用來安放對應的事件。
?????? 為了方便看出原理,將taskArr[]、osalInitTasks()簡化處理得到
值得一提的是,taskArr[]是先于tasksEvents[]聲明定義的,所以可以根據taskArr[]的長度來設置tasksEvents[]的長度與任務相匹配。
由osalInitTask(),任務ID號從0開始,按先后順序分別分配給各個任務,所以這個ID號與數組的索引也是相匹配的,設備必須的任務優先,從上圖看到,用戶自定義的任務ID應該是8。正是借助這個ID號將任務事件表中的事件元素和事件處理函數表中的事件處理函數對應了起來。
????????????????????????????????????????????????????????????????????????????????????????????????? 2018年1月22日星期一
???????????????????????????????????????????????????????????????????????????????????????????????????????? 武漢大學青樓
本文參考自:《ZigBee無線傳感器網絡設計與實現》 ? ? ?王小強等人編著化學工業出版社
??????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
總結
以上是生活随笔為你收集整理的zigbee协议栈 任务、事件与轮询机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MCU_ZigBee协议栈相关函数总结
- 下一篇: 磁盘阵列卡 远程监控(MegaRAID