8000 Handling duplicate scan result when filter mode is address and data · Issue #968 · h2zero/NimBLE-Arduino · GitHub
[go: up one dir, main page]

Skip to content

Handling duplicate scan result when filter mode is address and data #968

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
gkoh opened this issue May 25, 2025 · 10 comments
Open

Handling duplicate scan result when filter mode is address and data #968

gkoh opened this issue May 25, 2025 · 10 comments
Labels
bug Something isn't working

Comments

@gkoh
Copy link
Contributor
gkoh commented May 25, 2025

I've recently come across a device that actively advertises, then changes manufacturer data when set to pair.
After some poking about, I set the scan filter mode with:

NimBLEDevice::setScanFilterMode(CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE);

with the expectation that onResult() would be called due to a non-duplicate advertised device appearing.

This didn't happen, so debug logs got enabled.
It turns out the underlying esp framework does respect this scan mode, I can see the device being reported as 'new'.
However, after reviewing NimBLEScan, I think NimBLE-Arduino is only using the device address for its uniqueness check here and the log output:

Duplicate; updated: xxx

and thus onResult() does not get called when the data changes.

Is there a recommended way to handle this scenario?

For now I'm just starting the scan after the manufacturer data changes.

@h2zero
Copy link
Owner
h2zero commented May 25, 2025

This doesn't sound right, probably a bug, but this situation is different that I have seen before. The data should be reported when complete and it should follow the filtering.

@h2zero h2zero added the bug Something isn't working label May 25, 2025
@gkoh
Copy link
Contributor Author
gkoh commented May 25, 2025
8000

This doesn't sound right, probably a bug, but this situation is different that I have seen before. The data should be reported when complete and it should follow the filtering.

OK.
The condition for logging looks like this (in NimBLEScan.cpp):

                advertisedDevice->update(event, event_type);
                if (isLegacyAdv && event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
                    NIMBLE_LOGI(LOG_TAG, "Scan response from: %s", advertisedAddress.toString().c_str());
                } else {
                    NIMBLE_LOGI(LOG_TAG, "Duplicate; updated: %s", advertisedAddress.toString().c_str());
                }

and the corresponding onResult() call:

            // If not active scanning or scan response is not available
            // or extended advertisement scanning, report the result to the callback now.
            if (pScan->m_scanParams.passive || !isLegacyAdv || !advertisedDevice->isScannable()) {
                advertisedDevice->m_callbackSent++;
                pScan->m_pScanCallbacks->onResult(advertisedDevice);
            } else if (isLegacyAdv && event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
                advertisedDevice->m_callbackSent++;
                // got the scan response report the full data.
                pScan->m_pScanCallbacks->onResult(advertisedDevice);
            }

I'm quite sure isLegacyAdv is true, so the event_type must not be BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP.
When I get a chance, I'll hack in some debug and determine what is actually happening under the covers.

@gkoh
Copy link
Contributor Author
gkoh commented May 27, 2025

On first scan event, the output is:

I NimBLEScan: isLegacyAdv = 1, event_type = 4

where 4 == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP

On the second scan event (where the address is duplicate, but manufacturer data has changed), the event type changes to:

I NimBLEScan: isLegacyAdv = 1, event_type = 0

where 0 == BLE_HCI_ADV_RPT_EVTYPE_ADV_IND

@h2zero
Copy link
Owner
h2zero commented May 27, 2025

That makes sense, when the new advertisement comes it will not call onResult because it is not a scan response so you will need to catch it in the onDiscovered callback.

@gkoh
Copy link
Contributor Author
gkoh commented May 28, 2025

That makes sense, when the new advertisement comes it will not call onResult because it is not a scan response so you will need to catch it in the onDiscovered callback.

Ah!
I've updated to handle this, and yes, I get the callback.
However, onDiscovered() has no scan response data, so the device name (from an active scan) is always empty.

So, this now becomes a question of "how do I get a callback with active scan response data when manufacturer data changes?"

(Yes, I could handle this in the calling application by caching results)

@h2zero
Copy link
Owner
h2zero commented May 28, 2025

Good question, I think the logic needs to change such that when an advertisement is detected and the device is already known, the callback count value should be reset.

@gkoh
Copy link
Contributor Author
gkoh commented May 28, 2025

I started drilling down, but my knowledge thins out very quickly, so this may be all wrong.

nRF Connect confirms that even when the manufacturer data changes, active response data is returned.

So, I'm starting to think the problem is actually upstream or configuration.
With CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE, I would expect BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP for each 'unique' advertising device.
Debug shows that while EVTYPE_ADV_IND is received, we don't see a subsequent EVTYPE_SCAN_RSP.

I got stuck at ble_vhci_disc_duplicate_mode_enable(), where I have no idea what that VHCI function can expect. Searching online gets me nothing 😐

@h2zero
Copy link
Owner
h2zero commented May 28, 2025

This is a filter that is applied inside the controller and we cannot see that code. What I suspect is that the scan response doesn't come because it's data hasn't changed, I could be wrong and maybe it's a bug as well.

@gkoh
Copy link
Contributor Author
gkoh commented May 29, 2025

This is a filter that is applied inside the controller and we cannot see that code.

Is there any doco on the function signature? The bit mask passed in looks like magic.

What I suspect is that the scan response doesn't come because it's data hasn't changed, I could be wrong and maybe it's a bug as well.

Ah, yes, I could believe that as weird as it is.

@gkoh
Copy link
Contributor Author
gkoh commented May 29, 2025

What I suspect is that the scan response doesn't come because it's data hasn't changed, I could be wrong and maybe it's a bug as well.

Ah, yes, I could believe that as weird as it is.

I just tested this by changing the device name during scan.
And yes, it seems that was enough to trigger a scan response event!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants
0