This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC2652P: are channel masks saved into NVS after being modified in sample ZC/ZED applications?

Part Number: CC2652P

Hi,

I am going through the sample zc-thermostat application and noticed that both primary and secondary channel masks don't seem have been saved into NVS after they are changed via CUI. They always revert back to the default channel masks as defined in syscfg after power cycle. As a comparison, Pan ID seems to be written into NVS after it is changed and survives power cycle. The updated Pan ID will be displayed in CUI once intercept starts.

Judging from the code, both channel masks should have been persisted:

// zcl_sampleApps_ui.c

/*********************************************************************
 * @fn          uiActionProcessConfigureSecChannels
 *
 * @brief       State-machine action for configuring channel masks
 *
 * @param       _input - uart key or uart notification
 *              _pLines - pointers to the buffers to be displayed
 *              _pCurInfo - pointer to the cursor position. The position is given
 *                          by the length of _pLines and the number of lines.
 *                          If -1,-1 is provided, no pointer is displayed
 *
 * @return      none
 */
static void uiActionProcessConfigureSecChannels(const char _input, char* _pLines[3], CUI_cursorInfo_t* _pCurInfo)
{
    static uint32_t channelMask = SECONDARY_CHANLIST;

    if (_input == CUI_ITEM_INTERCEPT_START) {
        zstack_bdbGetAttributesRsp_t rsp;
        Zstackapi_bdbGetAttributesReq(uiAppEntity, &rsp);

        channelMask = rsp.bdbSecondaryChannelSet;
    }

    uiActionProcessConfigureChannels(_input, _pLines, _pCurInfo, &channelMask);

    if (_input == CUI_ITEM_INTERCEPT_STOP) {
        zstack_bdbSetAttributesReq_t req = {0};
        req.bdbSecondaryChannelSet = channelMask;
        req.has_bdbSecondaryChannelSet = true;
        Zstackapi_bdbSetAttributesReq(uiAppEntity, &req);
    }

    if (_input != CUI_ITEM_PREVIEW)
        strcpy(_pLines[2], " SEC CHANL MASK");
}


I dug a little deeper, it seems channel masks are considered part of bdbAttributes and are handled differently. bdbAttributes  are always loaded from default on startup, and are not written into NVS upon change.

// bdb.c

bdbAttributes_t bdbAttributes = BDB_ATTRIBUTES_DEFAULT_CONFIG;

// zstacktask.c
/**************************************************************************************************
 * @fn          processBdbSetAttributesReq
 *
 * @brief       Process BDB Set attributes Request
 *
 * @param       srcServiceTaskId - Source Task ID
 * @param       pMsg - pointer to message
 *
 * @return      TRUE to send the response back
 */
