第一篇:SimpleApp例程中兩種綁定機(jī)制程序流程
SimpleApp例程中兩種綁定機(jī)制程序流程
我使用的協(xié)議棧版本及例子信息: ZigBee2006ZStack-1.4.3-1.2.1個(gè)人注釋版_5.24ProjectszstackSamplesSimpleAppCC2430DB
建立一個(gè)綁定表格有3種方式:
(1)ZDO綁定請(qǐng)求:一個(gè)試運(yùn)轉(zhuǎn)的工具能告訴這個(gè)設(shè)備制作一個(gè)綁定報(bào)告
(2)ZDO終端設(shè)備綁定請(qǐng)求:設(shè)備能告訴協(xié)調(diào)器他們想建立綁定表格報(bào)告。該協(xié)調(diào)器將使協(xié)調(diào)并在這兩個(gè)設(shè)備上創(chuàng)建綁定表格條目。
(3)設(shè)備應(yīng)用:在設(shè)備上的應(yīng)用能建立或管理一個(gè)綁定表格。
有兩種可用的機(jī)制配置設(shè)備綁定:(1)如果目的設(shè)備的擴(kuò)展地址是已知的,則zb_BindDeviceRequest()函數(shù)能創(chuàng)建一個(gè)綁定條目。(2)如果擴(kuò)展地址是未知的,則一個(gè)“按鈕”可以利用。這樣的話,這個(gè)目的設(shè)備首先處于一種狀態(tài),它將被zb_AllowBindResponse()發(fā)出一個(gè)匹配響應(yīng);然后在源設(shè)備處,zb_AllowBindRequest()函數(shù)帶著空地址出發(fā).以上兩種綁定機(jī)制,最終都是用函數(shù)APSME_BindRequest()創(chuàng)建綁定。不同的是,前者采用的目的地址是64位擴(kuò)展地址,而后者采用的目的地址是16位網(wǎng)絡(luò)地址。前者已知擴(kuò)展地址,調(diào)用了ZDP_NwkAddrReq()函數(shù)獲得目的設(shè)備短地址;后者利用描述匹配得到了短地址,然后調(diào)用了ZDP_IEEEAddrReq()函數(shù),獲取目的設(shè)備的擴(kuò)展地址.************************************************************************************************************************** ************************************************************************************************************************** **************************************************************************************************************************
1、已知擴(kuò)展地址的綁定
這里可以直接調(diào)用函數(shù)zb_BindDevice()發(fā)起綁定請(qǐng)求:
zb_BindDevice(uint8 create,//是否創(chuàng)建綁定,TRUE則創(chuàng)建,FALSE則解除
uint16 commandId,//命令I(lǐng)D,基于某命令的綁定,相當(dāng)于簇
uint8 *pDestination)
//指向擴(kuò)展地址的指針
函數(shù)程序如下(已知擴(kuò)展地址的綁定部分)****************************************** void zb_BindDevice(uint8 create, uint16 commandId, uint8 *pDestination){
zAddrType_t destination;
uint8 ret = ZB_ALREADY_IN_PROGRESS;
if(create)//create = true 建立綁定
{
if(sapi_bindInProgress == 0xffff)//不允許綁定過程??
{ //--
if(pDestination)//已知擴(kuò)展地址的綁定,即*pDestination 為非NULL
{
destination.addrMode = Addr64Bit;
osal_cpyExtAddr(destination.addr.extAddr, pDestination);
//直接調(diào)用APS綁定請(qǐng)求函數(shù)
ret = APSME_BindRequest(sapi_epDesc.endPoint, //源EP
commandId,//簇ID &destination,//目的地址模式
sapi_epDesc.endPoint);//目的EP
if(ret == ZSuccess)//綁定成功
{
// Find nwk addr 發(fā)現(xiàn)網(wǎng)絡(luò)地址,得到被綁定設(shè)備的短地址
ZDP_NwkAddrReq(pDestination, ZDP_ADDR_REQTYPE_SINGLE, 0, 0);
osal_start_timerEx(ZDAppTaskID, ZDO_NWK_UPDATE_NV, 250);
}
} //--
else //未知目的擴(kuò)展地址,即*pDestination=NULL
{
ret = ZB_INVALID_PARAMETER;
destination.addrMode = Addr16Bit;
destination.addr.shortAddr = NWK_BROADCAST_SHORTADDR;//0xffff 描述符匹配請(qǐng)求:廣播
/*如果commandId是輸出簇,則檢測(cè)是否與本終端輸出簇列表中的某一項(xiàng)相匹配(相同)*/
if(ZDO_AnyClusterMatches(1, &commandId, sapi_epDesc.simpleDesc->AppNumOutClusters,sapi_epDesc.simpleDesc->pAppOutClusterList))
{
// Try to match with a device in the allow bind mode 尋找一個(gè)允許匹配狀態(tài)下的設(shè)備進(jìn)行描述符匹配
ret = ZDP_MatchDescReq(&destination, NWK_BROADCAST_SHORTADDR,sapi_epDesc.simpleDesc->AppProfId, 1, &commandId, 0,(cId_t *)NULL, 0);
}
/*如果commandId是輸入簇,則檢測(cè)是否與本終端輸入簇列表中的某一項(xiàng)相匹配(相同)*/
else if(ZDO_AnyClusterMatches(1, &commandId, sapi_epDesc.simpleDesc->AppNumInClusters,sapi_epDesc.simpleDesc->pAppInClusterList))
{
//尋找一個(gè)允許匹配狀態(tài)下的設(shè)備進(jìn)行描述符匹配
ret = ZDP_MatchDescReq(&destination, NWK_BROADCAST_SHORTADDR,sapi_epDesc.simpleDesc->AppProfId, 0,(cId_t *)NULL, 1, &commandId, 0);
}
if(ret == ZB_SUCCESS)
{
// Set a timer to make sure bind completes
osal_start_timerEx(sapi_TaskID, ZB_BIND_TIMER, AIB_MaxBindingTime);
sapi_bindInProgress = commandId;
return;// dont send cback event
}
} //--
}
SAPI_SendCback(SAPICB_BIND_CNF, ret, commandId);
}
else //create = false 刪除綁定
{
// Remove local bindings for the commandId
BindingEntry_t *pBind;
// Loop through bindings an remove any that match the cluster
while(pBind = bindFind(sapi_epDesc.simpleDesc->EndPoint, commandId, 0))
{
bindRemoveEntry(pBind);
}
osal_start_timerEx(ZDAppTaskID, ZDO_NWK_UPDATE_NV, 250);
}
return;} ****************************************** 在上面已知擴(kuò)展地址的綁定程序中調(diào)用了APS綁定函數(shù)APSME_BindRequest(),這個(gè)函數(shù)在兩個(gè)設(shè)備間建立綁定,通過APSME_BIND.confirm原語返回,而且這兩者是不可分割的。如果綁定成功,則調(diào)用函數(shù)ZDP_NwkAddrReq()得到目的設(shè)備的短地址。ZDP_NwkAddrReq()這個(gè)函數(shù)可以產(chǎn)生一個(gè)根據(jù)已知遙遠(yuǎn)設(shè)備的IEEE地址,請(qǐng)求得到16位短地址的信息.該信息以廣播的方式發(fā)送給網(wǎng)絡(luò)中的所有設(shè)備.2、未知擴(kuò)展地址的綁定(simpApp例子中默認(rèn)的綁定機(jī)制)該綁定方式下,在發(fā)送綁定請(qǐng)求前,先要讓被綁定的目的設(shè)備處于允許綁定模式。可以調(diào)用函數(shù)zb_AllowBind()進(jìn)入該模式,函數(shù)如下:
****************************************** //函數(shù)設(shè)置設(shè)備處于允許綁定模式 //timerout=0x00:不允許綁定 //timerout=0xff:一直處于綁定模式
//0 osal_stop_timerEx(sapi_TaskID, ZB_ALLOW_BIND_TIMER); if(timeout == 0) { afSetMatch(sapi_epDesc.simpleDesc->EndPoint, FALSE); } else { afSetMatch(sapi_epDesc.simpleDesc->EndPoint, TRUE);//設(shè)置允許響應(yīng)匹配描述符請(qǐng)求 if(timeout!= 0xFF) { if(timeout > 64) { timeout = 64; } //設(shè)置了允許匹配后,開啟一個(gè)定時(shí)器,時(shí)間為timeout*1000,//時(shí)間一到觸發(fā)sapi任務(wù)ZB_ALLOW_BIND_TIMER事件,SAPI_ProcessEvent()對(duì)其的處理是 //afSetMatch(sapi_epDesc.simpleDesc->EndPoint, FALSE)而取消允許綁定 osal_start_timerEx(sapi_TaskID, ZB_ALLOW_BIND_TIMER, timeout*1000); } } return;} ****************************************** 參數(shù)timeout是進(jìn)入綁定模式持續(xù)的時(shí)間(s)。如果設(shè)置為OxFF,則設(shè)備在任何時(shí)候都在允許綁定模式;如果設(shè)置為OxOO,則設(shè)備將通過該命令取消允許綁定模式.調(diào)用該函數(shù)使設(shè)備在給定時(shí)間內(nèi)進(jìn)入允許綁定模式.一個(gè)在允許綁定模式下同等的設(shè)備調(diào)用函數(shù)zb_BindDevice()能與之建立綁定,此時(shí)目的擴(kuò)展地址為空(參見上面zb_BindDevice()未知目的擴(kuò)展地址部分).zb_AllowBind()調(diào)用afSetMatch(),使之允許響應(yīng)ZDO的匹配描述符請(qǐng)求.以上設(shè)置目的設(shè)備允許綁定模式(比如simpleApp的燈設(shè)備),那在目的設(shè)備處于允許綁定模式的時(shí)間內(nèi),源設(shè)備(比如simpleApp的開關(guān)設(shè)備)可以調(diào)用zb_BindDevice()來發(fā)起綁定請(qǐng)求.此時(shí)執(zhí)行的程序如下: ****************************************** void zb_BindDevice(uint8 create, uint16 commandId, uint8 *pDestination){ ………… //-- else //未知目的擴(kuò)展地址,即*pDestination=NULL { ret = ZB_INVALID_PARAMETER; destination.addrMode = Addr16Bit; destination.addr.shortAddr = NWK_BROADCAST_SHORTADDR;//0xffff /*如果commandId是輸出簇,則檢測(cè)是否與本終端輸出簇列表中的某一項(xiàng)相匹配(相同)*/ if(ZDO_AnyClusterMatches(1, &commandId, sapi_epDesc.simpleDesc->AppNumOutClusters,sapi_epDesc.simpleDesc->pAppOutClusterList)) { // Try to match with a device in the allow bind mode //尋找一個(gè)允許匹配狀態(tài)下的設(shè)備進(jìn)行描述符匹配 ret = ZDP_MatchDescReq(&destination, NWK_BROADCAST_SHORTADDR,sapi_epDesc.simpleDesc->AppProfId, 1, &commandId, 0,(cId_t *)NULL, 0); } /*如果commandId是輸入簇,則檢測(cè)是否與本終端輸入簇列表中的某一項(xiàng)相匹配(相同)*/ else if(ZDO_AnyClusterMatches(1, &commandId, sapi_epDesc.simpleDesc->AppNumInClusters,sapi_epDesc.simpleDesc->pAppInClusterList)) { //尋找一個(gè)允許匹配狀態(tài)下的設(shè)備進(jìn)行描述符匹配 ret = ZDP_MatchDescReq(&destination, NWK_BROADCAST_SHORTADDR,sapi_epDesc.simpleDesc->AppProfId, 0,(cId_t *)NULL, 1, &commandId, 0); } if(ret == ZB_SUCCESS) { // Set a timer to make sure bind completes 設(shè)置一個(gè)時(shí)間,確保綁定完成 osal_start_timerEx(sapi_TaskID, ZB_BIND_TIMER, AIB_MaxBindingTime); sapi_bindInProgress = commandId;//允許基于commandId命令的綁定過程 return;// dont send cback event } } //--………… } ****************************************** 在之中調(diào)用了函數(shù)ZDP_MatchDescReq(),將建立和發(fā)送一個(gè)匹配描述符請(qǐng)求。用這個(gè)函數(shù)在一個(gè)應(yīng)用中的輸入/輸出簇列表中搜索匹配某條件的設(shè)備/應(yīng)用。該綁定響應(yīng)處理在SAPI_ProcessEvent事件處理函數(shù)中 case ZDO_CB_MSG: /*ZDO信息數(shù)據(jù)*/ SAPI_ProcessZDOMsgs((zdoIncomingMsg_t *)pMsg);看下SAPI_ProcessZDOMsgs()函數(shù) ****************************************** // SAPI_Init()函數(shù)中注冊(cè)了以下兩個(gè)ZDO信息 // ZDO_RegisterForZDOMsg(sapi_TaskID, NWK_addr_rsp);// ZDO_RegisterForZDOMsg(sapi_TaskID, Match_Desc_rsp);void SAPI_ProcessZDOMsgs(zdoIncomingMsg_t *inMsg){ switch(inMsg->clusterID) { //-------------------- case NWK_addr_rsp: ………… //-------------------- case Match_Desc_rsp: { zAddrType_t dstAddr; ZDO_ActiveEndpointRsp_t *pRsp = ZDO_ParseEPListRsp(inMsg); if(sapi_bindInProgress!= 0xffff)//commandId { // Create a binding table entry 創(chuàng)建一個(gè)綁定條目 dstAddr.addrMode = Addr16Bit; dstAddr.addr.shortAddr = pRsp->nwkAddr; /*調(diào)用這個(gè)函數(shù)來實(shí)現(xiàn)兩個(gè)設(shè)備的綁定*/ if(APSME_BindRequest(sapi_epDesc.simpleDesc->EndPoint, //源EP sapi_bindInProgress,//簇ID &dstAddr,//目的地址模式 pRsp->epList[0])== ZSuccess) //目的EP //成功實(shí)現(xiàn)綁定后 { //zb_BindDevice()中開啟了一個(gè)定時(shí)器,用于接收Match_Desc_rsp計(jì)時(shí) //如果接收到,則停止這個(gè)定時(shí)器,如下;如果溢出,則觸發(fā)相應(yīng)任務(wù)事件 osal_stop_timerEx(sapi_TaskID, ZB_BIND_TIMER); osal_start_timerEx(ZDAppTaskID, ZDO_NWK_UPDATE_NV, 250); sapi_bindInProgress = 0xffff; // Find IEEE addr ZDP_IEEEAddrReq(pRsp->nwkAddr, ZDP_ADDR_REQTYPE_SINGLE, 0, 0); // Send bind confirm callback to application zb_BindConfirm(sapi_bindInProgress, ZB_SUCCESS); } } } break; } } ****************************************** 以上內(nèi)容摘自《zigbee2006無線網(wǎng)絡(luò)與無線定位實(shí)戰(zhàn)》這本書,根據(jù)協(xié)議版本的不同作了一些修改。 實(shí)例中的兩種綁定機(jī)制,第一種(已知擴(kuò)展地址的綁定)流程,就是zb_BindDevice()根據(jù)擴(kuò)展地址直接調(diào)用APSME_BindRequest()創(chuàng)建綁定條目實(shí)現(xiàn)綁定,再得到其16位網(wǎng)絡(luò)地址;第二種(未知擴(kuò)展地址的綁定),因地址未知,須先經(jīng)過一個(gè)描述符匹配過程得到相匹配設(shè)備的16位短地址,然后通過APSME_BindRequest()創(chuàng)建綁定條目實(shí)現(xiàn)綁定,再得到其擴(kuò)展地址.下面引用《zigbee2006無線網(wǎng)絡(luò)與無線定位實(shí)戰(zhàn)》對(duì)未知擴(kuò)展地址的綁定流程的描述(以simpApp燈開關(guān)實(shí)驗(yàn)為例),根據(jù)協(xié)議版本不同作了相應(yīng)修改:(1)首先調(diào)用zb_AllowBind(myAllowBindTimeout)函數(shù),使管理設(shè)備(燈)處于允許綁定(匹配)響應(yīng)模式 (2)在myAllowBindTimeout規(guī)定的時(shí)間內(nèi),終端設(shè)備需要調(diào)用zb_BindDevice(TRUE, TOGGLE_LIGHT_CMD_ID,NULL)函數(shù)發(fā)送綁定(描述符匹配ZDP_MatchDescReq)請(qǐng)求.(3)當(dāng)管理器接收到匹配請(qǐng)求后,對(duì)該匹配作出響應(yīng),發(fā)送一個(gè)匹配響應(yīng)(P:在ZDO_ProcessMatchDescReq()函 數(shù)中),之后可以看到發(fā)送匹配響應(yīng)后的確認(rèn)事件(P:在ZDO_ProcessMatchDescReq()函數(shù)中): pRspSent->hdr.event = ZDO_MATCH_DESC_RSP_SENT;(4)當(dāng)終端接收到匹配響應(yīng)后,產(chǎn)生該事件: case Match_Desc_rsp: 該事件詳細(xì)處理過程參見SAPI_ProcessZDOMsgs,這里面調(diào)用了APSME_BindRequest()建立綁定,而且調(diào)用 了ZDP_IEEEAddrReq()得到被綁定的IEEE地址.(5)最后完成綁定,在終端設(shè)備建立綁定表格.一開始看書上這匹配過程還是蠻糾結(jié)的,下面詳細(xì)記錄下個(gè)人對(duì)未知擴(kuò)展地址的綁定流程的理解: ************************************************************************************************************************** ************************************************************************************************************************** ************************************************************************************************************************** 首先理清兩個(gè)節(jié)點(diǎn),以燈開關(guān)實(shí)驗(yàn)為例: 管理器(燈) 終端(開關(guān)) 1、-------------允許綁定模式----------------------- ---------- 2、------------- --<----<---<--------廣播發(fā)送描述符匹配請(qǐng)求(綁定請(qǐng)求) 3、-----接收后發(fā)送描述符匹配響應(yīng)-->--->--->-- ----------- 4、------------- ---------------接收后獲得管理器地址,建立終端與管理器間的綁定--- 第一步:管理器處于允許綁定模式,參見上面的記錄 第二步:終端調(diào)用zb_BindDevice()發(fā)送描述符匹配請(qǐng)求(即綁定請(qǐng)求)給管理器.zb_BindDevice()調(diào)用ZDP_MatchDescReq(): ****************************************** //函數(shù)建立和發(fā)送一個(gè)匹配描述請(qǐng)求.燈開關(guān)實(shí)驗(yàn)zb_BindDevice()中初始化為廣播: //destination.addr.shortAddr = NWK_BROADCAST_SHORTADDR;//使用這個(gè)函數(shù)查詢與應(yīng)用程序輸入或輸出簇列表相匹配的應(yīng)用程序或設(shè)備.//即發(fā)現(xiàn)服務(wù),或者叫自動(dòng)尋求匹配設(shè)備。afStatus_t ZDP_MatchDescReq(zAddrType_t *dstAddr, //目的地址類型 uint16 nwkAddr,//16位目的網(wǎng)絡(luò)地址 uint16 ProfileID,byte NumInClusters, cId_t *InClusterList,//簇輸入列表簇ID數(shù)及簇ID輸入數(shù)組 byte NumOutClusters, cId_t *OutClusterList, //簇輸出列表簇ID數(shù)及簇ID輸出數(shù)組 byte SecurityEnable){ /*指針pBuf指向ZDP_TmpBuf,下面為配置數(shù)組ZDP_TmpBuf[ ]*/ byte *pBuf = ZDP_TmpBuf;//ZDP_TmpBuf=ZDP_Buf+1;ZDP_Buf[80] // nwkAddr+ProfileID+NumInClusters+NumOutClusters.byte i, len = 2 + 2 + 1 + 1;// nwkAddr+ProfileID+NumInClusters+NumOutClusters.len +=(NumInClusters + NumOutClusters)* sizeof(uint16); if(len >= ZDP_BUF_SZ-1) { return afStatus_MEM_FAIL; } *pBuf++ = LO_UINT16(nwkAddr); // NWKAddrOfInterest *pBuf++ = HI_UINT16(nwkAddr); *pBuf++ = LO_UINT16(ProfileID); // Profile ID *pBuf++ = HI_UINT16(ProfileID); //------------------------- *pBuf++ = NumInClusters;// Input cluster list if(NumInClusters) { for(i=0;i *pBuf++ = LO_UINT16(InClusterList[i]); *pBuf++ = HI_UINT16(InClusterList[i]); } } //------------------------- *pBuf++ = NumOutClusters;// Output cluster list if(NumOutClusters) { for(i=0;i *pBuf++ = LO_UINT16(OutClusterList[i]); *pBuf++ = HI_UINT16(OutClusterList[i]); } } //------------------------- //注意這里clusterID設(shè)置為Match_Desc_req return fillAndSend(&ZDP_TransID, dstAddr, Match_Desc_req, len);} ****************************************** ZDP_MatchDescReq()中配置了clusterID=Match_Desc_req,dstAddr為廣播,數(shù)據(jù)為ZDP_TmpBuf的信息,通過fillAndSend()來發(fā)送,看下fillAndSend(): ****************************************** static afStatus_t fillAndSend(uint8 *transSeq, zAddrType_t *addr, cId_t clusterID, byte len){ afAddrType_t afAddr; ZADDR_TO_AFADDR(addr, afAddr); *(ZDP_TmpBuf-1)= *transSeq; return AF_DataRequest(&afAddr, &ZDApp_epDesc, clusterID,(uint16)(len+1),(uint8*)(ZDP_TmpBuf-1),transSeq, ZDP_TxOptions, AF_DEFAULT_RADIUS);} ****************************************** 可以看到fillAndSend()最終調(diào)用AF_DataRequest()來廣播發(fā)送描述符匹配請(qǐng)求.第三步:管理器接收到終端發(fā)送的描述符匹配請(qǐng)求(也即綁定請(qǐng)求).那管理器是如何作出處理的? 因?yàn)閆DO層是管理綁定的(綁定表建在APS中),管理器接收到的描述符匹配請(qǐng)求是發(fā)往其ZDO層的,首先來看下這個(gè)函數(shù):ZDP_IncomingData()****************************************** * @fn ZDP_IncomingData * * @brief This function indicates the transfer of a data PDU(ASDU)* from the APS sub-layer to the ZDO.* * @param pData-Incoming Message * * @return none */ //APS-->ZDO void ZDP_IncomingData(afIncomingMSGPacket_t *pData){ uint8 x = 0; uint8 handled; zdoIncomingMsg_t inMsg; inMsg.srcAddr.addrMode = Addr16Bit; inMsg.srcAddr.addr.shortAddr = pData->srcAddr.addr.shortAddr; inMsg.wasBroadcast = pData->wasBroadcast; inMsg.clusterID = pData->clusterId; inMsg.SecurityUse = pData->SecurityUse; inMsg.asduLen = pData->cmd.DataLength-1; inMsg.asdu = pData->cmd.Data+1; inMsg.TransSeq = pData->cmd.Data[0]; //通過 ZDO_SendMsgCBs()這個(gè)函數(shù)把ZDO信息發(fā)送到注冊(cè)過ZDO信息的任務(wù)中去.//比如sapi中SAPI_Init()注冊(cè)過兩種類型clusterId的ZDO信息:NWK_addr_rsp 和 Match_Desc_rsp //因此其它命令,比如請(qǐng)求命令不會(huì)發(fā)送到sapi應(yīng)用層中 //注意,End_Device_Bind_req這個(gè)ZDO信息是注冊(cè)在ZDAppTaskID任務(wù)中的.handled = ZDO_SendMsgCBs(&inMsg);#if defined(MT_ZDO_FUNC) MT_ZdoRsp(&inMsg);#endif //注意,這里只會(huì)對(duì)請(qǐng)求/設(shè)置/通知命令才調(diào)用相應(yīng)處理函數(shù),如果是響應(yīng)命令則不處理 //但是要ZDO信息處理表中包含的命令才有相應(yīng)的處理函數(shù),有些沒有的就不會(huì)調(diào)用 //比如End_Device_Bind_req,這個(gè)很重要,它在哪里被處理呢?在ZDApp層任務(wù)中,//函數(shù)ZDApp_RegisterCBs()把這個(gè)請(qǐng)求命令登記到了ZDAppTaskID,具體參見ZDApp_RegisterCBs() while(zdpMsgProcs[x].clusterID!= 0xFFFF)//一個(gè)個(gè)查詢過去 { if(zdpMsgProcs[x].clusterID == inMsg.clusterID) { zdpMsgProcs[x].pFn(&inMsg);//調(diào)用相應(yīng)ZDO信息處理函數(shù) return; //如x=6,為ZDO_ProcessMatchDescReq(); } x++; } // Handle unhandled message if(!handled) ZDApp_InMsgCB(&inMsg);} ****************************************** 這里涉及到三個(gè)函數(shù):ZDO_SendMsgCBs();zdpMsgProcs[x].pFn(&inMsg);ZDApp_InMsgCB(1)ZDO_SendMsgCBs():把ZDO接收信息發(fā)送到注冊(cè)過ZDO信息的任務(wù)中去;具體流程是比較接收信息的簇ID與注冊(cè)過的簇ID,有相同則調(diào)用osal_msg_send()觸發(fā)相應(yīng)任務(wù)事件,事件這里默認(rèn)為ZDO_CB_MSG,因此可以看到SAPI_ProcessEvent()中有這個(gè)事件.注意這個(gè)函數(shù)只會(huì)傳送信息到注冊(cè)過相應(yīng)ZDO信息的任務(wù)中去.(2)對(duì)于zdpMsgProcs[x].pFn(&inMsg),ZDProfile.c如下定義: //把pfnZDPMsgProcessor聲明為一種函數(shù)指針的類型別明,指向類似Fun(*inMsg)這種類型 //的函數(shù).如果用此別名來聲明一個(gè)指針變量,如:pfnZDPMsgProcessor pFn,則當(dāng)pFn獲取 //函數(shù)的地址后,就可以像調(diào)用原函數(shù)一樣來使用這個(gè)函數(shù)指針:pFn(*inMsg)typedef void(*pfnZDPMsgProcessor)(zdoIncomingMsg_t *inMsg);typedef struct { uint16 clusterID; pfnZDPMsgProcessor pFn;} zdpMsgProcItem_t;//定義一個(gè)zdpMsgProcItem_t類型的數(shù)組zdpMsgProcs[],則數(shù)組zdpMsgProcs[]中 //的每個(gè)元素都是zdpMsgProcItem_t類型的結(jié)構(gòu)體:{clusterID,pFn} CONST zdpMsgProcItem_t zdpMsgProcs[ ] = { { NWK_addr_req,zdpProcessAddrReq },{ IEEE_addr_req,zdpProcessAddrReq },{ Node_Desc_req,ZDO_ProcessNodeDescReq },{ Power_Desc_req,ZDO_ProcessPowerDescReq },{ Simple_Desc_req,ZDO_ProcessSimpleDescReq },{ Active_EP_req,ZDO_ProcessActiveEPReq },{ Match_Desc_req,ZDO_ProcessMatchDescReq },…………(后面省略) {0xFFFF, NULL} // Last };(3)ZDApp_InMsgCB():函數(shù)說明如下: * @brief This function is called to pass up any message that is * not yet supported.This allows for the developer to * support features themselves..這函數(shù)我就不去管了.回到剛才問題:管理器接收到描述符匹配請(qǐng)求后是如何處理的? 因?yàn)檫@里是接收到描述符匹配請(qǐng)求,SAPI_Init中沒有注冊(cè)過這個(gè)ZDO信息,因此不會(huì)通過ZDO_SendMsgCBs()發(fā)送到sapi應(yīng)用.然后查詢ZDO信息處理表,當(dāng)x=6時(shí)發(fā)現(xiàn)命令相符,調(diào)用ZDO_ProcessMatchDescReq()對(duì)描述符匹配請(qǐng)求進(jìn)行處理.下面來看下ZDO_ProcessMatchDescReq()函數(shù): ****************************************** void ZDO_ProcessMatchDescReq(zdoIncomingMsg_t *inMsg){ ………… // Parse the incoming message ………… //--------------------------發(fā)送描述符匹配請(qǐng)求的響應(yīng) if(ADDR_BCAST_NOT_ME == NLME_IsAddressBroadcast(aoi)) { ZDP_MatchDescRsp(inMsg->TransSeq, &(inMsg->srcAddr), ZDP_INVALID_REQTYPE,ZDAppNwkAddr.addr.shortAddr, 0, NULL, inMsg->SecurityUse); return; } else if((ADDR_NOT_BCAST == NLME_IsAddressBroadcast(aoi))&&(aoi!= ZDAppNwkAddr.addr.shortAddr)) { ZDP_MatchDescRsp(inMsg->TransSeq, &(inMsg->srcAddr), ZDP_INVALID_REQTYPE,ZDAppNwkAddr.addr.shortAddr, 0, NULL, inMsg->SecurityUse); return; } //-------------------------- ………… //發(fā)送匹配響應(yīng)后的確認(rèn)事件ZDO_MATCH_DESC_RSP_SENT pRspSent->hdr.event = ZDO_MATCH_DESC_RSP_SENT; ………… osal_msg_send(*epDesc->epDesc->task_id,(uint8 *)pRspSent); ………… } ****************************************** 可以看到這里管理器首先通過ZDP_MatchDescRsp()發(fā)送匹配響應(yīng)給終端.而ZDP_MatchDescRsp()宏定義為ZDP_EPRsp(),ZDP_EPRsp()設(shè)置clusterID為Match_Desc_rsp并調(diào)用FillAndSendTxOptions(),F(xiàn)illAndSendTxOptions()中調(diào)用fillAndSend(),fillAndSend()中最終調(diào)用AF_DataRequest()來發(fā)送匹配響應(yīng)給終端(燈).發(fā)送完匹配響應(yīng)后管理器觸發(fā)一個(gè)確認(rèn)事件ZDO_MATCH_DESC_RSP_SENT,來指示有個(gè)設(shè)備試圖與自己綁定.管理器是如何對(duì)這個(gè)確認(rèn)事件進(jìn)行處理的?如下: SAPI_ProcessEvent()中對(duì)ZDO_MATCH_DESC_RSP_SENT的處理: case ZDO_MATCH_DESC_RSP_SENT: /*發(fā)送匹配響應(yīng)*/ SAPI_AllowBindConfirm(((ZDO_MatchDescRspSent_t *)pMsg)->nwkAddr);來看下SAPI_AllowBindConfirm()這個(gè)函數(shù): ****************************************** * @fn SAPI_AllowBindConfirm * * @brief Indicates when another device attempted to bind to this device * * @param * * @return none */ void SAPI_AllowBindConfirm(uint16 source){ #if defined(MT_SAPI_CB_FUNC) /* First check if MT has subscribed for this callback.If so , pass it as a event to MonitorTest and return control to calling function after that */ if(SAPICB_CHECK(SPI_CB_SAPI_ALLOW_BIND_CNF)) { zb_MTCallbackAllowBindConfirm(source);//這里應(yīng)該是把請(qǐng)求匹配的設(shè)備的網(wǎng)絡(luò)地址通過串口發(fā)PC } else #endif //MT_SAPI_CB_FUNC { zb_AllowBindConfirm(source);//未定義 } } ****************************************** 管理器接收到終端發(fā)送的描述符匹配請(qǐng)求后,發(fā)送一個(gè)描述符匹配請(qǐng)求的響應(yīng)給終端,并觸發(fā)一個(gè)確認(rèn)事件指示有個(gè)設(shè)備試圖與本設(shè)備進(jìn)行綁定.第四步:終端接收到管理器發(fā)送的描述符匹配響應(yīng).同樣,這個(gè)響應(yīng)信息也是發(fā)往ZDO層的,因此首先要來看ZDP_IncomingData()這個(gè)函數(shù),具體見第三步.因?yàn)榻邮盏降捻憫?yīng)信息clusterID為Match_Desc_rsp,SAPI_Init注冊(cè)過,因此會(huì)通過ZDO_SendMsgCBs()把這個(gè)描述符匹配響應(yīng)信息發(fā)送到sapi應(yīng)用層,而在ZDO信息處理表中查詢不到相符合的clusterID,因此不會(huì)調(diào)用任何處理函數(shù).這里剛好與第二步中對(duì)描述符匹配請(qǐng)求的處理相反.下面來看下ZDO_SendMsgCBs()把這個(gè)描述符匹配響應(yīng)信息發(fā)送到sapi應(yīng)用層后的處理,ZDO_SendMsgCBs()發(fā)送的流程參見第三步,其最終觸發(fā)任務(wù)sapi的ZDO_CB_MSG事件,而sapi任務(wù)事件處理函數(shù)SAPI_ProcessEvent()通過調(diào)用SAPI_ProcessZDOMsgs()對(duì)其進(jìn)行處理: case ZDO_CB_MSG: /*ZDO信息*/ SAPI_ProcessZDOMsgs((zdoIncomingMsg_t *)pMsg); break;來看下SAPI_ProcessZDOMsgs(): ****************************************** // SAPI_Init()函數(shù)中注冊(cè)了以下兩個(gè)ZDO信息 // ZDO_RegisterForZDOMsg(sapi_TaskID, NWK_addr_rsp);// ZDO_RegisterForZDOMsg(sapi_TaskID, Match_Desc_rsp);void SAPI_ProcessZDOMsgs(zdoIncomingMsg_t *inMsg){ switch(inMsg->clusterID) { //-------------------- case NWK_addr_rsp: { ………… break; //-------------------- case Match_Desc_rsp: { zAddrType_t dstAddr; ZDO_ActiveEndpointRsp_t *pRsp = ZDO_ParseEPListRsp(inMsg); if(sapi_bindInProgress!= 0xffff)//允許基于commandID的綁定 { // Create a binding table entry 創(chuàng)建一個(gè)綁定條目 dstAddr.addrMode = Addr16Bit; dstAddr.addr.shortAddr = pRsp->nwkAddr;//通過描述符匹配響應(yīng)信息得到管理器的網(wǎng)絡(luò)地址 /*調(diào)用這個(gè)函數(shù)來實(shí)現(xiàn)兩個(gè)設(shè)備的綁定*/ if(APSME_BindRequest(sapi_epDesc.simpleDesc->EndPoint, //源EP sapi_bindInProgress,//簇ID &dstAddr,//目的地址模式 pRsp->epList[0])== ZSuccess) //目的EP //成功實(shí)現(xiàn)綁定后 { //zb_BindDevice()中開啟了一個(gè)定時(shí)器,用于接收Match_Desc_rsp計(jì)時(shí) //如果接收到,則停止這個(gè)定時(shí)器,如下;如果溢出,則觸發(fā)相應(yīng)任務(wù)事件 osal_stop_timerEx(sapi_TaskID, ZB_BIND_TIMER); osal_start_timerEx(ZDAppTaskID, ZDO_NWK_UPDATE_NV, 250); sapi_bindInProgress = 0xffff;//不允許綁定過程 // Find IEEE addr ZDP_IEEEAddrReq(pRsp->nwkAddr, ZDP_ADDR_REQTYPE_SINGLE, 0, 0); // Send bind confirm callback to application //告訴應(yīng)用綁定成功 zb_BindConfirm(sapi_bindInProgress, ZB_SUCCESS); } } } break; } } ****************************************** 可以看到通過接收到的描述符匹配響應(yīng)信息,終端獲得允許綁定模式下管理器的16位網(wǎng)絡(luò)地址: dstAddr.addr.shortAddr = pRsp->nwkAddr;最終調(diào)用APSME_BindRequest()來綁定終端設(shè)備與管理器.引用《ZigBee四種綁定方式在TI Z-Stack中的應(yīng)用》的一段話: 一、“終端設(shè)備綁定請(qǐng)求”這一命名有誤導(dǎo)的嫌疑。這一請(qǐng)求不僅僅適用于終端設(shè)備,而且適用于對(duì)希望在協(xié)調(diào)器上綁定的兩個(gè)設(shè)備中匹配的簇實(shí)施綁定。一旦這個(gè)函數(shù)被調(diào)用,將假設(shè)REFLECTOR這一編譯選項(xiàng)在所有希望使用這一服務(wù)的節(jié)點(diǎn)中都已經(jīng)打開。具體操作如下: (1) (Bind Req)Device 1--> Coordinator <---Device 2(Bind Req)協(xié)調(diào)器首先找出包含在綁定請(qǐng)求中的簇,然后對(duì)比每一設(shè)備的IEEE地址,如果簇可以匹配,而且這幾個(gè)設(shè)備沒有已經(jīng)存在的綁定表,那他將發(fā)送一個(gè)綁定應(yīng)答給每一個(gè)設(shè)備。(2) Device 1 <---NWK Addr Req------Coordinator-------NWK addr Req----> Device 2(3) Device 1----> NWK Addr Rsp---> Coordinator <----NWK addr Rsp <---Device 2(4) Device 1 <-----Bind Rsp <-----Coordinator-----> Bind Rsp----> Device 2 二、“描述符匹配”為源設(shè)備的服務(wù)發(fā)現(xiàn)提供了一種靈巧的方法。下面是具體的操作,這一過程并沒有通過協(xié)調(diào)器。(1) Device 1----> Match Descriptor request(broadcast or unicast)Device 2(2) Device 1 <----Match Descriptor response(if clusters, application profile id match)that includes src endpoint, src address <----Device 2 1號(hào)設(shè)備需要維護(hù)一個(gè)端點(diǎn)和地址的記錄。許多應(yīng)用服務(wù)最終都會(huì)使用第二種方法。 說明: 眼睛花了…… 1、本文作者所記錄,錯(cuò)誤之處還請(qǐng)高手指點(diǎn),本人隨時(shí)更新.2、歡迎交流,轉(zhuǎn)載請(qǐng)注明出處,謝謝! 3、具體請(qǐng)參考《SimpleApp和GenericApp實(shí)例綁定程序流程》 2010.6.01 ~XF 勞動(dòng)保險(xiǎn)處業(yè)務(wù)經(jīng)辦流程中需局各科室 協(xié)調(diào)辦理程序及建議 一、單位新增參保人員 企業(yè)勞資人員需先到就業(yè)處辦理參加社會(huì)保險(xiǎn)人員增加花名冊(cè)/備案花名冊(cè)后,再到3號(hào)窗口辦理單位新增參保人員。 建議:參照市局流程,簡化單位新增人員參保手續(xù),可否由企業(yè)勞資人員攜帶參保人員第二代身份證復(fù)印件兩張及參保人員近期1寸免冠照片2張直接到保險(xiǎn)處3號(hào)窗口辦理新增手續(xù)。 二、單位減少參保人員 企業(yè)勞資人員需先到勞動(dòng)仲裁科辦理解除(終止)勞動(dòng)關(guān)系后停止養(yǎng)老保險(xiǎn)通知書后,再到3號(hào)窗口辦理單位減少參保人員手續(xù)。 建議:參照市局現(xiàn)行流程,簡化單位減少參保人員手續(xù),可否根據(jù)簽訂和解除勞動(dòng)合同自愿簽證原則,由用人單位持解除勞動(dòng)關(guān)系證明書直接到3號(hào)窗口辦理減員手續(xù)。 三、農(nóng)保轉(zhuǎn)企保 勞保所工作人員持就業(yè)處辦理的宿遷市宿豫區(qū)錄用勞動(dòng)合同制職工花名冊(cè)和用工(退工)人員登記表到農(nóng)保處辦理老農(nóng)保轉(zhuǎn)企保人員花名冊(cè),再到勞動(dòng)保險(xiǎn)處209室辦理農(nóng)保轉(zhuǎn)企保手續(xù)。 建議:由農(nóng)保處派專人負(fù)責(zé)辦理該項(xiàng)業(yè)務(wù),盡量為服務(wù)對(duì)象提供方便。 四、養(yǎng)老金待遇審核 擬退休人員先到工資科辦理退休審批手續(xù),按工資科核準(zhǔn)時(shí)間至社保服務(wù)大廳14、15號(hào)窗口進(jìn)行養(yǎng)老賬戶維護(hù)(如有欠費(fèi)需足額繳費(fèi)后方可辦理相關(guān)手續(xù)),養(yǎng)老賬戶維護(hù)完畢后至勞動(dòng)保險(xiǎn)處207室審核養(yǎng)老待遇并打印《宿豫區(qū)企業(yè)職工基本養(yǎng)老保險(xiǎn)待遇審核表》,退休人員攜帶《宿豫區(qū)企業(yè)職工基本養(yǎng)老保險(xiǎn)待遇審核表》到工資科核準(zhǔn),最后返回207室交回《宿豫區(qū)企業(yè)職工基本養(yǎng)老保險(xiǎn)待遇審核表》進(jìn)檔永久保存。 建議:工資科派專人駐點(diǎn)保險(xiǎn)處辦理相關(guān)業(yè)務(wù),減少辦事人員往還奔波。 五、參保人員前補(bǔ)養(yǎng)老保險(xiǎn) 需前補(bǔ)養(yǎng)老保險(xiǎn)的參保人員持工資科認(rèn)定的企業(yè)職工補(bǔ)繳養(yǎng)老保險(xiǎn)年限認(rèn)定審批表到勞動(dòng)保險(xiǎn)處209室辦理特殊補(bǔ)繳手續(xù),如已經(jīng)與原單位解除勞動(dòng)關(guān)系還需提供勞動(dòng)仲裁科辦理解除(終止)勞動(dòng)關(guān)系后停止養(yǎng)老保險(xiǎn)通知書。 建議:有明確用工手續(xù),個(gè)人檔案中已經(jīng)明確記載用工性質(zhì)、參加工作時(shí)間的人員可直接到勞動(dòng)保險(xiǎn)處辦理特殊補(bǔ)繳手續(xù),減少辦事人員往還奔波。第二篇:勞動(dòng)保險(xiǎn)處業(yè)務(wù)經(jīng)辦流程中需局各科室協(xié)調(diào)辦理程序及建議