Selective Connection To a Specific Gateway

Hello!

I am having 3 nrf5340 devices; 2 Gateways and 1 Headset. I am trying to achieve the scenario where I can allow the Headset connects to selectively one of the 2 Gateways using a button on the headset as an interface for the user, and if the user presses on the button, the connection is shifted to the other Gateway.

Based on my observation in BIS, I noticed that the connection is established using the MAC Random Address, and since the Random Address keeps changing every time, my current solution is to store the random address of the Gateway that connects first to the headset and once the user presses on the button (i.e. to change the connection to a different Gateway), the headset keeps scanning until it receives another Random address, and using the function API bt_addr_le_cmp(const bt_addr_le_t *a, const bt_addr_le_t *b), I compare the newly arrived address with Gateway address that is stored previously. If both addresses match, the headset scans again for another random address, and if the addresses are different, it indicates that a new device has been found and thus connects to the new address and also stores its address (as in Gateway1 previously) for future comparisons. That way I can assure to connect to a new Gateway every time the user presses on the button on the Headset.

However, I do not think that solution is optimized enough because sometimes the scanning keeps receiving the same random address over and over again and thus taking so much time until it randomly picks up the new address. I would like to hear from you on how I can optimize this connection process. I am still new to the Nordic nrf 5340 development, and your advice is highly appreciated!

  • Hello,

    Have you tried to add only one of the devices to the whitelist using bt_le_whitelist_add()? I know you say that that the address is changing, but if you try to bond to both devices, but only keep the one you want to connect to in the whitelist, perhaps that does the trick. I must admit I haven't tested this in the nRF Connect SDK yet. 

    Best regards,

    Edvin

  • Thank you very much, Edvin, for your answer.

    After doing some research last time, I noticed that the Whitelist is where I can include all the addresses that I wish to connect to. However, in my case I just want to iterate the connection upon the user pressing the button (From Gateway 1 → Gateway 2) and vice versa (From Gateway 2 → Gateway 1), and I will not be able to determine the address of the second device. While searching for an answer last time, I came across something called the 'Blacklist', which can help me blacklist/hide the received address to give an opportunity for the scanner to search for a new address. This was a brilliant idea, but unfortunately, it is not supported in the current nRF SDK.

  • Are you bonded with the gateways? If so, the peripheral should know the IRK (Identity resolving key). I see that the way that you are currently searching through the addresses is pretty much working, right? What you want to do is to skip the comparing of new addresses if I understand correctly?

    Are you able to determine using bt_addr_le_cmp(const bt_addr_le_t *a, const bt_addr_le_t *b) whether the new address is the same device as before?

  • Hi Edvin. My apologies for the late reply. I don't think the headset is bonded with both gateways at the same time. It only bonds with a single device and I can hear the audio transmitted by that device only.

    Using my current implementation, the comparison I implemented helps me to disconnect, find a new device, and connect with that device, but I was thinking if I can find an optimized way to do that.  

    I was thinking to implement your suggested idea which is using the function bt_le_whitelist_add() in ble_tans.c file, but I faced an error 'undefined reference to bt_le_whitelist_add'. Based on your experience, would you mind to guide me regarding the best practice of using that function?

  • I see from some release notes (release-notes-2.7.rst) that bt_le_whitelist_add is deprecated in favor of bt_le_filter_accept_list_add(). Try using that function instead. 

    If you look at the definition of bt_le_filter_accept_list_add() in bt_rcp_gap_client.c (write it, right click, and go to definition), you can see that this function is only defined if 

    CONFIG_BT_FILTER_ACCEPT_LIST is defined, so you need to add this to prj.conf for the function to be usable:
    Another approach is to use something called directed advertising. If you look at where you call bt_le_adv_start(), you probably do so with BT_LE_ADV_CONN as the first parameter. You can also try to replace this with 
    BT_LE_ADV_CONN_DIR(_peer), where _peer is the peer address as a bt_addr_le_t parameter (I think).
    Try copying the address from the connected event, something like this:
    //Near top of main.c:
    bt_addr_le_t address_1 = NULL;
    bt_addr_le_t address_2 = NULL;
    
    static void connected(struct bt_conn *conn, uint8_t err)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	if (err) {
    		LOG_ERR("Connection failed (err %u)", err);
    		return;
    	}
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    	LOG_INF("Connected %s", log_strdup(addr));
    
        err = bt_le_filter_accept_list_add(addr);
        LOG_INF("err = %d", err);
    
    	current_conn = bt_conn_ref(conn);
    
    	dk_set_led_on(CON_STATUS_LED);
    	
    	// Copy this:
    	if (address_1 == NULL)
    	{
            address_1 = bt_conn_get_dst(conn);
        }
        else if (address_2 == NULL)
        {
            address_2 = bt_conn_get_dst(conn);
        }
    }
    
    ...
    // wherever you start advertising:
    err = bt_le_adv_start(BT_LE_ADV_CONN_DIR(addr_1), ad, ARRAY_SIZE(ad), ...)
    
    Best regards,
    Edvin
Related