2222# include " NimBLEDevice.h"
2323# include " NimBLELog.h"
2424
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+
2531# include < string>
2632# include < climits>
2733
34+ # define SR_TIMEOUT CONFIG_NIMBLE_CPP_SCAN_RSP_TIMEOUT
35+
2836static const char * LOG_TAG = " NimBLEScan" ;
2937static NimBLEScanCallbacks defaultScanCallbacks;
3038
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 {0 }, .rssi = 127 , .data = nullptr , .direct_addr {0 }};
43+
44+ extern " C" void ble_gap_rx_adv_report (ble_gap_disc_desc* desc);
45+
46+ static void sendDummyScanResponse (ble_npl_event* ev) {
47+ (void )ev;
48+ ble_gap_rx_adv_report (&dummyDesc);
49+ }
50+
51+ /* *
52+ * @brief This will call the scan result callback when a scan response is not received
53+ * and will delete the device from the vector when maxResults is 0.
54+ */
55+ void NimBLEScan::srTimerCb (ble_npl_event* event) {
56+ NimBLEScan* pScan = (NimBLEScan*)ble_npl_event_get_arg (event);
57+ ble_npl_time_t now = ble_npl_time_get ();
58+ NimBLEAdvertisedDevice* curDev = nullptr ;
59+ NimBLEAdvertisedDevice* nextDev = nullptr ;
60+
61+ for (auto & dev : pScan->m_scanResults .m_deviceVec ) {
62+ if (dev->m_callbackSent < 2 && dev->isScannable ()) {
63+ if (!curDev || (now - dev->m_time > now - curDev->m_time )) {
64+ nextDev = curDev;
65+ curDev = dev;
66+ continue ;
67+ }
68+
69+ if (!nextDev || now - dev->m_time > now - nextDev->m_time ) {
70+ nextDev = dev;
71+ }
72+ }
73+ }
74+
75+ if (curDev) {
76+ memcpy (&dummyDesc.addr , curDev->getAddress ().getBase (), sizeof (dummyDesc.addr ));
77+ NIMBLE_LOGI (LOG_TAG, " Scan response timeout for: %s" , curDev->getAddress ().toString ().c_str ());
78+ ble_npl_eventq_put (nimble_port_get_dflt_eventq (), &dummySrTimerEvent);
79+ }
80+
81+ // Restart timer if there are more devices waiting for scan responses.
82+ if (nextDev) {
83+ auto nextTime = now - nextDev->m_time ;
84+ if (nextTime >= SR_TIMEOUT) {
85+ nextTime = 1 ;
86+ } else {
87+ nextTime = SR_TIMEOUT - nextTime;
88+ }
89+ ble_npl_time_t ticks;
90+ ble_npl_time_ms_to_ticks (nextTime, &ticks);
91+ ble_npl_callout_reset (&pScan->m_srTimer , ticks);
92+ }
93+ }
94+ # endif
95+
3196/* *
3297 * @brief Scan constructor.
3398 */
@@ -36,13 +101,22 @@ NimBLEScan::NimBLEScan()
36101 // default interval + window, no whitelist scan filter,not limited scan, no scan response, filter_duplicates
37102 m_scanParams{0 , 0 , BLE_HCI_SCAN_FILT_NO_WL, 0 , 1 , 1 },
38103 m_pTaskData{nullptr },
39- m_maxResults{0xFF } {}
104+ m_maxResults{0xFF } {
105+ # if SR_TIMEOUT
106+ ble_npl_callout_init (&m_srTimer, nimble_port_get_dflt_eventq (), NimBLEScan::srTimerCb, this );
107+ ble_npl_event_init (&dummySrTimerEvent, sendDummyScanResponse, NULL );
108+ # endif
109+ }
40110
41111/* *
42112 * @brief Scan destructor, release any allocated resources.
43113 */
44114NimBLEScan::~NimBLEScan () {
45115 clearResults ();
116+ # if SR_TIMEOUT
117+ ble_npl_callout_deinit (&m_srTimer);
118+ ble_npl_event_deinit (&dummySrTimerEvent);
119+ # endif
46120}
47121
48122/* *
@@ -109,6 +183,9 @@ int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
109183 advertisedDevice = new NimBLEAdvertisedDevice (event, event_type);
110184 pScan->m_scanResults .m_deviceVec .push_back (advertisedDevice);
111185 NIMBLE_LOGI (LOG_TAG, " New advertiser: %s" , advertisedAddress.toString ().c_str ());
186+ # if SR_TIMEOUT
187+ advertisedDevice->m_time = ble_npl_time_get ();
188+ # endif
112189 } else {
113190 advertisedDevice->update (event, event_type);
114191 if (isLegacyAdv && event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
@@ -132,6 +209,13 @@ int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
132209 advertisedDevice->m_callbackSent ++;
133210 // got the scan response report the full data.
134211 pScan->m_pScanCallbacks ->onResult (advertisedDevice);
212+ # if SR_TIMEOUT
213+ } else if (isLegacyAdv && !ble_npl_callout_is_active (&pScan->m_srTimer )) {
214+ // Start the timer to wait for the scan response.
215+ ble_npl_time_t ticks;
216+ ble_npl_time_ms_to_ticks (SR_TIMEOUT, &ticks);
217+ ble_npl_callout_reset (&pScan->m_srTimer , ticks);
218+ # endif
135219 }
136220
137221 // If not storing results and we have invoked the callback, delete the device.
@@ -144,13 +228,15 @@ int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
144228
145229 case BLE_GAP_EVENT_DISC_COMPLETE: {
146230 NIMBLE_LOGD (LOG_TAG, " discovery complete; reason=%d" , event->disc_complete .reason );
231+ # if SR_TIMEOUT
232+ ble_npl_callout_stop (&pScan->m_srTimer );
233+ # endif
234+ pScan->m_pScanCallbacks ->onScanEnd (pScan->m_scanResults , event->disc_complete .reason );
147235
148236 if (pScan->m_maxResults == 0 ) {
149237 pScan->clearResults ();
150238 }
151239
152- pScan->m_pScanCallbacks ->onScanEnd (pScan->m_scanResults , event->disc_complete .reason );
153-
154240 if (pScan->m_pTaskData != nullptr ) {
155241 NimBLEUtils::taskRelease (*pScan->m_pTaskData , event->disc_complete .reason );
156242 }
@@ -379,6 +465,10 @@ bool NimBLEScan::stop() {
379465 return false ;
380466 }
381467
468+ # if SR_TIMEOUT
469+ ble_npl_callout_stop (&m_srTimer);
470+ # endif
471+
382472 if (m_maxResults == 0 ) {
383473 clearResults ();
384474 }
@@ -483,11 +573,11 @@ void NimBLEScan::clearResults() {
483573 * @brief Dump the scan results to the log.
484574 */
485575void NimBLEScanResults::dump () const {
486- #if CONFIG_NIMBLE_CPP_LOG_LEVEL >=3
576+ # if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 3
487577 for (const auto & dev : m_deviceVec) {
488578 NIMBLE_LOGI (LOG_TAG, " - %s" , dev->toString ().c_str ());
489579 }
490- #endif
580+ # endif
491581} // dump
492582
493583/* *
0 commit comments