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.

  1. 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.

  2. Cluster, attribute, and simple descriptor values should be extracted from the original application file switch.c and placed in zcl_samplesw_data.c including:

    • CONST zclAttrRec_t zclSampleSw_Attrs[]

    • uint8 CONST zclSampleSw_NumAttributes

    • const cId_t zclSampleSw_[In/Out]ClusterList

    • SimpleDescriptionFormat_t zclSampleSw_SimpleDesc

  3. Modify the following Z-Stack 3.1.0 example files based on the Z-Stack 1.2.2a project.

    • zcl_samplesw.h application event definitions

    • zcl_samplesw.c event loop cases and callbacks

  4. Do not copy the Z-Stack 1.2.2a main.c file and only make changes to the following lines of the 3.1.0 main.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:

  1. 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

  2. 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.

  3. 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.

  4. Green Power is enabled in 3.0, and therefore the following is added:

    • gp_endpointInit(zclSampleLight_Entity); and app_Green_Power_Init inside zclSampleLight_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
      
  5. 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);
      }
      
  6. A UART interface is preferred over LCD.

  7. zclSampleSw_Init initializes Z-Stack in a different structure from Switch_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();
    }
    
  8. 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.