Peripheral fails to re-start advertising after disconnecting from Client

I'm having some issues with my Peripheral failing to restart advertising after its disconnected from the Client.

In my main loop, I am looking at a bunch of flags to decide what to do next, and part of that is to check one that tracks the BLE status:

typedef enum
{
	BLE_CONNECTED,
	BLE_DISCONNECTED,
	BLE_ADVERTISING,
	BLE_NOT_STARTED,
	BLE_STOPPED
} bt_current_state;

In my callback that gets called when I disconnect from the Client, I set this flag to BLE_ADVERSTING:

void disconnected(struct bt_conn *conn, uint8_t reason)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    LOG_INF("INFO: Disconnected from %s (reason 0x%02x)", addr, reason);

	bt_status = BLE_ADVERTISING;
}

Then in my main loop, I look for this flag being set to BLE_ADVERSTING and I update my scan response data, then attempt to update the adversting data with this new scan response data:

if (bt_status == BLE_ADVERTISING)
{
	update_sr_data(sst_data, sr_data);
	update_adv_data();
}

But for some reason, I am getting an error when I make a call to update_adv_data.  This function does the following:

void update_adv_data(void)
{
	int8_t err;
	
	err = bt_le_adv_update_data(ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
	if (err & (bt_status == BLE_ADVERTISING))
	{
		LOG_ERR("ERROR: Adv data update failed (err %d)",err);
	}
}

I am getting an error of -11 from that call to bt_le_adv_update_data which seems to indicate that the Peripheral isn't actually advertising if I understand this section of that API correctly:

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

So, I'm trying to work out where things are falling over, as I would expect that once the Peripheral disconnects, it should automatically restart advertising.  I know its at least getting the disconnect callback because I see the printk() statement from that callback on my Terminal software:

INFO: Disconnected from F4:21:CA:73:F6:AE (public) (reason 0x16)

If I understand that code correctly, it means that the Local Host (my Client) has initiated the disconnect, which is what I am expecting to happen.  What I can't seem to work out is why my Peripheral then fails to re-start advertising.

Can anyone assist me in what I need to be looking at to try and resolve this issue?

Regards

Mike

Parents
  • Hi Mike. 

    I would expect that once the Peripheral disconnects, it should automatically restart advertising.

    This is partially true. Most of the samples implements this functionality, because in most use cases it makes sense to start advertising once the device disconnects. 

    However, this is controlled by the application. So after your device disconnects to have to make sure that bt_le_adv_start() is called. 

    You can use the function bt_le_adv_update_data() if your advertising is already started. 

    Br, 
    Joakim

Reply
  • Hi Mike. 

    I would expect that once the Peripheral disconnects, it should automatically restart advertising.

    This is partially true. Most of the samples implements this functionality, because in most use cases it makes sense to start advertising once the device disconnects. 

    However, this is controlled by the application. So after your device disconnects to have to make sure that bt_le_adv_start() is called. 

    You can use the function bt_le_adv_update_data() if your advertising is already started. 

    Br, 
    Joakim

Children
  • Hi Joakim,

    I eventually got to the bottom of the issue.  I'd blindly copied some code from another example that was providing notifications on a characteristic, and in the connection callback for that example, they had the following line:

    current_conn = bt_conn_ref(conn);

    The current_conn parameter was used to make changes to the MTU and a few other connection parameters.  But calling bt_conn_ref() I believe is incrementing the connection counter, so when I disconnected, I believe I was only disconnecting from one connection, or the connection counter was such that it was indicating there was still a valid connection.  So, when I went to update the advertisting data, it still was effectively connected, not advertising, hence the error messages.

    I can fix this issue in two ways:

    1. Add bt_conn_unref(current_con) in my disconnect callback

    2. Calling current_con = conn in my connection callback, and excluding the call to bt_conn_ref().

    I'm not exactly sure why you could use bt_conn_ref() and I'm not sure which of the above solutions is actually the correct (or if they both are, then better) option.

    Regards,

    Mike

  • Hi Joakim,

    Seems I spoke too soon.  I'm still having this issue.

    For whatever reason, when I have an iOS Client (such as the nRF Connect App) attempt to disconnect from my device, the connection remains valid and I cannot see it re-advertise.

    The only way I seem to be able to get the disconnection to work successfully is to actually have a Disconnect Service and Characteristic, and when the Client writes to the Characteristic, I call:

    // Function to update the value of disconnect_status when Client writes to it
    static ssize_t write_disconnect_status(struct bt_conn *conn,
    			       const struct bt_gatt_attr *attr, const void *buf,
    			       uint16_t len, uint16_t offset, uint8_t flags)
    {
    	LOG_DBG("INFO: Received value for disconnect_status: %d", ((uint8_t *) buf)[0]);
    	disconnect_status = ((uint8_t *) buf)[0];
    	if (disconnect_status)
    	{
    		uint8_t rv = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
    		if (rv == 0) {
    			LOG_DBG("INFO: Peripheral successfully disconencted from Central");
    			disconnect_status = 0;
    		}
    		else {
    			LOG_DBG("ERROR: Peripheral failed to disconenct from Central");
    		}
    	}
    	return len;
    }

    This then successfully forces a disconnection of the current connection.

    Yet, if the iOS Client simply issues a disconnect request, the disconnect callback I have defined doesn't appear to get called.

    My Peripheral is Paired and Bonded to the Client (I need this for getting the CTS).  Not sure if this is part of the problem?

    I recall seeing this issue about a year ago (refer to this link) and was never really able to resolve it beyond have a specific Service/Characteristic that would enable me to force a disconnection.

    If I used an nRF52-DK as my Client, and have this interfaced to the nRF Connect for Desktop Bluetooth Low Energy Standalone App on my Windows machine, then when I press the "disconnect" button on that, it successfully disconnects from the Peripheral and the Peripheral will start to advertise again.

    Regards,

    Mike

Related