ZigBee綁定指南
一、綁定(Binding)綁定是一種控制兩個(gè)或者多個(gè)設(shè)備應(yīng)用層之間信息流傳遞的機(jī)制。在ZigBee2006發(fā)布版本中,它被稱為源綁定,所有的設(shè)備都可以執(zhí)行綁定機(jī)制。綁定允許應(yīng)用程序發(fā)送一個(gè)數(shù)據(jù)包而不需
一、綁定(Binding)
綁定是一種控制兩個(gè)或者多個(gè)設(shè)備應(yīng)用層之間信息流傳遞的機(jī)制。在ZigBee2006發(fā)布版本中,它被稱為源綁定,所有的設(shè)備都可以執(zhí)行綁定機(jī)制。
綁定允許應(yīng)用程序發(fā)送一個(gè)數(shù)據(jù)包而不需要知道目標(biāo)設(shè)備的短地址(此時(shí)將目標(biāo)設(shè)備的短地址設(shè)置為無(wú)效地址0xFFFE )。應(yīng)用支持子層(APS )從它的綁定表中確定目標(biāo)設(shè)備的短地址,然后將數(shù)據(jù)發(fā)送給目標(biāo)應(yīng)用或者目標(biāo)組。如果在綁定表中找到的短地址不止一個(gè),協(xié)議棧會(huì)向所有找到的短地址發(fā)送數(shù)據(jù)。
說(shuō)明:綁定是基于設(shè)備應(yīng)用層端點(diǎn)的綁定,而且綁定只能在互為" 補(bǔ)充的" 設(shè)備間被創(chuàng)建。也就是說(shuō),當(dāng)兩個(gè)設(shè)備已經(jīng)在他們的簡(jiǎn)單描述符結(jié)構(gòu)中登記為一樣的命令I(lǐng)D, 并且一個(gè)作為輸入另一個(gè)作為輸出時(shí), 綁定才能成功。
圖1:綁定圖示
上圖為兩個(gè)設(shè)備建立的綁定關(guān)系,從上圖我們理解綁定是基于端點(diǎn)(endpoint)的綁定。在設(shè)備1中端點(diǎn)號(hào)(endpoint )為3的開(kāi)關(guān)1與設(shè)備2中端點(diǎn)號(hào)(endpoint )為5、7、8的燈建立了綁定。設(shè)備1中端點(diǎn)號(hào)(endpoint )為2的開(kāi)關(guān)與設(shè)備2中端點(diǎn)號(hào)(endpoint )為17的燈建立了綁定。
二、建立綁定表(Building a Binding Table)
有三種方法可以建立一個(gè)綁定表:
● Zigbee Device Object Bind Request(ZDO 綁定請(qǐng)求)——通過(guò)一個(gè)命令告訴設(shè)備創(chuàng)
建一個(gè)綁定表記錄
● Zigbee Device Object End Device Bind Request(ZDO 終端綁定請(qǐng)求)——兩個(gè)設(shè)備
可以告訴協(xié)調(diào)器它們想要建立一個(gè)綁定表記錄。協(xié)調(diào)器來(lái)協(xié)調(diào)并在兩個(gè)設(shè)備中創(chuàng)建
綁定表記錄。
● Device Application(設(shè)備應(yīng)用)—一個(gè)設(shè)備上的應(yīng)用程序建立或者管理一個(gè)綁定表
三、綁定表的建立
TI 的Zstack2006協(xié)議棧中提供兩種可用的機(jī)制來(lái)配置設(shè)備綁定:
(1)如果目的設(shè)備的擴(kuò)展地址是已知的
1
,(2)如果目的設(shè)備的擴(kuò)展地址是未知的
3.1、 已知擴(kuò)展地址的綁定
如果已經(jīng)知道要綁定目標(biāo)設(shè)備的擴(kuò)展地址,那么在源設(shè)備端只需通過(guò)函數(shù)zb_BindDevice ()函數(shù)便可以進(jìn)行綁定,zb_BindDevice ()中地址要設(shè)置為目標(biāo)設(shè)備的擴(kuò)展地址。
綁定函數(shù)說(shuō)明:
zb_BindDevice ( uint8 create, //創(chuàng)建還是刪除綁定,TRUE 創(chuàng)建,F(xiàn)ALSE 刪除
uint16 commandId, //命令I(lǐng)D ,綁定是基于命令I(lǐng)D 的綁定
uint8 *pDestination ) //擴(kuò)展地址,可以為NULL ,決定綁定類型
程序代碼:
1、基于擴(kuò)展地址的綁定:
void zb_BindDevice ( uint8 create, uint16 commandId, uint8 *pDestination ) {
if ( create )//這里為TRUE 創(chuàng)建綁定條目
{
if ( pDestination )//長(zhǎng)地址不為空
{
//地址模式為64位地址,即擴(kuò)展地址
destination.addrMode = Addr64Bit;
//將參數(shù)pDestination 的值復(fù)制到 destination.addr.extAddr中
osal_cpyExtAddr( destination.addr.extAddr, pDestination );
//調(diào)用函數(shù) APSME_BindRequest進(jìn)行基于長(zhǎng)地址的綁定
ret = APSME_BindRequest( sapi_epDesc.endPoint, commandId,
&destination, sapi_epDesc.endPoint );
if ( ret == ZSuccess )
{
//綁定成功后獲取目的設(shè)備的短地址
ZDP_NwkAddrReq(pDestination, ZDP_ADDR_REQTYPE_SINGLE, 0, 0 );
//定時(shí)觸發(fā)事件 ZDO_NWK_UPDATE_NV
osal_start_timerEx( ZDAppTaskID, ZDO_NWK_UPDATE_NV, 250 );
}
……
2
,}
函數(shù)說(shuō)明:
1) 、void *osal_cpyExtAddr( void *dest, void *src )
說(shuō)明:該函數(shù)的作用是復(fù)制擴(kuò)展地址。將*src指向的擴(kuò)展地址復(fù)制到指針*dest指向的內(nèi)存 參數(shù)說(shuō)明:*dest----------------------------目標(biāo)地址指針
*src-----------------------------源地址指針
返回值:指針
2) 、ZStatus_t APSME_BindRequest( byte SrcEndpInt, uint16 ClusterId,
zAddrType_t *DstAddr, byte DstEndpInt)
說(shuō)明:應(yīng)用支持子層綁定函數(shù),通過(guò)該函數(shù)可以在兩個(gè)設(shè)備間的應(yīng)用層創(chuàng)建綁定,以原語(yǔ)APSME_BIND.confirm返回綁定結(jié)果。注意這里傳遞的地址是64位的擴(kuò)展地址。
參數(shù)說(shuō)明:SrcEndpInt ---------------------------源設(shè)備的端點(diǎn)
ClusterId ------------------------------簇ID
*DstAddr -----------------------------目標(biāo)設(shè)備的地址
DstEndpInt ---------------------------目標(biāo)設(shè)備的端點(diǎn)
由上述參數(shù)我們可以看出綁定時(shí)基于端點(diǎn)和簇的綁定
返回值:ZStatus_t狀態(tài)值
3)、afStatus_t ZDP_NwkAddrReq( byte *IEEEAddress, byte ReqType,
byte StartIndex, byte SecurityEnable ) 說(shuō)明:調(diào)用該函數(shù)可以由設(shè)備的擴(kuò)展地址獲取設(shè)備的網(wǎng)絡(luò)地址,該消息以廣播的形式發(fā)送給網(wǎng)絡(luò)中的所有設(shè)備請(qǐng)求設(shè)備的短地址。如果一個(gè)設(shè)備的擴(kuò)展地址和消息中所攜帶的擴(kuò)展地址相同則會(huì)將自己的網(wǎng)絡(luò)地址返回。
參數(shù)說(shuō)明:*IEEEAddress ----------------------------目標(biāo)設(shè)備擴(kuò)展地址指針
ReqType -----------------------------------相應(yīng)類型
StartIndex ---------------------------------開(kāi)始索引
SecurityEnable ---------------------------安全選項(xiàng)
返回值:afStatus_t狀態(tài)值
其他說(shuō)明:ReqType 響應(yīng)類型說(shuō)明,它的值可以是以下二者之一
ZDP_NWKADDR_REQTYPE_SINGLE-----------返回設(shè)備的短地址和擴(kuò)展地址
ZDP_NWKADDR_REQTYPE_EXTENDED-----返回設(shè)備及相關(guān)設(shè)備的短地址和擴(kuò)展地址
4) 、byte osal_start_timerEx( byte taskID, UINT16 event_id, UINT16 timeout_value ) 說(shuō)明:通過(guò)該函數(shù)將定時(shí)觸發(fā)對(duì)應(yīng)任務(wù)id 為taskID 的事件event_id。定時(shí)時(shí)長(zhǎng)為timeout_value。在timeout_value溢出后將觸發(fā)事件event_id。
3
,參數(shù)說(shuō)明:taskID --------------------------------------任務(wù)id
event_id ------------------------------------事件
timeout_value -----------------------------溢出時(shí)間
返回值:ZSUCCESS 或者NO_TIMER_AVAIL
已知擴(kuò)展地址綁定總結(jié):在已知擴(kuò)展地址綁定過(guò)程中,通過(guò)調(diào)用APSME_BindRequest()完成綁定,在綁定成功后又調(diào)用ZDP_NwkAddrReq()函數(shù)獲取了綁定目標(biāo)設(shè)備的16為網(wǎng)絡(luò)地址。當(dāng)上述步驟全部完成后,定時(shí)觸發(fā)了事件ZDO_NWK_UPDATE_NV對(duì)網(wǎng)絡(luò)狀態(tài)進(jìn)行更新。
2、未知擴(kuò)展地址的綁定
這種綁定模式需要使要綁定的目標(biāo)設(shè)備首先處于允許綁定的狀態(tài)。源設(shè)備通過(guò)函數(shù)zb_BindDevice ()(擴(kuò)展地址參數(shù)為NULL )進(jìn)行綁定。這里用到了ZDO 消息,首先我們回顧一下ZDO 消息的流程,以請(qǐng)求IEEE 地址為例,具體流程圖如下:
圖2:ZDO 消息流程圖
A ) 、目標(biāo)設(shè)備允許綁定。
使要綁定的目標(biāo)設(shè)備處于允許綁定的模式,可以調(diào)用函數(shù)zb_AllowBind ()使目標(biāo)設(shè)備進(jìn)入允許綁定模式。
程序代碼:
void zb_AllowBind ( uint8 timeout )
{
osal_stop_timerEx(sapi_TaskID, ZB_ALLOW_BIND_TIMER);
if ( timeout == 0 )
4
,{
afSetMatch(sapi_epDesc.simpleDesc->EndPoint, FALSE);
}
else
{
afSetMatch(sapi_epDesc.simpleDesc->EndPoint, TRUE);
if ( timeout != 0xFF )
{
if ( timeout > 64 )
{
timeout = 64;
}
osal_start_timerEx(sapi_TaskID, ZB_ALLOW_BIND_TIMER, timeout*1000);
}
}
return;
}
說(shuō)明:
1)、參數(shù)timeout
參數(shù)timeout 是目標(biāo)設(shè)備進(jìn)入綁定模式持續(xù)的時(shí)間(s)。如果設(shè)置為OxFF, 則該設(shè)備在任何時(shí)候都是允許綁定模式;如果設(shè)置為0x00, 則取消目標(biāo)設(shè)備進(jìn)入允許綁定模式。如果設(shè)定的時(shí)間大于64s 就默認(rèn)為64s 。
2)、uint8 afSetMatch( uint8 ep, uint8 action )
說(shuō)明:允許或者禁止設(shè)備響應(yīng)ZDO 的描述符匹配請(qǐng)求。如果action 參數(shù)為TRUE 允許匹配,反之如果是FALSE 則禁止匹配。
參數(shù)說(shuō)明:ep --------------------------------------端點(diǎn)endpoint
action----------------------------------允許或者禁止匹配
返回值:TRUE 或者 FALSE
3)、事件 ZB_ALLOW_BIND_TIMER
如果設(shè)定了允許ZDO 描述符匹配,而設(shè)定的時(shí)間不是0xFFFF ,即不是在任何時(shí)間都允許,那么就定時(shí)時(shí)長(zhǎng)為timeout 來(lái)觸發(fā)事件ZB_ALLOW_BIND_TIMER關(guān)閉ZDO 描述符匹配。
ZB_ALLOW_BIND_TIMER事件處理函數(shù):
UINT16 SAPI_ProcessEvent( byte task_id, UINT16 events )
5
,{
……
if ( events & ZB_ALLOW_BIND_TIMER )
{
//這里action 的參數(shù)為FALSE 即關(guān)閉匹配描述符響應(yīng)
afSetMatch(sapi_epDesc.simpleDesc->EndPoint, FALSE);
return (events ^ ZB_ALLOW_BIND_TIMER);
}
……
}
B 、源設(shè)備發(fā)起綁定請(qǐng)求
當(dāng)目標(biāo)設(shè)備已經(jīng)進(jìn)入允許綁定模式,則源設(shè)備可以使用函數(shù)zb_BindDevice()(地址參數(shù)設(shè)置為NULL )發(fā)送綁定請(qǐng)求。
程序代碼:
void zb_BindDevice ( uint8 create, uint16 commandId, uint8 *pDestination ) {
if ( create )
{
if ( pDestination )//已知擴(kuò)展地址的綁定
{
……
}
else//未知擴(kuò)展地址的綁定
{
destination.addrMode = Addr16Bit;//16位短地址模式
//目的地址為廣播地址,在全網(wǎng)進(jìn)行匹配
destination.addr.shortAddr = NWK_BROADCAST_SHORTADDR;
//以下從兩個(gè)方向進(jìn)行Cluster 匹配
if ( ZDO_AnyClusterMatches( 1, &commandId,
sapi_epDesc.simpleDesc->AppNumOutClusters,
sapi_epDesc.simpleDesc->pAppOutClusterList ) )
{
//匹配一個(gè)在允許綁定模式下的設(shè)備
6
,ret = ZDP_MatchDescReq( &destination, NWK_BROADCAST_SHORTADDR,
sapi_epDesc.simpleDesc->AppProfId, 1, &commandId, 0, (cId_t *)NULL, 0 ); }
else if ( ZDO_AnyClusterMatches( 1, &commandId,
sapi_epDesc.simpleDesc->AppNumInClusters,
sapi_epDesc.simpleDesc->pAppInClusterList ) )
{
//匹配一個(gè)在允許綁定模式下的設(shè)備
ret = ZDP_MatchDescReq( &destination, NWK_BROADCAST_SHORTADDR,
sapi_epDesc.simpleDesc->AppProfId, 0, (cId_t *)NULL, 1, &commandId, 0 ); }
if ( ret == ZB_SUCCESS )
{
osal_start_timerEx(sapi_TaskID, ZB_BIND_TIMER, AIB_MaxBindingTime);
return; // dont send cback event
}
……
}
函數(shù)說(shuō)明:
1)、byte ZDO_AnyClusterMatches( byte ACnt, uint16 *AList, byte BCnt, uint16 *BList ) 說(shuō)明:在兩個(gè)鏈表或者數(shù)組中尋找相同的簇(Cluster ),即在*Alist和*Blist匹配相同的簇(Cluster ),如果找到則返回TRUE 否則返回FALSE 。通過(guò)該函數(shù)在輸入簇和輸出簇中尋找對(duì)應(yīng)的commandId 是否存在。如果存在則會(huì)調(diào)用匹配描述符函數(shù)進(jìn)行匹配。
參數(shù)說(shuō)明:ACnt ------------------------------------A鏈表中條目的數(shù)量
*AList ----------------------------------鏈表A
BCnt ------------------------------------B鏈表中條目的數(shù)量
*BList ----------------------------------鏈表B
返回值:TRUE 或者 FALSE
2)、afStatus_t ZDP_MatchDescReq( zAddrType_t *dstAddr, uint16 nwkAddr,
uint16 ProfileID,
byte NumInClusters, cId_t *InClusterList,
byte NumOutClusters, cId_t *OutClusterList,
byte SecurityEnable )
7
,說(shuō)明:通過(guò)該函數(shù)將向網(wǎng)絡(luò)中發(fā)送一條Match_Desc_req的消息,進(jìn)行ZDO 描述符匹配。匹配描述符是基于ProfileID 和ClusterID 匹配。
參數(shù)說(shuō)明:dstAddr ------------------------------------目的地址
ProfileID ---------------------------------- ProfileID
NumInClusters ---------------------------輸入簇?cái)?shù)量
InClusterList ------------------------------輸入簇列表
NumOutClusters -------------------------輸出簇?cái)?shù)量
OutClusterList ----------------------------輸出簇列表
SecurityEnable ----------------------------安全選項(xiàng)
返回值:afStatus_t狀態(tài)
3)、事件ZB_BIND_TIMER
說(shuō)明:當(dāng)發(fā)出描述符匹配請(qǐng)求后,定時(shí)觸發(fā)事件ZB_BIND_TIMER告知上層綁定是否建立成功,定時(shí)時(shí)長(zhǎng)為AIB_MaxBindingTime,該時(shí)長(zhǎng)要保證綁定工作在觸發(fā)事件ZB_BIND_TIMER前完成。
C 、當(dāng)源設(shè)備發(fā)出匹配描述符請(qǐng)求Match_Desc_req,全網(wǎng)進(jìn)行匹配,并最終觸發(fā)了匹配描述符應(yīng)答Match_Desc_rsp通告匹配結(jié)果。具體代碼如下:
程序代碼:
case Match_Desc_rsp:
{
zAddrType_t dstAddr;
ZDO_ActiveEndpointRsp_t *pRsp = ZDO_ParseEPListRsp( inMsg );
if ( sapi_bindInProgress != 0xffff )
{
dstAddr.addrMode = Addr16Bit;
dstAddr.addr.shortAddr = pRsp->nwkAddr;
if ( APSME_BindRequest( sapi_epDesc.simpleDesc->EndPoint,
sapi_bindInProgress, &dstAddr, pRsp->epList[0] ) == ZSuccess ) {
osal_stop_timerEx(sapi_TaskID, ZB_BIND_TIMER);
osal_start_timerEx( ZDAppTaskID, ZDO_NWK_UPDATE_NV, 250 );
sapi_bindInProgress = 0xffff;
ZDP_IEEEAddrReq( pRsp->nwkAddr, ZDP_ADDR_REQTYPE_SINGLE, 0, 0 ); zb_BindConfirm( sapi_bindInProgress, ZB_SUCCESS );
8
,}
}
}
函數(shù)說(shuō)明:
1)、ZDO_ActiveEndpointRsp_t *ZDO_ParseEPListRsp( zdoIncomingMsg_t *inMsg ) 說(shuō)明:通過(guò)調(diào)用函數(shù),對(duì)匹配結(jié)果進(jìn)行處理。
參數(shù)說(shuō)明:*inMsg --------------------------------接收到的信息
返回值:ZDO_ActiveEndpointRsp_t
2)、ZStatus_t APSME_BindRequest( byte SrcEndpInt, uint16 ClusterId,
zAddrType_t *DstAddr, byte DstEndpInt); 說(shuō)明:應(yīng)用支持子層綁定函數(shù),通過(guò)該函數(shù)可以在兩個(gè)設(shè)備間的應(yīng)用層創(chuàng)建綁定,以原語(yǔ)APSME_BIND.confirm返回綁定結(jié)果。注意這里傳遞的地址是64位的擴(kuò)展地址。 參數(shù)說(shuō)明:SrcEndpInt ---------------------------源設(shè)備的端點(diǎn)
ClusterId ------------------------------簇ID
*DstAddr -----------------------------目標(biāo)設(shè)備的地址
DstEndpInt ---------------------------目標(biāo)設(shè)備的端點(diǎn)
由上述參數(shù)我們可以看出綁定時(shí)基于端點(diǎn)和簇的綁定
返回值:ZStatus_t狀態(tài)值
3)、 afStatus_t ZDP_IEEEAddrReq( uint16 shortAddr, byte ReqType,
byte StartIndex, byte SecurityEnable )
說(shuō)明:調(diào)用該函數(shù)可以由設(shè)備的網(wǎng)絡(luò)地址獲取設(shè)備的擴(kuò)展地址,該消息以單播的形式發(fā)送給目的設(shè)備。目的設(shè)備接收到請(qǐng)求后將自己的擴(kuò)展地址返回。
參數(shù)說(shuō)明:shortAddr ----------------------------目標(biāo)設(shè)備短地址
ReqType -----------------------------------相應(yīng)類型
StartIndex ---------------------------------開(kāi)始索引
SecurityEnable ---------------------------安全選項(xiàng)
返回值:afStatus_t狀態(tài)值
綁定總結(jié):
以上兩種綁定機(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ò)展地址。
9
,四、刪除綁定
void zb_BindDevice ( uint8 create, uint16 commandId, uint8 *pDestination ) {
if ( create )//創(chuàng)建綁定條目
{
……
}
else//刪除綁定條目 creat為FALSE
{
// 刪除本地綁定條目中對(duì)應(yīng)于commandId 的綁定條目
BindingEntry_t *pBind;
// 在綁定表中查找對(duì)應(yīng)于commandId 的綁定條目
while ( pBind = bindFind( sapi_epDesc.simpleDesc->EndPoint, commandId, 0 ) ) {
bindRemoveEntry(pBind);//刪除找到的對(duì)應(yīng)于commandId 的綁定條目
}
osal_start_timerEx( ZDAppTaskID, ZDO_NWK_UPDATE_NV, 250 );
}
return;
}
ZDO_NWK_UPDATE_NV
函數(shù)說(shuō)明:
1)、BindingEntry_t *bindFind( uint8 ep, uint16 clusterID, uint8 skipping )
說(shuō)明:在綁定表中尋找對(duì)應(yīng)于clusterID 的綁定條目。
參數(shù)說(shuō)明:ep ------------------------------------------端點(diǎn)
clusterID ---------------------------------簇ID
返回值:綁定條目指針
2)、byte bindRemoveEntry( BindingEntry_t *pBind )
說(shuō)明:在綁定表中刪除對(duì)應(yīng)的綁定條目。
參數(shù)說(shuō)明:*pBind -------------------------------------指向綁定條目的指針
返回值:TURE 或者FALSE
3) 、byte osal_start_timerEx( byte taskID, UINT16 event_id, UINT16 timeout_value ) 10