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!

  • 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