Scan does not shows short/long names for HR peripheral(s)

Dear all,

I'm having difficulties scanning as a central device showing the short /long names like e.g. "Polar H10 xxxxxxxx" I can see the names when scanning on my smart phone. I've  attached a sample program that detects that HR peripheral are present but no names pop up. What am I missing here. I've attached a sample project

Thanks in advance 

- - - - - - - - - - - - - - - - TARGET RESET - - - - - - - - - - - - - - - - -
*** Booting nRF Connect SDK v2.9.0-7787b2649840 ***
*** Using Zephyr OS v3.7.99-1f8f3dc29142 ***
[00:00:00.303,985] <inf> fs_nvs: 2 Sectors of 4096 bytes
[00:00:00.304,229] <inf> fs_nvs: alloc wra: 0, f58
[00:00:00.304,473] <inf> fs_nvs: data wra: 0, 100
[00:00:00.330,535] <inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)
[00:00:00.330,871] <inf> bt_hci_core: HW Variant: nRF53x (0x0003)
[00:00:00.331,146] <inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 45.41337 Build 3074452168
[00:00:00.367,553] <inf> bt_hci_core: No ID address. App must call settings_load()
[00:00:00.369,689] <inf> bt_hci_core: Identity: F4:BD:C5:F4:BE:C8 (random)
[00:00:00.369,995] <inf> bt_hci_core: HCI: version 6.0 (0x0e) revision 0x206b, manufacturer 0x0059
[00:00:00.370,361] <inf> bt_hci_core: LMP: version 6.0 (0x0e) subver 0x206b
Starting scan test OK
Heart Rate Service found, [DEVICE]: FF:B8:CB:D9:2C:28 (random), AD evt type 0, AD data len 0, RSSI -54
Heart Rate Service found, [DEVICE]: FF:B8:CB:D9:2C:28 (random), AD evt type 0, AD data len 0, RSSI -57
Heart Rate Service found, [DEVICE]: FF:B8:CB:D9:2C:28 (random), AD evt type 0, AD data len 0, RSSI -57
Heart Rate Service found, [DEVICE]: FF:B8:CB:D9:2C:28 (random), AD evt type 0, AD data len 0, RSSI -57
Heart Rate Service found, [DEVICE]: FF:B8:CB:D9:2C:28 (random), AD evt type 0, AD data len 0, RSSI -52
Heart Rate Service found, [DEVICE]: FF:B8:CB:D9:2C:28 (random), AD evt type 0, AD data len 0, RSSI -55
Heart Rate Service found, [DEVICE]: FF:B8:CB:D9:2C:28 (random), AD evt type 0, AD data len 0, RSSI -55
Heart Rate Service found, [DEVICE]: FF:B8:CB:D9:2C:28 (random), AD evt type 0, AD data len 0, RSSI -53
Heart Rate Service found, [DEVICE]: FF:B8:CB:D9:2C:28 (random), AD evt type 0, AD data len 0, RSSI -55
Heart Rate Service found, [DEVICE]: FF:B8:CB:D9:2C:28 (random), AD evt type 0, AD data len 0, RSSI -52

