This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Find name of advertiser

Hi - I am trying to port some code from nRF5 SDK to NRF Connect SDK. 

I set up a scan for a specific BT_SCAN_FILTER_TYPE_NAME name and then using the scan_filter_no_match event I get the details of the peripheral that caused the event.

I then make sure that the UUID matches what I am looking for and then see if the rssi is greater than the strongest value I have found so far. If so, then I save the peer address.

After three seconds I stop the scan and then start scanning again using SCAN_ADDR_FILTER so that that peripheral connects to me.

I would like to know how to achieve the same with NRF CONNECT SDK. Below is the existing code from NRF5 SDK.

Please help....

case NRF_BLE_SCAN_EVT_NOT_FOUND: // new case added. Implement ble_advdata.c->ble_advdata_name_find() type function here
{
ble_gap_evt_adv_report_t const * adv_report = p_scan_evt->params.p_not_found;

/* Scan encoded adv. payload for data of type BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME */
parsed_len = ble_advdata_search(adv_report->data.p_data, adv_report->data.len, &data_offset, BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME);

if (parsed_len != 0)
{
/* Name found if parsed_len != 0 */
p_parsed = &adv_report->data.p_data[data_offset];

// make sure not besecure
if (*p_parsed != 'B')
{
data_offset = 0;
parsed_len = ble_advdata_search(adv_report->data.p_data, adv_report->data.len, &data_offset, BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE);
p_parsed = &adv_report->data.p_data[data_offset];

if (parsed_len != 0)
{
if (memcmp(&bsc_service_uuid, p_parsed, parsed_len)== 0)
{
if (p_scan_evt->params.filter_match.p_adv_report->rssi > scanrssi)
{
memcpy_fast(&strongest_peer, &p_scan_evt->params.filter_match.p_adv_report->peer_addr, 8);
scanrssi = p_scan_evt->params.filter_match.p_adv_report->rssi;
sysStat.found = 1;
}
}
}
}
}
break;
}

Parents Reply Children
  • Hi,

    I made a simple example which I hope will show how this works. Here the scan module filter on UUID, and for advertising packets (and scan response packets) that match I also search for the name and print that. You can do the same in any combination to look fore more data and or other data.

    #include <zephyr/types.h>
    #include <stddef.h>
    #include <inttypes.h>
    #include <errno.h>
    #include <zephyr.h>
    #include <sys/printk.h>
    
    #include <bluetooth/bluetooth.h>
    #include <bluetooth/hci.h>
    #include <bluetooth/conn.h>
    #include <bluetooth/uuid.h>
    #include <bluetooth/gatt.h>
    #include <bluetooth/gatt_dm.h>
    #include <bluetooth/scan.h>
    #include <settings/settings.h>
    
    #define NAME_LEN            30
    
    
    static bool data_cb(struct bt_data *data, void *user_data)
    {
    	char *name = user_data;
    	uint8_t len;
    
    	switch (data->type) {
    
    	case BT_DATA_NAME_SHORTENED:
    		// Fallthrough
    	case BT_DATA_NAME_COMPLETE:
    	 	len = MIN(data->data_len, NAME_LEN - 1);
    		memcpy(name, data->data, len);
    		name[len] = '\0';
    		return false; // Do not search anymore
    	default:
    		return true; // Continue seraching through data
    	}
    }
    
    
    static void scan_filter_match(struct bt_scan_device_info *device_info,
    			      struct bt_scan_filter_match *filter_match,
    			      bool connectable)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(device_info->recv_info->addr, addr, sizeof(addr));
    
    	printk("Filters matched. Address: %s connectable: %s\n",
    		addr, connectable ? "yes" : "no");
    
    	// Parse advertising packet searching for advertising name.
    	char name[NAME_LEN];
    	(void)memset(name, 0, sizeof(name));
    	bt_data_parse(device_info->adv_data, data_cb, name);
    	printk("name: %s\n", name);
    }
    
    
    static void scan_filter_no_match(struct bt_scan_device_info *device_info,
    				 bool connectable)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	if (device_info->recv_info->adv_type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND) {
    		bt_addr_le_to_str(device_info->recv_info->addr, addr,
    				  sizeof(addr));
    		printk("Direct advertising received from %s\n", addr);
    	}
    }
    
    
    BT_SCAN_CB_INIT(scan_cb, scan_filter_match, scan_filter_no_match,
    		NULL, NULL);
    
    static void scan_init(void)
    {
    	int err;
    
    	struct bt_scan_init_param scan_init = {
    		.connect_if_match = 0,
    		.scan_param = NULL,
    	};
    
    	bt_scan_init(&scan_init);
    	bt_scan_cb_register(&scan_cb);
    
    	err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_UUID, BT_UUID_BAS);
    	if (err) {
    		printk("Scanning filters cannot be set (err %d)\n", err);
    		return;
    	}
    
    	err = bt_scan_filter_enable(BT_SCAN_UUID_FILTER, false);
    	if (err) {
    		printk("Filters cannot be turned on (err %d)\n", err);
    	}
    }
    
    
    void main(void)
    {
    	int err;
    
    	printk("Starting Bluetooth Scanner sample");
    
    	err = bt_enable(NULL);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return;
    	}
    
    	printk("Bluetooth initialized\n");
    
    	if (IS_ENABLED(CONFIG_SETTINGS)) {
    		settings_load();
    	}
    
    	scan_init();
    
    	err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
    	if (err) {
    		printk("Scanning failed to start (err %d)\n", err);
    		return;
    	}
    
    	printk("Scanning successfully started\n");
    }
    

    I want to mention one thing which sometimes cause confusion. The functionality used here works on single packets alone, so if for instance the UUID is in the advertisement packet and the name in the scan response, then you will not find both with this approach (this is also the same with the scan module in the nRF5 DK). You would have to put your own logic on top if you need such functionality.

  • Great - That is what I wanted. Thank you. I appreciate your help.

    Will close.

Related