/
pvvx
/
TLB2Z
Обзор
Документация
Войти
/
pvvx
/
TLB2Z
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/SDK/stack/zigbee/bdb/bdb.c
1 979 строк
53 KB
Victor
add SDK, new cfg tb03f, add zg-807z
19 фев 2026, 08:55
19 фев 2026, 08:55
627d0d5
Код
Авторство
О чём код?
/******************************************************************************************************** * @file bdb.c * * @brief This is the source file for bdb * * @author Zigbee Group * @date 2021 * * @par Copyright (c) 2021, Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK") * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *******************************************************************************************************/ /********************************************************************** * INCLUDES */ #include "../common/includes/zb_common.h" #include "../zcl/zcl_include.h" #include "../zcl/zll_commissioning/zcl_zll_commissioning_internal.h" #include "includes/bdb.h" /********************************************************************** * TYPEDEFS */ typedef struct{ u8 dstAddrMode; union{ struct{ addrExt_t dstExtAddr; u8 dstEp; }; u16 dstGroupId; }dstAddr; }zdo_bind_dstAddr_t; /********************************************************************** * GLOBAL VARIABLES */ bdb_ctx_t g_bdbCtx = {0}; /********************************************************************** * CONSTANT */ #define BDB_COMMISSION_TIME_INTV 5 //second #define BDB_TOUCHLINK_CAP_EN() (g_bdbAttrs.nodeCommissioningCapability & BDB_NODE_COMMISSION_CAP_TOUCHLINK) #define POLY 0x8408 /********************************************************************** * LOCAL FUNCTIONS */ static void bdb_task(void *arg); static void bdb_commissioningInfoSave(void *arg); static void bdb_binding(zdo_bind_dstAddr_t *pDstAddr, u8 clusterNum, u16 *clusterList); static void bdb_findingAndBinding(findBindDst_t *pDstInfo); static void bdb_simpleDescReqSend(void *arg); static u8 bdb_commissioningFindBind(void); static u8 bdb_commissioningNetworkFormation(void); static u8 bdb_commissioningNetworkSteer(void); static u8 bdb_topLevelCommissioning(u8 role); static u8 bdb_topLevelCommissiongConfirm(void); static void bdb_retrieveTcLinkKeyTimerStop(void); static void bdb_touchLinkCallback(u8 status, void *arg); static void bdb_commssionUtilityCallback(u8 cmd, void *arg); extern void bdb_touchLinkPreCfg(u8 endpoint, bdb_commissionSetting_t *setting, const zcl_touchlinkAppCallbacks_t *tlCb); extern void bdb_coordinatorStart(void); extern void bdb_routerStart(void); extern void bdb_endDeviceStart(u8 repower); extern void bdb_outgoingFrameCountUpdate(u8 repower); extern void bdb_scanCfg(u32 chanMask, u8 duration); extern void bdb_factoryNewDevCfg(u8 touchLinkEn, u8 chan); /********************************************************************** * LOCAL CONSTANTS */ const bdb_attrTbl_t g_bdbAttrTbl[] = { {OFFSETOF(bdb_attr_t, primaryChannelSet), 4}, {OFFSETOF(bdb_attr_t, secondaryChannelSet), 4}, {OFFSETOF(bdb_attr_t, commissioningGroupId), 2}, {OFFSETOF(bdb_attr_t, commissioningMode), 1}, {OFFSETOF(bdb_attr_t, commissioningStatus), 1}, {OFFSETOF(bdb_attr_t, joiningNodeEui64), 8}, {OFFSETOF(bdb_attr_t, joiningNodeNewTCLinkKey), 16}, {OFFSETOF(bdb_attr_t, nodeCommissioningCapability), 1}, {OFFSETOF(bdb_attr_t, joinUsesInstallCodeKey), 1}, {OFFSETOF(bdb_attr_t, nodeIsOnANetwork), 1}, {OFFSETOF(bdb_attr_t, nodeJoinLinkKeyType), 1}, {OFFSETOF(bdb_attr_t, tcRequireKeyExchange), 1}, {OFFSETOF(bdb_attr_t, scanDuration), 1}, {OFFSETOF(bdb_attr_t, tcLinkKeyExchangeAttempts), 1}, {OFFSETOF(bdb_attr_t, tcLinkKeyExchangeAttemptsMax),1}, {OFFSETOF(bdb_attr_t, tcLinkKeyExchangeMethod), 1}, {OFFSETOF(bdb_attr_t, tcNodeJoinTimeout), 1}, }; const bdb_attr_t g_bdbAttrsDft = { .primaryChannelSet = BDBC_TL_PRIMARY_CHANNEL_SET, .secondaryChannelSet = BDBC_TL_SECONDARY_CHANNEL_SET, .commissioningGroupId = 0xffff, .commissioningStatus = BDB_COMMISSION_STA_SUCCESS, .commissioningMode.networkSteer = 1, .nodeJoinLinkKeyType = LINKKEY_TYPE_TC, .tcRequireKeyExchange = 1, //tcRequireKeyExchange: true .scanDuration = 3, .tcLinkKeyExchangeAttemptsMax = BDBC_REC_SAME_NETWROK_RETRY_ATTEMPTS, .tcLinkKeyExchangeMethod = TCKEY_EXCHANGE_METHOD_APSRK, .tcNodeJoinTimeout = 0x0f, //seconds }; const zcl_touchlinkAppCallbacks_t bdb_touchlinkCb = {bdb_touchLinkCallback, bdb_commssionUtilityCallback}; /********************************************************************** * FUNCTIONS */ /** * @brief set flag for global link key * * @param[in] lk, link key * * @return None */ void bdb_globalLinkKeySet(u8 *lk){ SSIB_GLK_FLAG_SET(SS_GLB_LK_PRECONF); if(lk == tcLinkKeyCentralDefault){ SSIB_GLK_FLAG_SET(SS_GLB_LK_TC_DEFAULT); } if(lk == linkKeyDistributedMaster){ SSIB_GLK_FLAG_SET(SS_GLB_LK_MASTER); } if(lk == linkKeyDistributedCertification){ SSIB_GLK_FLAG_SET(SS_GLB_LK_CERTIFICATION); } } /** * @brief set the correct link key * * @return None */ void bdb_globalLinkKeyFix(bool isFactoryNew){ if(isFactoryNew){ return; } u8 flag = SSIB_GLK_FLAG_GET(); if(flag == SS_GLB_LK_TC_DEFAULT){ ss_ib.tcLinkKey = (u8 *)tcLinkKeyCentralDefault; }else if(flag == SS_GLB_LK_MASTER){ ss_ib.distributeLinkKey = (u8 *)linkKeyDistributedMaster; }else if(flag == SS_GLB_LK_CERTIFICATION){ ss_ib.distributeLinkKey = (u8 *)linkKeyDistributedCertification; } } /********************************************************************* * @fn bdb_commissioningInfoSave * * @brief * * @param arg * * @return None */ _CODE_BDB_ static void bdb_commissioningInfoSave(void *arg) { #if NV_ENABLE nv_nwkFrameCountSaveToFlash(ss_ib.outgoingFrameCounter); zdo_ssInfoSaveToFlash(); zb_info_save(NULL); /* store neighbor table */ nwk_parentNodeInfoStore(); #endif g_bdbCtx.factoryNew = 0; g_bdbAttrs.commissioningMode.networkSteer = 1; } /********************************************************************* * @fn queueInit * * @brief * * @param pFindBindQ * * @return TRUE / FALSE */ _CODE_BDB_ static findBindQ_t *queueInit(void) { findBindQ_t *pFindBindQ = (findBindQ_t *)ev_buf_allocate(sizeof(findBindQ_t)); if(pFindBindQ){ pFindBindQ->front = 0; pFindBindQ->rear = 0; } return pFindBindQ; } static void queueClear(findBindQ_t *pFindBindQ) { if(pFindBindQ){ ev_buf_free((u8 *)pFindBindQ); g_bdbCtx.pFindBindQ = NULL; } } /********************************************************************* * @fn isQueueEmpty * * @brief * * @param pFindBindQ * * @return TRUE / FALSE */ _CODE_BDB_ static bool isQueueEmpty(findBindQ_t *pFindBindQ) { if(!pFindBindQ){ return TRUE; } if(pFindBindQ->front == pFindBindQ->rear){ return TRUE; }else{ return FALSE; } } /********************************************************************* * @fn isQueueFull * * @brief * * @param pFindBindQ * * @return TRUE / FALSE */ _CODE_BDB_ static bool isQueueFull(findBindQ_t *pFindBindQ) { if(((pFindBindQ->rear + 1) % FIND_BIND_QUEUE_SIZE) == pFindBindQ->front){ return TRUE; }else{ return FALSE; } } /********************************************************************* * @fn queuePush * * @brief * * @param pFindBindQ * dstInfo * * @return TRUE / FALSE */ _CODE_BDB_ static bool queuePush(findBindQ_t *pFindBindQ, findBindDst_t dstInfo) { if(isQueueFull(pFindBindQ)){ return FALSE; } pFindBindQ->rear = (pFindBindQ->rear + 1) % FIND_BIND_QUEUE_SIZE; pFindBindQ->findBindDstInfo[pFindBindQ->rear].addr = dstInfo.addr; pFindBindQ->findBindDstInfo[pFindBindQ->rear].endpoint = dstInfo.endpoint; return TRUE; } /********************************************************************* * @fn queuePop * * @brief * * @param pFindBindQ * dstInfo * * @return TRUE / FALSE */ _CODE_BDB_ static bool queuePop(findBindQ_t *pFindBindQ, findBindDst_t *pDstInfo) { if(isQueueEmpty(pFindBindQ)){ return FALSE; } pFindBindQ->front = (pFindBindQ->front + 1) % FIND_BIND_QUEUE_SIZE; pDstInfo->addr = pFindBindQ->findBindDstInfo[pFindBindQ->front].addr; pDstInfo->endpoint = pFindBindQ->findBindDstInfo[pFindBindQ->front].endpoint; return TRUE; } #if 0 /********************************************************************* * @fn queueHeadGet * * @brief * * @param pFindBindQ * pDstInfo * * @return TRUE / FALSE */ _CODE_BDB_ static bool queueHeadGet(findBindQ_t *pFindBindQ, findBindDst_t *pDstInfo) { if(isQueueEmpty(pFindBindQ)){ return FALSE; } pDstInfo->addr = pFindBindQ->findBindDstInfo[(pFindBindQ->front + 1) % FIND_BIND_QUEUE_SIZE].addr; pDstInfo->endpoint = pFindBindQ->findBindDstInfo[(pFindBindQ->front + 1) % FIND_BIND_QUEUE_SIZE].endpoint; return TRUE; } #endif static void bdb_findBindRst(void) { queueClear(g_bdbCtx.pFindBindQ); memset((u8 *)&g_bdbCtx.findDstInfo, 0, sizeof(findBindDst_t)); memset((u8 *)&g_bdbCtx.bindDstInfo, 0, sizeof(findBindDst_t)); } /********************************************************************* * @fn bdb_binding * * @brief for initiator * * @param pDstAddr * clusterNum * clusterList * * @return None */ _CODE_BDB_ static void bdb_binding(zdo_bind_dstAddr_t *pDstAddr, u8 clusterNum, u16 *clusterList) { zdo_bind_req_t req; memset(&req, 0, sizeof(zdo_bind_req_t)); u8 bindStatus = ZDO_SUCCESS; ZB_IEEE_ADDR_COPY(req.src_addr, NIB_IEEE_ADDRESS()); req.src_endpoint = g_bdbCtx.simpleDesc->endpoint; req.dst_addr_mode = pDstAddr->dstAddrMode; if(req.dst_addr_mode == LONG_EXADDR_DSTENDPOINT){ ZB_IEEE_ADDR_COPY(req.dst_ext_addr, pDstAddr->dstAddr.dstExtAddr); req.dst_endpoint = pDstAddr->dstAddr.dstEp; }else if(req.dst_addr_mode == SHORT_GROUPADDR_NODSTENDPOINT){ req.dst_group_addr = pDstAddr->dstAddr.dstGroupId; } for(u8 i = 0; i < clusterNum; i++){ req.cid16_l = clusterList[i]; req.cid16_h = clusterList[i]>>8; u8 sn = 0; bindStatus = zb_zdoBindUnbindReq(TRUE, &req, &sn, NULL); if(bindStatus == ZDO_TABLE_FULL){ BDB_STATUS_SET(BDB_COMMISSION_STA_BINDING_TABLE_FULL); u32 evt = BDB_EVT_COMMISSIONING_FINDORBIND_FINISH; TL_SCHEDULE_TASK(bdb_task, (void *)evt); break; } } ev_buf_free((u8 *)g_bdbCtx.matchClusterList); g_bdbCtx.matchClusterNum = 0; g_bdbCtx.matchClusterList = NULL; if(bindStatus == ZDO_SUCCESS){ if(g_bdbCtx.bdbAppCb && g_bdbCtx.bdbAppCb->bdbFindBindSuccessCb){ g_bdbCtx.bdbAppCb->bdbFindBindSuccessCb(&g_bdbCtx.bindDstInfo); } } if(bindStatus != ZDO_TABLE_FULL){ TL_SCHEDULE_TASK(bdb_simpleDescReqSend, NULL); } } /********************************************************************* * @fn bdb_ieeeAddrResp * * @brief for initiator * * @param arg * * @return None */ _CODE_BDB_ static void bdb_ieeeAddrResp(void *arg) { zdo_zdpDataInd_t *p = (zdo_zdpDataInd_t *)arg; zdo_ieee_addr_resp_t *resp = (zdo_ieee_addr_resp_t *)p->zpdu; if(resp->status == ZDO_SUCCESS){ zdo_bind_dstAddr_t bindDstAddr; memset((u8 *)&bindDstAddr, 0, sizeof(zdo_bind_dstAddr_t)); bindDstAddr.dstAddrMode = APS_LONG_DSTADDR_WITHEP; bindDstAddr.dstAddr.dstEp = g_bdbCtx.bindDstInfo.endpoint; ZB_IEEE_ADDR_COPY(bindDstAddr.dstAddr.dstExtAddr, resp->ieee_addr_remote); bdb_binding(&bindDstAddr, g_bdbCtx.matchClusterNum, g_bdbCtx.matchClusterList); } } /********************************************************************* * @fn bdb_findingAndBinding * * @brief for initiator * * @param pDstInfo * * @return None */ _CODE_BDB_ static void bdb_findingAndBinding(findBindDst_t *pDstInfo) { zdo_bind_dstAddr_t bindDstAddr; memset((u8 *)&bindDstAddr, 0, sizeof(zdo_bind_dstAddr_t)); #ifdef ZCL_GROUP if(g_bdbAttrs.commissioningGroupId != 0xFFFF){ epInfo_t dstEpInfo; TL_SETSTRUCTCONTENT(dstEpInfo, 0); dstEpInfo.dstAddrMode = APS_SHORT_DSTADDR_WITHEP; dstEpInfo.dstEp = pDstInfo->endpoint; dstEpInfo.dstAddr.shortAddr = pDstInfo->addr; dstEpInfo.profileId = HA_PROFILE_ID; dstEpInfo.txOptions = 0;//APS_TX_OPT_ACK_TX; dstEpInfo.radius = 0; u8 groupName[8] = {0}; zcl_group_addCmd(g_bdbCtx.simpleDesc->endpoint, &dstEpInfo, FALSE, g_bdbAttrs.commissioningGroupId, groupName); bindDstAddr.dstAddrMode = APS_SHORT_GROUPADDR_NOEP; bindDstAddr.dstAddr.dstGroupId = g_bdbAttrs.commissioningGroupId; bdb_binding(&bindDstAddr, g_bdbCtx.matchClusterNum, g_bdbCtx.matchClusterList); }else #endif { addrExt_t dstExtAddr; ZB_IEEE_ADDR_ZERO(dstExtAddr); u8 extAddrGot = zb_address_ieee_by_short(pDstInfo->addr, dstExtAddr); if((extAddrGot != SUCCESS) || ((extAddrGot == SUCCESS) && ZB_IEEE_ADDR_IS_ZERO(dstExtAddr))){ zdo_ieee_addr_req_t ieeeAddrReq; u8 sn = 0; memset(&ieeeAddrReq, 0, sizeof(zdo_ieee_addr_req_t)); ieeeAddrReq.nwk_addr_interest = pDstInfo->addr; ieeeAddrReq.req_type = ZDO_ADDR_REQ_SINGLE_RESP; zb_zdoIeeeAddrReq(pDstInfo->addr, &ieeeAddrReq, &sn, bdb_ieeeAddrResp); }else{ bindDstAddr.dstAddrMode = APS_LONG_DSTADDR_WITHEP; bindDstAddr.dstAddr.dstEp = pDstInfo->endpoint; ZB_IEEE_ADDR_COPY(bindDstAddr.dstAddr.dstExtAddr, dstExtAddr); bdb_binding(&bindDstAddr, g_bdbCtx.matchClusterNum, g_bdbCtx.matchClusterList); } } } /********************************************************************* * @fn bdb_SimpleDescResp * * @brief for initiator * * @param arg * * @return None */ _CODE_BDB_ static void bdb_SimpleDescResp(void *arg) { zdo_zdpDataInd_t *p = (zdo_zdpDataInd_t *)arg; zdo_simple_descriptor_resp_t *simpDescResp = (zdo_simple_descriptor_resp_t *)p->zpdu; if(simpDescResp->status == SUCCESS){ if(g_bdbCtx.matchClusterList || g_bdbCtx.matchClusterNum){ return; } if(g_bdbCtx.identifyTimer){ TL_ZB_TIMER_CANCEL(&g_bdbCtx.identifyTimer); } u8 *pClusterListInfo = simpDescResp->simple_descriptor.listInfo; u8 inClusterNum = *pClusterListInfo++; if(inClusterNum){ g_bdbCtx.matchClusterList = (u16 *)ev_buf_allocate(sizeof(u16) * inClusterNum); if(g_bdbCtx.matchClusterList){ for(u8 i = 0; i < g_bdbCtx.clusterNum; i++){ u8 *pClusterListInfo_temp = pClusterListInfo; for(u8 j = 0; j < inClusterNum; j++){ u16 clusterId = BUILD_U16(pClusterListInfo_temp[0], pClusterListInfo_temp[1]); if(g_bdbCtx.clusterList[i] == clusterId){ g_bdbCtx.matchClusterList[g_bdbCtx.matchClusterNum++] = clusterId; } pClusterListInfo_temp += 2; } } if(g_bdbCtx.matchClusterNum){ g_bdbCtx.bindDstInfo.addr = simpDescResp->nwk_addr_interest; g_bdbCtx.bindDstInfo.endpoint = simpDescResp->simple_descriptor.endpoint; bdb_findingAndBinding(&g_bdbCtx.bindDstInfo); return; } ev_buf_free((u8 *)g_bdbCtx.matchClusterList); g_bdbCtx.matchClusterNum = 0; g_bdbCtx.matchClusterList = NULL; } } } TL_SCHEDULE_TASK(bdb_simpleDescReqSend, NULL); } /********************************************************************* * @fn bdb_commissioningFindBindSimpleDescReq * * @brief for initiator * * @param None * * @return None */ _CODE_BDB_ static void bdb_commissioningFindBindSimpleDescReq(void) { if(BDB_STATE_GET() == BDB_STATE_COMMISSIONING_FINDORBIND && g_bdbCtx.role == BDB_COMMISSIONING_ROLE_INITIATOR){ zdo_simple_descriptor_req_t req; u8 sn = 0; memset(&req, 0, sizeof(zdo_simple_descriptor_req_t)); req.endpoint = g_bdbCtx.findDstInfo.endpoint; req.nwk_addr_interest = g_bdbCtx.findDstInfo.addr; zb_zdoSimpleDescReq(g_bdbCtx.findDstInfo.addr, &req, &sn, bdb_SimpleDescResp); } } /********************************************************************* * @fn bdb_simpleDescReqTimeoutCb * * @brief for initiator * * @param arg * * @return */ _CODE_BDB_ static s32 bdb_simpleDescReqTimeoutCb(void *arg) { TL_SCHEDULE_TASK(bdb_simpleDescReqSend, NULL); g_bdbCtx.identifyTimer = NULL; return -1; } /********************************************************************* * @fn bdb_simpleDescReqSend * * @brief for initiator * * @param arg * * @return */ _CODE_BDB_ static void bdb_simpleDescReqSend(void *arg) { if(queuePop(g_bdbCtx.pFindBindQ, &g_bdbCtx.findDstInfo)){ if(g_bdbCtx.identifyTimer){ TL_ZB_TIMER_CANCEL(&g_bdbCtx.identifyTimer); } u32 evt = BDB_EVT_COMMISSIONING_FINDORBIND_SIMPLE_DESC_REQ; TL_SCHEDULE_TASK(bdb_task, (void *)evt); u32 simpleDescReqTimeout = 5000; #ifdef ZB_ED_ROLE if(zb_getPollRate()){ simpleDescReqTimeout = zb_getPollRate() * 3; } #endif g_bdbCtx.identifyTimer = TL_ZB_TIMER_SCHEDULE(bdb_simpleDescReqTimeoutCb, NULL, simpleDescReqTimeout); }else{ //g_bdbAttrs.commissioningStatus = BDB_COMMISSION_STA_SUCCESS; BDB_STATUS_SET(BDB_COMMISSION_STA_SUCCESS); u32 evt = BDB_EVT_COMMISSIONING_FINDORBIND_FINISH; TL_SCHEDULE_TASK(bdb_task, (void *)evt); } } /********************************************************************* * @fn bdb_findBindIdentifyQueryTimeout * * @brief the callback of the Find and Bind Identify query response received timeout for initiator. * * @param arg * * @return */ _CODE_BDB_ static s32 bdb_findBindIdentifyQueryTimeout(void *arg) { if(isQueueEmpty(g_bdbCtx.pFindBindQ)){ //g_bdbAttrs.commissioningStatus = BDB_COMMISSION_STA_NO_IDENTIFY_QUERY_RESPONSE; BDB_STATUS_SET(BDB_COMMISSION_STA_NO_IDENTIFY_QUERY_RESPONSE); u32 evt = BDB_EVT_COMMISSIONING_FINDORBIND_FINISH; TL_SCHEDULE_TASK(bdb_task, (void *)evt); }else{ TL_SCHEDULE_TASK(bdb_simpleDescReqSend, NULL); } g_bdbCtx.identifyTimer = NULL; return -1; } /********************************************************************* * @fn bdb_findBindIdentifyTimeout * * @brief the callback of the Find and Bind Identify timeout for target * * @param arg * * @return */ _CODE_BDB_ static s32 bdb_findBindIdentifyTimeout(void *arg) { static u32 timerIdentifyCnt = 0; u16 identifyTime = 0; u16 attrLen = 0; if(zcl_getAttrVal(g_bdbCtx.simpleDesc->endpoint, ZCL_CLUSTER_GEN_IDENTIFY, ZCL_ATTRID_IDENTIFY_TIME, &attrLen, (u8 *)&identifyTime) != ZCL_STA_SUCCESS){ g_bdbCtx.identifyTimer = NULL; return -1; } if(identifyTime == 0 || timerIdentifyCnt++ >= BDBC_MIN_COMMISSIONING_TIME / BDB_COMMISSION_TIME_INTV){ timerIdentifyCnt = 0; //g_bdbAttrs.commissioningStatus = BDB_COMMISSION_STA_SUCCESS; BDB_STATUS_SET(BDB_COMMISSION_STA_SUCCESS); u32 evt = BDB_EVT_COMMISSIONING_FINDORBIND_FINISH; TL_SCHEDULE_TASK(bdb_task, (void *)evt); g_bdbCtx.identifyTimer = NULL; return -1; } return 0; } /********************************************************************* * @fn bdb_commissioningFindBind * * @brief * * @param None * * @return None */ _CODE_BDB_ static u8 bdb_commissioningFindBind(void) { if(g_bdbAttrs.commissioningMode.findOrBind){ if(g_bdbAttrs.nodeIsOnANetwork){ /* Perform finding & binding according to cluster class */ if(g_bdbCtx.role == BDB_COMMISSIONING_ROLE_TARGET){ /* * Set IdentifyTime to more than bdbMinCommissioningTime * * */ /* Handle identify query requests from the initiator until Identify timer expired*/ if(!g_bdbCtx.identifyTimer){ g_bdbCtx.identifyTimer = TL_ZB_TIMER_SCHEDULE(bdb_findBindIdentifyTimeout, NULL, BDB_COMMISSION_TIME_INTV * 1000); } if(g_bdbCtx.bdbAppCb->bdbIdentifyCb){ g_bdbCtx.bdbAppCb->bdbIdentifyCb(g_bdbCtx.simpleDesc->endpoint, NIB_NETWORK_ADDRESS(), BDBC_MIN_COMMISSIONING_TIME); } }else{ epInfo_t dstEpInfo; TL_SETSTRUCTCONTENT(dstEpInfo, 0); dstEpInfo.dstAddrMode = APS_SHORT_DSTADDR_WITHEP; dstEpInfo.dstAddr.shortAddr = 0xffff; dstEpInfo.dstEp = 0xff; dstEpInfo.profileId = HA_PROFILE_ID; zcl_identify_identifyQueryCmd(g_bdbCtx.simpleDesc->endpoint, &dstEpInfo, TRUE); u32 identifyQueryRcvTimeout = 5000; #ifdef ZB_ED_ROLE if(zb_getPollRate()){ identifyQueryRcvTimeout = zb_getPollRate() * 3; } #endif /* Start a timer to check if identify query response are received. */ if(!g_bdbCtx.identifyTimer){ g_bdbCtx.identifyTimer = TL_ZB_TIMER_SCHEDULE(bdb_findBindIdentifyQueryTimeout, NULL, identifyQueryRcvTimeout); } } return BDB_STATE_COMMISSIONING_FINDORBIND; } } return BDB_STATE_IDLE; } /********************************************************************* * @fn bdb_commissioningNetworkFormation * * @brief start Network formation during commissioning * * @param None * * @return None */ _CODE_BDB_ static u8 bdb_commissioningNetworkFormation(void) { u8 bdbFormation = BDB_STATE_IDLE; if(!g_bdbAttrs.commissioningMode.networkFormation){ return bdb_commissioningFindBind(); }else{ if(g_bdbAttrs.nodeIsOnANetwork){ return bdb_commissioningFindBind(); }else{ #if ZB_ROUTER_ROLE #if ZB_COORDINATOR_ROLE ss_securityModeSet(SS_SEMODE_CENTRALIZED); #else if((!g_bdbAttrs.nodeIsOnANetwork)||(ZB_IEEE_ADDR_IS_INVALID(ss_ib.trust_center_address))){ ss_securityModeSet(SS_SEMODE_DISTRIBUTED); } #endif u32 scanChannels = aps_ib.aps_channel_mask; /* network formation */ zb_nwkFormation(scanChannels, g_bdbAttrs.scanDuration); bdbFormation = 1; return BDB_STATE_COMMISSIONING_NETWORK_FORMATION; #endif } } return bdbFormation; } /********************************************************************* * @fn bdb_mgmtPermitJoiningConfirm * * @brief Mgmt_PermitJoining confirm handle * * @param arg * * @return None */ _CODE_BDB_ static void bdb_mgmtPermitJoiningConfirm(void *arg) { #if ZB_ROUTER_ROLE /* Enable permit join for more than bdbcMinCommissioningTime seconds */ #if ZB_COORDINATOR_ROLE zb_nlmePermitJoiningRequest(BDBC_MIN_COMMISSIONING_TIME); #else zb_nlmePermitJoiningRequest(BDBC_MIN_COMMISSIONING_TIME); #endif #endif //g_bdbAttrs.commissioningStatus = BDB_COMMISSION_STA_SUCCESS; BDB_STATUS_SET(BDB_COMMISSION_STA_SUCCESS); if(BDB_STATE_GET() == BDB_STATE_COMMISSIONING_NETWORK_STEER){ u32 evt = BDB_EVT_COMMISSIONING_NETWORK_STEER_FINISH; TL_SCHEDULE_TASK(bdb_task, (void *)evt); }else if(BDB_STATE_GET() == BDB_STATE_COMMISSIONING_NETWORK_FORMATION){ u32 evt = BDB_EVT_COMMISSIONING_NETWORK_FORMATION_FINISH; TL_SCHEDULE_TASK(bdb_task, (void *)evt); } if(g_bdbAttrs.nodeIsOnANetwork){ bdb_commissioningInfoSave(NULL); } } /********************************************************************* * @fn bdb_mgmtPermitJoiningTrig * * @brief send bdb_mgmtPermitJoining * * @param arg * * @return None */ _CODE_BDB_ static void bdb_mgmtPermitJoiningTrig(void *arg) { u8 sn = 0; zb_mgmtPermitJoinReq(0xfffc, BDBC_MIN_COMMISSIONING_TIME, 0x01, &sn, NULL); TL_SCHEDULE_TASK(bdb_mgmtPermitJoiningConfirm, NULL); } /********************************************************************* * @fn bdb_retrieveTcLinkKeyTimerStop * * @brief stop the procedure of retrieving trust center link key * * @param None * * @return None */ _CODE_BDB_ static void bdb_retrieveTcLinkKeyTimerStop(void) { if(g_bdbCtx.retrieveTcLkKeyTimer){ TL_ZB_TIMER_CANCEL(&g_bdbCtx.retrieveTcLkKeyTimer); } } /********************************************************************* * @fn bdb_retrieveTcLinkKeyDone * * @brief retrieving Trust center link Key is done * * @param status * * @return None */ _CODE_BDB_ void bdb_retrieveTcLinkKeyDone(u8 status) { /* now send permit join command */ u32 evt = BDB_EVT_IDLE; bdb_retrieveTcLinkKeyTimerStop(); if(status == BDB_COMMISSION_STA_SUCCESS){ BDB_STATUS_SET(BDB_COMMISSION_STA_SUCCESS); g_bdbAttrs.nodeIsOnANetwork = 1; evt = BDB_EVT_COMMISSIONING_NETWORK_STEER_PERMITJOIN; }else{ aps_ib.aps_authenticated = 0; BDB_STATUS_SET(BDB_COMMISSION_STA_TCLK_EX_FAILURE); g_bdbAttrs.nodeIsOnANetwork = 0; evt = BDB_EVT_COMMISSIONING_NETWORK_STEER_FINISH; } TL_SCHEDULE_TASK(bdb_task, (void *)evt); } /********************************************************************* * @fn bdb_nodeDescRespHandler * * @brief the handler of receiving node description response * * @param arg * * @return None */ _CODE_BDB_ static void bdb_nodeDescRespHandler(void *arg) { zdo_zdpDataInd_t *p = (zdo_zdpDataInd_t *)arg; zdo_node_descript_resp_t *rsp = (zdo_node_descript_resp_t*)p->zpdu; /*Did the server mask indicate revision r21 or greater?*/ //TODO if((rsp->status == ZDO_SUCCESS)){ u8 stackRev = (rsp->node_descriptor.server_mask >> 9) & 0x3f; if(stackRev >= 21){ ss_apsmeRequestKeyReq_t requestKey; TL_SETSTRUCTCONTENT(requestKey, 0); requestKey.keyType = SS_KEYREQ_TYPE_TCLK; requestKey.dstAddr.shortAddr = 0x0000; requestKey.dstAddrMode = ZB_ADDR_16BIT_DEV_OR_BROADCAST; if(zb_apsmeRequestKeyReq(&requestKey) == RET_OK){ g_bdbAttrs.nodeIsOnANetwork = 0; return; } } }else{ return; } bdb_retrieveTcLinkKeyDone(BDB_COMMISSION_STA_SUCCESS); } /********************************************************************* * @fn bdb_retrieveTcLinkKeyTimeout * * @brief the handler for the timeout of retrieving trust center link key * * @param arg * * @return None */ _CODE_BDB_ static s32 bdb_retrieveTcLinkKeyTimeout(void *arg) { if(g_bdbAttrs.tcLinkKeyExchangeAttempts++ < g_bdbAttrs.tcLinkKeyExchangeAttemptsMax){ /* send node description */ u8 sn = 0; zdo_node_descriptor_req_t req; req.nwk_addr_interest = 0x0000; zb_zdoNodeDescReq(0x0000, &req, &sn, bdb_nodeDescRespHandler); return 0; }else{ if(!zb_isDeviceJoinedNwk()){ g_bdbAttrs.tcLinkKeyExchangeAttempts = 0; g_bdbCtx.retrieveTcLkKeyTimer = NULL; /*wait until leave confirm */ bdb_retrieveTcLinkKeyDone(BDB_COMMISSION_STA_TCLK_EX_FAILURE); return -1; } /* leave the network */ nlme_leave_req_t req; ZB_IEEE_ADDR_COPY(req.deviceAddr, g_zbMacPib.extAddress); req.rejoin = 0; req.removeChildren = 0; if(!g_bdbCtx.leaveDoing){ if(RET_OK == zb_nlmeLeaveReq(&req)){ g_bdbCtx.leaveDoing = 1; } } return 3 * 1000; } } /********************************************************************* * @fn bdb_retrieveTcLinkKeyStart * * @brief retrieve trust center link key * * @param None * * @return None */ _CODE_BDB_ static s32 bdb_retrieveTcLinkKeyStart(void *arg) { if(g_bdbAttrs.tcLinkKeyExchangeMethod == TCKEY_EXCHANGE_METHOD_APSRK){ /* send node description */ u8 sn = 0; zdo_node_descriptor_req_t req; req.nwk_addr_interest = 0x0000; zb_zdoNodeDescReq(0x0000, &req, &sn, bdb_nodeDescRespHandler); g_bdbCtx.leaveDoing = 0; g_bdbAttrs.tcLinkKeyExchangeAttempts = 0; g_bdbAttrs.tcLinkKeyExchangeAttemptsMax = 3; if(!g_bdbCtx.retrieveTcLkKeyTimer){ g_bdbCtx.retrieveTcLkKeyTimer = TL_ZB_TIMER_SCHEDULE(bdb_retrieveTcLinkKeyTimeout, NULL, BDBC_TC_LINK_KEY_EXCHANGE_TIMEOUT * 1000); } }else{ bdb_retrieveTcLinkKeyDone(BDB_COMMISSION_STA_SUCCESS); } return -1; } /********************************************************************* * @fn bdb_networkSteerNonFactoryNew * * @brief start Network Steer during commissioning for non-factory new node * * @param arg * * @return */ _CODE_BDB_ static void bdb_networkSteerNonFactoryNew(void) { /* step2: Broadcast Mgmt_Permit_Joining_req command */ bdb_mgmtPermitJoiningTrig(NULL); } _CODE_BDB_ void bdb_nwkDiscCnfCb(void) { #if 0 u8 addNebNum = g_zb_neighborTbl.additionNeighborNum; printf("discCnfCb: addNebNum = %d\n", addNebNum); for(u8 i = 0; i < 6; i++){ printf("======idx = %d======\n", i); printf("addr = %x, panId = %x\n", g_zb_neighborTbl.additionNeighborTbl[i].shortAddr, g_zb_neighborTbl.additionNeighborTbl[i].panId); printf("permit = %x, depth = %d\n", g_zb_neighborTbl.additionNeighborTbl[i].permitJoining, g_zb_neighborTbl.additionNeighborTbl[i].depth); } #endif zb_assocJoinReq(); } /********************************************************************* * @fn bdb_networkSteerFactoryNew * * @brief start Network Steer during commissioning for factory new node * * @param arg * * @return */ _CODE_BDB_ static void bdb_networkSteerFactoryNew(void) { //g_bdbAttrs.commissioningStatus = BDB_COMMISSION_STA_IN_PROGRESS; u32 scanChannels = aps_ib.aps_channel_mask; u8 scanDuration = g_bdbAttrs.scanDuration; /* perform join work flow */ zb_nwkDiscovery(scanChannels, scanDuration, bdb_nwkDiscCnfCb); } /********************************************************************* * @fn bdb_commissioningNetworkSteer * * @brief start Network Steer during commissioning * * @param arg * * @return */ _CODE_BDB_ static u8 bdb_commissioningNetworkSteer(void) { u8 status = BDB_STATE_IDLE; if(!g_bdbAttrs.commissioningMode.networkSteer){ status = bdb_commissioningNetworkFormation(); }else{ /* * perform network steer * */ status = BDB_STATE_COMMISSIONING_NETWORK_STEER; if(g_bdbAttrs.nodeIsOnANetwork){ /* rejoin */ bdb_networkSteerNonFactoryNew(); }else{ /* join */ bdb_networkSteerFactoryNew(); } } return status; } /********************************************************************* * @fn bdb_task * * @brief * * @param arg * * @return */ static void bdb_task(void *arg) { u32 evt = (u32)arg; u8 status = BDB_STATE_IDLE; u8 sn = 0; switch (BDB_STATE_GET()){ case BDB_STATE_INIT: //factory new or non-factory new device BDB_STATE_SET(BDB_STATE_IDLE); if(evt == BDB_EVT_INIT_DONE){ if(g_bdbCtx.bdbAppCb->bdbInitCb){ g_bdbCtx.bdbAppCb->bdbInitCb(g_bdbCtx.initResult, g_bdbAttrs.nodeIsOnANetwork); } if(g_bdbAttrs.nodeIsOnANetwork){ nv_nwkFrameCountSaveToFlash(ss_ib.outgoingFrameCounter); if(g_bdbCtx.initResult == BDB_INIT_STATUS_SUCCESS){ if((zdo_ssInfoKeyGet() != ss_ib.activeSecureMaterialIndex) || (g_zbInfo.macPib.phyChannelCur != g_bdbCtx.channel) || g_zbNwkCtx.parentIsChanged|| g_bdbCtx.forceJoin){ g_zbNwkCtx.parentIsChanged = 0; TL_SCHEDULE_TASK(bdb_commissioningInfoSave, NULL); //for tcRejoin when the network key is changed } #if ZB_ROUTER_ROLE g_zbNwkCtx.joinAccept = 1; /* check if sending parent announcement */ zb_zdoSendParentAnnce(); #endif } } g_bdbCtx.inited = 0; g_bdbCtx.forceJoin = 0; } break; case BDB_STATE_IDLE: /* * commissioning start handle * */ if(evt == BDB_EVT_COMMISSIONING_START){ if(!g_bdbAttrs.commissioningMode.touchlink){ status = bdb_commissioningNetworkSteer(); }else{ /* * perform touch link for initiator * * */ #if ((ROUTER || END_DEVICE) && TOUCHLINK_SUPPORT) if(g_bdbCtx.role == BDB_COMMISSIONING_ROLE_INITIATOR){ zcl_touchLinkStart(); status = BDB_STATE_COMMISSIONING_TOUCHLINK; } #endif } if(status == BDB_STATE_IDLE){ /* confirm to application */ g_bdbAttrs.commissioningStatus = BDB_COMMISSION_STA_NO_NETWORK; if(g_bdbCtx.bdbAppCb->bdbcommissioningCb){ g_bdbCtx.bdbAppCb->bdbcommissioningCb(g_bdbAttrs.commissioningStatus, NULL); } } BDB_STATE_SET(status); }else if(evt == BDB_STATE_REJOIN_DONE){ bdb_topLevelCommissiongConfirm(); } break; case BDB_STATE_COMMISSIONING_TOUCHLINK: if(evt == BDB_EVT_COMMISSIONING_TOUCHLINK_NO_RESP){ /* * if no scan response received, start network steer * */ g_bdbAttrs.commissioningMode.touchlink = 0; BDB_STATE_SET(BDB_STATE_IDLE); //ststus = BDB_COMMISSION_STA_NO_SCAN_RESPONSE g_bdbAttrs.commissioningStatus = BDB_STATUS_GET(); #if ZB_ED_ROLE bdb_topLevelCommissioning(BDB_COMMISSIONING_ROLE_INITIATOR); #else bdb_topLevelCommissioning(BDB_COMMISSIONING_ROLE_TARGET); #endif }else if(evt == BDB_EVT_COMMISSIONING_TOUCHLINK_FINISH){ /* confirm to application */ bdb_topLevelCommissiongConfirm(); BDB_STATE_SET(BDB_STATE_IDLE); } break; case BDB_STATE_COMMISSIONING_NETWORK_STEER: if(evt == BDB_EVT_COMMISSIONING_NETWORK_STEER_RETRIEVE_TCLINK_KEY){ TL_ZB_TIMER_SCHEDULE(bdb_retrieveTcLinkKeyStart, NULL, 1000); }else if(evt == BDB_EVT_COMMISSIONING_NETWORK_STEER_PERMITJOIN){ #if ZB_ROUTER_ROLE g_zbNwkCtx.joinAccept = 1; #endif zb_mgmtPermitJoinReq(0xfffc, BDBC_MIN_COMMISSIONING_TIME, 0x01, &sn, NULL); TL_SCHEDULE_TASK(bdb_mgmtPermitJoiningConfirm,NULL); }else if(evt == BDB_EVT_COMMISSIONING_NETWORK_STEER_FINISH){ status = bdb_commissioningNetworkFormation(); if(status == BDB_STATE_IDLE){ /* confirm to application */ bdb_topLevelCommissiongConfirm(); } BDB_STATE_SET(status); } break; case BDB_STATE_COMMISSIONING_NETWORK_FORMATION: if(evt == BDB_EVT_COMMISSIONING_NETWORK_FORMATION_PERMITJOIN){ g_bdbAttrs.commissioningMode.networkSteer = 1; zb_mgmtPermitJoinReq(0xfffc, BDBC_MIN_COMMISSIONING_TIME, 0x01, &sn, NULL); TL_SCHEDULE_TASK(bdb_mgmtPermitJoiningConfirm,NULL); }else if(evt == BDB_EVT_COMMISSIONING_NETWORK_FORMATION_FINISH){ status = bdb_commissioningFindBind(); if(status == BDB_STATE_IDLE){ /* confirm to application */ bdb_topLevelCommissiongConfirm(); } BDB_STATE_SET(status); } break; case BDB_STATE_COMMISSIONING_FINDORBIND: if(evt == BDB_EVT_COMMISSIONING_FINDORBIND_SIMPLE_DESC_REQ){ bdb_commissioningFindBindSimpleDescReq(); }else if(evt == BDB_EVT_COMMISSIONING_FINDORBIND_FINISH){ bdb_findBindRst(); bdb_topLevelCommissiongConfirm(); BDB_STATE_SET(BDB_STATE_IDLE); } break; default: break; } } /********************************************************************* * @fn bdb_task_delay * * @brief * * @param arg * * @return */ _CODE_BDB_ static s32 bdb_task_delay(void *arg) { TL_SCHEDULE_TASK(bdb_task, arg); return -1; } /********************************************************************* * @fn bdb_zdoStartDevCnf * * @brief node start confirm handle * * @param startDevCnf * * @return */ _CODE_BDB_ void bdb_zdoStartDevCnf(zdo_start_device_confirm_t *startDevCnf){ u32 evt = BDB_EVT_IDLE; u8 state = BDB_STATE_GET(); switch(state){ case BDB_STATE_IDLE: /* for rejoin indication by the stack */ if(startDevCnf->status == SUCCESS){ //g_bdbAttrs.commissioningStatus = BDB_COMMISSION_STA_SUCCESS; g_bdbAttrs.nodeIsOnANetwork = 1; #if ZB_ROUTER_ROLE g_zbNwkCtx.joinAccept = 1; #endif BDB_STATUS_SET(BDB_COMMISSION_STA_SUCCESS); if((zdo_ssInfoKeyGet() != ss_ib.activeSecureMaterialIndex) || (g_zbInfo.macPib.phyChannelCur != g_bdbCtx.channel) || g_zbNwkCtx.parentIsChanged || g_bdbCtx.forceJoin){ g_zbNwkCtx.parentIsChanged = 0; TL_SCHEDULE_TASK(bdb_commissioningInfoSave, NULL); } }else{ if(startDevCnf->status == ZDO_NETWORK_LOST){ BDB_STATUS_SET(BDB_COMMISSION_STA_PARENT_LOST); }else{ /* rejoin failed */ BDB_STATUS_SET(BDB_COMMISSION_STA_REJOIN_FAILURE); } } g_bdbCtx.forceJoin = 0; evt = BDB_STATE_REJOIN_DONE; TL_SCHEDULE_TASK(bdb_task, (void *)evt); break; case BDB_STATE_INIT: evt = BDB_EVT_INIT_DONE; g_bdbCtx.initResult = BDB_INIT_STATUS_SUCCESS; if(startDevCnf->status != SUCCESS){ g_bdbCtx.initResult = BDB_INIT_STATUS_FAILURE; } TL_SCHEDULE_TASK(bdb_task, (void *)evt); break; #if ((ROUTER || END_DEVICE) && TOUCHLINK_SUPPORT) case BDB_STATE_COMMISSIONING_TOUCHLINK: if(startDevCnf->status == SUCCESS){ g_bdbAttrs.nodeIsOnANetwork = 1; #if ZB_ROUTER_ROLE g_zbNwkCtx.joinAccept = 1; #endif ss_securityModeSet(SS_SEMODE_DISTRIBUTED); TL_SCHEDULE_TASK(bdb_commissioningInfoSave, NULL); } zcl_touchLinkDevStartIndicate((void *)((u32)(startDevCnf->status))); break; #endif case BDB_STATE_COMMISSIONING_NETWORK_STEER: if(startDevCnf->status == SUCCESS){ //g_bdbAttrs.commissioningStatus = BDB_COMMISSION_STA_SUCCESS; g_bdbAttrs.nodeIsOnANetwork = 1; BDB_STATUS_SET(BDB_COMMISSION_STA_SUCCESS); if(!ZB_IEEE_ADDR_IS_INVALID(ss_ib.trust_center_address) && ss_ib.securityLevel){ evt = BDB_EVT_COMMISSIONING_NETWORK_STEER_RETRIEVE_TCLINK_KEY; /* add it for the sdk later than 2.1.0.0, because the global link maybe be changed to default key but not the pre-config key*/ bdb_globalLinkKeySet(ss_ib.tcLinkKey); }else{ evt = BDB_EVT_COMMISSIONING_NETWORK_STEER_PERMITJOIN; bdb_globalLinkKeySet(ss_ib.distributeLinkKey); } TL_ZB_TIMER_SCHEDULE(bdb_task_delay, (void *)evt, 200); }else{ //g_bdbAttrs.commissioningStatus = BDB_COMMISSION_STA_NO_NETWORK; BDB_STATUS_SET(BDB_COMMISSION_STA_NO_NETWORK); evt = BDB_EVT_COMMISSIONING_NETWORK_STEER_FINISH; TL_SCHEDULE_TASK(bdb_task, (void *)evt); } break; case BDB_STATE_COMMISSIONING_NETWORK_FORMATION: if(startDevCnf->status == SUCCESS){ g_bdbAttrs.nodeIsOnANetwork = 1; g_zbNwkCtx.joinAccept = 1; //g_bdbAttrs.commissioningStatus = BDB_COMMISSION_STA_SUCCESS; BDB_STATUS_SET(BDB_COMMISSION_STA_SUCCESS); evt = BDB_EVT_COMMISSIONING_NETWORK_FORMATION_PERMITJOIN; if(g_bdbCtx.bdbAppCb->bdbcommissioningCb){ g_bdbCtx.bdbAppCb->bdbcommissioningCb(BDB_COMMISSION_STA_FORMATION_DONE, NULL); } }else{ /* confirm to application */ //g_bdbAttrs.commissioningStatus = BDB_COMMISSION_STA_FORMATION_FAILURE; BDB_STATUS_SET(BDB_COMMISSION_STA_FORMATION_FAILURE); evt = BDB_EVT_COMMISSIONING_NETWORK_FORMATION_FINISH; } TL_SCHEDULE_TASK(bdb_task, (void *)evt); break; default: //TL_SCHEDULE_TASK(zb_info_save,NULL); break; } } /********************************************************************* * @fn bdb_touchLinkCallback * * @brief * * @param status * arg * * @return */ _CODE_BDB_ static void bdb_touchLinkCallback(u8 status, void *arg) { //printf("touchLinkCb: sta = %x\n", status); u32 evt = BDB_EVT_IDLE; if(status == ZCL_ZLL_TOUCH_LINK_STA_TARGET_START){ zb_nwkDiscoveryStop(); BDB_STATE_SET(BDB_STATE_COMMISSIONING_TOUCHLINK); g_bdbAttrs.commissioningMode.touchlink = 1; g_bdbCtx.role = BDB_COMMISSIONING_ROLE_TARGET; }else if(status == ZCL_ZLL_TOUCH_LINK_STA_NO_SERVER){ /* * if no scan response received, start classic commissioning, * resume some information which is changed during touch link * * */ if(is_device_factory_new()){ bdb_scanCfg(g_bdbAttrs.primaryChannelSet | g_bdbAttrs.secondaryChannelSet, g_bdbAttrs.scanDuration); /* start classic commissioning */ evt = BDB_EVT_COMMISSIONING_TOUCHLINK_NO_RESP; //g_bdbAttrs.commissioningStatus = BDB_COMMISSION_STA_NO_SCAN_RESPONSE; BDB_STATUS_SET(BDB_COMMISSION_STA_NO_SCAN_RESPONSE); }else{ evt = BDB_EVT_COMMISSIONING_TOUCHLINK_FINISH; //g_bdbAttrs.commissioningStatus = BDB_COMMISSION_STA_TARGET_FAILURE; BDB_STATUS_SET(BDB_COMMISSION_STA_TARGET_FAILURE); } }else{ evt = BDB_EVT_COMMISSIONING_TOUCHLINK_FINISH; if(status == ZCL_ZLL_TOUCH_LINK_STA_SUCC || status == ZCL_ZLL_TOUCH_LINK_STA_EXIST){ //g_bdbAttrs.commissioningStatus = BDB_COMMISSION_STA_SUCCESS; BDB_STATUS_SET(BDB_COMMISSION_STA_SUCCESS); }else{ //g_bdbAttrs.commissioningStatus = BDB_COMMISSION_STA_TARGET_FAILURE; if(is_device_factory_new()){ BDB_STATUS_SET(BDB_COMMISSION_STA_TARGET_FAILURE); aps_ib.aps_authenticated = 0; }else{ BDB_STATUS_SET(BDB_COMMISSION_STA_SUCCESS); } } } TL_SCHEDULE_TASK(bdb_task, (void *)evt); } /********************************************************************* * @fn bdb_commssionUtilityCallback * * @brief * * @param cmd * arg * * @return */ _CODE_BDB_ static void bdb_commssionUtilityCallback(u8 cmd, void *arg) { } /********************************************************************* * @fn bdb_topLevelCommissiongConfirm * * @brief the top level commissioning callback * * @param status * * @return */ _CODE_BDB_ static u8 bdb_topLevelCommissiongConfirm(void){ g_bdbAttrs.commissioningStatus = BDB_STATUS_GET(); if(g_bdbCtx.identifyTimer){ TL_ZB_TIMER_CANCEL(&g_bdbCtx.identifyTimer); } if(g_bdbCtx.bdbAppCb->bdbcommissioningCb){ g_bdbCtx.bdbAppCb->bdbcommissioningCb(g_bdbAttrs.commissioningStatus, NULL); } if(g_bdbAttrs.commissioningStatus == BDB_COMMISSION_STA_SUCCESS){ u8 len = 0; tl_zbMacAttrGet(MAC_PHY_ATTR_CURRENT_CHANNEL, &g_bdbCtx.channel, &len); #if ZB_COORDINATOR_ROLE if(g_bdbCtx.factoryNew == 1){ bdb_commissioningInfoSave(NULL); g_bdbCtx.factoryNew = 0; } #endif }else{ #if ZB_ROUTER_ROLE if(BDB_TOUCHLINK_CAP_EN() && is_device_factory_new()){ /* * set channel from primaryChannelSet in bdb attributes * */ ZB_TRANSCEIVER_SET_CHANNEL(g_bdbCtx.channel); rf_setTrxState(RF_STATE_RX); } #endif } return 0; } /********************************************************************* * @fn bdb_topLevelCommissioning * * @brief the top level commissioning procedure that is activated on some trigger * * @param target * * @return */ _CODE_BDB_ static u8 bdb_topLevelCommissioning(u8 target){ /* restore persistent ZigBee data */ if(BDB_STATE_GET() != BDB_STATE_IDLE || !zdo_ifZdoNwkManagerIdle() || g_bdbAttrs.commissioningStatus == BDB_COMMISSION_STA_IN_PROGRESS){ return BDB_STATE_COMMISSIONING_BUSY; } g_bdbCtx.role = target; g_bdbAttrs.commissioningStatus = BDB_COMMISSION_STA_IN_PROGRESS; u32 evt = BDB_EVT_COMMISSIONING_START; TL_SCHEDULE_TASK(bdb_task, (void *)evt); return BDB_STATE_IDLE; } /********************************************************************* * @fn bdb_networkFormationStart * * @brief start network formation * * @param bdb state: * * @return */ _CODE_BDB_ u8 bdb_networkFormationStart(void) { g_bdbAttrs.commissioningMode.networkSteer = 0; g_bdbAttrs.commissioningMode.touchlink = 0; g_bdbAttrs.commissioningMode.findOrBind = 0; g_bdbAttrs.commissioningMode.networkFormation = 1; return bdb_topLevelCommissioning(BDB_COMMISSIONING_ROLE_TARGET); } /********************************************************************* * @fn bdb_networkSteerStart * * @brief classic join start * * @param None * * @return */ _CODE_BDB_ u8 bdb_networkSteerStart(void) { g_bdbAttrs.commissioningMode.networkFormation = 0; g_bdbAttrs.commissioningMode.touchlink = 0; g_bdbAttrs.commissioningMode.findOrBind = 0; g_bdbAttrs.commissioningMode.networkSteer = 1; return bdb_topLevelCommissioning(BDB_COMMISSIONING_ROLE_TARGET); } /********************************************************************* * @fn bdb_networkTouchLinkStart * * @brief * * @param role: BDB_COMMISSIONING_ROLE_INITIATOR or BDB_COMMISSIONING_ROLE_TARGET * * @return */ _CODE_BDB_ u8 bdb_networkTouchLinkStart(u8 role) { g_bdbAttrs.commissioningMode.networkSteer = 1; g_bdbAttrs.commissioningMode.networkFormation = 0; g_bdbAttrs.commissioningMode.findOrBind = 0; g_bdbAttrs.commissioningMode.touchlink = 1; return bdb_topLevelCommissioning(role); } /********************************************************************* * @fn bdb_findAndBindStart * * @brief * * @param role: BDB_COMMISSIONING_ROLE_INITIATOR or BDB_COMMISSIONING_ROLE_TARGET * * @return */ _CODE_BDB_ u8 bdb_findAndBindStart(u8 role) { g_bdbAttrs.commissioningMode.networkSteer = 0; g_bdbAttrs.commissioningMode.networkFormation = 0; g_bdbAttrs.commissioningMode.touchlink = 0; g_bdbAttrs.commissioningMode.findOrBind = 1; return bdb_topLevelCommissioning(role); } /********************************************************************* * @fn check the bdb state * * @brief * * @param 1: idle, 0: busy * * @return */ bool bdb_isIdle(void){ if(BDB_STATE_GET() == BDB_STATE_IDLE && g_bdbAttrs.commissioningStatus != BDB_COMMISSION_STA_IN_PROGRESS){ return 1; } return 0; } /********************************************************************* * @fn bdb_init * * @brief bdb Initialization * * @param simple_desc * setting * cb * repower * * @return None */ _CODE_BDB_ u8 bdb_init(af_simple_descriptor_t *simple_desc, bdb_commissionSetting_t *setting, bdb_appCb_t *cb, u8 repower){ if(g_bdbCtx.inited){ return 1; } g_bdbCtx.inited = 1; g_bdbCtx.bdbAppCb = cb; g_bdbCtx.simpleDesc = simple_desc; g_bdbCtx.commissionSettings = setting; g_bdbCtx.factoryNew = zb_isDeviceFactoryNew(); BDB_STATE_SET(BDB_STATE_INIT); /* security config, must be first. */ #if SECURITY_ENABLE if(g_bdbCtx.securityDisable){ ss_zdoInit(FALSE); }else{ ss_zdoInit(TRUE); } #else ss_zdoInit(FALSE); #endif /* pre-configure the link key here. */ bdb_linkKeyCfg(setting, g_bdbCtx.factoryNew); /* add it for the sdk later than 2.1.0.0, because the global link maybe be changed to default key but not the pre-config key*/ bdb_globalLinkKeyFix(g_bdbCtx.factoryNew); /* pre-configure the nwk key here. */ if(g_bdbCtx.factoryNew){ //u8 preNwkKey[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; //zb_preConfigNwkKey(preNwkKey, TRUE); } #if ((ROUTER || END_DEVICE) && TOUCHLINK_SUPPORT) /* pre-configure for touch link */ bdb_touchLinkPreCfg(simple_desc->endpoint, setting, &bdb_touchlinkCb); #endif bdb_scanCfg(g_bdbAttrs.primaryChannelSet | g_bdbAttrs.secondaryChannelSet, g_bdbAttrs.scanDuration); g_bdbAttrs.commissioningStatus = BDB_COMMISSION_STA_SUCCESS; g_bdbAttrs.nodeIsOnANetwork = g_bdbCtx.factoryNew ? 0 : 1; if(g_bdbAttrs.nodeIsOnANetwork){ /* update outgoing frame count */ bdb_outgoingFrameCountUpdate(repower); #if ZB_COORDINATOR_ROLE bdb_coordinatorStart(); #elif ZB_ROUTER_ROLE bdb_routerStart(); #elif ZB_ED_ROLE bdb_endDeviceStart(repower); #endif }else{ /* if it's a factory-new device,do nothing except configure some attribute for touch link */ bdb_factoryNewDevCfg(BDB_TOUCHLINK_CAP_EN(), setting->touchlinkChannel); u32 evt = BDB_EVT_INIT_DONE; TL_SCHEDULE_TASK(bdb_task, (void *)evt); } /* get the real operation channel for non-factory new device */ u8 len = 0; tl_zbMacAttrGet(MAC_PHY_ATTR_CURRENT_CHANNEL, &g_bdbCtx.channel, &len); return 0; } /********************************************************************* * @fn bdb_join_direct() * * @brief join/establish a network directly * * @param channel * panId * shortAddr * extPanId * nwkKey * inited * * @return None */ _CODE_BDB_ u8 bdb_join_direct(u8 channel, u16 panId, u16 shortAddr, u8 *extPanId, u8 *nwkKey, u8 type, u8 inited, u8 *tcAddr){ u8 ret = FAILURE; if((BDB_STATE_GET() == BDB_STATE_IDLE) && (!g_bdbAttrs.nodeIsOnANetwork)){ g_bdbCtx.forceJoin = 1; ss_securityModeSet(type); zb_joinAFixedNetwork(channel, panId, shortAddr, extPanId, nwkKey, tcAddr); if(inited){ aps_ib.aps_authenticated = 1; aps_ib.aps_use_insecure_join = FALSE; /* AIB */ #if ZB_COORDINATOR_ROLE bdb_coordinatorStart(); #elif ZB_ROUTER_ROLE bdb_routerStart(); #elif ZB_ED_ROLE bdb_endDeviceStart(1); #endif } ret = SUCCESS; } return ret; } /********************************************************************* * @fn bdb_findBindMatchClusterSet * * @brief for initiator * * @param clusterNum * clusterId * * @return None */ _CODE_BDB_ void bdb_findBindMatchClusterSet(u8 clusterNum, u16 clusterId[]) { g_bdbCtx.clusterNum = clusterNum; g_bdbCtx.clusterList = clusterId; } /********************************************************************* * @fn bdb_addIdentifyActiveEpForFB * * @brief for initiator * * @param dstInfo * * @return TRUE / FALSE */ _CODE_BDB_ bool bdb_addIdentifyActiveEpForFB(findBindDst_t dstInfo) { if(BDB_STATE_GET() == BDB_STATE_COMMISSIONING_FINDORBIND && g_bdbCtx.role == BDB_COMMISSIONING_ROLE_INITIATOR){ if(!g_bdbCtx.pFindBindQ){ g_bdbCtx.pFindBindQ = queueInit(); if(!g_bdbCtx.pFindBindQ){ return FALSE; } } return queuePush(g_bdbCtx.pFindBindQ, dstInfo); } return FALSE; } /********************************************************************* * @fn bdb_defaultReportingCfg * * @brief * * @param endpoint * profileID * clusterID * attrID * minReportInt * maxReportInt * reportableChange * * @return zcl status */ _CODE_BDB_ status_t bdb_defaultReportingCfg(u8 endpoint, u16 profileID, u16 clusterID, u16 attrID, u16 minReportInt, u16 maxReportInt, u8 *reportableChange) { zclCfgReportRec_t cfgReportRec; TL_SETSTRUCTCONTENT(cfgReportRec, 0); reportCfgInfo_t *pEntry = zcl_reportCfgInfoEntryFind(endpoint, clusterID, attrID); if(pEntry){ return ZCL_STA_DUPLICATE_EXISTS; } zclAttrInfo_t *pAttrEntry = zcl_findAttribute(endpoint, clusterID, attrID); if(!pAttrEntry){ return ZCL_STA_UNSUPPORTED_ATTRIBUTE; } cfgReportRec.attrID = attrID; cfgReportRec.dataType = pAttrEntry->type; cfgReportRec.direction = 0; cfgReportRec.minReportInt = minReportInt; cfgReportRec.maxReportInt = maxReportInt; cfgReportRec.reportableChange = reportableChange; return zcl_configureReporting(endpoint, profileID, clusterID, &cfgReportRec); } /********************************************************************* * @fn bdb_attrSet * * @brief set attributes for base device behavior * * @param attrId - attribute identify * value - the value set to bdb's attribute * * @return None */ _CODE_BDB_ void bdb_attrSet(u8 attrId, u8 *value) { if(attrId > BDB_ATTR_TC_NODE_JOIN_TIMEOUT || attrId < BDB_ATTR_PRIMARY_CHANNEL_SET){ return; } u8 len = g_bdbAttrTbl[attrId-BDB_ATTR_PRIMARY_CHANNEL_SET].len; memcpy((u8 *)&g_bdbAttrs+g_bdbAttrTbl[attrId-BDB_ATTR_PRIMARY_CHANNEL_SET].offset, value, len); return; } /********************************************************************* * @fn bdb_attrGet * * @brief get attributes for base device behavior * * @param attrId - attribute identify * value - the value gotten from bdb's attribute * len - the length of the bdb's attribute * * @return BDB_COMMISSION_STA_SUCCESS / BDB_COMMISSION_STA_NOT_PERMITTED */ _CODE_BDB_ u8 bdb_attrGet(u8 attrId, u8* value, u8* len) { if(attrId > BDB_ATTR_TC_NODE_JOIN_TIMEOUT || attrId < BDB_ATTR_PRIMARY_CHANNEL_SET){ return BDB_COMMISSION_STA_NOT_PERMITTED; } *len = g_bdbAttrTbl[attrId-BDB_ATTR_PRIMARY_CHANNEL_SET].len; memcpy(value, (u8 *)&g_bdbAttrs+g_bdbAttrTbl[attrId-BDB_ATTR_PRIMARY_CHANNEL_SET].offset, *len); return BDB_COMMISSION_STA_SUCCESS; } /********************************************************************* * @fn tl_bdbReset * * @brief * * @param None * * @return None */ _CODE_BDB_ void tl_bdbReset(void) { af_simple_descriptor_t *sd = g_bdbCtx.simpleDesc; bdb_appCb_t *bcb = g_bdbCtx.bdbAppCb; bdb_commissionSetting_t *commissionSet = g_bdbCtx.commissionSettings; g_bdbAttrs.nodeIsOnANetwork = 0; memset((u8 *)&g_bdbCtx,0,sizeof(g_bdbCtx)); bdb_init(sd, commissionSet, bcb, 1); } /********************************************************************* * @fn tl_bdbReset2FN * * @brief Clear all ZigBee persistent data except the outgoing NWK frame counter * and perform a reset such that the target is in much the same state as * it was when it left the factory. * * @param None * * @return None */ _CODE_BDB_ void tl_bdbReset2FN(void) { nv_resetToFactoryNew(); zb_reset(); tl_bdbReset(); } /********************************************************************* * @fn tl_bdbAttrInit * * @brief * * @param None * * @return None */ _CODE_BDB_ void tl_bdbAttrInit(void) { memcpy(&g_bdbAttrs, &g_bdbAttrsDft, sizeof(bdb_attr_t)); } _CODE_BDB_ u16 tl_bdbInstallCodeCRC16(u8 *pInstallCode, u8 len) { u16 crc = 0xffff; if(len == 0){ return (~crc); } u8 i; u8 data; do{ for(i = 0, data = 0xff & *pInstallCode++; i < 8; i++, data >>= 1){ if((crc & 0x0001) ^ (data & 0x0001)){ crc = (crc >> 1) ^ POLY; }else{ crc >>= 1; } } }while(--len); crc = ~crc; return crc; } _CODE_BDB_ void tl_bdbUseInstallCode(u8 *pInstallCode, u8 *pKey) { u8 tmpBuf[SEC_KEY_LEN + 2]; memcpy((u8 *)tmpBuf, (u8 *)pInstallCode, SEC_KEY_LEN); u16 crc = tl_bdbInstallCodeCRC16(pInstallCode, SEC_KEY_LEN); tmpBuf[SEC_KEY_LEN] = (u8)(crc & 0xff); tmpBuf[SEC_KEY_LEN + 1] = (u8)(crc >> 8); ss_mmoHash(tmpBuf, SEC_KEY_LEN + 2, pKey); } /** * @brief Load install code from NV * * @param[out] keyType * @param[out] derivedKey * * @return None */ _CODE_BDB_ u8 bdb_preInstallCodeLoad(u8 *keyType, u8 derivedKey[]) { u8 invalidInstallCode[SEC_KEY_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; u8 installCode[SEC_KEY_LEN]; flash_read(CFG_PRE_INSTALL_CODE, SEC_KEY_LEN, (u8 *)installCode); if(!memcmp((u8 *)installCode, (u8 *)invalidInstallCode, SEC_KEY_LEN)){ return RET_NOT_FOUND; } tl_bdbUseInstallCode(installCode, derivedKey); *keyType = SS_UNIQUE_LINK_KEY; return RET_OK; } /** * @brief Add pre-install code to NV * * @param[in] ieeeAddr: the ieee address of the device using unique link key join * * @param[in] pInstallCode: the pointer of install code * * @return None */ _CODE_BDB_ void bdb_preInstallCodeAdd(addrExt_t ieeeAddr, u8 *pInstallCode) { if(!pInstallCode || ZB_IS_64BIT_ADDR_INVALID(ieeeAddr) || ZB_IS_64BIT_ADDR_ZERO(ieeeAddr)){ return; } ss_dev_pair_set_t keyPair; if(NV_SUCC == ss_devKeyPairFind(ieeeAddr, &keyPair)){ return; } memset((u8 *)&keyPair, 0, sizeof(ss_dev_pair_set_t)); tl_bdbUseInstallCode(pInstallCode, keyPair.linkKey); memcpy(keyPair.device_address, ieeeAddr, 8); keyPair.incomingFrameCounter = keyPair.outgoingFrameCounter = 0; keyPair.apsLinkKeyType = SS_UNIQUE_LINK_KEY; keyPair.keyAttr = SS_UNVERIFIED_KEY; ss_devKeyPairSave(&keyPair); }