(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()創建綁定條目實現綁定,再得到其擴展地址.