22
22
# include " NimBLEDevice.h"
23
23
# include " NimBLELog.h"
24
24
25
+ # if defined(CONFIG_NIMBLE_CPP_IDF)
26
+ # include " nimble/nimble_port.h"
27
+ # else
28
+ # include " nimble/porting/nimble/include/nimble/nimble_port.h"
29
+ # endif
30
+
25
31
# include < string>
26
32
# include < climits>
27
33
34
+ # define SR_TIMEOUT CONFIG_NIMBLE_CPP_SCAN_RSP_TIMEOUT
35
+
28
36
static const char * LOG_TAG = " NimBLEScan" ;
29
37
static NimBLEScanCallbacks defaultScanCallbacks;
30
38
39
+ # if SR_TIMEOUT
40
+ static ble_npl_event dummySrTimerEvent;
41
+ static ble_gap_disc_desc dummyDesc{
42
+ .event_type = BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP, .length_data = 0 , .addr {}, .rssi = 127 , .data = nullptr , .direct_addr {}};
43
+
44
+ extern " C" void ble_gap_rx_adv_report (ble_gap_disc_desc* desc);
45
+
46
+ /* *
47
+ * @brief Sends dummy (null) scan response data to the scan event handler in order to
48
+ * provide the scan result to the callbacks when a device hasn't responded to the
49
+ * scan request in time. This is called by the host task from the default event queue.
50
+ */
51
+ static void sendDummyScanResponse (ble_npl_event* ev) {
52
+ (void )ev;
53
+ ble_gap_rx_adv_report (&dummyDesc);
54
+ }
55
+
56
+ /* *
57
+ * @brief This will schedule an event to run in the host task that will call sendDummyScanResponse
58
+ * which will send a null data scan response to the scan event handler if the device
59
+ * hasn't responded to a scan response request within the timeout period.
60
+ */
61
+ void NimBLEScan::srTimerCb (ble_npl_event* event) {
62
+ NimBLEScan* pScan = (NimBLEScan*)ble_npl_event_get_arg (event);
63
+ NimBLEAdvertisedDevice* curDev = nullptr ;
64
+ NimBLEAdvertisedDevice* nextDev = nullptr ;
65
+ ble_npl_time_t now = ble_npl_time_get ();
66
+
67
+ for (auto & dev : pScan->m_scanResults .m_deviceVec ) {
68
+ if (dev->m_callbackSent < 2 && dev->isScannable ()) {
69
+ if (!curDev || (now - dev->m_time > now - curDev->m_time )) {
70
+ nextDev = curDev;
71
+ curDev = dev;
72
+ continue ;
73
+ }
74
+
75
+ if (!nextDev || now - dev->m_time > now - nextDev->m_time ) {
76
+ nextDev = dev;
77
+ }
78
+ }
79
+ }
80
+
81
+ // Add the event to the host queue
82
+ if (curDev) {
83
+ memcpy (&dummyDesc.addr , curDev->getAddress ().getBase (), sizeof (dummyDesc.addr ));
84
+ NIMBLE_LOGI (LOG_TAG, " Scan response timeout for: %s" , curDev->getAddress ().toString ().c_str ());
85
+ ble_npl_eventq_put (nimble_port_get_dflt_eventq (), &dummySrTimerEvent);
86
+ }
87
+
88
+ // Restart the timer for the next device that we are expecting a scan response from
89
+ if (nextDev) {
90
+ auto nextTime = now - nextDev->m_time ;
91
+ if (nextTime >= SR_TIMEOUT) {
92
+ nextTime = 1 ;
93
+ } else {
94
+ nextTime = SR_TIMEOUT - nextTime;
95
+ }
96
+
97
+ ble_npl_time_t ticks;
98
+ ble_npl_time_ms_to_ticks (nextTime, &ticks);
99
+ ble_npl_callout_reset (&pScan->m_srTimer , ticks);
100
+ }
101
+ }
102
+ # endif
103
+
31
104
/* *
32
105
* @brief Scan constructor.
33
106
*/
@@ -36,13 +109,22 @@ NimBLEScan::NimBLEScan()
36
109
// default interval + window, no whitelist scan filter,not limited scan, no scan response, filter_duplicates
37
110
m_scanParams{0 , 0 , BLE_HCI_SCAN_FILT_NO_WL, 0 , 1 , 1 },
38
111
m_pTaskData{nullptr },
39
- m_maxResults{0xFF } {}
112
+ m_maxResults{0xFF } {
113
+ # if SR_TIMEOUT
114
+ ble_npl_callout_init (&m_srTimer, nimble_port_get_dflt_eventq (), NimBLEScan::srTimerCb, this );
115
+ ble_npl_event_init (&dummySrTimerEvent, sendDummyScanResponse, NULL );
116
+ # endif
117
+ }
40
118
41
119
/* *
42
120
* @brief Scan destructor, release any allocated resources.
43
121
*/
44
122
NimBLEScan::~NimBLEScan () {
45
123
clearResults ();
124
+ # if SR_TIMEOUT
125
+ ble_npl_callout_deinit (&m_srTimer);
126
+ ble_npl_event_deinit (&dummySrTimerEvent);
127
+ # endif
46
128
}
47
129
48
130
/* *
@@ -114,6 +196,9 @@ int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
114
196
advertisedDevice = new NimBLEAdvertisedDevice (event, event_type);
115
197
pScan->m_scanResults .m_deviceVec .push_back (advertisedDevice);
116
198
NIMBLE_LOGI (LOG_TAG, " New advertiser: %s" , advertisedAddress.toString ().c_str ());
199
+ # if SR_TIMEOUT
200
+ advertisedDevice->m_time = ble_npl_time_get ();
201
+ # endif
117
202
} else {
118
203
advertisedDevice->update (event, event_type);
119
204
if (isLegacyAdv && event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
@@ -137,6 +222,13 @@ int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
137
222
advertisedDevice->m_callbackSent ++;
138
223
// got the scan response report the full data.
139
224
pScan->m_pScanCallbacks ->onResult (advertisedDevice);
225
+ # if SR_TIMEOUT
226
+ } else if (isLegacyAdv && !ble_npl_callout_is_active (&pScan->m_srTimer )) {
227
+ // Start the timer to wait for the scan response.
228
+ ble_npl_time_t ticks;
229
+ ble_npl_time_ms_to_ticks (SR_TIMEOUT, &ticks);
230
+ ble_npl_callout_reset (&pScan->m_srTimer , ticks);
231
+ # endif
140
232
}
141
233
142
234
// If not storing results and we have invoked the callback, delete the device.
@@ -149,13 +241,15 @@ int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
149
241
150
242
case BLE_GAP_EVENT_DISC_COMPLETE: {
151
243
NIMBLE_LOGD (LOG_TAG, " discovery complete; reason=%d" , event->disc_complete .reason );
244
+ # if SR_TIMEOUT
245
+ ble_npl_callout_stop (&pScan->m_srTimer );
246
+ # endif
247
+ pScan->m_pScanCallbacks ->onScanEnd (pScan->m_scanResults , event->disc_complete .reason );
152
248
153
249
if (pScan->m_maxResults == 0 ) {
154
250
pScan->clearResults ();
155
251
}
156
252
157
- pScan->m_pScanCallbacks ->onScanEnd (pScan->m_scanResults , event->disc_complete .reason );
158
-
159
253
if (pScan->m_pTaskData != nullptr ) {
160
254
NimBLEUtils::taskRelease (*pScan->m_pTaskData , event->disc_complete .reason );
161
255
}
@@ -384,6 +478,10 @@ bool NimBLEScan::stop() {
384
478
return false ;
385
479
}
386
480
481
+ # if SR_TIMEOUT
482
+ ble_npl_callout_stop (&m_srTimer);
483
+ # endif
484
+
387
485
if (m_maxResults == 0 ) {
388
486
clearResults ();
389
487
}
0 commit comments