Using bt_le_adv_update_data()

This is a continuation of Case ID: 272157

That case resolved issues I had dynamically changing the device name (and having that new name show up in advertising).

It seemed to work OK when developing the code using the nRF52840-DK board.

i'm now using that code with nRF Connect SDK 2.0.0 and Visual Studio code (and Zephyr) on a custom board.   The target device is nrf52840 in a BL654PA module.

The code to "rename" the device is:

int newBleAdvName(char *newName) {
  int err;

  // Update the device name
  printk("Set new name: %s\n",newName);
  err = bt_set_name(newName);
  if(err) {
    printk("Error setting device name: %d\n", err);
  } else {
printk("Changed device name to: %s\n", newName);
    // Update the advertising and scan response data needed to update the advertised device name
    // Only need to modify the scan response data in this example as name is in scan response here.
    sd->data = newName;
    sd->data_len = strlen(newName);
    err = bt_le_adv_update_data(ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
    if(err) {
      printk("Error setting advertised name: %d\n", err);
    } else {
printk("Changed advertised name to: %s\n", newName);
    }
  }
  return err;
}

When invoked, function fails, returning error code -11    From errno.h        #define EAGAIN 11       /**< No more contexts */  

Here is a screen capture of the RTT console output during that time:

If I set a breakpoint to try to step through, I get an exception:

I suspect this is due to some real-time interaction with the BLE stack, so I think the error code message is what I need to resolve.

It's unclear to me what "No more contexts" means or how to correct this.

Do you have any suggestions?

Thanks!

Parents
  • The hardfault gave the faulting instruction address. Can you check in your .map file what function exists there. What is the context in which you are calling newBleAdvName?

  • Hi Susheel,

    Thanks...

    The hardfault only occurs when I insert breakpoints (attempting to debug), so I think this is associated with BLE realtime issues being violated.    But the hardfault address points to:

    0x38 modules/nrf/subsys/mpsl/init/lib..__nrf__subsys__mpsl__init.a(mpsl_init.c.obj)

    newBleAdvName is called due to a characteristic being written to the device (from the central) that assigns a new device name to the device.    So it is called from a "characteristic written" callback in the device.    This is the expected behavior, but the calls to bt_set_name and bt_le_adv_update_data return -11.     I'm not sure what the "No more contexts" indicates.

    Thanks again!                                                                                                                                                                                                                                                                                                                                                                      

  • Does advertising have to be active for "bt_le_adv_update_data" to execute successfully?   Is this what the "context" error refers to?

  • I do not think that the advertising needs to be active but it needs to be enabled before you can update data.

    in zephyr\subsys\bluetooth\host\adv.c:bt_le_adv_update_data: 

    847 (NCSv2.0.0)

    	if (!atomic_test_bit(adv->flags, BT_ADV_ENABLED)) {
    		return -EAGAIN;
    	}

  • Thanks...    I saw this when I was trying to figure out why this is failing.

    It appears that the flag "BT_ADV_ENABLED" is an internal flag, maintained by the code in adv.c

    And from a quick reading of the code, it looks like this flag indicates whether or not advertising is active.

    So if I want to dynamically change the advertised name, do I need to make sure advertising is active before calling bt_le_adv_update_data?    If so, how?  There doesn't seem to be a call that exposes "BT_ADV_ENABLED" (for testing).   

    What I intend (have implemented) is a BLE characteristic (that can be written to the peripheral) that contains a new device name.   When written, the peripheral saves the name, but also attempts to call bt_le_adv_update_data.    Note that to receive the characteristic the device (peripheral) has to be connected, so advertising is not active.  So when the new name is received, bt_le_adv_update_data fails with an error code of -11, which appears to be the test of BT_ADB_ENABLED.     The intent is for this device to use the new name when the device starts advertising again.  (I actually disconnect from the device (from the central) after confirmation of writing the new name has been reported, so the device will start advertising again.)    But since the call to bt_le_adv_update_data failed, the new name is not used.

    Also note that when the device is turned on (reset), the name to use for advertising is read from persistent storage and, after advertising is "started", assigned using bt_le_adv_update_data.    This call works with no error message.

    So it appears that advertising needs to be active for this call to work.   Is there a reason for this?

    Thanks...

  • As a test, I commented out the three lines (847-849) of adv.c, where the BT_ADV_ENABLED flag is tested.    This eliminates the test that causes the name-change failure.    

    This results in the name being changed as intended/expected.   

    So now the question becomes, does this break anything else?    Is this a "bug" in this function?

    Thanks...

  • I cannot see that there is anything in the specification that says that the advertiser needs to be enabled to change the data. It seems like this check might not be needed to update the advertising data offline (when advertiser is not running)

Reply Children
  • OK, thanks...   I'll continue to "comment it out" in my code.    Can you start the process of having it removed from the official code?

    Thanks!

  • I will start a process to review that part of code internally. Thanks for your suggestions and patience.

  • CktDesigner said:
    Does advertising have to be active for "bt_le_adv_update_data" to execute successfully?   Is this what the "context" error refers to?

    It is technically not required for the advertiser to be active (as per spec) to update the adv data while advertiser is not running. But in our solution, when you start advertiser using  bt_le_adv_start, you need to give adv data anyways to this function. So there is no point in updating the adv data when adv is not active/running. 

    The if condition in question was only making sure that this logic applies that there is no point in updating adv data when adv is not running since you need to update it anyway when you start advertiser. But, I see absolutely no harm in commenting out this check.

  • I had this same issue when calling bt_le_adv_update_data() from a connection disconnect callback.
    You don't need to edit the SDK source code - the problem can be fixed by running the call to bt_le_adv_update_data() in a workqueue thread. I'm not sure if this works because it run in the desired context, or whether it works because it introduces a delay.

    void refresh_advertising_data(struct k_work *work)
    {
    	// Update the ID in the advertising data, because the user might have changed it
    	// when they were connected.
    	update_advertising_data();
    
    	int err = bt_le_adv_update_data(ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
    	if (err) {
    		printk("Advertising failed to update (err %d)\n", err);
    	}
    }
    
    K_WORK_DEFINE(refresh_advertising_data_work, refresh_advertising_data);
    
    static void disconnected(struct bt_conn *conn, uint8_t reason)
    {
    	printk("Disconnected (reason %u)\n", reason);
    
    	dk_set_led_off(CON_STATUS_LED);
    
    	// Update the ID in the advertising data, because the user might have changed it
    	// when they were connected.
    	k_work_submit(&refresh_advertising_data_work);
    }

  • We had a similiar issue, and using a workqueue thread solves it.

    However, I'm very anxious to understand _why_ it works, and whether our customers can rely on it. Do you have any light to shed here ?

    Edit: We found the source of our issue. Calling `bt_le_adv_update_data()` consumed the remaining stack of the calling thread. Putting it in a workqueue gave it a separate stack, and that solved the issue. Increasing the stack size of the calling thread also solved it. You might perhaps have had a similar issue .

Related