Z-Stack 1.2.2a (CC26x0) to Z-Stack 3.1.0¶
This section will describe a way to migrate a project from Z-Stack 1.2.2a for CC26x0 to a Z-Stack 3.1.0 project.
For this guide, SampleSwitch from Z-Stack 1.2.2a for CC26x0 will be ported over to Z-Stack 3.1.0. The two releases are vastly divergent due to differences in both device and project dependencies, as is covered in CC26x0 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 CC26x0 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_switch from C:\ti\simplelink_zigbee_sdk_plugin_2_20_00_06\examples\rtos\CC13xx or CC26xx_LAUNCHXL\zstack is chosen as a starting point.
Cluster, attribute, and simple descriptor values should be extracted from the original application file
switch.c
and placed inzcl_samplesw_data.c
including:CONST zclAttrRec_t zclSampleSw_Attrs[]
uint8 CONST zclSampleSw_NumAttributes
const cId_t zclSampleSw_[In/Out]ClusterList
SimpleDescriptionFormat_t zclSampleSw_SimpleDesc
Modify the following Z-Stack 3.1.0 example files based on the Z-Stack 1.2.2a project.
zcl_samplesw.h
application event definitionszcl_samplesw.c
event loop cases and callbacks
Do not copy the Z-Stack 1.2.2a
main.c
file and only make changes to the following lines of the 3.1.0main.c
#include "zcl_samplesw.h" /* Kick off application */ zclSampleSw_task(&zstack_user0Cfg.nvFps);
if the task name has been changed inside of
zcl_samplesw.c
The following items specifically concern zcl_sampleswitch.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_MANUAL_START
is deprecated as no longer being optional
Apply changes from TI-RTOS 2.11 drivers used in Z-STack 1.2.2a for the CC26x0 to the TI-RTOS drivers included with the SimpleLink CC13xx/CC26xx SDK.
TI-RTOS Kernel is now packaged with the SimpleLink CC13xx/CC26xx SDK. When migrating from the Z-Stack 1.2.2a for the CC26x0, the following drivers have changed. Please see the changes to these files between TI-RTOS for SimpleLink CC13xx/CC26xx 2.14.01.20 with the supplied headers in the SimpleLink CC13xx/CC26xx SDK.
PDMCC26XX.h
PDMCC26XX_util.h
PINCC26XX.h
PWMTimerCC26XX.h
UARTCC26XX.h
WatchdogCC26XX.h
For additional information on how Z-Stack 3.10 uses TI-RTOS see TI-RTOS7 (RTOS Kernel) Overview. and the TI-RTOS examples included with SimpleLink CC13xx/CC26xx SDK. The following is an example of the necessary changes:
Timer_setTimeout( LevelControlClkHandle, 100 ); Timer_start(&LevelControlClkStruct);
versus
Clock_setTimeout( mainScreenClkHandle, (SWITCH_MAINSCREEN_TIMEOUT * TIMER_MS_ADJUSTMENT) ); Util_startClock(&mainScreenClkStruct);
Due to this and the reasons further provided below, all related code from Z-Stack 1.2.2 should not be transferred to the Z-Stack 3.1.0 project.
Separate 3.0 projects are used for each Zigbee device whereas the CC26x0 projects only had enough flash memory for end devices, therefore the
ZG_BUILD_ENDDEVICE_TYPE
definition is necessary.Green 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); }
A UART interface is preferred over LCD.
zclSampleSw_Init
initializes Z-Stack in a different structure fromSwitch_initialization
,static void zclSampleSw_initialization(void) { /* Initialize user clocks */ zclSampleSw_initializeClocks(); /* Initialize keys */ Board_Key_initialize(zclSampleSw_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(&zclSampleSw_Entity, &sem); //Initialize stack zclSampleSw_Init(); }
static void zclSampleSw_Init( void ) { // Set destination address to indirect zclSampleSw_DstAddr.addrMode = (afAddrMode_t)AddrNotPresent; zclSampleSw_DstAddr.endPoint = 0; zclSampleSw_DstAddr.addr.shortAddr = 0; //Register Endpoint zclSampleSwEpDesc.endPoint = SAMPLESW_ENDPOINT; zclSampleSwEpDesc.simpleDesc = &zclSampleSw_SimpleDesc; zclport_registerEndpoint(zclSampleSw_Entity, &zclSampleSwEpDesc); // Register the ZCL General Cluster Library callback functions zclGeneral_RegisterCmdCallbacks( SAMPLESW_ENDPOINT, &zclSampleSw_CmdCallbacks ); // Register the application's attribute list and reset to default values zclSampleSw_ResetAttributesToDefaultValues(); zcl_registerAttrList( SAMPLESW_ENDPOINT, zclSampleSw_NumAttributes, zclSampleSw_Attrs ); // Register the Application to receive the unprocessed Foundation command/response messages zclport_registerZclHandleExternal(zclSampleSw_ProcessIncomingMsg); //Write the bdb initialization parameters zclSampleSw_initParameters(); //Setup ZDO callbacks SetupZStackCallbacks(); #ifdef ZCL_DIAGNOSTIC // Register the application's callback function to read/write attribute data. // This is only required when the attribute data format is unknown to ZCL. zcl_registerReadWriteCB( SAMPLESW_ENDPOINT, zclDiagnostic_ReadWriteAttrCB, NULL ); if ( zclDiagnostic_InitStats() == ZSuccess ) { // Here the user could start the timer to save Diagnostics to NV } #endif #ifdef ZCL_DIAGNOSTIC // Register the application's callback function to read/write attribute data. // This is only required when the attribute data format is unknown to ZCL. zcl_registerReadWriteCB( SAMPLESW_ENDPOINT, zclDiagnostic_ReadWriteAttrCB, NULL ); if ( zclDiagnostic_InitStats() == ZSuccess ) { // Here the user could start the timer to save Diagnostics to NV } #endif UI_Init(zclSampleSw_Entity, &events, sem, SAMPLEAPP_LCD_AUTO_UPDATE_EVT, SAMPLEAPP_PROCESS_UI_UART_EVT, &zclSampleSw_IdentifyTime, APP_TITLE, &zclSampleSw_UiUpdateLcd, zclSampleSw_UiStatesMain); #if defined ( BDB_TL_INITIATOR ) touchLinkInitiatorApp_Init(zclSampleSw_Entity); #elif defined ( BDB_TL_TARGET ) touchLinkTargetApp_Init(zclSampleSw_Entity); #endif UI_UpdateLcd(); #ifdef PER_TEST per_interface_init(sem, zclSampleSw_Entity, SAMPLESW_ENDPOINT ); #endif }
instead of
static void Switch_initialization(void) { /* Initialize variables */ zswDstAddr.addrMode = zstack_AFAddrMode_NONE; zswDstAddr.addr.shortAddr = 0; zswDstAddr.endpoint = 0; zswDstAddr.panID = 0; #if defined (ZCL_EZMODE) zclport_registerEZModeTimerCB(Switch_setEzmodeTimerCallback); #endif Switch_initializeClocks(); /* Initialize keys */ Board_Key_initialize(Switch_processKeyChangeCallback); /* Initialize the LCD */ Board_LCD_open(); LCD_WRITE_STRING( (char *)sDeviceName, LCD_PAGE1 ); #if defined (ZCL_EZMODE) LCD_WRITE_STRING( (char *)sSwEZMode, LCD_PAGE2 ); #elif defined (ZSTACK_MANUAL_START) LCD_WRITE_STRING( (char *)sSwStart, LCD_PAGE2 ); #else LCD_WRITE_STRING( (char *)sClearLine, LCD_PAGE2 ); #endif LCD_WRITE_STRING( (char *)sSwHelp, LCD_PAGE3 ); /* 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(&zswEntity, &sem); // Initialize the ZStack Switch_initializeZStack(); }
static void Switch_initializeZStack(void) { // Initialize the ZStack Thread bool startDev = true; // default to auto-start // Setup the endpoints zswRegEndpoints(); // Setup indications from ZStack zswSetupZStackCallbacks(); #if defined (ZSTACK_MANUAL_START) || defined (ZCL_EZMODE) // Check to see if the device is already part of a network, // to see if we need to invoke EZMode or Manual startup startDev = zclport_isAlreadyPartOfNetwork(zswEntity); #endif #if defined (ZSTACK_MANUAL_START) // Setup the Manual Start module Switch_initializeZstartDiscovery(); #endif #if defined (ZCL_EZMODE) { // Register EZ-Mode zcl_RegisterEZMode(&ezmodeRegisterData); Board_Led_control(board_led_type_LED1, board_led_state_BLINK); } #endif if(startDev) { zstack_devStartReq_t startReq = {0}; // Start the ZStack Thread startReq.startDelay = 0; (void)Zstackapi_DevStartReq(zswEntity, &startReq); #if defined (ZCL_EZMODE) // Clear the EZ Mode line LCD_WRITE_STRING( (char *)sClearLine, LCD_PAGE2 ); #endif } // Register the ZCL General Cluster Library callback functions zclGeneral_RegisterCmdCallbacks(SWITCH_EP, &cmdCallbacks); // Register the application's attribute list zcl_registerAttrList(SWITCH_EP, SWITCH_MAX_ATTRIBUTES, zswAttrs); // Update the ZStack Parameters zswWriteParameters(); }
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.