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 CC26x2. 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. This section will only address application-level changes, network configuration changes are further discussed in CC253x to CC26x2.

  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_light from C:\ti\simplelink_zigbee_sdk_plugin_2_20_00_06\examples\rtos\CC26x2_LAUNCHXL\zstack is chosen as a starting point.

  2. 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 descriptors
    • zcl_samplelight.h application event definitions
    • zcl_samplelight.c event loop cases and callbacks
  3. 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.0 main.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:

  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_REPORT is deprecated as no longer being optional
  2. 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-RTOS (RTOS Kernel) Overview.

  3. 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 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. Key events are now handled locally in zclSampleLight_processKey instead of zclSampleLight_HandleKeys. A UART interface is preferred over LCD.

  7. main.c calls the zclSampleLight_task function

    void 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 and zclSampleLight_Init.

  8. 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 );
    
  9. zclSampleLight_process_loop is used in place of zclSampleLight_event_loop and uses ICall to receive messages instead of SYS_EVENT_MSG events and osal_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**
    }
    
  10. zclSampleLight_processZStackMsgs and zclSampleLight_processAfIncomingMsgInd is used in place of zclSampleLight_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;
      }
      
  11. Structure type zclIncomingMsg_t has been renamed zclIncoming_t

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