NimBLE-Arduino 2.5.0
Loading...
Searching...
No Matches
NimBLEScan.h
1/*
2 * Copyright 2020-2026 Ryan Powell <ryan@nable-embedded.io> and
3 * esp-nimble-cpp, NimBLE-Arduino contributors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#ifndef NIMBLE_CPP_SCAN_H_
19#define NIMBLE_CPP_SCAN_H_
20
21#include "nimconfig.h"
22#if CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_OBSERVER
23
24# include "NimBLEAdvertisedDevice.h"
25# include "NimBLEUtils.h"
26
27# ifdef USING_NIMBLE_ARDUINO_HEADERS
28# include "nimble/nimble/host/include/host/ble_gap.h"
29# else
30# include "host/ble_gap.h"
31# endif
32
33# include <vector>
34# include <cinttypes>
35# include <cstdio>
36
37class NimBLEDevice;
38class NimBLEScan;
41class NimBLEAddress;
42
51 public:
52 void dump() const;
53 int getCount() const;
54 const NimBLEAdvertisedDevice* getDevice(uint32_t idx) const;
55 const NimBLEAdvertisedDevice* getDevice(const NimBLEAddress& address) const;
56 std::vector<NimBLEAdvertisedDevice*>::const_iterator begin() const;
57 std::vector<NimBLEAdvertisedDevice*>::const_iterator end() const;
58
59 private:
60 friend NimBLEScan;
61 std::vector<NimBLEAdvertisedDevice*> m_deviceVec;
62};
63
70 public:
71 bool start(uint32_t duration, bool isContinue = false, bool restart = true);
72 bool isScanning();
73 void setScanCallbacks(NimBLEScanCallbacks* pScanCallbacks, bool wantDuplicates = false);
74 void setActiveScan(bool active);
75 void setInterval(uint16_t intervalMs);
76 void setWindow(uint16_t windowMs);
77 void setDuplicateFilter(uint8_t enabled);
78 void setLimitedOnly(bool enabled);
79 void setFilterPolicy(uint8_t filter);
80 bool stop();
81 void clearResults();
83 NimBLEScanResults getResults(uint32_t duration, bool is_continue = false);
84 void setMaxResults(uint8_t maxResults);
85 void erase(const NimBLEAddress& address);
86 void erase(const NimBLEAdvertisedDevice* device);
87 void setScanResponseTimeout(uint32_t timeoutMs);
88 std::string getStatsString() const { return m_stats.toString(); }
89
90# if CONFIG_BT_NIMBLE_EXT_ADV
91 enum Phy { SCAN_1M = 0x01, SCAN_CODED = 0x02, SCAN_ALL = 0x03 };
92 void setPhy(Phy phyMask);
93 void setPeriod(uint32_t periodMs);
94# endif
95
96 private:
97 friend class NimBLEDevice;
98
99 struct stats {
100# if MYNEWT_VAL(NIMBLE_CPP_LOG_LEVEL) >= 4
101 uint32_t devCount = 0; // unique devices seen for the first time
102 uint32_t dupCount = 0; // repeat advertisements from already-known devices
103 uint32_t srMinMs = UINT32_MAX;
104 uint32_t srMaxMs = 0;
105 uint64_t srTotalMs = 0; // uint64 to avoid overflow on long/busy scans
106 uint32_t srCount = 0; // matched scan responses (advertisement + SR pair)
107 uint32_t orphanedSrCount = 0; // scan responses received with no prior advertisement
108 uint32_t missedSrCount = 0; // scannable devices for which no SR ever arrived
109
110 void reset() {
111 devCount = 0;
112 dupCount = 0;
113 srMinMs = UINT32_MAX;
114 srMaxMs = 0;
115 srTotalMs = 0;
116 srCount = 0;
117 orphanedSrCount = 0;
118 missedSrCount = 0;
119 }
120
121 void incDevCount() { devCount++; }
122 void incDupCount() { dupCount++; }
123 void incMissedSrCount() { missedSrCount++; }
124 void incOrphanedSrCount() { orphanedSrCount++; }
125
126 std::string toString() const {
127 std::string out;
128 out.resize(400); // should be more than enough for the stats string
129 snprintf(&out[0],
130 out.size(),
131 "Scan stats:\n"
132 " Devices seen : %" PRIu32 "\n"
133 " Duplicate advs : %" PRIu32 "\n"
134 " Scan responses : %" PRIu32 "\n"
135 " SR timing (ms) : min=%" PRIu32 ", max=%" PRIu32 ", avg=%" PRIu64 "\n"
136 " Orphaned SR : %" PRIu32 "\n"
137 " Missed SR : %" PRIu32 "\n",
138 devCount,
139 dupCount,
140 srCount,
141 srCount ? srMinMs : 0,
142 srCount ? srMaxMs : 0,
143 srCount ? srTotalMs / srCount : 0,
144 orphanedSrCount,
145 missedSrCount);
146 return out;
147 }
148
149 // Records scan-response round-trip time.
150 void recordSrTime(uint32_t ticks) {
151 uint32_t ms;
152 ble_npl_time_ticks_to_ms(ticks, &ms);
153
154 if (ms < srMinMs) {
155 srMinMs = ms;
156 }
157 if (ms > srMaxMs) {
158 srMaxMs = ms;
159 }
160 srTotalMs += ms;
161 srCount++;
162 return;
163 }
164# else
165 void reset() {}
166 void incDevCount() {}
167 void incDupCount() {}
168 void incMissedSrCount() {}
169 void incOrphanedSrCount() {}
170 std::string toString() const { return ""; }
171 void recordSrTime(uint32_t ticks) {}
172# endif
173 } m_stats;
174
175 NimBLEScan();
176 ~NimBLEScan();
177 static int handleGapEvent(ble_gap_event* event, void* arg);
178 void onHostSync();
179 static void srTimerCb(ble_npl_event* event);
180
181 // Linked list helpers for devices awaiting scan responses
182 void addWaitingDevice(NimBLEAdvertisedDevice* pDev);
183 void removeWaitingDevice(NimBLEAdvertisedDevice* pDev);
184 void clearWaitingList();
185 void resetWaitingTimer();
186
187 NimBLEScanCallbacks* m_pScanCallbacks;
188 ble_gap_disc_params m_scanParams;
189 NimBLEScanResults m_scanResults;
190 NimBLETaskData* m_pTaskData;
191 ble_npl_callout m_srTimer{};
192 ble_npl_time_t m_srTimeoutTicks{};
193 uint8_t m_maxResults;
194 NimBLEAdvertisedDevice* m_pWaitingListHead{}; // head of linked list for devices awaiting scan responses
195 NimBLEAdvertisedDevice* m_pWaitingListTail{}; // tail of linked list for FIFO ordering
196
197# if CONFIG_BT_NIMBLE_EXT_ADV
198 uint8_t m_phy{SCAN_ALL};
199 uint16_t m_period{0};
200# endif
201};
202
207 public:
208 virtual ~NimBLEScanCallbacks() {}
209
214 virtual void onDiscovered(const NimBLEAdvertisedDevice* advertisedDevice);
215
220 virtual void onResult(const NimBLEAdvertisedDevice* advertisedDevice);
221
227 virtual void onScanEnd(const NimBLEScanResults& scanResults, int reason);
228};
229
230#endif // CONFIG_BT_ENABLED CONFIG_BT_NIMBLE_ROLE_OBSERVER
231#endif // NIMBLE_CPP_SCAN_H_
A BLE device address.
Definition NimBLEAddress.h:42
A representation of a BLE advertised device found by a scan.
Definition NimBLEAdvertisedDevice.h:45
A model of a BLE Device from which all the BLE roles are created.
Definition NimBLEDevice.h:126
A callback handler for callbacks associated device scanning.
Definition NimBLEScan.h:206
virtual void onDiscovered(const NimBLEAdvertisedDevice *advertisedDevice)
Called when a new device is discovered, before the scan result is received (if applicable).
Definition NimBLEScan.cpp:784
virtual void onScanEnd(const NimBLEScanResults &scanResults, int reason)
Called when a scan operation ends.
Definition NimBLEScan.cpp:792
virtual void onResult(const NimBLEAdvertisedDevice *advertisedDevice)
Called when a new scan result is complete, including scan response data (if applicable).
Definition NimBLEScan.cpp:788
Perform and manage BLE scans.
Definition NimBLEScan.h:69
void setWindow(uint16_t windowMs)
Set the window to actively scan.
Definition NimBLEScan.cpp:484
void setPhy(Phy phyMask)
Set the PHYs to scan.
Definition NimBLEScan.cpp:503
void setScanResponseTimeout(uint32_t timeoutMs)
Set the scan response timeout.
Definition NimBLEScan.cpp:382
NimBLEScanResults getResults()
Get the results of the scan.
Definition NimBLEScan.cpp:696
void setScanCallbacks(NimBLEScanCallbacks *pScanCallbacks, bool wantDuplicates=false)
Set the call backs to be invoked.
Definition NimBLEScan.cpp:461
void setFilterPolicy(uint8_t filter)
Sets the scan filter policy.
Definition NimBLEScan.cpp:443
void setInterval(uint16_t intervalMs)
Set the interval to scan.
Definition NimBLEScan.cpp:476
void erase(const NimBLEAddress &address)
Delete peer device from the scan results vector.
Definition NimBLEScan.cpp:629
bool stop()
Stop an in progress scan.
Definition NimBLEScan.cpp:602
void setLimitedOnly(bool enabled)
Set whether or not the BLE controller only reports scan results from devices advertising in limited d...
Definition NimBLEScan.cpp:421
void setActiveScan(bool active)
Should we perform an active or passive scan? The default is a passive scan. An active scan means that...
Definition NimBLEScan.cpp:398
void setPeriod(uint32_t periodMs)
Set the extended scanning period.
Definition NimBLEScan.cpp:514
void setDuplicateFilter(uint8_t enabled)
Set whether or not the BLE controller should only report results from devices it has not already seen...
Definition NimBLEScan.cpp:412
void setMaxResults(uint8_t maxResults)
Sets the max number of results to store.
Definition NimBLEScan.cpp:452
bool isScanning()
Get the status of the scanner.
Definition NimBLEScan.cpp:492
bool start(uint32_t duration, bool isContinue=false, bool restart=true)
Start scanning.
Definition NimBLEScan.cpp:527
void clearResults()
Clear the stored results of the scan.
Definition NimBLEScan.cpp:703
A class that contains and operates on the results of a BLE scan.
Definition NimBLEScan.h:50
std::vector< NimBLEAdvertisedDevice * >::const_iterator end() const
Get iterator to the end of the vector of advertised device pointers.
Definition NimBLEScan.cpp:762
int getCount() const
Get the count of devices found in the last scan.
Definition NimBLEScan.cpp:736
std::vector< NimBLEAdvertisedDevice * >::const_iterator begin() const
Get iterator to the beginning of the vector of advertised device pointers.
Definition NimBLEScan.cpp:754
const NimBLEAdvertisedDevice * getDevice(uint32_t idx) const
Return the specified device at the given index. The index should be between 0 and getCount()-1.
Definition NimBLEScan.cpp:746
void dump() const
Dump the scan results to the log.
Definition NimBLEScan.cpp:724
A structure to hold data for a task that is waiting for a response.
Definition NimBLEUtils.h:33