scan_test.zip

  • Strange. Very good that you shared the code! It makes it easier to troubleshoot.

    I am by no means any expert on this but I had a quick look at your code and digged a bit during the evening in how Bluetooth Advertising works.

    I can see that you have enabled Extended Advertising by setting `CONFIG_BT_EXT_ADV=y` in your `prj.conf` file. But I am not sure that this means that your peripherals actually use Extended Advertising or not.

    If your peripherals are not using Extended Advertising a qualified guess from my side is that the name of the peripheral does not fit in the `ADV_IND` packet. To get the name of such a device an active scanner (which you have configured) sends a `ADV_SCAN_REQ` to the peripheral when it first sees it. The peripheral should then respond with a `ADV_SCAN_RSP` which hopefully includes the Name you are looking for.

    Now, the problem is that the `ADV_SCAN_RSP` message is filtered away in the `device_found()` function here:

    if ( BT_GAP_ADV_TYPE_ADV_IND != type ) 
    {
        return;
    }

    If you change the code snippet above to also accept the type `BT_GAP_ADV_TYPE_SCAN_RSP` you should be able to read out the name on more peripherals that are using Legacy Advertising.

    However, you should probably also add support for peripherals that use Extended Advertising, so add `BT_GAP_ADV_TYPE_EXT_ADV` as well there.

    To check that a peripheral can be connected to it seems like the callback registered using `bt_le_scan_cb_register()` gives you more information. See the Observer example in Zephyr for an example how it can be used. If you want to use that example as a quick test you should enable support for Extended Advertising and perhaps also change the scanning type from Passive to Active.

    As a side note it could be worth mentioning that the reason why `AD data len` is printed as `0` is that the function `bt_data_parse()` "consumes" `ad`. So to get a proper printout of the length you need to save that field before calling that function.

    Another side note is that the function `data_cb()` returns `false` as soon as it has found a name. That means that fields following the name field will not be parsed. I think it is better to just get rid of that `return false` there. That could save some time for a future programmer wondering why not all fields are parsed.

  • Hi Jakob,

    Thank you so much for the support.

    First I tried the the code without any message filtering. No luck. I then tried the observer example. The observer example does show the name(s) for extended advertising,  There must be a subtle difference when using the explicit callback and the original code? 

    Instead of only seeing type =0,  I  now also see the extended type (4) . See below:

    DEVICE]: FF:B8:CB:D9:2C:28 (random), AD evt type 4, Tx Pwr: 127, RSSI -56 Data status: 0, AD data len: 20 Name: Polar H10 BF9FFE2B C:1 S:1 D:0 SR:1 E:0 Pri PHY: LE 1M, Sec PHY: No packets, Interval: 0x0000 (0 ms), SID: 255
    [DEVICE]: FF:B8:CB:D9:2C:28 (random), AD evt type 4, Tx Pwr: 127, RSSI -60 Data status: 0, AD data len: 20 Name: Polar H10 BF9FFE2B C:1 S:1 D:0 SR:1 E:0 Pri PHY: LE 1M, Sec PHY: No packets, Interval: 0x0000 (0 ms), SID: 255
    [DEVICE]: FF:B8:CB:D9:2C:28 (random), AD evt type 0, Tx Pwr: 127, RSSI -57 Data status: 0, AD data len: 20 Name: C:1 S:1 D:0 SR:0 E:0 Pri PHY: LE 1M, Sec PHY: No packets, Interval: 0x0000 (0 ms), SID: 255
    [DEVICE]: FF:B8:CB:D9:2C:28 (random), AD evt type 4, Tx Pwr: 127, RSSI -56 Data status: 0, AD data len: 20 Name: Polar H10 BF9FFE2B C:1 S:1 D:0 SR:1 E:0 Pri PHY: LE 1M, Sec PHY: No packets, Interval: 0x0000 (0 ms), SID: 255
    [DEVICE]: FF:B8:CB:D9:2C:28 (random), AD evt type 0, Tx Pwr: 127, RSSI -58 Data status: 0, AD data len: 20 Name: C:1 S:1 D:0 SR:0 E:0 Pri PHY: LE 1M, Sec PHY: No packets, Interval: 0x0000 (0 ms), SID: 255
    [DEVICE]: FF:B8:CB:D9:2C:28 (random), AD evt type 4, Tx Pwr: 127, RSSI -58 Data status: 0, AD data len: 20 Name: Polar H10 BF9FFE2B C:1 S:1 D:0 SR:1 E:0 Pri PHY: LE 1M, Sec PHY: No packets, Interval: 0x0000 (0 ms), SID: 255
    [DEVICE]: FF:B8:CB:D9:2C:28 (random), AD evt type 0, Tx Pwr: 127, RSSI -56 Data status: 0, AD data len: 20 Name: C:1 S:1 D:0 SR:0 E:0 Pri PHY: LE 1M, Sec PHY: No packets, Interval: 0x0000 (0 ms), SID: 255
    [DEVICE]: FF:B8:CB:D9:2C:28 (random), AD evt type 4, Tx Pwr: 127, RSSI -55 Data status: 0, AD data len: 20 Name: Polar H10 BF9FFE2B C:1 S:1 D:0 SR:1 E:0 Pri PHY: LE 1M, Sec PHY: No packets, Interval: 0x0000 (0 ms), SID: 255
    [DEVICE]: FF:B8:CB:D9:2C:28 (random), AD evt type 0, Tx Pwr: 127, RSSI -56 Data status: 0, AD data len: 20 Name: C:1 S:1 D:0 SR:0 E:0 Pri PHY: LE 1M, Sec PHY: No packets, Interval: 0x0000 (0 ms), SID: 255

    Best regards,

    Wim

  • Maybe a foolish question but I noticed that the bt_data_parse callback is called multiple times such that I cannot use the user data for both retrieving the heart rate boolean flag and the name in one instance. I was assuming that the parsing part continues under the hood retrieving all data and then returns. So how do I associate the name with the other information I receive?

  • There are no foolish questions!

    I am not sure there is a difference between the two callbacks in that aspect but perhaps you are right. I cannot verify that now. But go for the register callback approach then! As I wrote, it also gives you some more information.

    I think what you want is to have a table of devices so that you can keep track of them. Perhaps something like:

    #define NAME_LEN 30
    
    typedef struct {
      bool used;
      bt_addr_le_t address;
      char name[NAME_LEN];
      int64_t last_seen;
    } device_t;
    
    static device_t s_devices[50];
    
    device_t *find_device(const bt_addr_le_t *address)
    {
    	for (ssize_t i = 0; i < ARRAY_SIZE(s_devices); i++) {
    		if (s_devices[i].used && bt_addr_le_eq(&s_devices[i].address, address)) {
    			return &s_devices[i];
    		}
    	}
    	return NULL;
    }
    
    device_t *add_device(const bt_addr_le_t *address)
    {
    	for (ssize_t i = 0; i < ARRAY_SIZE(s_devices); i++) {
    		if (!s_devices[i].used) {
    			s_devices[i].used = true;
    			s_devices[i].address = *address;
    			s_devices[i].last_seen = k_uptime_get();
    			return &s_devices[i];
    		}
    	}
    	return NULL;
    }

    Now that you have a table of devices you can fill in information as soon as you collect it.

  • Yes that is a good approach! I checked two peripherals and it turns out that they behave differently:

    scan receive
    Heart Rate Service found, Name is Instinct 2X Solar type = 9, parse function called 3 times
    name is Instinct 2X Solar
    scan receive
    scan receive
    Heart Rate Service found, Name is Instinct 2X Solar type = 9, parse function called 3 times
    name is Instinct 2X Solar

    The above does parser the name and UUID in one step The next does not

    scan receive
    Heart Rate Service found, parse function called 4 times
    name is
    scan receive
    Name is Polar H10 BF9FFE2B type = 9, parse function called 1 times
    scan receive
    Heart Rate Service found, parse function called 4 times

    So I think I can continue now using the address and name association Thanks again 

    Wim

Related