SimpleApp例程中兩種綁定機制程序流程


建立一個綁定表格有3種方式:
(1)ZDO綁定請求:一個試運轉的工具能告訴這個設備製作一個綁定報告
(2)ZDO終端設備綁定請求:設備能告訴協調器他們想建立綁定表格報告。該協調器將使協調並在這兩個設備上創建綁定表格條目。

(3)設備應用:在設備上的應用能建立或管理一個綁定表格。

有兩種可用的機制配置設備綁定:
(1)如果目的設備的擴展地址是已知的,則zb_BindDeviceRequest()函數能創建一個綁定條目。
(2)如果擴展地址是未知的,則一個"按鈕"可以利用。這樣的話,這個目的設備首先處於一種狀態,它將被zb_AllowBindResponse()發出一個匹配響應;然後在源設備處,zb_AllowBindRequest()函數帶着空地址出發.

      以上兩種綁定機制,最終都是用函數APSME_BindRequest()創建綁定。不同的是,前者採用的目的地址是64位擴展地址,而後者採用的目的地址是16位網絡地址。前者已知擴展地址,調用了ZDP_NwkAddrReq()函數獲得目的設備短地址;後者利用描述匹配得到了短地址,然後調用了ZDP_IEEEAddrReq()函數,獲取目的設備的擴展地址.

 1、已知擴展地址的綁定

這裏可以直接調用函數zb_BindDevice()發起綁定請求:
    zb_BindDevice ( uint8 create,         //是否創建綁定,TRUE則創建,FALSE則解除
                    uint16 commandId,            //命令ID,基於某命令的綁定,相當於簇

                    uint8 *pDestination )         //指向擴展地址的指針

函數程序如下(已知擴展地址的綁定部分)
******************************************
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 )  //已知擴展地址的綁定,即*pDestination 爲非NULL
      {
        destination.addrMode = Addr64Bit;
        osal_cpyExtAddr( destination.addr.extAddr, pDestination );

        //直接調用APS綁定請求函數
        ret = APSME_BindRequest( sapi_epDesc.endPoint,  //源EP
                                commandId,                      //簇ID
                                &destination,                    //目的地址模式
                                sapi_epDesc.endPoint ); //目的EP

        if ( ret == ZSuccess )  //綁定成功
        {
          // Find nwk addr 發現網絡地址,得到被綁定設備的短地址
          ZDP_NwkAddrReq(pDestination, ZDP_ADDR_REQTYPE_SINGLE, 0, 0 );
          osal_start_timerEx( ZDAppTaskID, ZDO_NWK_UPDATE_NV, 250 );
        }
      }
//---------------------------------
      else  //未知目的擴展地址,即*pDestination=NULL
      {
        ret = ZB_INVALID_PARAMETER;
        destination.addrMode = Addr16Bit;
        destination.addr.shortAddr = NWK_BROADCAST_SHORTADDR;  //0xffff 描述符匹配請求:廣播
        /*如果commandId是輸出簇,則檢測是否與本終端輸出簇列表中的某一項相匹配(相同)*/
        if ( ZDO_AnyClusterMatches( 1, &commandId, sapi_epDesc.simpleDesc->AppNumOutClusters,
                                                sapi_epDesc.simpleDesc->pAppOutClusterList ) )
        {
          // Try to match with a device in the allow bind mode 尋找一個允許匹配狀態下的設備進行描述符匹配
          ret = ZDP_MatchDescReq( &destination, NWK_BROADCAST_SHORTADDR,
              sapi_epDesc.simpleDesc->AppProfId, 1, &commandId, 0, (cId_t *)NULL, 0 );
        }
         /*如果commandId是輸入簇,則檢測是否與本終端輸入簇列表中的某一項相匹配(相同)*/
        else if ( ZDO_AnyClusterMatches( 1, &commandId, sapi_epDesc.simpleDesc->AppNumInClusters,
                                                sapi_epDesc.simpleDesc->pAppInClusterList ) )
        {       //尋找一個允許匹配狀態下的設備進行描述符匹配
          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;
}

******************************************
在上面已知擴展地址的綁定程序中調用了APS綁定函數APSME_BindRequest(),這個函數在兩個設備間建立綁定,通過APSME_BIND.confirm原語返回,而且這兩者是不可分割的。如果綁定成功,則調用函數ZDP_NwkAddrReq()得到目的設備的短地址。ZDP_NwkAddrReq()這個函數可以產生一個根據已知遙遠設備的IEEE地址,請求得到16位短地址的信息.該信息以廣播的方式發送給網絡中的所有設備.

2、未知擴展地址的綁定(simpApp例子中默認的綁定機制)
該綁定方式下,在發送綁定請求前,先要讓被綁定的目的設備處於允許綁定模式。可以調用函數zb_AllowBind()進入該模式,函數如下:

******************************************

//函數設置設備處於允許綁定模式
//timerout=0x00:不允許綁定
//timerout=0xff:一直處於綁定模式
//0<timeout<65:允許綁定的時間(單位/秒)

void zb_AllowBind ( uint8 timeout )
{

  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);  //設置允許響應匹配描述符請求
    if ( timeout != 0xFF )
    {
      if ( timeout > 64 )
      {
        timeout = 64;
      }
      //設置了允許匹配後,開啓一個定時器,時間爲timeout*1000,
      //時間一到觸發sapi任務ZB_ALLOW_BIND_TIMER事件,SAPI_ProcessEvent()對其的處理是
      //afSetMatch(sapi_epDesc.simpleDesc->EndPoint, FALSE)而取消允許綁定
      osal_start_timerEx(sapi_TaskID, ZB_ALLOW_BIND_TIMER, timeout*1000);
    }
  }
  return;
}
******************************************
    參數timeout是進入綁定模式持續的時間(s)。如果設置爲OxFF,則設備在任何時候都在允許綁定模式;如果設置爲OxOO,則設備將通過該命令取消允許綁定模式.
    調用該函數使設備在給定時間內進入允許綁定模式.一個在允許綁定模式下同等的設備調用函數zb_BindDevice()能與之建立綁定,此時目的擴展地址爲空(參見上面zb_BindDevice()未知目的擴展地址部分).zb_AllowBind()調用afSetMatch(),使之允許響應ZDO的匹配描述符請求.
    以上設置目的設備允許綁定模式(比如simpleApp的燈設備),那在目的設備處於允許綁定模式的時間內,源設備(比如simpleApp的開關設備)可以調用zb_BindDevice()來發起綁定請求.此時執行的程序如下:

