Directed advertising - peer address

Hello everyone

I am using BLE Peripheral UART and Central UART samples to send data between two nrf5340 dev. kits.

I'm trying to set the directed advertising on the peripheral, so it accepts only connections request from my peer, but I can't find, in which format should i set the address of the central. I tried to change it this way in peripheral main, but it did not connect.

err = bt_le_adv_start(((struct bt_le_adv_param[]) { 
{ .id = BT_ID_DEFAULT, .sid = 0, .secondary_max_skip = 0, 
.options = (BT_LE_ADV_OPT_CONNECTABLE), .interval_min = (0x00a0), 
.interval_max = (0x00f0), .peer = {0xF0,0x33,0x4D,0x3A,0x9F,0x6B}, } }),
ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));

I am also a little bit confused of the Bluetooth LE Device Adress in addr.h library.

/** Bluetooth Device Address */
typedef struct {
	uint8_t  val[BT_ADDR_SIZE];
} bt_addr_t;
/**/

/** Length in bytes of an LE Bluetooth address. Not packed, so no sizeof() */
#define BT_ADDR_LE_SIZE 7
/** Bluetooth LE Device Address */
typedef struct {
	uint8_t      type;
	bt_addr_t a;
} bt_addr_le_t;

What does the variable type mean and in which way should I write the bt_addr_t?

Here is the log from J-Link RTT Viewer

00> [00:00:00.272,583] <inf> fs_nvs: 2 Sectors of 4096 bytes
00> [00:00:00.272,583] <inf> fs_nvs: alloc wra: 0, fc8
00> [00:00:00.272,583] <inf> fs_nvs: data wra: 0, 2c
00> [00:00:00.300,354] <inf> bt_hci_core: No ID address. App must call settings_load()
00> [00:00:00.300,354] <inf> peripheral_uart: Bluetooth initialized
00> [00:00:00.949,981] <inf> peripheral_uart: Connected F0:33:4D:3A:9F:6B (random)
00> [00:00:01.664,978] <wrn> peripheral_uart: Failed to send data over BLE connection

Could please somebody help me or give me any advice?

