This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Active scanning with enabled filter causes sending SCAN_REQ to every advertiser

Hi everybody,

I saw topics with similar naming like mine, but none of them actually describes my issue.

I develop some simple scanner and advertiser solution.

On advertiser side I've implemented ADV_SCAN_IND and SCAN_RSP packets. In ADV_SCAN_IND I've put some custom UUID to easy find my advertisers if there is many BLE devices around. In SCAN_RSP there is my custom data (0xFF - manufacture data).

On scanner side I've turned on active scanning with turned on filtering by UUID (same solution as it is in some sample code).

I've observed some strange behaviors:

1. Scanner side invokes "filter match" callback when ADV_SCAN_IND packet is received with correct UUID...and then "filter no match" callback when SCAN_RSP packet is received which contains my own custom data. To avoid this would I need to put UUID data also in SCAN_RSP packet? Or maybe some scanner configuration should be changed?

2. Even if in ADV_SCAN_IND there is no matching data (no UUID field), my scanner sends SCAN_REQ anyway...I think is pointless to waste time for sending SCAN_REQ for different advertisers.

- Can I configure my scanner in a way that it will send SCAN_REQ only to devices which contain correct data in first ADV_SCAN_IND?

- Can I avoid invoking "no filter match" callback for devices which have correct data only in ADV_SCAN_IND packets?

Best regards,