******************************************
void zb_BindDevice ( uint8 create, uint16 commandId, uint8 *pDestination )
{
  …………
//---------------------------------
      else //未知目的擴展地址,即*pDestination=NULL
      {
        ret = ZB_INVALID_PARAMETER;
        destination.addrMode = Addr16Bit;
        destination.addr.shortAddr = NWK_BROADCAST_SHORTADDR; //0xffff
        /*如果commandId是輸出簇,則檢測是否與本終端輸出簇列表中的某一項相匹配(相同)*/
        if ( ZDO_AnyClusterMatches( 1, &commandId, sapi_epDesc.simpleDesc->AppNumOutClusters,
                                                sapi_epDesc.simpleDesc->pAppOutClusterList ) )
        {
          // Try to match with a device in the allow bind mode
          //尋找一個允許匹配狀態下的設備進行描述符匹配
          ret = ZDP_MatchDescReq( &destination, NWK_BROADCAST_SHORTADDR,
              sapi_epDesc.simpleDesc->AppProfId, 1, &commandId, 0, (cId_t *)NULL, 0 );
        }
        /*如果commandId是輸入簇,則檢測是否與本終端輸入簇列表中的某一項相匹配(相同)*/
        else if ( ZDO_AnyClusterMatches( 1, &commandId, sapi_epDesc.simpleDesc->AppNumInClusters,
                                                sapi_epDesc.simpleDesc->pAppInClusterList ) )
        {      //尋找一個允許匹配狀態下的設備進行描述符匹配
          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; //允許基於commandId命令的綁定過程
          return; // dont send cback event
        }
      }
//---------------------------------
 …………
}
******************************************
在之中調用了函數ZDP_MatchDescReq(),將建立和發送一個匹配描述符請求。用這個函數在一個應用中的輸入/輸出簇列表中搜索匹配某條件的設備/應用。該綁定響應處理在SAPI_ProcessEvent事件處理函數中
        case ZDO_CB_MSG: /*ZDO信息數據*/
          SAPI_ProcessZDOMsgs( (zdoIncomingMsg_t *)pMsg );
看下SAPI_ProcessZDOMsgs()函數

******************************************
//  SAPI_Init()函數中註冊了以下兩個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 創建一個綁定條目
          dstAddr.addrMode = Addr16Bit;            
          dstAddr.addr.shortAddr = pRsp->nwkAddr; 

          /*調用這個函數來實現兩個設備的綁定*/
          if ( APSME_BindRequest( sapi_epDesc.simpleDesc->EndPoint,  //源EP
                     sapi_bindInProgress,                                //簇ID
                     &dstAddr,                                                    //目的地址模式
                     pRsp->epList[0] ) == ZSuccess )               //目的EP
          //成功實現綁定後
          {
            //zb_BindDevice()中開啓了一個定時器,用於接收Match_Desc_rsp計時
            //如果接收到,則停止這個定時器,如下;如果溢出,則觸發相應任務事件
            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;
  }
}
******************************************

以上內容摘自《zigbee2006無線網絡與無線定位實戰》這本書,根據協議版本的不同作了一些修改。
實例中的兩種綁定機制,第一種(已知擴展地址的綁定)流程,就是zb_BindDevice()根據擴展地址直接調用APSME_BindRequest()創建綁定條目實現綁定,再得到其16位網絡地址;第二種(未知擴展地址的綁定),因地址未知,須先經過一個描述符匹配過程得到相匹配設備的16位短地址,然後通過APSME_BindRequest()創建綁定條目實現綁定,再得到其擴展地址.

發佈了16 篇原創文章 · 獲贊 1 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章