Sorry for maybe stupid questions, I am just beginner and did not find it anywhere.

  • Hi,


    Before we start digging into potential guides and tutorials I need to know which SDK and version of that SDK you are working with. Could you supply me with that information?
     
    And don't worry about this being a stupid or beginners question. The information can be hard to find at first if you don't quite know where to look, so I'll do my best to help you find it!

    Kind regards,
    Andreas

  • Hello

    thank you for the support! I am using nRF Connect SDK v1.9.1, so the latest.

  • Hi,

    Allright, I'll do my best to explain how to do this and as well supply some recommended resources for you to examine if desired. You may step away from the addr.h library and rather take a look at the scanning module for filtering.

    The central_uart sample is set up to connect one peripheral device with the Nordic UART Service (NUS) enabled. Here the central scans for a specific message with a filter that scans for the NUS Service UUID, at line 497. In the Peripheral device, the scan response data is set up with the NUS UUID that the Central device scans for. When the filter matches with a peripheral it connects. This uses the scanning module, which contains various filters that can be used, including a filter that scans for a name instead of the service UUID. If you wanted, you could modify the samples to use this filter instead and connect with a name as illustrated below:

    1) Changes to Central:

    In scan_init() change the filter type from UUID to NAME both places.

    static int scan_init(void)
    {
    	int err;
    	struct bt_scan_init_param scan_init = {
    		.connect_if_match = 1,
    	};
    
    	bt_scan_init(&scan_init);
    	bt_scan_cb_register(&scan_cb);
    
    	// err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_UUID, BT_UUID_NUS_SERVICE);
    	err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_NAME, "Nordic_UART_Service");
    	if (err) {
    		LOG_ERR("Scanning filters cannot be set (err %d)", err);
    		return err;
    	}
    	// err = bt_scan_filter_enable(BT_SCAN_UUID_FILTER, false);
    	err = bt_scan_filter_enable(BT_SCAN_NAME_FILTER, false);
    	if (err) {
    		LOG_ERR("Filters cannot be turned on (err %d)", err);
    		return err;
    	}
    
    	LOG_INF("Scan module initialized");
    	return err;
    }

    2) Changes to Peripheral: 

    From line 73 change the ad and sd data to the following

    static const struct bt_data ad[] = {
    	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
    	// BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
    };
    
    // static const struct bt_data sd[] = {
    // 	BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_NUS_VAL),
    // };
    
    static const struct bt_data sd[] = {
    	BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
    };

    3) Optionally

    • Customize the peripheral name in proj.conf in the peripheral sample to something you choose yourself. Remember to also edit the string in 1).

    There are several other ways to make a central only connect to specific peripherals, but this is one of the simplest ways.

    Here are some great resources containing information and how-to-dos for creating a Bluetooth Low Energy application. They might be quite detailed and it might take some time to wrap ones head around it, but they have helped me learning more about the Bluetooth stack we use in nRF Connect SDK. Part 2 in this written guide also contains snippets from central_uart and breaks them down and explains some of the functions for connecting and scanning to peripherals

    These tutorials are written for older version of nRF Connect SDK (v1.3.1 and v1.5.1), but they are still mostly applicable to v1.9.1. There will come a supported BLE fundamentals course at Nordic Academy in some time, so you may register to get notified when it gets published.

    Please feel free to follow up with more questions if you have any regarding this topic and otherwise let me know if this is of any help!

    Kind regards,
    Andreas

  • Hello Andreas

    first of all thank you for the great support! I went through the tutorials and it was really helpful. 

    What now I am interested in is: Is there a way that the peripheral accepts connection request only from one specific central? Because now I can still connect the peripheral from other centrals too (for example from mobile phone with nRF Connect app). I think the directed advertising should be the solution, but I am still not able to manage it. 

    I tried it in two ways

    	bt_addr_le_t peer_addr;
    
    	bt_addr_le_from_str("F0:33:4D:3A:9F:6B", "random", &peer_addr);
    	
    	err = bt_le_adv_start(((struct bt_le_adv_param[]) { { .id = BT_ID_DEFAULT, 
    	.sid = 0, 
    	.secondary_max_skip = 0, 
    	.options = (BT_LE_ADV_OPT_DIR_MODE_LOW_DUTY), 
    	.interval_min = (0x00a0), .interval_max = (0x00f0), 
    	.peer = &peer_addr, } }), 
    	ad, ARRAY_SIZE(ad), sd,
    	ARRAY_SIZE(sd));

    bt_addr_le_t peer_addr;
    bt_addr_le_from_str("F0:33:4D:3A:9F:6B", "random", &peer_addr);
    
    err = bt_le_adv_start(BT_LE_ADV_CONN_DIR(&peer_addr), ad, ARRAY_SIZE(ad), sd,
    			      ARRAY_SIZE(sd));

    but in both cases I get error -22 and the peripheral can't start advertising.

    another option, as mentioned in this video https://webinars.nordicsemi.com/everything-you-need-to-know-about-4 should be estabilishing a whitelist, but I also was not able to find a guide, how to do it in the nrf connect SDK. 

    I found just this ticket, but it did not help me much.

    https://devzone.nordicsemi.com/f/nordic-q-a/83526/best-practice-of-using-the-whitelist-in-nrf5340

    would you have some more advice for me?

    and thank you for the tip for Nordic Academy too, I think it is great idea and I am looking forward for more tutorials there Slight smile

    Kind regards

    Jirik

  • Hi Jirik,

    Now we need some kind of filtering of what centrals the peripherals should be interested in connecting to. As a default, the central and peripheral samples are set up to connect to each other based on the service UUID-filter I mentioned in my previous reply (or the device name as I did in the modified sample), but the peripheral also advertises to the world and everyone nearby that the peripheral is connectable, thus you are able to connect to it with your phone.

    One option to exclude every other central from connecting to the peripheral might be direct advertising but I haven't looked into this yet, so lets look into the option of whitelisting first. This part is a bit tricky as you state there are little to no guides on how to do this in NCS (hopefully some will come). In addition to this, the whitelisting functionality mentioned in the webinar is deprecated in NCS to my knowledge, and "bt_le_filter_accept_list_add()" from "ble_adv.c" located in "ncs\v1.9.1\nrf\subsys\caf\modules", together with the config setting "CONFIG_BT_FILTER_ACCEPT_LIST=y" is used.  I have not fully managed to set up a sample that does this, but I will continue to work on it during this week whenever I have time, so I will supply it to you if I finish it. In the meanwhile I will give you some pointers to where you may continue to work.


    To do what you describe you need to do the following:

    1. Investigate "ble_adv.c" located in "ncs\v1.9.1\nrf\subsys\caf\modules". bt_le_filter_accept_list_add() should let you set up a list of device addresses that your peripheral accepts the connection initiation from. 
    2. Obtain the address or set the address of the Central device. You may do this by setting up a Wireshark BLE sniffer. When the setup is done, you can filter the scanning on the peripheral address, which you can obtain in nRF Connect for Mobile as seen in the picture below. This will let you see all the advertisements, scan responses and scan requests coming to this device. What we're looking for is the device that initiates your connection, which will be the central, in my case the address c2:04:4b:0c:72:3b
    3. Set up a whitelist of the device that the peripheral should connect to. Use the functionality mentioned in 1) together with 2)

    Some more "philosophical" things to consider, albeit not necessarily relevant for the question you're asking. Depending on the scale of operation you are aiming to work on this might not be the best solution. If you're working with a low number of devices, i.e a couple of devices on your desk, this should be no problem at all. But if you're creating a product that should be scaled up several magnitudes you should consider setting up a more scripted/automated way of doing this. In addition to this, if you aim on whitelisting a mobile phone as a central, you will most likely require additional functionality such as bonding and encryption when whitelisting. But both of these are modules that can be added after the whitelisting is working properly if they are necessary!

    As mentioned, I will keep on investigating how the whitelisting works with a simple sample and supply it if I get it to work! Let me know about your progress if you manage to set it up yourself with these pointers and if you have any additional questions!

    Edit: I believe this case supported by a colleague of mine might also be of help! The customer seems to have a similar question to you regarding limiting the devices that should be able to connect to your device

    Kind regards,
    Andreas


Related