zigbee 串口不稳定_Zigbee
Zigbee 不完全整
基本概念:
計算機網絡定義:
? 1.用通信鏈路將分散的多臺計算機、終端、外設等互聯起來,使之能彼此通信,同時共享各種硬件、軟件和數據資源,整個系統可稱為計算機網絡
? 2.計算機網絡將地理位置不同的具獨立功能的多臺主機、外設或其它設備,通過通信線路進行連接,在網絡操作系統、管理軟件及通信協議的管理協調下,實現資源共享和信息傳遞的完整系統。
計算機網絡的作用:資源共享、信息交換、協同處理。
計算機網絡在邏輯上可以分為通訊子網和資源子網。按網絡傳輸分配可以分為點對點分類和廣播分類。按網絡規模和覆蓋范圍可以分為局域網、城域網以及廣域網。計算機網絡的作用資源共享、信息交換、協同處理。
計算機網絡的四個產生階段:第一階段:分散的多個終端連接到一臺中心機上,典型:美國飛機訂票系統;第二階段:多主機通過通信鏈路互聯,典型:ARPANET;第三階段:互聯互通階段: 網絡互連遵循統一的技術標準(OSI模型和TCP/IP模型),成為第三代網絡。第四階段:高速網絡階段:光纖高速網絡、多媒體網絡、智能網絡、無線網絡,成為第四代網絡。
網絡協議的三要素:語義、語法、定時。
三網融合:計算機網絡、電信網絡、廣播電視網絡。
ZigBee網絡協議架構通過分層實現,每一層相當于一個模塊,且為上層提供服務,層與層之間通過服務接入點接口進行信息交換。
在網狀網絡中,每個設備都可以與在無線通信范圍內的其他設備進行通信。
CC2530是8位單片機,具有兩個串口、21個通用I/O端口引腳(19個4mA、2個20mA)。芯片具有8KB、16KB、32KB在線可編程的FLASH、同時具有8KB的數據存儲能力(RAM)。具有低功耗模式、2.4GHz IEEE802.15.4兼容的RF收發器、支持精確鏈路指示、不具備多路DAC轉換器。8路輸入且可配置的12位ADC。從芯片CC2530的組成框圖看,三個模塊中組成CPU及相關存儲模塊、外設、時鐘和電源管理模塊和無線模塊。
單片機最小系統包括單片機、電源引腳、復位電路和晶振電路組成。
無線網絡發展幾個階段:
? 第一代(1G)無線系統是面向語音的模擬無線系統,使用FDMA技術實現。 第二代(2G)無線系統是面向語音的數字無線系統,使用TDMA或窄帶CDMA技術實現。第三代(3G)無線系統把蜂窩電話、PCS語音業務以及移動數據業務用各種分組交換數據業務綜合在一個高語音質量、高容量、高速率的網絡系統中。
Zigbee無線通信技術的特點:Zigbee無線技術是一種新興的短距離、低復雜度、低功耗、低數據速率、低成本的技術。
Zigbee適合傳輸低反應時間、周期性、間歇性的數據,不適合傳輸高延遲的數據。
所有的ZigBee設備都具有連接網絡和斷開網絡的功能。ZIgBee網絡是一種自組織網絡、分布式網絡。 「可能涉及Zigbee如何組網的過程」
依據IEEE802.15.4標準建立。可使用的頻段有三個:2.4GHZ、歐洲868MHZ、美國915MHZ,不同頻段可用的信道分別是16、1、10個。短地址14位,長地址64位。Zigbee最多可支持240個設備。非開源意思是看不見源碼,只提供函數借口(API)
分層(key):從下到上:物理層 媒體訪問控制層(MAC) 「IEEE802.15.4定義」 網絡層 應用層「Zigbee聯盟定義」
對各層的基本功能了解:物理層:定義了無線信道和MAC子層之間的接口,提供了物理層數據服務和管理服務。「激活和關閉射頻收發器/對當前信道進行能量檢測/對收發的包進行鏈路質量指示/收發數據和空閑信道評估/信道選擇/數據單元收發/向MAC層提供管理服務接口」
MAC層:MAC層提供網絡層和物理層之間的接口。「實現對從基本物理層數據單元中提取MAC層數據包的進一步處理,并發送信標,利用信標與父節點同步,能量檢測,主動、被動、孤立掃描機制,關聯和退出關聯,CSMA/CA沖突避免信道訪問控制機制,時隙劃分, MAC層數據傳輸及安全機制等功能。」
網絡層(核心層):利用IEEE 802.15.4標準使MAC子層正確工作,并為應用層提供服務接口。「主要負責網絡層協議數據單元收發、網絡管理和路由管理。網絡管理主要包括網絡啟動、設備請求加入/離開網絡、網絡發現、網絡地址分配等。 路由管理包括鄰居節點發現、路由發現、路由維護、消息單播、多播、廣播實現等 」
應用層:包括應用支持子層(APS)、應用框架(AF)、 ZigBee設備對象(ZDO)及ZDO管理平臺。應用支持子層(APS),作為應用層的一個組成部分,它提供了網絡層(NWK)和應用層(APL)之間的接口。 「應用支持子層負責應用層協議數據單元數據的傳輸、設備綁定表創建和維護、組表的管理和維護、數據可靠傳輸等。應用框架「AF層」主要為方便程序員進行開發而在ZigBee設備中為所實現的應用對象提供的模板。應用對象就是使用ZigBee聯盟制定的Profile進行開發的,并在協議棧上運行的應用程序。安全服務層安全服務向NWK層和APS提供了安全服務,主要完成一些加密工作,包括密鑰建立、密鑰傳輸、幀保護和設備管理。』
設備分類:
? 全功能設備支持 IEEE802.15.4標準定義的所有功能和特性,并擁有較多的存儲資源、計算能力。半功能設備只支持標準定義的一部分,功能簡單。
? ZigBee 網絡中的設備按照各自作用不同可以分為協調器節點、路由器節點和終端節點。全功能設備既可以作為協調器、路由器,也可以作為終端;半功能設備只能作為終端。
協調器(key):
? 負責網絡的啟動,配置網絡使用的信道和網絡標識符(PAN ID),完成網絡成員的地址分配、節點綁定、建立安全層等任務。協調器是網絡的第一個設備,是整個網絡的中心。一個ZigBee網絡只有一個網絡協調器。當網絡建立成功后,協調器便充當路由器的角色。
路由器(key):
? 主要實現允許設備加入網絡、擴展網絡覆蓋的物理范圍和數據包路由的功能。一般處于活躍狀態,由主電源供電 「擴展網絡是指該設備可以作為網絡中的潛在父節點,允許更多的路由和終設備接入網絡。路由器最為重要的功能是“允許多跳路由”。路由節點存儲路由表、負責尋找、建立及修復數據包路由路徑。」
終端設備:
? 通過ZigBee協調器或者ZigBee路由器接入到網絡中,主要負責數據采集或控制功能,不允許其他節點通過它加入到網絡中。多數時間處于休眠狀態,電池供電。
組網過程:
? 組建網絡:節點上電,判斷是否是全功能設備->判斷是否已經加入到其他網絡->信道掃描,選擇合適的信道->設置PAN-ID和協調器短地址,網絡初始化成功,等待其他節點加入網絡。
? 節點加入網絡:通過全功能節點加入網絡。分為首次加入網絡和再次入網,再次入網采用孤兒掃描。
網狀/樹形/星形網絡三者比較:自行擴展。
Zigbee相關技術:
節點:一個節點包含一組設備,并對應一個無線信號收發器,只能使用一個無線通信信道。「一個節點對應一個設備」
端點:應用對象駐留的地方,是協議棧應用層的入口,為實現一個設備描述而定義的一組群集。一個設備最多支持240個用戶自定義端點。「0分配給ZDO,用與設備管理,255用于廣播,241-254保留擴展」
群集(Cluster):一個端點可以具有多個群集,使用群集號(Cluster ID)分配。分為輸入群集和輸出群集,多個節點通過群集號位不同端點建立一個邏輯連接,即綁定(Bonding)「群集是屬性的集合,包含一個或多個屬性」簇的含義指設備或應用對象之間的消息。
規約(Profile):相同應用對象采用的所有群集的集合稱為規約。目的是為了制定標準,兼容不同制造商之間的產品,說明了設備類型、接口等。還有一種協議棧規約(Zigbee和Zigbee Pro),定義網絡類型、網絡深度等。
節點地址:
? 擴展地址:IEEE地址,64位,設備商固化在設備中。短地址:稱為網絡地址,由協調器進行分配,通過端點號+短地址確定一個終端。
PANID:網絡標號。不同PANID代表不同網絡。PANID16位,PANID為0xFFFF時,協調器隨機選擇一個PANID作為網絡標號建立網絡,終端隨機選擇一個信號最強的網絡加入網絡。
事件:系統定義事件和用戶定義事件,16位獨熱碼。
間接通信/直接通信:間接通信指各個節點通關端點的綁定建立通信關系。直接通信需要獲取對方的地址。
綁定:一種多個應用設備之間信息流的控制機制。
數據傳送方式:單點傳送(Unicast):將素舉報發送給一個已知網絡地址的設備。廣播傳送(Indirect):應用程序需要將數據包發送給網絡的每一個設備,廣播傳送的目標地址:0xFFFF--傳送到網絡上的所有設備。0xFFFC--只發送給協調器和路由器, 0xFFFD--數據包傳送到網絡上所有非睡眠設備。
LQI;鏈路信號質量。最差0x00-最強0xff
RSSI信號強度,越小越好。
Zigbee協議棧任何數據利用幀格式來組織,每層都有特定的幀結構。(分為鍵值對和報文,報文適合傳遞數據量大的消息,支持任何數據傳輸)
Zigbee具有兩種休眠模式:輕度休眠「定時器休眠」和深度休眠。
應用框架(AF)主要為方便程序員進行開發而在ZigBee設備中為所實現的應用對象提供的模板,由設備對應的( 端口號和短地址)兩部分組成。 ZigBee協議棧的系統輕度休眠模式時一個預定延時后不能喚醒執行任務。(F) ZigBee協議棧的系統進入深度休眠模式,需要一個外部觸發來喚醒設備。 ZigBee協議棧的端點,包括任務號、端點號、簡單描述符、潛藏周期四項。 ZigBee協議棧中定義的設備狀態類型devStates_t中,不包含終端節點狀態。(F) ZigBee協議棧的兩種休眠模式:真休眠(定時器休眠)和假休眠。(F) 在ZigBee協議中如果一個消息來到了節點上,是通過( 終端「不是端點)來投遞消息到某一個具體的應用程序對象 不同的ZigBee協議棧版本使用不同的地址分配方案,ZigBee 2007使用(隨機分配地址的方案) 在ZigBee協議中,(全功能節點)能夠承擔協調器和路由器的功能。 在ZigBee協議中,(應用程序對象)是指針對目標物理量或事件都會提供控制或測量功能,實際的通信實體 ? 在ZigBee協議中,事件分為系統級事件和任務級事件,系統級事件可以(在任務間傳遞的事件),任務級事件在任務內使用的事件。 ZigBee協議建立路由的原則是(按照需要建立路由),既有優點也有缺點,優點是節省資源,缺點是實時性不好。 在Zigbee中,OSAL指的是操作系統抽象層。 使用ZigBee協議棧編程,每個任務有一個任務號,有一個初始化函數和一個事件處理函數,(端口)提供的其他函數都會被這兩個函數直接或間接地調用到。 使用ZigBee協議棧編程,(簇)僅提供一個消息隊列及消息處理的功能。 函數osalInitTasks( void )初始化了事件隊列。ZigBee協議中,端點描述符結構體endPointDesc_t的成員變量有端點號endPoint、簡單描述符SimpleDescriptionFormat_t、網絡發送速度afNetworkLatencyReq_t和(指向任務ID即Task_ID的指針) 當PAN_ID設置為0x1234時,協調器(使用0x1234作為網絡標號,建立網絡)路由器和終端(路由器和終端節點只能加入網絡標號為0x1234的網絡) 鏈接器控制文件所在的文件夾(Tools) !從代碼角度看,一個任務是由一個(初始化函數)和一個事件處理函數組成的。 任務ID,又叫任務號,每個任務都有自己的消息隊列,任務號的作用是(事件發生時,使用該任務號獲取消息)C++跨平臺調用
一般用于將C++代碼以標準C形式輸出(即以C的形式被調用),這是因為C++雖然常被認為是C的超集,但是C++的編譯器還是與C的編譯器不同的。C中調用C++中的代碼這樣定義會是安全的。 #ifdefined(__cplusplus)||defined(c_plusplus) //跨平臺定義方法extern "C"{#endif簡單的用在windows下可以如下定義:#ifdef __cplusplusextern "C"{//... 正常的聲明段}#endif協議棧
APP:應用層目錄,這是用戶創建各種不同工程的區域,在這個目錄中包含了應用層的內容和這個項目的主要內容,在協議棧里面一般是以操作系統的任務實現的。HAL:硬件層目錄,包含有與硬件相關的配置和驅動及操作函數。
MAC:MAC 層目錄,包含了MAC 層的參數配置文件及其MAC 的LIB 庫的函數接口文件。
MT: 監控調試層,主要用于調試目的,即實現通過串口調試各層,與各層進行直接交互。
NWK:網絡層目錄,含網絡層配置參數文件及網絡層庫的函數接口文件,APS 層庫的函數接口。
OSAL:協議棧的操作系統。
Profile:AF 層目錄,包含AF 層處理函數文件。
Security:安全層目錄,安全層處理函數接口文件,比如加密函數等。
Services:地址處理函數目錄,包括著地址模式的定義及地址處理函數。
Tools:工程配置目錄,包括空間劃分及ZStack 相關配置信息。
ZDO:ZDO 目錄。
ZMac: MAC 層目錄,包括MAC 層參數配置及MAC 層LIB 庫函數回調處理函數。
ZMain:主函數目錄,包括入口函數main()及硬件配置文件。
Output:輸出文件目錄,這個自動生成的。
ZMain函數中,一方面進行系統的初始化,一方面對事件進行輪循。
Zstack的工作原理圖
Zstack運行流程圖如上。綜上,Zstack最重要的兩個步驟即事件的初始化以及事件的處理,其余各層的初始化Ti公司基本已經為你做完了。
用戶自定義事件初始化:
Main -> oasl_init_system()
OSAL工作機制
OSAL任務初始化
oaslInitTask()函數中對任務進行初始化,在此創建任務表。
void osalInitTasks( void ) {uint8 taskID = 0;tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));macTaskInit( taskID++ );nwk_init( taskID++ );Hal_Init( taskID++ ); #if defined( MT_TASK )MT_TaskInit( taskID++ ); #endifAPS_Init( taskID++ ); #if defined ( ZIGBEE_FRAGMENTATION )APSF_Init( taskID++ ); #endifZDApp_Init( taskID++ ); #if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )//ip沖突和跳頻相關ZDNwkMgr_Init( taskID++ ); #endif//task_init functionDNUI_SampleApp_Init(taskID); } //任務初始化函數如上,更具taskCnt的數量申請對應的事件表,兩者通過taskID一一對應,然后對各層定義進行初始化,taskID越小,其優先級越高。這個函數可用于自定義相關的任務。例:DNUI_SampleApp_Init(),對應用戶自定義的初始化函數,用戶需要用到的相關初始化都在其內定義。OSAL通過輪詢查看任務表判斷各層有無事件發生。OSAL如何處理事件
//操作系統啟動函數 void osal_start_system( void ) { #if !defined ( ZBIT ) && !defined ( UBIT )for(;;) // Forever Loop #endif{osal_run_system();} } //可見操作系統通過for無限循環osal_run_system()進入oasl_run_system( )一探究竟
//操作系統運行函數 void osal_run_system( void ) {uint8 idx = 0; //掃描哪個時間被觸發,標志位置一//更新定時器osalTimeUpdate();//查看硬件方法是否有事件發生Hal_ProcessPoll();//硬件初始化輪詢調用//從最高優先級任務一次判斷每個任務是否有事件的觸發,有則跳出循環do {if (tasksEvents[idx]) // Task is highest priority that is ready.{break;}} while (++idx < tasksCnt);//idx小于任務數量,即有時間發生//so hard to understandif (idx < tasksCnt){uint16 events;halIntState_t intState;HAL_ENTER_CRITICAL_SECTION(intState);//關中斷,防止干擾events = tasksEvents[idx];//調用事件去處理函數,coz taskArr是一個函數指針,tasksEvents[idx] = 0; // Clear the Events for this task。表示此類任務事件//執行finsih,在事件處理函數中又調用消息處理函數HAL_EXIT_CRITICAL_SECTION(intState);activeTaskID = idx;//設置activeTaskID的作用?events = (tasksArr[idx])( idx, events );//核心中的核心,taskArr和tasksEvent中的idx相同,返回處理過事件的eventsactiveTaskID = TASK_NO_TASK;HAL_ENTER_CRITICAL_SECTION(intState);tasksEvents[idx] |= events; // Add back unprocessed events to the current task./將處理過的events對應的tasksEvents位清0HAL_EXIT_CRITICAL_SECTION(intState);}//定義低功耗,則進入低功耗模式 #if defined( POWER_SAVING )else // Complete pass through all task events with no activity?{osal_pwrmgr_powerconserve(); // Put the processor/system into sleep} #endif //定義協同操作,進入協同操作/* Yield in case cooperative scheduling is being used. */ #if defined (configUSE_PREEMPTION) && (configUSE_PREEMPTION == 0){osal_task_yield();} #endif } //函數設計非常巧妙,首先調用定時器和硬件初始化輪詢函數。 //通過do...while...循環,對事件進行查看,一旦有事件發生便跳出循環,進行事件處理,把事件存入event中并調用taskArr[idx](idx,events)進行對應事件的函數處理Hal_ProcessPoll( );poll在linux中相當于把文件掛起,此函數可能有這個意思;進入事件處理函數TaskArr[].
taskArr是一個存放各事件處理函數的指針數組。存放對應taskid上產生事件的事件處理函數。const pTaskEventHandlerFn tasksArr[] = {macEventLoop,nwk_event_loop,Hal_ProcessEvent, #if defined( MT_TASK )MT_ProcessEvent, #endifAPS_event_loop, #if defined ( ZIGBEE_FRAGMENTATION )APSF_ProcessEvent, #endifZDApp_event_loop, #if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )ZDNwkMgr_event_loop, #endifDNUI_SampleApp_ProcessEvent }; //以上定義了各層task的事件處理函數。其中最后的DNUI_SampleApp_ProcessEvent;調用的是用戶自定義的事件處理函數。用戶對于系統或各自定義事件產生的動作都在此定義 uint16 DNUI_SampleApp_ProcessEvent( uint8 task_id, uint16 events ) {afIncomingMSGPacket_t *MSGpkt; //定義一個接受消息的指針if ( events & SYS_EVENT_MSG ){MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( task_id );//將對應taskid上的消息隊列中的消息取出進行處理while ( MSGpkt )//有事件接受{switch ( MSGpkt->hdr.event )//根據消息頭判斷,如果接收到了無線數據{//無線接受消息,A設備用AF_DataRequest()發送消息,b設備街道消息觸發此事件case AF_INCOMING_MSG_CMD: //incoming msg type megsif(DNUI_SampleApp_NwkState == DEV_ZB_COORD)//若為協調器事件{//--start--協調器接收數據的處理邏輯 HalUARTWrite(0,MSGpkt->cmd.Data,MSGpkt->cmd.DataLength-1); //--end--協調器接收數據的處理邏輯 }else if(DNUI_SampleApp_NwkState == DEV_END_DEVICE){//--start--終端設備接收數據的處理邏輯 //--end--終端設備接收數據的處理邏輯 }else if(DNUI_SampleApp_NwkState == DEV_ROUTER){//--start--路由器接收數據的處理邏輯 //--end--路由器接收數據的處理邏輯 }break; //網絡狀態改變case ZDO_STATE_CHANGE: //ZDO has changed the device's network state DNUI_SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status);//statusif(DNUI_SampleApp_NwkState == DEV_END_DEVICE){ //--start--終端設備接收數據的處理邏輯 osal_start_timerEx(task_id,DNUI_SAMPLEAPP_ENDDEVICE_PERIODIC_MSG_EVT,1000); //--end--終端設備接收數據的處理邏輯 } else if(DNUI_SampleApp_NwkState == DEV_ZB_COORD){//--start--協調器接收數據的處理邏輯 //--end--協調器接收數據的處理邏輯 }else if(DNUI_SampleApp_NwkState == DEV_ROUTER){//--start--路由器接收數據的處理邏輯 //--end--路由器接收數據的處理邏輯 } break;default:break;} //消息處理完后,釋放消息所占據的內存空間,在zigbee中接收到的消息放在堆上,//需要用deallocate函數將其內存釋放,否則容易導致內存泄露osal_msg_deallocate( (uint8 *)MSGpkt ); //WHY DNUI_sampleAppTaskIDMSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( DNUI_SampleAppTaskID);} return (events ^ SYS_EVENT_MSG);//SYS_EVENT_MSG =0X8000,系統事件//按理解當事件處理完畢后將事件對應位清0,解封裝的過程,有事件的時候就將對應出置1} //若產生用戶自定義事件,在此處理if ( events & DNUI_SAMPLEAPP_ENDDEVICE_PERIODIC_MSG_EVT ) //0x01{ //發送設置,數據發送可以使用AF_DataRequest函數實現,該函數調用協議棧里與硬件相關的函數AF_DataRequest( &Coor_Addr, &DNUI_SampleApp_epDesc,DNUI_SAMPLEAPP_DATATEST_CLUSTER_ID,3, //Lab6buf,&DNUI_SampleApp_TransID,//任務id號指針AF_DISCV_ROUTE,//有效位掩碼發送選項AF_DEFAULT_RADIUS );osal_start_timerEx( task_id, DNUI_SAMPLEAPP_ENDDEVICE_PERIODIC_MSG_EVT,1000); return (events ^ DNUI_SAMPLEAPP_ENDDEVICE_PERIODIC_MSG_EVT);} return 0; }通過Osal_set_event(taskid , flag)函數將相應的標志位置1,在之后的協議棧運行過程中就會根據需要調用這個函數。此函數為Osal的核心函數,包含很多重要的結構和函數。
afIncomingMSGPacket_t *MSGpkt
一個消息包的結構內容typedef struct {osal_event_hdr_t hdr; /* OSAL Message header */uint16 groupId; /* Message's group ID - 0 if not set */uint16 clusterId; /* Message's cluster ID */afAddrType_t srcAddr; /* Source Address, if endpoint is STUBAPS_INTER_PAN_EP,it's an InterPAN message */uint16 macDestAddr; /* MAC header destination short address */uint8 endPoint; /* destination endpoint */uint8 wasBroadcast; /* TRUE if network destination was a broadcast address */uint8 LinkQuality; /* The link quality of the received data frame */uint8 correlation; /* The raw correlation value of the received data frame */int8 rssi; /* The received RF power in units dBm */uint8 SecurityUse; /* deprecated */uint32 timestamp; /* receipt timestamp from MAC */uint8 nwkSeqNum; /* network header frame sequence number */afMSGCommandFormat_t cmd; /* Application Data */ } afIncomingMSGPacket_t; ---------------------------------------------------------------------- typedef struct {uint8 event;uint8 status; } osal_event_hdr_t;typedef struct {union{uint16 shortAddr;ZLongAddr_t extAddr;} addr;afAddrMode_t addrMode;uint8 endPoint;uint16 panId; // used for the INTER_PAN feature } afAddrType_t;// Generalized MSG Command Format typedef struct {uint8 TransSeqNumber;uint16 DataLength; // Number of bytes in TransDatauint8 *Data; } afMSGCommandFormat_t;AF_DataRequest()
afStatus_t AF_DataRequest( afAddrType_t *dstAddr, endPointDesc_t *srcEP,uint16 cID, uint16 len, uint8 *buf, uint8 *transID,uint8 options, uint8 radius ) { }//很重要的一個APi函數,處理過程過于復雜,只展示參數。返回值adStatus_t = uint8*dstAddr - Full ZB destination address: Nwk Addr + End Point.全終端節點,網絡號和終端號
*srcEP - Origination (i.e. respond to or ack to) End Point Descr.
//終端節點的描述符
cID - A valid cluster ID as specified by the Profile.
//有效簇ID
len - Number of bytes of data pointed to by next param.
//發送數據的長度
*buf - A pointer to the data bytes to send.
//指向發送數據的指針
*transID - A pointer to a byte which can be modified and which will be used as the transaction sequence number of the msg.
options - Valid bit mask of Tx options.
radius - Normally set to AF_DEFAULT_RADIUS.
//跳數,一般為10跳
*transID - Incremented by one if the return value is success.
afStatus_t - See previous definition of afStatus_... types.
關于osal_msg_receive( )函數用于從消息隊列中取出函數
uint8 *osal_msg_receive( uint8 task_id ) {osal_msg_hdr_t *listHdr;osal_msg_hdr_t *prevHdr = NULL;osal_msg_hdr_t *foundHdr = NULL;halIntState_t intState; //unsigned char// Hold off interruptsHAL_ENTER_CRITICAL_SECTION(intState);// Point to the top of the queuelistHdr = osal_qHead;// Look through the queue for a message that belongs to the asking taskwhile ( listHdr != NULL ){if ( (listHdr - 1)->dest_id == task_id ){if ( foundHdr == NULL ){// Save the first onefoundHdr = listHdr;}else{// Second msg found, stop lookingbreak;}}if ( foundHdr == NULL ){prevHdr = listHdr;}listHdr = OSAL_MSG_NEXT( listHdr );}// Is there more than one?if ( listHdr != NULL ){// Yes, Signal the task that a message is waitingosal_set_event( task_id, SYS_EVENT_MSG );}else{// No moreosal_clear_event( task_id, SYS_EVENT_MSG );}// Did we find a message?if ( foundHdr != NULL ){// Take out of the link listosal_msg_extract( &osal_qHead, foundHdr, prevHdr );}// Release interruptsHAL_EXIT_CRITICAL_SECTION(intState);return ( (uint8*) foundHdr ); }typedef struct {void *next;uint16 len;uint8 dest_id; } osal_msg_hdr_t;typedef struct {uint8 event;uint8 status; } osal_event_hdr_t;由于系統檢測到相關事件觸發此函數,如果觸發了系統事件,需要通過oasl_msg_receive()確認是否真有事件發生,如果不止一個系統事件,通過setevent函數進行再次設置。
關于 osal_start_timerEx()函數,設置該taskid對應時間的定時,沒到一個定時時長觸發一次任務事件。(但是這個觸發設置在哪并沒有找到對應的函數。
uint8 osal_start_timerEx( uint8 taskID, uint16 event_id, uint16 timeout_value ) {halIntState_t intState; //unsigned char typeosalTimerRec_t *newTimer;//HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts.// Add timernewTimer = osalAddTimer( taskID, event_id, timeout_value );HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts.return ( (newTimer != NULL) ? SUCCESS : NO_TIMER_AVAIL ); }事件的管理
事件管理
事件管理詳見【OSAL如何處理事件】
幾個系統事件
SYS_EVENT_MSG(0x8000),為系統強制事件,該事件主要用來發送全局的系統信息,主要有以下信息:
事件處理首先根據事件類號判斷是何種事件,根據任務號得到消息指針pMSG,最后更具消息指針內的結構pMSG->event 來處理具體的事件。在ZcomDef.h中定義。AF_DATA_CONFIRM_CMD:數據收到確認。A設備發送數據,B設備收到數據后返回應答Ack觸發此次事件。AF_INCOMING_MSG_CMD:Incoming MSG type message收到報文類型的消息;A設備用AF_DataRequest函數發出報文消息,B設備收到報文消息將觸發AF_INCOMING_MSG_CMD事件。
AF_INCOMING_KWP_CMD:收到鍵值對類型的消息。
AF_INCOMING_GRP_KVP_CMD:收到群鍵值對類型的消息KEY_CHANGE:按鍵觸發事件「Key Events」
ZDO_NEW_DSTADDR:ZDO設備獲取新地址ZDO_STATE_CHANGE:ZDO網絡狀態改變,A設備的網絡狀態發生改變,就會觸發這個事件
ZDO_MATCH_DESC_RSP_SENT:
ZDO_CB_MSG:收到ZDO反饋消息。
關于無線節點和端點的解釋
一個節點可以有多個端點,每個端點對應一個taskid ,每增加一個端點,需要為其配置一個新的任務id。在zstack協議棧中,我們采用AF_DataRequest這個函數進行無線數據包發送,在AF_DataRequest函數的參數中,SampleApp_Periodic_DstAddr目的地址,目的地址中便包含了16位的短地址(協調器默認為0x0000)以及端點號endpoint。終端將數據包發出,短地址匹配的協調器會收到這個消息(短地址匹配不對則丟棄該包),然后協議棧底層進行解析,將數據包發給協調器的對應endpoint(不匹配則丟棄該包)。
簡單來說,endpoint是用來管理同一個節點上不同任務的工具,相當于一個分類箱,將不同功能分別存放在不同任務上,這樣做的好處是規范數據包,你不用去規定第幾個字節是屬于哪個模塊信息。
端點的管理:
每個節點都有物理地址(MAC)和網絡地址(短地址),每個節點都有241個端點,如果設備需要綁定,必須在網絡層注冊一個或多個端點,進行數據的發送以及綁定表的建立。1、Zigbee節點(Radio unit) Zigbee本身其實只是一種協議規范,落實到具體目標上無非就是一個具有2.4G射頻發射接收功能和單片機功能的一塊電路板(TI的2530、2430,意法半導體的STM32W108處理器都在一塊芯片上集成了這兩個部分,Ember和飛思卡爾也有集成的,也有一些非集成的方案),在這塊電路板上去運行Zigbee的協議,并且按照協議規范的射頻頻段和無線數據封包格式來在多個這樣的電路板之間實現無線通信。這就引出了節點的概念(英文大致叫做Device,我這里稱之為Radio unit吧),理解起來就是這塊能夠實現無線通信的電路了。如果不是zigbee,而是之前的那些諸如nrf905這樣的射頻芯片,如果其沒有協議棧支持,這個節點就是通信的全部了。 2、zigbee的EndPoint Endpoint這個概念在Zigbee中絕對是非常重要的。因為所有的Zigbee無線數據包都必須有一個Endpoint為目標。那么什么是Endpoint呢?從理解的層面上來說,Endpoint是一個radio unit上的真正的數據目標。按照協議規范,0號endpoint是Zigbee device object(ZDO)用的一個端點,255號是用作廣播用途,我們可以自己設定的是1~240號,其余的保留。在一個Radio unit上可以實現多個EndPoint。當進行無線數據收發的時候,數據包里面就必須包含radio unit信息(設備的短地址),端點信息(destination endpoint number)。也就是說一個radio unit在接收到一個數據包后,會在協議棧的底層進行解析,比對應該把這個數據包發給哪個endpoint,如果找不到,這個包將被丟棄。
短地址+端點號=確定一個終端節點
3、例子 下面我舉兩個例子來解釋一下endpoint的問題 例子一:一個無線節點(radio unit)A上有一個溫濕度傳感器,有一個空調控制系統;另外一個無線節點B則負責接收A發回的溫度數據,并通過一定的算法來控制空調系統。我們不管B如何實現,只研究A如何實現。這種情況的一個很規范的實現方式是:溫濕度傳感器設置一個endpoint,比如為10號;空調控制系統設置一個endpoint,比如為20號。還要說明的是:還應該為每一個endpoint建立一個任務,這樣在注冊端點描述符的時候(調用afRegister函數),就會向協議棧底層說明處理這個端點數據的任務是誰。這樣:當B想要獲取溫濕度的時候,他將會發出一個包含A的短地址和10號端點的信息,這個信息到了A,協議棧會將這個消息轉給10號端點所對應的task去處理,管理空調的20號端點根本就看不到這個消息;類似地,如果B想要控制空調,他發出的數據包將包含A的短地址和20號端點信息,A收到消息后會發給20號端點的task去處理。(需要注意的是:在網絡層面經常會有發給ZDO的消息,這時候信息包的端點號就將是0號)。這種將不同功能分配到不同endpoint上的方法非常有利于任務的劃分,是一種很正規的方法。 例子二、一個無線節點(radio uint)A上有4個LED需要被控制,另外一個無線節點B則有4個開關用來控制這4個LED。這種情形的規范實現方式還是要為每一個LED設置一個endpoint(允許的范圍內你任意指定,只要不重復),并為每個endpoint建立一個task。這樣處理之后,B可以用同樣的命令來控制4個LED,而不是每一個led 用不同的命令,這種情況在public profile實際上是必須這么做的。
上面兩個例子可能很多同學認為太麻煩,完全可以變通。變通的想法就是我所有的被控對象都落在一個endpoint上,但是我發的數據包內容不同,接收端這個endpoint通過解析數據包的內容來判斷具體該做什么,這種方式實際上完全可以實現,不過需要你自己規定一下數據包的格式,即第幾個字節表示什么。。。。。 雖然這可以實現要求,但是我很不贊成這樣,一方面實際上是增加了你程序設計的復雜度,另一方面完全沒有了互聯的可能,尤其是當你用ZCL的時候,這種方式就行不通了。
source
Osal定時器組織模式
Osal_start_timer()是如何調用set_event()函數,整個協作的過程詳見課程參考資料。
通過定時器數據鏈表將其組織起來,這個鏈表由osal_timer_update()函數來管理,由osalTimerUpdate以ms為單位對這些“軟定時器”減計數,當定時器溢出,即調用osal_set_event函數。osal_start_timerEx通過osalAddTimer向鏈表中添加定時器,由osalTimerUpdate來減計數,當這個定時器溢出后,則會對taskID對應的task設置一個event_id,從而讓這個任務在后面的主循環中運行到。能夠在主循環中運行到的原因是會調用osal_set_event函數來實現主循環里對此項任務的調用
———————————————— https://blog.csdn.net/Rhiney_97/article/details/89739491

byte osal_start_timerEx( byte taskID, UINT16 event_id, UINT16 timeout_value ) { halIntState_t intState;osalTimerRec_t *newTimer;HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts.// Add timernewTimer = osalAddTimer( taskID, event_id, timeout_value );if ( newTimer ){ #ifdef POWER_SAVING// Update timer registersosal_retune_timers();(void)timerActive; #endif// Does the timer need to be started?if ( timerActive == FALSE ){osal_timer_activate( TRUE );}}osal_start_timerEx() ->osal_add_timer()
typedef struct{void *next;uint16 timeout; uint16 event_flag;uint8 task_id;uint16 reloadTimeout;} osalTimerRec_t //定時器數據鏈表結構體數據發送/消息
串口發送函數
typedef struct {bool configured; // 配置與否uint8 baudRate; // 波特率bool flowControl; // 流控制uint16 flowControlThreshold; //在RX緩存達到maxRxBufSize之前還有多少字節空余。當到達maxRxBufSize –flowControlThreshold時并且流控制打開時,會觸發相應的應用事件:HAL_UART_RX_ABOUT_FULLuint8 idleTimeout; // 在idleTimout 時間內RX還沒有得到新的數據,將會觸發相應的事件 HAL_UART_RX_TIMEOUT halUARTBufControl_t rx;// 接收halUARTBufControl_t tx;// 發送bool intEnable; // 中斷使能uint32 rxChRvdTime; // 接收數據時間halUARTCBack_t callBackFunc; // 回調函數 }halUARTCfg_t;typedef struct {uint16 bufferHead; //Rx/Tx 緩沖區中的起始字節位置的索引uint16 bufferTail; // Rx/Tx 緩沖區中的末尾字節位置的索引 uint16 maxBufSize; // Rx/Tx 緩沖區一次最多接收或發送的字節數,當接收或者發送字節數到達該值時,產生HAL_UART_RX_FULL or HAL_UART_TX_FULL事件。uint8 *pBuffer; //指向接收字節的緩沖區 }halUARTBufControl_t;消息接受
一般來說,一個消息對應一個事件。if ( events & SYS_EVENT_MSG ){MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );while ( MSGpkt ){switch ( MSGpkt->hdr.event )...}由以上可見,消息作為系統事件接受的。消息的使用與事件類似,使用byte osal_msg_send(byte destination task ,byte *ptr) 觸發,這個函數有兩個參數分別為接收事件任務的ID,另一個為指向消息的指針,用于向一個任務發送命令或消息數據。osal_msg_allocate()
uint8 * osal_msg_allocate( uint16 len) {osal_msg_hdr_t *hdr;if ( len == 0 )return ( NULL );hdr = (osal_msg_hdr_t *) osal_mem_alloc( (short)(len + sizeof( osal_msg_hdr_t )) );if ( hdr ){hdr->next = NULL;hdr->len = len;hdr->dest_id = TASK_NO_TASK;return ( (uint8 *) (hdr + 1) );}elsereturn ( NULL ); }typedef struct {void *next;uint16 len;uint8 dest_id; } osal_msg_hdr_t;由以上可知,消息由兩個部分組成:消息頭和消息的實際內容。消息頭為協議棧定義的,消息內容我們自己添加的。osal_mag_send()
uint8 osal_msg_send( uint8 destination_task, uint8 *msg_ptr ) {if ( msg_ptr == NULL )return ( INVALID_MSG_POINTER );if ( destination_task >= tasksCnt ){osal_msg_deallocate( msg_ptr );return ( INVALID_TASK );}// Check the message headerif ( OSAL_MSG_NEXT( msg_ptr ) != NULL ||OSAL_MSG_ID( msg_ptr ) != TASK_NO_TASK ){osal_msg_deallocate( msg_ptr );return ( INVALID_MSG_POINTER );}OSAL_MSG_ID( msg_ptr ) = destination_task;// queue messageosal_msg_enqueue( &osal_qHead, msg_ptr );// Signal the task that a message is waitingosal_set_event( destination_task, SYS_EVENT_MSG );return ( SUCCESS ); }//以上,osal_msg_engueue()為入棧操作,消息是按照隊列的方式被操作的。 //osal_set_event( destination_task, SYS_EVENT_MSG );這句的定義很重要,在發送消息后,觸發系統事件,暗示我們消息處理函數去哪找。osal_msg_receive
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events ) {afIncomingMSGPacket_t *MSGpkt;if ( events & SYS_EVENT_MSG ){MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );while ( MSGpkt ){switch ( MSGpkt->hdr.event ){// Received when a key is pressedcase KEY_CHANGE:SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );break;// Received when a messages is received (OTA) for this endpointcase AF_INCOMING_MSG_CMD:SampleApp_MessageMSGCB( MSGpkt );break;...}}} typedef struct {uint8 event;uint8 status; } osal_event_hdr_t;osal_event_hdr_t,包含事件發生的標志和狀態,用來找到事件對應消息的。然后通過消息中的Event來判斷需要進行的操作。
相關消息事件在ZComDef.h中定義
##消息隊列的維護
系統事件會在對應接收到消息后在對應的Event中觸發。
消息的處理與使用與事件類似,使用byte_osal_msg_send(byte destination , byte_*msg_ptr)函數觸發,指向一個任務發送命令或數據消息,同時出發系統消息任務。
消息是按照隊列的方式進行管理的,
重要函數Collection
ASDU:Zigbee協議中APS應用服務數單元AF_DataRequest()
向指定的節點的端口發送數據。端點借助單項鏈表進行管理,用戶需要使用某個端點繼續通訊時,先要調用afResiger注冊相應的端點向端點管理鏈表添加一條記錄。
端點的接受過程:afIncomingData函數提取來自APS層數據包中的目標端點號,匹配對應的端點。
//若配置應用ID、應用配置ID,則數據會被打包, 借助OSAL的消息機制,最終發送到相應對點應用對象的消息處理函數。
Question :
并未找到此函數在何處調用。在老師AF_DataRequest()函數說明文檔中標注:
發送數據通過在應用層調用函數void SampleApp_SendFlashMessage(uint 16 flashTime),其參數為發送的數據。afStatus_t AF_DataRequest( //afStatus_t == uint 8 afAddrType_t *dstAddr, //*dstAddr 發送網絡號+端點號,即確定一個事件 endPointDesc_t *srcEP,//終端節點的描述 uint16 cID, //簇id uint16 len, //發送數據長度 uint8 *buf, //發送數據緩沖區 uint8 *transID,//任務ID號指針 uint8 options, //有效位掩碼發送選項 uint8 radius//傳送跳數,常為AF_DEFAULT_RADIUS,10跳 )Uint 16 cID: 簇ID號,具體應用串ID
uint8 options:
? #defineAF_FRAGMENTED 0x01
? #defineAF_ACK_REQUEST 0x10 //需要接收方的確認
? #defineAF_DISCV_ROUTE 0x20
? #defineAF_EN_SECURITY 0x40
# defineAF_SKIP_ROUTING 0x80
afAddrType_t
typedef struct { union { uint16 shortAddr; //短地址ZlongAddr_t extAddr;//長地址 byte ZLongAddr_t[8],8個8字節,即64位}addr; afAddrMode_t addrMode;//傳送模式 ,廣播/單點/間接...byte endPoint; //端點號 1-240,區分不同端點uint panID //網絡號 同一節點的網絡號相同 }afAddrType_t;endPointDesc_t 端點描述集群
typedef struct { byte endPoint; //端點號 byte* task_id; //指向任務的TASK_IDSimpleDescriptionFormat_t *simpleDesc; //簡單的端點描述 afNetworkLatencyReq_t latencyReq; //網路延遲請求:有noLaencyReqs/fastBeacons/slowBeacons.三種模式 }endPointDesc_t;afAddrMode_t 地址發送模式
typedef enum//afAddrMode_t數據傳送類型 { afAddrNotPresent = AddrNotPresent, //間接傳送,直接按照綁定表傳輸。 afAddr16Bit = Addr16Bit,//短地址傳輸,即點對點傳輸,在傳輸是需要設置addr.shortAddr為目的節點的16為地址 adAddr64bit = Addr64bit,//點對點,通過IEEE地址傳輸 afAddrGroup = AddrGroup,//傳輸在一個組內傳輸。地址模式設置為afAddGroup,且addr.shortAddr設置為組id。 afAddrBroadcast = AddrBroadcast //廣播傳送。 } afAddrMode_t;//數據傳送類型endPointDesc_t. 設備端點描述符
typedef struct {byte endPoint;byte *task_id; // Pointer to location of the Application task ID.SimpleDescriptionFormat_t *simpleDesc; //設備簡單描述符afNetworkLatencyReq_t latencyReq;} endPointDesc_t;//設備端點描述符SimpleDescriptionFormat_t 簡單描述符群集
typedef struct{ byte EndPoint; //EP uint16 AppProfId; //應用規范ID uint16 AppDeviceId; //特定規范ID的設備類型 byte AppDevVer:4; //特定規范ID的設備的版本 byte Reserved:4; byte AppNumInClusters;//輸入簇ID的個數 cId_t *pAppInClusterList;//輸入簇ID的列表的指針byte AppNumOutClusters; //輸出簇ID的個數 cId_t *pAppOutClusterList;//輸出簇ID的列表 的指針 }SimpleDescriptionFormat_t;afStatus_t
typedef enum {afStatus_SUCCESS,//0x00afStatus_FAILED ,//0x01afStatus_MEM_Error,//0x10afStatus_INVALID_PARAMETER,//0x02afStatus_NO_ROUTE//0xCD } afStatus_t;halUARTCfg_t類型 串口設置
typedef struct {bool configured;//uint8 baudRate;//bool flowControl;//uint16 flowControlThreshold;//uint8 idleTimeout;//如果在idleTimout 時間內RX還沒//有得到新的數據,將會觸發相應的事件HAL_UART_RX_TIMEOUT ,這時應用可以選擇讀出所有RX的值或者一部分。halUARTBufControl_t rx;//用于控制RX緩存halUARTBufControl_t tx;//用于控制TX緩存bool intEnable;//uint32 rxChRvdTime;//halUARTCBack_t callBackFunc;//回調函數 }halUARTCfg_t;osal_start_timeEx()
(一旦網絡狀態變化)進行任務初始化,設置任務,發送編號,設定時間函數幫助我們登記任務,設置編號,設定定時器時間。任務即確定在哪個task,編號則確定觸發什么事件,定時器則是間隔多久觸發這個事件。
Dev_States_t
網絡狀態結構體、定義了節點各個網絡狀態 typedef enum {DEV_HOLD, // Initialized - not started automaticallyDEV_INIT, // Initialized - not connected to anythingDEV_NWK_DISC, // Discovering PAN's to joinDEV_NWK_JOINING, // Joining a PANDEV_NWK_SEC_REJOIN_CURR_CHANNEL, // ReJoining a PAN in secure mode scanning in current channel, only for end devicesDEV_END_DEVICE_UNAUTH, // Joined but not yet authenticated by trust centerDEV_END_DEVICE, // Started as device after authenticationDEV_ROUTER, // Device joined, authenticated and is a routerDEV_COORD_STARTING, // Started as Zigbee CoordinatorDEV_ZB_COORD, // Started as Zigbee CoordinatorDEV_NWK_ORPHAN, // Device has lost information about its parent..DEV_NWK_KA, // Device is sending KeepAlive message to its parentDEV_NWK_BACKOFF, // Device is waiting before trying to rejoinDEV_NWK_SEC_REJOIN_ALL_CHANNEL, // ReJoining a PAN in secure mode scanning in all channels, only for end devicesDEV_NWK_TC_REJOIN_CURR_CHANNEL, // ReJoining a PAN in Trust center mode scanning in current channel, only for end devicesDEV_NWK_TC_REJOIN_ALL_CHANNEL // ReJoining a PAN in Trust center mode scanning in all channels, only for end devices } devStates_t;osalTimerRec_t結構體
typedef struct {void *next;uint16 timeout;uint16 event_flag;uint8 task_id;uint16 reloadTimeout; } osalTimerRec_t;消息的傳輸
afIncomingData()函數用來從APS層傳遞一個ASDU到AF層,中間調用afBuildMSGIncoming()函數,為APS層建立一個特定格式的消息包,最后調用osal_msg_send()把消息傳送到AF層。
處理AF層數據包的大致流程: afIncomingData() -> adBuildMSGIncoming()->osal_msg_send()->oasl_set_event()
setevent()
在tasksEvent數組中對應的taskid位置設置eventsuint8 osal_set_event( uint8 task_id, uint16 event_flag ) {if ( task_id < tasksCnt ){halIntState_t intState;HAL_ENTER_CRITICAL_SECTION(intState); // Hold off interruptstasksEvents[task_id] |= event_flag; // Stuff the event bit(s)HAL_EXIT_CRITICAL_SECTION(intState); // Release interruptsreturn ( SUCCESS );}else{return ( INVALID_TASK );} }AfIncomingData()
當節點收到數據時,會調用AfIncomingData()
afIncomingMSGPacket_t
接受發送的數據,afIncomingMSGPacket_t結構體為消息的封裝內容。 typedef struct {osal_event_hdr_t hdr; /* OSAL Message header */uint16 groupId; /* Message's group ID - 0 if not set */uint16 clusterId; /* Message's cluster ID */afAddrType_t srcAddr; /* Source Address, if endpoint is STUBAPS_INTER_PAN_EP,it's an InterPAN message */uint16 macDestAddr; /* MAC header destination short address */uint8 endPoint; /* destination endpoint */uint8 wasBroadcast; /* TRUE if network destination was a broadcast address */uint8 LinkQuality; /* The link quality of the received data frame */uint8 correlation; /* The raw correlation value of the received data frame */int8 rssi; /* The received RF power in units dBm */uint8 SecurityUse; /* deprecated */uint32 timestamp; /* receipt timestamp from MAC */afMSGCommandFormat_t cmd; /* Application Data */} afIncomingMSGPacket_t;//afIncomingMSGPacket_t gtwRxFromNode;// Generalized MSG Command Formattypedef struct // afMSGCommandFormat_t; {byte TransSeqNumber;uint16 DataLength; // Number of bytes in TransDatabyte *Data;} afMSGCommandFormat_t;數據的發送和接受
對接收方需要做的兩件事1)注冊一個端點,通過在XXXXApp_Init()函數里調用afRegister()來實現。如果需要處理ZDO消息和案件消息還得調用相應的注冊函數ZDO_RegisterForZDOMsg,RegisterForKeys。
2)注冊了端點和消息之后,需要寫一個消息處理函數,來響應各種消息,這個函數通常叫作XXXXApp_ProcessEvent()。
對于發送來說,事情就簡單了,只要調AF_DataRequest()函數,向指定的節點的端口發送數據即可。
從AF.C和AF.H可以看到端點是借助單向鏈表來管理的。用戶需要使用某個端點進行通訊時,先要調用afRegister注冊相應的端點向端點管理鏈表添加一條記錄。
端點一 注冊之后,在接收和發送兩個過程中都會使用到。
在接收過程,afIncomingData函數提取來自APS層數據包中的目標端點號,搜索節點已注冊的端點號,進行匹配。如果端點號匹配則需要進一步匹配應用配置ID,應用配置ID也匹配的語,數據包就會被打包,然后借助OSAL的消息機制,最終發送到相應端點應用對象的消息處理函數。
在發送過程,端點信息被AF_DataRequest讀取,填寫到數據包相關的區域,如果端點注冊了回調函數,回調函數將在數據發送前被調用。
數據收發過程中雙方必需指定端點號和網絡地址,這樣才能在一個節點中確定一個任務。一個端點對應一個任務,一個任務可以掛載多個端點。
端點里可以定義多個簇,發送的時候定義哪個端點中的哪個簇。
?Zstack Osal定時器事件觸發流程分析
系統事件的幾種類型。
系統事件觸發的條件。
Zstack對于端點的管理。(單項鏈表)
協調器和終端節點的設備號以及端點號可以都一樣嗎?是不是協調器有協調器的設備號和端點號,終端節點有終端節點的。二者不相干:
ProfileID必須一樣
DeviceID可以不一樣
Endpoint也可以不一樣,但是通信的時候必須要知道目的設備的Endpoint,負責無法通信上。
Profile ID只是一類應用的ID號,比方說智能家居,無線開關,溫度傳感器,doorlock,窗簾控制器等等,屬于智能家居的產品,那么他們的profile ID都是一樣的。智能家居是0x0104device ID是值一個profile ID下面,不同設備的id號,設置這個ID號的目的在于知道ID號,就知道這個設備具備哪些功能。
比方說一個on/off Light 和一個Dimmer Light的device id是不一樣的,功能不同。
總結
Q:
Zstack控制在代碼一樣的情況下將設備分別燒成協調器、終端,路由器。
流程整理
如果一個節點(Radio Unit)有多個終端設置,每增加一個終端節點,設置對應的taskid,并對其進行注冊,接入鏈表,終端節點是通過鏈表進行維護的,通過端點號對其進行查找;注冊完畢,對其進行初始化,然后為每一個taskid建立一個任務處理函數,對其進行操作。
總結
以上是生活随笔為你收集整理的zigbee 串口不稳定_Zigbee的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苹果手机怎么查看路由器密码苹果手机如何查
- 下一篇: 电脑硬盘坏了怎么修复电脑硬盘坏了怎么修复