How to read advertising BLE devices' name?

I've google the heck out of this, but I feel like I'm missing something because there are zero results.

I am developing a BLE central device, and the program is supposed to scan for advertising BLE devices, and list their address and name. Since the program is based off the "BLE Central" example, I have no issue reading their addresses, however, I cannot figure out how to read device names (e.g. "Zephyr BLE Module").

I know the BLE devices are advertising their names because I can see their names when I use the nRF Connect bluetooth app, but I want to be able to see their names through my own program, and print it to the console.

If it matters, the peripheral device is using the "BLE Peripheral" example.

Parents
  • Hi. 

    If you use the bt_central example I you can add the following lines and functions to print out the device names: 

    Updated device found function: 

    static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
    			 struct net_buf_simple *ad)
    {
    	char addr_str[BT_ADDR_LE_STR_LEN];
    	char name[30];
    	int err;
    
    	if (default_conn) {
    		return;
    	}
    
    	/* We're only interested in connectable events */
    	if (type != BT_GAP_ADV_TYPE_ADV_IND &&
    	    type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND) {
    		return;
    	}
    
    	bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
    	printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
    
    	//seting up the bt_data_parse function and prints it. 
    	//
    	bt_data_parse(ad, data_cb, name);
    	printk("Device found: %s \n", name);
    
    	/* connect only to devices in close proximity */
    	if (rssi < -70) {
    		return;
    	}
    
    	if (bt_le_scan_stop()) {
    		return;
    	}
    
    	err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN,
    				BT_LE_CONN_PARAM_DEFAULT, &default_conn);
    	if (err) {
    		printk("Create conn to %s failed (%u)\n", addr_str, err);
    		start_scan();
    	}
    }

    Added function data_cb 

    #define NAME_LEN 30
    
    static bool data_cb(struct bt_data *data, void *user_data)
    {
    	char *name = user_data;
    
    	switch (data->type) {
    	case BT_DATA_NAME_SHORTENED:
    	case BT_DATA_NAME_COMPLETE:
    		memcpy(name, data->data, MIN(data->data_len, NAME_LEN - 1));
    		return false;
    	default:
    		return true;
    	}
    }
    

    Now your central will print out the name of the devices found during scanning. 

    Regards

    Runar

  • Thanks for the reply. I added this code, but I'm still not getting anything.

    The terminal says "Device Found: ", but does not actually list a name. However, the available devices definitely do have friendly names, as proven by my iPhone.

    Scanning successfully started
    Device Found: xx:xx:xx:xx:xx:x1 (random) (RSSI -79)
    Device Found:
    Device Found: xx:xx:xx:xx:xx:x2 (random) (RSSI -82)
    Device Found:
    Device Found: xx:xx:xx:xx:xx:x3 (random) (RSSI -60)
    Device Found:
    Connected: xx:xx:xx:xx:xx:x3 (public)
    Disconnected: xx:xx:xx:xx:xx:x3 (public) (reason 0x3e)

    Here are the functions after I've edited them:

    static bool data_cb(struct bt_data *data, void *user_data){
    
    	char *name = user_data;
    
    	switch(data->type){
    		case BT_DATA_NAME_SHORTENED:
    		case BT_DATA_NAME_COMPLETE:
    			memcpy(name, data->data, MIN(data->data_len, NAME_LEN - 1));
    			return false;
    		default:
    			return false;
    	}
    }

    static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
    			 struct net_buf_simple *ad)
    {
    	char addr_str[BT_ADDR_LE_STR_LEN];
    	char name[30];
    	int err;
    
    	if (default_conn) {
    		return;
    	}
    
    	/* We're only interested in connectable events */
    	if (type != BT_GAP_ADV_TYPE_ADV_IND &&
    	    type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND) {
    		return;
    	}
    
    	bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
    	printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
    
    	//setting up the bt_data_parse function and prints it.
    	bt_data_parse(ad, data_cb, name);
    	printk("Device found: %s \n", name);
    
    	/* connect only to devices in close proximity */
    	if (rssi < -70) {
    		return;
    	}
    
    	if (bt_le_scan_stop()) {
    		return;
    	}
    
    	err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN,
    				BT_LE_CONN_PARAM_DEFAULT, &default_conn);
    	if (err) {
    		printk("Create conn to %s failed (%u)\n", addr_str, err);
    		start_scan();
    	}
    }

    In the switch-case statement in the 'data_cb' function, it is triggering 'default', not 'BT_DATA_NAME_SHORTENED' or 'BT_DATA_NAME_COMPLETE'.

  • Interesting, I will see if I can replicate it. You could not find any names at all? 

    Also, do you have another dk you can set up as an peripheral? 

    Regards

    Runar

Reply Children
  • You could not find any names at all? 

    None, and there are at least 4 bluetooth devices advertising their name nearby.

    do you have another dk you can set up as an peripheral? 

    My central device is an nRF52840 DK, and I've been using an nRF52840 MDK Dongle as a peripheral.

    In case this helps, here's what the prj.conf and CMakeLists.txt files look like:

    CONFIG_BT=y
    CONFIG_BT_CENTRAL=y

    # SPDX-License-Identifier: Apache-2.0
    
    cmake_minimum_required(VERSION 3.20.0)
    find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
    project(central)
    
    target_sources(app PRIVATE
      src/main.c
    )
    
    zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth)

  • Do you advertise device name from your peripheral? I tested with the peripheral_uart example and I could find it without any problems using the code I have you, 

    Regards

    Runar

  • Do you advertise device name from your peripheral?

    Yes, but also so do the other devices around me.

    I tried with a brand new project, totally clean, same issue.

    Device found: C6:65:16:45:84:67 (public) (RSSI -75)
    Device found:
    Connected: C6:65:16:45:84:67 (public)
    Disconnected: C6:65:16:45:84:67 (reason 0x3e)
    Scanning successfully started

    After uploading the "peripheral_uart" example to the peripheral device, the name now DOES show up in the terminal on the central device DK. However, other devices still do not, including the "peripheral" (without uart) example.

    Why is that? I want to use the "peripheral" example, not the "peripheral_uart". What is causing this issue?

  • Hi, 

    Can you try to change "start_scan" to:

     

    err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
    
    to
    
    err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, device_found);

    and

    add update device_found with this:

    	if (type != BT_GAP_ADV_TYPE_ADV_IND &&
    	    type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND &&
    		type != BT_GAP_ADV_TYPE_SCAN_RSP  ) {
    		return;
    	}

    Regards

    Runar

  • Just tried this, but no change to the result.

    "peripheral_uart" to "central" shows the name.

    "peripheral" to "central" does not show the name.

Related