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.

LP-EM-CC2340R53: How to safely update BLE advertising data periodically on CC2340R53?

Part Number: LP-EM-CC2340R53

Tool/software:

I'm using the CC2340R53 with the Basic BLE example, and I want to periodically update the BLE advertising data with sensor values.

To do this, I'm using a separate application thread that sets a flag or sends a message to the BLE thread. Inside the BLE thread, I try to:

  1. Call GapAdv_disable(peripheralAdvHandle_1)

  2. Then call GapAdv_prepareLoadByHandle() and GapAdv_loadByHandle() to update the adv data

  3. Then start advertising again using GapAdv_enable()

However, GapAdv_disable() returns bleAlreadyInRequestedMode (0x11), which seems to suggest that advertising is already stopped.

Below is my function to stop, initialize and start the advertising again (I have changed the advData1 buffer before calling the below function itself):

bStatus_t post_ble_adv_data_update(void)
{
    bStatus_t status = SUCCESS;

    // Stop current advertising
    status = BLEAppUtil_advStop(peripheralAdvHandle_1);
     printf("BLEAppUtil_advStop Error Code: %d\n", status);
    // It’s okay if the adv was already stopped, but block only on true errors
    if ((status != SUCCESS) && (status != bleAlreadyInRequestedMode))
    {
        return status;
    }

    sleep(1);

    // Reinitialize advertising set
    status = BLEAppUtil_initAdvSet(&peripheralAdvHandle_1, &advSetInitParamsSet_1);
    if (status != SUCCESS) {
        printf("BLEAppUtil_initAdvSet Error Code: %d\n", status);
        return status;
    }

    // Start advertising with new parameters
    status = BLEAppUtil_advStart(peripheralAdvHandle_1, &advSetStartParamsSet_1);
    if (status != SUCCESS) {
        printf("BLEAppUtil_advStart Error Code: %d\n", status);
    }
return status;
}
  • Hi,

    Thank you for reaching out. To safely update advertising data, I would wait until the BLEAPPUTIL_ADV_START_AFTER_DISABLE event is received. This event is posted to the application after the stack has fully disabled advertising. The BLEAPPUTIL_ADV_START_AFTER_ENABLE event is received when the advertisements have been enabled.

    Best Regards,

    Jan

  • Helo!  

    Thank you for the suggestion.

    I tried the recommended approach by waiting for the BLEAPPUTIL_ADV_START_AFTER_DISABLE event before attempting to update the advertising data. This did resolve the bleAlreadyInRequestedMode error — I'm now able to stop advertising without any issues.

    However, I'm facing a new issue: after re-initializing the advertising data, the manufacturer-specific data is no longer visible in the advertisement payload. I only see the 0x09 (Complete Local Name) type data being advertised. The rest of the custom fields, especially the manufacturer data, seems to be missing.

    Could you please guide me on how to ensure the manufacturer-specific data is correctly set and visible after restarting the advertising?

    Best regards,
    Shivam Singh

  • Hi Shivam,

    Glad to hear we were able to make some progress! Can you share how you are re-initializing the advertising data? Typically, the manufacturer data is stored in the scan response. Are you setting the scan response as well?

    Best Regards,

    Jan

  • Hi Jan,

    Thanks for your message!

    Yes, currently I have two threads running—mainThread and the BLE task from the TI example. Every 30 seconds, the mainThread triggers a timer that sends a custom command to the BLE thread using:  BLEAppUtil_enqueueMsg(BLEAPPUTIL_EVT_APPLICATION, NULL);

    In the bleapputil_task.c, I’ve added a handler for BLEAPPUTIL_EVT_APPLICATION, where I perform the following steps:
    1. Stop the current advertising: BLEAppUtil_advStop(peripheralAdvHandle_1);
    2. Wait for a second to ensure clean stop.
    3. Reinitialize the advertising set: BLEAppUtil_initAdvSet(&peripheralAdvHandle_1, &advSetInitParamsSet_1);
    4. Wait again briefly.
    5. Start advertising with the new parameters: BLEAppUtil_advStart(peripheralAdvHandle_1, &advSetStartParamsSet_1);

    I also tried without adding sleep(1) and also tried to wait for code to reach in BLEAPPUTIL_ADV_END_AFTER_DISABLE in this switch case before initializing the adv again.

    Currently, I am updating the manufacturer data in the advertising packet itself, not in the scan response. I plan to explore setting the scan response data as well if needed.

    Let me know if you see any improvements or alternate suggestions to this approach.

    Best regards,
    Shivam

  • Hi Shivam,

    Got it. If you are scanning with a phone, then not updating the scan response is likely the issue. Most phones report the scan response data when scanning instead of the advertising data. Can you add the manufacturer data to the scan response to see if the issue goes away?

    Best Regards,

    Jan

  • Hi Jan,

    Thanks for the clarification!

    I did try modifying the scan response data at runtime, but observed that it also gets cleared or disappears after attempting the update. I suspect I might be missing a specific step or sequence required when updating the scan response dynamically.

    Is there any example or sample project available that demonstrates how to properly update advertising and scan response data periodically at runtime? That would really help me validate my approach and ensure I'm handling the updates correctly.

    Appreciate your continued support.

    Best regards,
    Shivam

  • Hi Shivam,

    We don't have a pre-made code that does this, but if you share your latest code snippets, I would be happy to take a look! Another point to consider is that smartphones will often cache the first scan response data and adv data pair that is seen from a particular device and not report any changes unless a complete new scan is done. To force the cache to clear, please exit your BLE app and turn off & on the BLE functionality on your phone. You could also use a BLE sniffer to confirm if the packets are truly changing.

    Best Regards,

    Jan

  • Hi Jan,

    Thanks again for the suggestions!

    I tried toggling BLE off and on, as well as restarting the scanning app to clear any potential caching on the smartphone side. However, it didn’t make any difference—the updated advertising or scan response data still wasn’t visible.

    I also tested using a BLE sniffer and was able to identify the issue there. I’m attaching the relevant sniffer screenshots along with the code snippets and the bleapputil_task.c file for your reference.

    Please change the ADV_OFFSET to 7 in sensor_task.c file.

    I’d really appreciate it if you could take a look and let me know if anything stands out or needs to be handled differently.

    Best regards,
    Shivam

    /******************************************************************************
    
    @file  BLEAppUtil_task.c
    
    @brief This file contains the BLEAppUtil module task function and related
           functionality
    
    Group: WCS, BTS
    Target Device: cc23xx
    
    ******************************************************************************
    
     Copyright (c) 2022-2025, Texas Instruments Incorporated
     All rights reserved.
    
     Redistribution and use in source and binary forms, with or without
     modification, are permitted provided that the following conditions
     are met:
    
     *  Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
    
     *  Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.
    
     *  Neither the name of Texas Instruments Incorporated nor the names of
        its contributors may be used to endorse or promote products derived
        from this software without specific prior written permission.
    
     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    
    ******************************************************************************
    
    
    *****************************************************************************/
    
    
    /*********************************************************************
     * INCLUDES
     */
    #include "ti/ble/app_util/framework/bleapputil_api.h"
    #include "ti/ble/app_util/framework/bleapputil_internal.h"
    #include "app_main.h"
    
    /*********************************************************************
     * MACROS
     */
    
    
    /*********************************************************************
    * CONSTANTS
    */
    // Task configuration
    #define appTaskStack            NULL
    #define BLEAPPUTIL_QUEUE_EVT    0x40000000
    #define EVENT_PEND_FOREVER      0xFFFFFFFF
    
    /*********************************************************************
    * TYPEDEFS
    */
    
    /*********************************************************************
    * GLOBAL VARIABLES
    */
    
    /*********************************************************************
    * LOCAL VARIABLES
    */
    
    /*********************************************************************
    * LOCAL FUNCTIONS
    */
    void *BLEAppUtil_Task(void *arg);
    
    /*********************************************************************
     * EXTERN FUNCTIONS
    */
    
    /*********************************************************************
    * CALLBACKS
    */
    
    /*********************************************************************
     * PUBLIC FUNCTIONS
     */
    
    /*********************************************************************
    * LOCAL FUNCTIONS
    */
    
    /*********************************************************************
     * @fn      BLEAppUtil_createBLEAppUtilTask
     *
     * @brief   Create the BLEAppUtil task.
     *
     * @return  SUCCESS, otherwise retVal error.
     */
    int BLEAppUtil_createBLEAppUtilTask(void)
    {
        int retVal = 0;
        pthread_attr_t param_attribute;
        struct sched_param param;
    
        retVal =  pthread_attr_init(&param_attribute);
        param.sched_priority = BLEAppUtilLocal_GeneralParams->taskPriority;
    
        retVal |= pthread_attr_setschedparam(&param_attribute, &param);
        retVal |= pthread_attr_setstack(&param_attribute, appTaskStack, BLEAppUtilLocal_GeneralParams->taskStackSize);
        retVal |= pthread_attr_setdetachstate(&param_attribute, PTHREAD_CREATE_DETACHED);
    
        retVal |= pthread_create(&BLEAppUtil_theardEntity.threadId,
                                 &param_attribute,
                                 &BLEAppUtil_Task,
                                 NULL);
        return retVal;
    }
    
    /*********************************************************************
     * @fn      BLEAppUtil_enqueueMsg
     *
     * @brief   Enqueue the message from the BLE stack to the application queue.
     *
     * @param   event - message event.
     * @param   pData - pointer to the message from BLE stack.
     *
     * @return  SUCCESS   - message was enqueued successfully
     * @return  otherwise - error value is returned
     */
    status_t BLEAppUtil_enqueueMsg(uint8_t event, void *pData)
    {
        int8_t status = SUCCESS;
        BLEAppUtil_appEvt_t msg;
    
        // Check if the queue is valid
        if (BLEAppUtil_theardEntity.queueHandle == (mqd_t)-1)
        {
            return(bleNotReady);
        }
    
        msg.event = event;
        msg.pData = pData;
    
        // Send the msg to the application queue
        status = mq_send(BLEAppUtil_theardEntity.queueHandle,(char*)&msg,sizeof(msg),1);
    
        return status;
    }
    
    /*********************************************************************
     * @fn      BLEAppUtil_Task
     *
     * @brief   The BLEAppUtil task function.
     *          This function registers to get stack events, call the stack
     *          initializing function and process the events that are
     *          enqueued to it's queue.
     *          Note: The data is freed in this function, the application
     *                needs to copy the data in order to save it in order
     *                to use it outside the event handler of the application.
     *
     * @return  None
     */
    void *BLEAppUtil_Task(void *arg)
    {
        // Register to the stack and create queue and event
        BLEAppUtil_stackRegister();
    
        // Init the ble stack
        BLEAppUtil_stackInit();
    
        // Application main loop
        for (;;)
        {
            BLEAppUtil_appEvt_t pAppEvt;
    
            // wait until receive queue message
            if (mq_receive(BLEAppUtil_theardEntity.queueHandle, (char*)&pAppEvt, sizeof(pAppEvt), NULL) > 0)
            {
                BLEAppUtil_msgHdr_t *pMsgData = (BLEAppUtil_msgHdr_t *)pAppEvt.pData;
                bool freeMsg = FALSE;
    
                switch (pAppEvt.event)
                {
                  case BLEAPPUTIL_EVT_APPLICATION:
                  {
                    
                    ////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                    // bStatus_t status;
                    // // Don't free anything since we're going to use the same buffer to re-load
                    // status = GapAdv_prepareLoadByHandle(peripheralAdvHandle_1, GAP_ADV_FREE_OPTION_DONT_FREE);
    
                    // // Only update the data when return is successful
                    // if (status == SUCCESS)
                    // {
                    //     // Sample buffer modification
                    //     advData1[3] = 0xAF;
    
                    //     // Reload buffer to handle
                    //     // Here the advDataLen = sizeof(advData1) and it is setup in the app\_peripheral.c
                    //     // under advSetInitParamsSet_1
                    //     GapAdv_loadByHandle(peripheralAdvHandle_1, GAP_ADV_DATA_TYPE_ADV, advSetInitParamsSet_1.advDataLen, advData1);
                    //     printf("BLEAPPUTIL_EVT_APPLICATION SUCCESS\n");
                    // }
                    // else {
                    //     printf("BLEAPPUTIL_EVT_APPLICATION Failure Error Code: %d\n", status);
                    // }
                    ////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
                    // GapAdv_prepareLoadByHandle(0, GAP_ADV_FREE_OPTION_ADV_DATA);
    
                    // // Allocate new buffer (and then fill it as desired)
                    // uint8_t *advData2= ICall_malloc(sizeof(advData1));
                    // memcpy(advData2, advData1, sizeof(advData1));
    
                    // // Load the new buffer to the advertisement set handle
                    // GapAdv_loadByHandle(peripheralAdvHandle_1, GAP_ADV_DATA_TYPE_ADV, sizeof(advData1), advData2);
    
                    ////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                    bStatus_t status = SUCCESS;
    
                    // Stop current advertising
                    status = BLEAppUtil_advStop(peripheralAdvHandle_1);
                    printf("BLEAppUtil_advStop Error Code: %d\n", status);
                    
                    //// Tried GapAdv_destroy(), didn't resolved any issue
                    // status = GapAdv_destroy(peripheralAdvHandle_1, GAP_ADV_FREE_OPTION_DONT_FREE);
                    // printf("GapAdv_destroy Error Code: %d\n", status);
    
    
                    // Reinitialize advertising set
                    start_updated_adv = true;
                    status = BLEAppUtil_initAdvSet(&peripheralAdvHandle_1, &advSetInitParamsSet_1);
                    printf("BLEAppUtil_initAdvSet Error Code: %d\n", status);
    
                    // // GapAdv_loadByHandle(peripheralAdvHandle_1, GAP_ADV_DATA_TYPE_ADV, advSetInitParamsSet_1.advDataLen, advSetInitParamsSet_1.advData);
    
                    // Start advertising with new parameters
                    status = BLEAppUtil_advStart(peripheralAdvHandle_1, &advSetStartParamsSet_1);
                    printf("BLEAppUtil_advStart Error Code: %d\n", status);
    
                    break;
                  }
    
                  case BLEAPPUTIL_EVT_UPDATE_APPLICATION:
                  {
                    bStatus_t status = SUCCESS;
    
                    // Reinitialize advertising set
                    status = BLEAppUtil_initAdvSet(&peripheralAdvHandle_1, &advSetInitParamsSet_1);
                    printf("BLEAppUtil_initAdvSet Error Code: %d\n", status);
    
                    // sleep(1);
    
                    // GapAdv_loadByHandle(peripheralAdvHandle_1, GAP_ADV_DATA_TYPE_ADV, advSetInitParamsSet_1.advDataLen, advSetInitParamsSet_1.advData);
    
                    // Start advertising with new parameters
                    status = BLEAppUtil_advStart(peripheralAdvHandle_1, &advSetStartParamsSet_1);
                    printf("BLEAppUtil_advStart Error Code: %d\n", status);
    
                    break;
                  }
    
                  case BLEAPPUTIL_EVT_STACK_CALLBACK:
                  {
                      // Cast to the stack MSG pointer format passed to the enqueue function
                      BLEAppUtil_stackMsgData_t *stackMsg = (BLEAppUtil_stackMsgData_t *)pAppEvt.pData;
    
                      if(stackMsg != NULL)
                      {
                          // Set the flag to true to indicate that BLEAppUtil_freeMsg
                          // should be used to free the msg
                          freeMsg = TRUE;
                          // Point to the msg that was received from the stack,
                          // it will be freed in the end of this function
                          pMsgData = stackMsg->pMessage;
    
                          // Process the stack event received
                          BLEAppUtil_processStackEvents(stackMsg->pMessage, stackMsg->eventAndHandlerType);
    
                          // Free the stack msg
                          BLEAppUtil_free(stackMsg);
                      }
                    break;
                  }
                  case BLEAPPUTIL_EVT_ADV_CB_EVENT:
                      BLEAppUtil_processAdvEventMsg(pMsgData);
                      break;
    
                  case BLEAPPUTIL_EVT_SCAN_CB_EVENT:
                      BLEAppUtil_processScanEventMsg(pMsgData);
                      break;
    
                  case BLEAPPUTIL_EVT_PAIRING_STATE_CB:
                      BLEAppUtil_processPairStateMsg(pMsgData);
                      break;
    
                  case BLEAPPUTIL_EVT_PASSCODE_NEEDED_CB:
                      BLEAppUtil_processPasscodeMsg(pMsgData);
                      break;
    
                  case BLEAPPUTIL_EVT_CONN_EVENT_CB:
                  {
                      // Cast to a msg from the type allocated in the callback
                      BLEAppUtil_connEventNoti_t *connNotiData = (BLEAppUtil_connEventNoti_t *)pMsgData;
    
                      // Point to the msg that was received from the stack,
                      // it will be freed in the end of this function
                      pMsgData = (BLEAppUtil_msgHdr_t *)connNotiData->connEventReport;
    
                      BLEAppUtil_processConnEventMsg(connNotiData);
    
                      // Free the data allocated in the callback
                      BLEAppUtil_free(connNotiData);
                      break;
                  }
    
                  case BLEAPPUTIL_EVT_CALL_IN_BLEAPPUTIL_CONTEXT:
                  {
                      ((BLEAppUtil_CallbackToInvoke_t *)pMsgData)->callback(((BLEAppUtil_CallbackToInvoke_t *)pMsgData)->data);
    
                      // Verify that the data is not NULL before freeing it
                      if(((BLEAppUtil_CallbackToInvoke_t *)pMsgData)->data != NULL)
                      {
                          BLEAppUtil_free(((BLEAppUtil_CallbackToInvoke_t *)pMsgData)->data);
                      }
                      break;
                  }
    
                  case BLEAPPUTIL_EVT_HANDOVER_SN_EVENT_CB:
                  {
                      BLEAppUtil_processHandoverEventMsg(BLEAPPUTIL_HANDOVER_START_SERVING_EVENT_CODE, pMsgData);
                      break;
                  }
    
                  case BLEAPPUTIL_EVT_HANDOVER_CN_EVENT_CB:
                  {
                      BLEAppUtil_processHandoverEventMsg(BLEAPPUTIL_HANDOVER_START_CANDIDATE_EVENT_CODE, pMsgData);
                      break;
                  }
    
                  case BLEAPPUTIL_EVT_CS_EVENT_CB:
                  {
                      BLEAppUtil_processCsEventMsg(BLEAPPUTIL_CS_EVENT_CODE, pMsgData);
                      break;
                  }
                  case BLEAPPUTIL_EVT_CMS_CONN_UPDATE_CB:
                  {
                      BLEAppUtil_processCmEventMsg(BLEAPPUTIL_CM_CONN_UPDATE_EVENT_CODE, pMsgData);
                      break;
                  }
    
                  case BLEAPPUTIL_EVT_CM_REPORT_EVENT_CB:
                  {
                      BLEAppUtil_processCmEventMsg(BLEAPPUTIL_CM_REPORT_EVENT_CODE, pMsgData);
                      break;
                  }
    
                  case BLEAPPUTIL_EVT_CM_CONN_STATUS_EVENT_CB:
                  {
                      BLEAppUtil_processCmEventMsg(BLEAPPUTIL_CM_CONN_STATUS_EVENT_CODE, pMsgData);
                      // Release the inner data
                      BLEAppUtil_free( ((cmStatusEvt_t*)pMsgData)->pEvtData );
                      break;
                  }
    
                  default:
                      break;
                }
    
    
                // Free the data
                if (pMsgData && freeMsg)
                {
                    // Use freeMsg
                    BLEAppUtil_freeMsg(pMsgData);
                }
                else if (pMsgData)
                {
                    // Use free
                    BLEAppUtil_free(pMsgData);
                    pMsgData = NULL;
                }
                else
                {
                    /* this else clause is required, even if the
                    programmer expects this will never be reached
                    Fix Misra-C Required: MISRA.IF.NO_ELSE */
                }
            }
        }
    }
    
    /////////////////////////////////////////////////////////////////////////
    // Help functions
    /////////////////////////////////////////////////////////////////////////
    
    /*********************************************************************
     * @fn      BLEAppUtil_convertBdAddr2Str
     *
     * @brief   Convert Bluetooth address to string.
     *
     * @param   pAddr - BD address
     *
     * @return  BD address as a string
     */
    char *BLEAppUtil_convertBdAddr2Str(uint8_t *pAddr)
    {
        uint8_t     charCnt;
        char        hex[] = "0123456789ABCDEF";
        static char str[(2*B_ADDR_LEN)+3];
        char        *pStr = str;
    
        *pStr++ = '0';
        *pStr++ = 'x';
    
        // Start from end of addr
        pAddr += B_ADDR_LEN;
    
        for (charCnt = B_ADDR_LEN; charCnt > 0; charCnt--)
        {
            *pStr++ = hex[*--pAddr >> 4];
            *pStr++ = hex[*pAddr & 0x0F];
        }
      *pStr = 0;
    
        return str;
    }
    
    bleapputil_internal.hbasic_ble_oad_dual_image_LP_EM_CC2340R53_freertos_ticlang (2).zip

  • Hi Jan,

    Adding below code snippet, resolved my issue:

    // Free the buffer (to avoid double copying) since we're loading a new buffer
    // However, only free the buffer if it's allocated in the application.
    // Using out of box example, the buffer is a global array and can not be freed
    GapAdv_prepareLoadByHandle(peripheralAdvHandle_1, GAP_ADV_FREE_OPTION_ADV_DATA);


    Best Regards,
    Shivam Singh