Adam

  • Hello,

    I understand that in your case, you only want to use active scanning if it is one of your own devices, and therefore it is a waste of time to send a scan request for devices that you know aren't relevant. However, this is the way that bluetooth works. If you enable active scanning (which will send scan requests), then you will send scan requests for all advertising packs that you receive (that claim to have a scan response packet). The reason for this is partly that you don't have much time between the initial advertisement and the scan request, so there is no time to involve the CPU to decide whether or not to send it. 

    Also, in many cases these filters are used to determine whether you want to connect to a device or not. And in those cases, you may not know whether the data that you are looking for is in the initial advertising packet or in the scan response packet. So you would have to send a scan request even though the initial scan response packet didn't match the filter. 

    - Can I configure my scanner in a way that it will send SCAN_REQ only to devices which contain correct data in first ADV_SCAN_IND?

    No

    - Can I avoid invoking "no filter match" callback for devices which have correct data only in ADV_SCAN_IND packets?

    No.

    I am not completely sure what exactly you want to do, but I imagine that you want to use the UUID to find your devices, and then look at the scan response packet from those devices only. Perhaps something like this can work:

    1: save the address of all the devices that match the UUID in the original advertising packet in an array.

    2: Whenever you receive a scan response, see if the address matches any of the addresses in the array, and proceed to interpret the data only if the address is present.

    I guess you could add the UUID in your scan response packet as well, but I suspect that the reason you are using a scan response packet in the first place is because you couldn't fit the UUID and the vendor specific (custom) data in the same advertising packet (but I may be wrong). If you can fit them in the same packet, see if you can fit everything into the initial advertising packet, and then you can skip the scan response packet altogether.

    Best regards,

    Edvin

  • Hi Edvin,

    thank you for your fully explainable response! :) I'm quite new in BLE and in Nordic products, so some obvious stuff is still new to me.

    About sending scan response - you're right, I forgot that time between receiving first advertising data and sending SCAN_REQ / CONNECT_IND is quite tight (150us).

    Right now I've implemented something similar as you suggested. I've put simple machine state and "match flags" in "no_match" callback and if data in both received packets is ok, I can determine if it's my peripherals.

    Just to make sure - if my device is connectable, I have to send CONNECT_IND after receiving first packet, Trying to establish connection in callback from receiving second packet is pointless, right? Then advertiser would need to send at least 2 adv packets, right?

    From the advertiser device I have small issue with whitelists.

    I would like to response for SCAN_REQ only to "my" centrals. But central can send in SCAN_REQ only it's own random address. During every scanning "session" scanner will have different (random) address. Let's say I can send private static address of central during "initial phase", but it gives me nothing when scanner will send random address in SCAN_REQ.

    How to properly handle it? I saw some article to make pairing and use IRK keys to resolve random address into private address, but I couldn't find any example for that.

    For any help thanks in advance!

    Adam

  • Kedlov said:
    Just to make sure - if my device is connectable, I have to send CONNECT_IND after receiving first packet, Trying to establish connection in callback from receiving second packet is pointless, right? Then advertiser would need to send at least 2 adv packets, right?

    Typically, the flow is that you receive an advertising packet, with or without a scan response (that doesn't really matter). Then you decide whether you want to connect to it or not. If you want to connect, you will call the API that will connect to the device (which depends on what SDK version you are using. Are you using the nRF5 SDK, or are you using NCS?). When this is called, the scanner will then wait for the next advertising packet from that device, and it will send the connect_ind immediately after receiving the advertisement. 

    This next part is also dependent on what SDK you are using, but the principle will be the same.

    In BLE you have several address types. In private addresses, you can have resolvable or unresolvable addresses. Resolvable addresses means that there is an IRK (Identity Resolving Key), which you can use to figure out whether a seemingly random address actually belongs to a known device or not. I don't know exactly how that works on the mathematical level, but the Bluetooth Low Energy stack supports this. 

    What are you using to scan? Is it another nRF chip, a phone? Or something else?

    And what SDK version are you using?

    Best regards,

    Edvin

  • Thanks for reply!

    I'm using NCS updated to v2.0.0, based on some example projects generated from "Create a new application from sample" and now I explore most common use case scenarios which would also adjust to my projects' requirements.

    Some of this requirements is:

    - use radio as short as possible (connectionless beacon mode)

    - get information is central node really received data or we should repeat it (data will change in some intervals but we shouldn't miss any of that data)

    - from central point of view - sends scan requests only to "my" peripherals

    - from peripheral point of view - sends scan responses only to "my" centrals

    In BLE you have several address types. In private addresses, you can have resolvable or unresolvable addresses. Resolvable addresses means that there is an IRK (Identity Resolving Key), which you can use to figure out whether a seemingly random address actually belongs to a known device or not.

    Exactly this is what i needed to know, thanks! Actually after tests with some example which used bonding, when my peripheral was bonded with scanner, I was able to see its static private address, so I think that bonding and storing IRK keys are essentials which I need in my peripheral to know which scanner is "my" scanner.

    What are you using to scan? Is it another nRF chip, a phone? Or something else?

    I will use nRF chip, for few tests I've used phone but scanning performance was too low for me. With scanner on nRF52840 I think I was able to catch almost very first advertising packet every time. Time from starting advertising to send scan response was around 4-15ms (probably depends of current scanning and adv channel)

    Thanks to your reply, now I know how to figure out if scan request comes from my scanner.

    Now the issue is following:

    Let's say I have few hundreds peripheral nodes. Creating bond (by manually clicking some buttons for pairing mode) only to generate IRK keys would be time consuming. Let's say I could program this keys through wired connection during production or change the roles and central for few seconds would broadcast it's IRK key to all sensors in close proximity. I saw OOB pairing by using NFC and external antenna but we want to cut piece price for every peripheral node.

    After this long "preamble" here comes my question ;)

    Is it possible to manually create/save IRK keys which will be later used to resolve scanner private address?

    For any help, thanks in advance!

    Adam

  • Kedlov said:

    - from central point of view - sends scan requests only to "my" peripherals

    - from peripheral point of view - sends scan responses only to "my" centrals

    No. That is not possible.

    So if you plan to not bond the devices, how do you plan to transfer the IRK? And why do you need to change addresses in the first place? I am not sure whether or not you can set this manually in NCS, but even if you can, you would only be able to change the address every ~15 minutes, or in that order. Not between every advertising packet. If you are not connecting, I don't see what sort of security this adds.

    To put you on track, you can use the configuration CONFIG_BT_PRIVACY=y to enable address switching. You can also try to see if you figure out how the IRK is set using 

    int bt_id_create(bt_addr_le_t *addr, uint8_t *irk) from id.c. I think you can use this, and set the IRK to whatever you like (look at the declaration of bt_id_create() in bluetooth.h. As long as it is not all zeroes (or a null pointer), you just need the scanner to be aware of the same IRK.

    BR,

    Edvin

Related