static bool processBdbSetAttributesReq( uint8_t srcServiceTaskId, void *pMsg )
{
  zstackmsg_bdbSetAttributesReq_t *pPtr = (zstackmsg_bdbSetAttributesReq_t *)pMsg;

  if ( pPtr->pReq )
  {
    pPtr->hdr.status = zstack_ZStatusValues_ZSuccess;

#if (ZG_BUILD_JOINING_TYPE)
    if ( pPtr->pReq->has_bdbTCLinkKeyExchangeAttemptsMax )
    {
    	bdbAttributes.bdbTCLinkKeyExchangeAttemptsMax = pPtr->pReq->bdbTCLinkKeyExchangeAttemptsMax;
    }

    if ( pPtr->pReq->has_bdbTCLinkKeyExchangeMethod )
    {
    	bdbAttributes.bdbTCLinkKeyExchangeMethod = pPtr->pReq->bdbTCLinkKeyExchangeMethod;
    }
#endif

    if ( pPtr->pReq->has_bdbCommissioningGroupID )
    {
    	bdbAttributes.bdbCommissioningGroupID = pPtr->pReq->bdbCommissioningGroupID;
    }

    if ( pPtr->pReq->has_bdbPrimaryChannelSet )
    {
    	bdbAttributes.bdbPrimaryChannelSet = pPtr->pReq->bdbPrimaryChannelSet;
    }

    if ( pPtr->pReq->has_bdbScanDuration )
    {
    	bdbAttributes.bdbScanDuration = pPtr->pReq->bdbScanDuration;
    }

    if ( pPtr->pReq->has_bdbSecondaryChannelSet )
    {
    	bdbAttributes.bdbSecondaryChannelSet = pPtr->pReq->bdbSecondaryChannelSet;
    }

#if (ZG_BUILD_COORDINATOR_TYPE)
    if ( pPtr->pReq->has_bdbJoinUsesInstallCodeKey )
    {
    	bdbAttributes.bdbJoinUsesInstallCodeKey = pPtr->pReq->bdbJoinUsesInstallCodeKey;
    }

    if ( pPtr->pReq->has_bdbTrustCenterNodeJoinTimeout )
    {
    	bdbAttributes.bdbTrustCenterNodeJoinTimeout = pPtr->pReq->bdbTrustCenterNodeJoinTimeout;
    }

    if ( pPtr->pReq->has_bdbTrustCenterRequireKeyExchange )
    {
    	bdbAttributes.bdbTrustCenterRequireKeyExchange = pPtr->pReq->bdbTrustCenterRequireKeyExchange;
    }
#endif
  }
  else
  {
    pPtr->hdr.status = zstack_ZStatusValues_ZInvalidParameter;
  }

  return (TRUE);
}

If we as users want to set channels mask per each installation, how do we go about it? Save channel masks as customized NV item and use them to override bdbAttributes on system startup or save the whole or part of bdbAttributes into NVS?

Please advise, and thanks in advance.

ZL

  • Hi ZL,

    There is a channel list stored in NV (ZCD_NV_CHANLIST from zcomdef.h) but this is not changed by the CUI in the default examples.  To implement this functionality you would add a Zstackapi_sysConfigWriteReq to the CUI_ITEM_INTERCEPT_STOP case of uiActionProcessConfigurePriChannels from zcl_sampleapps_ui.c:

              zstack_sysConfigWriteReq_t writeReq = {0};
              // Update the config Channel List, defined in znwk_config.h
              writeReq.has_chanList = true;
              writeReq.chanList = channelMask;
              Zstackapi_sysConfigWriteReq(uiAppEntity, &writeReq);

    This will only affect the primary channel list as secondary channel lists are not considered by NV memory.  You can also follow Application Non-Volatile Memory instructions if you would like to add custom NV memory items to your application.

    Regards,
    Ryan

  • While this saves changed channel masks into NVS, I assume we will also need to read them from NVS before formation of network on coordinator and joining a network on router and end devices. Where would be the best place to place such code? Something like the following ?

    /*********************************************************************
     * @fn          uiActionStartComissioning
     *
     * @brief       action function to trigger commissioning
     *
     * @return      none
     */
    static void uiActionStartComissioning(const int32_t _itemEntry)
    {
      // reset network connection string before commissioning again
      uiCommissioningNetworkConnectionStr = NULL;
    
      if (*gpBdbCommisioningModes != 0)
      {
        zstack_bdbStartCommissioningReq_t zstack_bdbStartCommissioningReq;
    
        FBMatchesFound = 0;
    
        uiCommissioningIsInitializing = TRUE;
    
        zstack_bdbStartCommissioningReq.commissioning_mode = *gpBdbCommisioningModes;
    	
    	// TODO: read channel masks from NVS
    	// Pass channel masks to bdbAttributes before nwkFormation and commissioning
    
        Zstackapi_bdbStartCommissioningReq(uiAppEntity,&zstack_bdbStartCommissioningReq);
      }
    }

  • As with the uiActionProcessConfigurePriChannels CUI_ITEM_INTERCEPT_STOP case, you will need to determine a location for which Zstackapi_bdbSetAttributesReq is called for bdbPrimaryChannelSet.  That can be from uiActionStartComissioning, however keep in mind that this function is only called for the UART UI and is not used for other commissioning methods such as from the pushbutton or a custom automatic start.

    Regards,
    Ryan