Z-Stack 1.2.2a (CC253x) to Z-Stack 3.1.0¶
This section will describe a way to migrate a project from Z-Stack 1.2.2a for CC253x to a Z-Stack 3.1.0 project.
For this guide, SampleLight from Z-Stack 1.2.2a for CC253x will be ported over to Z-Stack 3.1.0. The two releases are vastly divergent due to differences in both device and RTOS support, as is covered in CC253x to CC13xx or CC26xx. The recommended approach is to start with a Z-Stack 3.1.0 project that contains the same base application as the porting target project and merge any custom functionality.
Note
Z-Stack HA 1.2.2a is based off of the Zigbee PRO 2012 (r20) specification whereas Z-Stack 3.x.x follows Zigbee PRO 2015 (r21) and later. There are several significant changes between these specifications that greatly affect the behavior of the Zigbee mesh network, including child aging, enhanced security, BDB specification, and Green Power as described in the What’s New in Zigbee 3.0 White Paper <https://www.ti.com/lit/swra615>. This section will only address application-level changes, network configuration changes are further discussed in CC253x to CC13xx or CC26xx.
Choose a Z-Stack 3.1.0 example project that contains your target project’s base functionality. For reference and use in this example, zc_light from C:\ti\simplelink_zigbee_sdk_plugin_2_20_00_06\examples\rtos\CC13xx or CC26xx_LAUNCHXL\zstack is chosen as a starting point.
Modify the following Z-Stack 3.1.0 example files if any of the corresponding were added or altered in the Z-Stack 1.2.2a project.
zcl_samplelight_data.c
clusters, attributes, or simple descriptorszcl_samplelight.h
application event definitionszcl_samplelight.c
event loop cases and callbacks
Do not copy the Z-Stack 1.2.2a
OSAL_SampleLight.c
file and only make changes to the following lines of the 3.1.0main.c
#include "zcl_samplelight.h" /* Kick off application */ zclSampleLight_task(&zstack_user0Cfg.nvFps);
if the task name has been changed inside of
zcl_samplelight.c
The following items specifically concern zcl_samplelight.c
:
Note the following differences for which all related code from Z-Stack 1.2.2a should not be transferred to the Z-Stack 3.1.0 project:
#define ZCL_EZMODE
is no longer used as this functionality is replaced by 3.0 Base Device Behavior#define ZCL_REPORT
is deprecated as no longer being optional
Note the following changes due to the TI-RTOS implementation:
ICALL framework used to dispatch messages between Z-Stack and the application
Semaphores used to post and pend during event callbacks
Timer handling, i.e
Timer_setTimeout( LevelControlClkHandle, 100 ); Timer_start(&LevelControlClkStruct);
versus
osal_start_timerEx( zclSampleLight_TaskID, SAMPLELIGHT_LEVEL_CTRL_EVT, 100 );
. Due to this and the reasons further provided below, all related code from Z-Stack 1.2.2a should not be transferred to the Z-Stack 3.1.0 project. For more information, please refer to TI-RTOS7 (RTOS Kernel) Overview.Separate 3.0 projects are used for each Zigbee device instead of a common application with multiple configurations, therefore the
ZG_BUILD_[COORDINATOR/RTR/ENDDEVICE]_TYPE
definitions are necessaryGreen Power is enabled in 3.0, and therefore the following is added:
gp_endpointInit(zclSampleLight_Entity);
andapp_Green_Power_Init
insidezclSampleLight_Init
In
zclSampleLight_process_loop
#if !defined (DISABLE_GREENPOWER_BASIC_PROXY) && (ZG_BUILD_RTR_TYPE) if(events & SAMPLEAPP_PROCESS_GP_DATA_SEND_EVT) { zcl_gpSendNotification(); events &= ~SAMPLEAPP_PROCESS_GP_DATA_SEND_EVT; } if(events & SAMPLEAPP_PROCESS_GP_EXPIRE_DUPLICATE_EVT) { gp_expireDuplicateFiltering(); events &= ~SAMPLEAPP_PROCESS_GP_EXPIRE_DUPLICATE_EVT; } #endif
In
zclSampleLight_processZStackMsgs
:#if !defined (DISABLE_GREENPOWER_BASIC_PROXY) && (ZG_BUILD_RTR_TYPE) case zstackmsg_CmdIDs_GP_DATA_IND: { zstackmsg_gpDataInd_t *pInd; pInd = (zstackmsg_gpDataInd_t*)pMsg; gp_processDataIndMsg( &(pInd->Req) ); } break; case zstackmsg_CmdIDs_GP_SECURITY_REQ: { zstackmsg_gpSecReq_t *pInd; pInd = (zstackmsg_gpSecReq_t*)pMsg; gp_processSecRecMsg( &(pInd->Req) ); } break; case zstackmsg_CmdIDs_GP_CHECK_ANNCE: { zstackmsg_gpCheckAnnounce_t *pInd; pInd = (zstackmsg_gpCheckAnnounce_t*)pMsg; gp_processCheckAnnceMsg( &(pInd->Req) ); } #endif
Base Device Behavior is added to 3.0 and the following is added as such:
In
zclSampleLight_Init
:#if defined ( BDB_TL_INITIATOR ) touchLinkInitiatorApp_Init(zclSampleLight_Entity); #elif defined ( BDB_TL_TARGET ) touchLinkTargetApp_Init(zclSampleLight_Entity); #endif
zclSampleLight_initParameters
:static void zclSampleLight_initParameters(void) { zstack_bdbSetAttributesReq_t zstack_bdbSetAttrReq; zstack_bdbSetAttrReq.bdbCommissioningGroupID = BDB_DEFAULT_COMMISSIONING_GROUP_ID; zstack_bdbSetAttrReq.bdbPrimaryChannelSet = BDB_DEFAULT_PRIMARY_CHANNEL_SET; zstack_bdbSetAttrReq.bdbScanDuration = BDB_DEFAULT_SCAN_DURATION; zstack_bdbSetAttrReq.bdbSecondaryChannelSet = BDB_DEFAULT_SECONDARY_CHANNEL_SET; zstack_bdbSetAttrReq.has_bdbCommissioningGroupID = TRUE; zstack_bdbSetAttrReq.has_bdbPrimaryChannelSet = TRUE; zstack_bdbSetAttrReq.has_bdbScanDuration = TRUE; zstack_bdbSetAttrReq.has_bdbSecondaryChannelSet = TRUE; #if (ZG_BUILD_COORDINATOR_TYPE) zstack_bdbSetAttrReq.has_bdbJoinUsesInstallCodeKey = TRUE; zstack_bdbSetAttrReq.has_bdbTrustCenterNodeJoinTimeout = TRUE; zstack_bdbSetAttrReq.has_bdbTrustCenterRequireKeyExchange = TRUE; zstack_bdbSetAttrReq.bdbJoinUsesInstallCodeKey = BDB_DEFAULT_JOIN_USES_INSTALL_CODE_KEY; zstack_bdbSetAttrReq.bdbTrustCenterNodeJoinTimeout = BDB_DEFAULT_TC_NODE_JOIN_TIMEOUT; zstack_bdbSetAttrReq.bdbTrustCenterRequireKeyExchange = BDB_DEFAULT_TC_REQUIRE_KEY_EXCHANGE; #endif #if (ZG_BUILD_JOINING_TYPE) zstack_bdbSetAttrReq.has_bdbTCLinkKeyExchangeAttemptsMax = TRUE; zstack_bdbSetAttrReq.has_bdbTCLinkKeyExchangeMethod = TRUE; zstack_bdbSetAttrReq.bdbTCLinkKeyExchangeAttemptsMax = BDB_DEFAULT_TC_LINK_KEY_EXCHANGE_ATTEMPS_MAX; zstack_bdbSetAttrReq.bdbTCLinkKeyExchangeMethod = BDB_DEFAULT_TC_LINK_KEY_EXCHANGE_METHOD; #endif Zstackapi_bdbSetAttributesReq(zclSampleLight_Entity, &zstack_bdbSetAttrReq); }
In
zclSampleLight_process_loop
:#if ZG_BUILD_ENDDEVICE_TYPE if ( events & SAMPLEAPP_END_DEVICE_REJOIN_EVT ) { zstack_bdbZedAttemptRecoverNwkRsp_t zstack_bdbZedAttemptRecoverNwkRsp; Zstackapi_bdbZedAttemptRecoverNwkReq(zclSampleLight_Entity,&zstack_bdbZedAttemptRecoverNwkRsp); events &= ~SAMPLEAPP_END_DEVICE_REJOIN_EVT; } #endif
In
zclSampleLight_processZStackMsgs
:switch(pMsg->hdr.event) { case zstackmsg_CmdIDs_BDB_NOTIFICATION: { zstackmsg_bdbNotificationInd_t *pInd; pInd = (zstackmsg_bdbNotificationInd_t*)pMsg; zclSampleLight_ProcessCommissioningStatus(&(pInd->Req)); } break; case zstackmsg_CmdIDs_BDB_IDENTIFY_TIME_CB: { zstackmsg_bdbIdentifyTimeoutInd_t *pInd; pInd = (zstackmsg_bdbIdentifyTimeoutInd_t*) pMsg; uiProcessIdentifyTimeChange(&(pInd->EndPoint)); } break; case zstackmsg_CmdIDs_BDB_BIND_NOTIFICATION_CB: { zstackmsg_bdbBindNotificationInd_t *pInd; pInd = (zstackmsg_bdbBindNotificationInd_t*) pMsg; uiProcessBindNotification(&(pInd->Req)); } break; #if (ZG_BUILD_JOINING_TYPE) case zstackmsg_CmdIDs_BDB_CBKE_TC_LINK_KEY_EXCHANGE_IND: { zstack_bdbCBKETCLinkKeyExchangeAttemptReq_t zstack_bdbCBKETCLinkKeyExchangeAttemptReq; /* Z3.0 has not defined CBKE yet, so lets attempt default TC Link Key exchange procedure * by reporting CBKE failure. */ zstack_bdbCBKETCLinkKeyExchangeAttemptReq.didSuccess = FALSE; Zstackapi_bdbCBKETCLinkKeyExchangeAttemptReq(zclSampleLight_Entity, &zstack_bdbCBKETCLinkKeyExchangeAttemptReq); } break; case zstackmsg_CmdIDs_BDB_FILTER_NWK_DESCRIPTOR_IND: /* User logic to remove networks that do not want to join * Networks to be removed can be released with Zstackapi_bdbNwkDescFreeReq */ Zstackapi_bdbFilterNwkDescComplete(zclSampleLight_Entity); break; #endif #ifdef BDB_TL_TARGET case zstackmsg_CmdIDs_BDB_TOUCHLINK_TARGET_ENABLE_IND: { zstackmsg_bdbTouchLinkTargetEnableInd_t *pInd; pInd = (zstackmsg_bdbTouchLinkTargetEnableInd_t*)pMsg; uiProcessTouchlinkTargetEnable(pInd->Enable); } break; #endif }
zclSampleLight_ProcessCommissioningStatus(bdbCommissioningModeMsg_t *bdbCommissioningModeMsg)
:static void zclSampleLight_ProcessCommissioningStatus(bdbCommissioningModeMsg_t *bdbCommissioningModeMsg) { switch(bdbCommissioningModeMsg->bdbCommissioningMode) { case BDB_COMMISSIONING_FORMATION: if(bdbCommissioningModeMsg->bdbCommissioningStatus == BDB_COMMISSIONING_SUCCESS) { zstack_bdbStartCommissioningReq_t zstack_bdbStartCommissioningReq; //After formation, perform nwk steering again plus the remaining commissioning modes that has not been process yet zstack_bdbStartCommissioningReq.commissioning_mode = BDB_COMMISSIONING_MODE_NWK_STEERING | bdbCommissioningModeMsg->bdbRemainingCommissioningModes; Zstackapi_bdbStartCommissioningReq(zclSampleLight_Entity,&zstack_bdbStartCommissioningReq); } else { //Want to try other channels? //try with bdb_setChannelAttribute } break; case BDB_COMMISSIONING_NWK_STEERING: if(bdbCommissioningModeMsg->bdbCommissioningStatus == BDB_COMMISSIONING_SUCCESS) { //YOUR JOB: //We are on the nwk, what now? } else { //See the possible errors for nwk steering procedure //No suitable networks found //Want to try other channels? //try with bdb_setChannelAttribute } break; case BDB_COMMISSIONING_FINDING_BINDING: if(bdbCommissioningModeMsg->bdbCommissioningStatus == BDB_COMMISSIONING_SUCCESS) { //YOUR JOB: } else { //YOUR JOB: //retry?, wait for user interaction? } break; case BDB_COMMISSIONING_INITIALIZATION: //Initialization notification can only be successful. Failure on initialization //only happens for ZED and is notified as BDB_COMMISSIONING_PARENT_LOST notification //YOUR JOB: //We are on a network, what now? break; #if ZG_BUILD_ENDDEVICE_TYPE case BDB_COMMISSIONING_PARENT_LOST: if(bdbCommissioningModeMsg->bdbCommissioningStatus == BDB_COMMISSIONING_NETWORK_RESTORED) { //We did recover from losing parent } else { //Parent not found, attempt to rejoin again after a fixed delay Timer_setTimeout( EndDeviceRejoinClkHandle, SAMPLEAPP_END_DEVICE_REJOIN_DELAY ); Timer_start(&EndDeviceRejoinClkStruct); } break; #endif } UI_UpdateComissioningStatus(bdbCommissioningModeMsg); }
Key events are now handled locally in
zclSampleLight_processKey
instead ofzclSampleLight_HandleKeys
. A UART interface is preferred over LCD.main.c
calls thezclSampleLight_task
functionvoid zclSampleLight_task(NVINTF_nvFuncts_t *pfnNV) { // Save and register the function pointers to the NV drivers pfnZdlNV = pfnNV; zclport_registerNV(pfnZdlNV, ZCL_PORT_SCENE_TABLE_NV_ID); // Initialize application zclSampleLight_initialization(); // No return from task process zclSampleLight_process_loop(); }
to initialize the application
static void zclSampleLight_initialization(void) { /* Initialize user clocks */ zclSampleLight_initializeClocks(); /* Initialize keys */ Board_Key_initialize(zclSampleLight_changeKeyCallback); /* Initialize the LEDS */ Board_Led_initialize(); // Register the current thread as an ICall dispatcher application // so that the application can send and receive messages. ICall_registerApp(&zclSampleLight_Entity, &sem); //Initialize stack zclSampleLight_Init(); }
which in-turn initializes the clocks, keys, LEDs, and ICall dispatcher before initializing the stack. This is compared with Z-Stack 1.2.2a where all of the above was accomplished in
main
andzclSampleLight_Init
.zclSampleLight_Init
registers endpoints using//Register Endpoint zclSampleLightEpDesc.endPoint = SAMPLELIGHT_ENDPOINT; zclSampleLightEpDesc.simpleDesc = &zclSampleLight_SimpleDesc; zclport_registerEndpoint(zclSampleLight_Entity, &zclSampleLightEpDesc);
instead of
// Register the Simple Descriptor for this application zclHA_Init( &zclSampleLight_SimpleDesc );
and registers applications with
// Register the Application to receive the unprocessed Foundation command/response messages zclport_registerZclHandleExternal(zclSampleLight_ProcessIncomingMsg);
as compared to
// Register the Application to receive the unprocessed Foundation command/response messages zcl_registerForMsg( zclSampleLight_TaskID );
zclSampleLight_process_loop
is used in place ofzclSampleLight_event_loop
and uses ICall to receive messages instead ofSYS_EVENT_MSG
events andosal_msg_receive
ICall_ServiceEnum stackid; ICall_EntityID dest; zstackmsg_genericReq_t *pMsg = NULL; /* Wait for response message */ if(ICall_wait(ICALL_TIMEOUT_FOREVER) == ICALL_ERRNO_SUCCESS) { /* Retrieve the response message */ if(ICall_fetchServiceMsg(&stackid, &dest, (void **)&pMsg) == ICALL_ERRNO_SUCCESS) { if( (stackid == ICALL_SERVICE_CLASS_ZSTACK) && (dest == zclSampleLight_Entity) ) { if(pMsg) { zclSampleLight_processZStackMsgs(pMsg); // Free any separately allocated memory Zstackapi_freeIndMsg(pMsg); } } if(pMsg) { ICall_freeMsg(pMsg); } } //**EVENT HANDLING NOT SHOWN** }
zclSampleLight_processZStackMsgs
andzclSampleLight_processAfIncomingMsgInd
is used in place ofzclSampleLight_ProcessIncomingMsg
In
zclSampleLight_processZStackMsgs
:switch(pMsg->hdr.event) { //**OTHER CASES NOT SHOWN** case zstackmsg_CmdIDs_AF_INCOMING_MSG_IND: { // Process incoming data messages zstackmsg_afIncomingMsgInd_t *pInd; pInd = (zstackmsg_afIncomingMsgInd_t *)pMsg; zclSampleLight_processAfIncomingMsgInd( &(pInd->req) ); } break; }
Structure type
zclIncomingMsg_t
has been renamedzclIncoming_t
Add any other Z-Stack 1.2.2a application changes to the Z-Stack 3.1.0 file if not pertaining to the items listed above.
Note
Difference comparison software is recommended for discerning all differences between software stacks.