Skip to content

Commit ca46c60

Browse files
committed
Set default timeout to default window time and add debug stats
1 parent a4191e7 commit ca46c60

6 files changed

Lines changed: 114 additions & 20 deletions

File tree

src/NimBLEAdvertisedDevice.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,19 +58,19 @@ NimBLEAdvertisedDevice::NimBLEAdvertisedDevice(const ble_gap_event* event, uint8
5858
* @brief Update the advertisement data.
5959
* @param [in] event The advertisement event data.
6060
*/
61-
void NimBLEAdvertisedDevice::update(const ble_gap_event* event, uint8_t eventType) {
61+
bool NimBLEAdvertisedDevice::update(const ble_gap_event* event, uint8_t eventType) {
6262
# if MYNEWT_VAL(BLE_EXT_ADV)
6363
const auto& disc = event->ext_disc;
6464
if (!disc.length_data) { // dummy sr, just return, don't update anything
65-
return;
65+
return false;
6666
}
6767

6868
if (m_dataStatus == BLE_GAP_EXT_ADV_DATA_STATUS_INCOMPLETE) {
6969
m_payload.reserve(m_advLength + disc.length_data);
7070
m_payload.insert(m_payload.end(), disc.data, disc.data + disc.length_data);
7171
m_dataStatus = disc.data_status;
7272
m_advLength = m_payload.size();
73-
return;
73+
return true;
7474
}
7575

7676
m_dataStatus = disc.data_status;
@@ -80,17 +80,18 @@ void NimBLEAdvertisedDevice::update(const ble_gap_event* event, uint8_t eventTyp
8080
# endif
8181

8282
if (!disc.length_data) { // dummy sr, just return, don't update anything
83-
return;
83+
return false;
8484
}
8585

8686
m_rssi = disc.rssi;
8787
if (eventType == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP && isLegacyAdvertisement()) {
8888
m_payload.insert(m_payload.end(), disc.data, disc.data + disc.length_data);
89-
return;
89+
return true;
9090
}
9191
m_advLength = disc.length_data;
9292
m_payload.assign(disc.data, disc.data + disc.length_data);
9393
m_callbackSent = 0; // new data, reset callback sent flag
94+
return true;
9495
} // update
9596

9697
/**

src/NimBLEAdvertisedDevice.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ class NimBLEAdvertisedDevice {
154154
friend class NimBLEScan;
155155

156156
NimBLEAdvertisedDevice(const ble_gap_event* event, uint8_t eventType);
157-
void update(const ble_gap_event* event, uint8_t eventType);
157+
bool update(const ble_gap_event* event, uint8_t eventType);
158158
uint8_t findAdvField(uint8_t type, uint8_t index = 0, size_t* data_loc = nullptr) const;
159159
size_t findServiceData(uint8_t index, uint8_t* bytes) const;
160160

src/NimBLEScan.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,9 @@ extern "C" void ble_gap_rx_adv_report(ble_gap_disc_desc* desc);
6060
* provide the scan result to the callbacks when a device hasn't responded to the
6161
* scan request in time. This is called by the host task from the default event queue.
6262
*/
63-
static void sendDummyScanResponse(ble_npl_event* ev) {
63+
void NimBLEScan::sendDummyScanResponse(ble_npl_event* ev) {
6464
(void)ev;
65+
NimBLEDevice::getScan()->m_stats.incMissedSrCount();
6566
# if MYNEWT_VAL(BLE_EXT_ADV)
6667
ble_gap_rx_ext_adv_report(&dummyDesc);
6768
# else
@@ -128,7 +129,7 @@ NimBLEScan::NimBLEScan()
128129
m_maxResults{0xFF} {
129130
ble_npl_callout_init(&m_srTimer, nimble_port_get_dflt_eventq(), NimBLEScan::srTimerCb, this);
130131
ble_npl_event_init(&dummySrTimerEvent, sendDummyScanResponse, NULL);
131-
ble_npl_time_ms_to_ticks(MYNEWT_VAL(NIMBLE_CPP_SCAN_RSP_TIMEOUT), &m_srTimeoutTicks);
132+
ble_npl_time_ms_to_ticks(BLE_GAP_SCAN_FAST_WINDOW, &m_srTimeoutTicks);
132133
} // NimBLEScan::NimBLEScan
133134

134135
/**
@@ -198,6 +199,8 @@ int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
198199
// If we haven't seen this device before; create a new instance and insert it in the vector.
199200
// Otherwise just update the relevant parameters of the already known device.
200201
if (advertisedDevice == nullptr) {
202+
pScan->m_stats.incDevCount();
203+
201204
// Check if we have reach the scan results limit, ignore this one if so.
202205
// We still need to store each device when maxResults is 0 to be able to append the scan results
203206
if (pScan->m_maxResults > 0 && pScan->m_maxResults < 0xFF &&
@@ -206,6 +209,7 @@ int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
206209
}
207210

208211
if (isLegacyAdv && event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
212+
pScan->m_stats.incOrphanedSrCount();
209213
NIMBLE_LOGI(LOG_TAG, "Scan response without advertisement: %s", advertisedAddress.toString().c_str());
210214
}
211215

@@ -218,7 +222,14 @@ int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
218222
if (isLegacyAdv) {
219223
if (event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
220224
NIMBLE_LOGI(LOG_TAG, "Scan response from: %s", advertisedAddress.toString().c_str());
225+
if (!pScan->m_stats.recordSrTime(ble_npl_time_get() - advertisedDevice->m_time,
226+
pScan->m_scanParams.window * 625 / 1000)) {
227+
NIMBLE_LOGD(LOG_TAG,
228+
"Abnormal scan response time, stats ignored for device: %s",
229+
advertisedAddress.toString().c_str());
230+
}
221231
} else {
232+
pScan->m_stats.incDupCount();
222233
NIMBLE_LOGI(LOG_TAG, "Duplicate; updated: %s", advertisedAddress.toString().c_str());
223234
// Restart scan-response timeout when we see a new non-scan-response
224235
// legacy advertisement during active scanning for a scannable device.
@@ -269,6 +280,13 @@ int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
269280

270281
case BLE_GAP_EVENT_DISC_COMPLETE: {
271282
ble_npl_callout_stop(&pScan->m_srTimer);
283+
for (const auto& dev : pScan->m_scanResults.m_deviceVec) {
284+
if (dev->isScannable() && dev->m_callbackSent < 2) {
285+
pScan->m_stats.incMissedSrCount();
286+
pScan->m_pScanCallbacks->onResult(dev);
287+
}
288+
}
289+
272290
NIMBLE_LOGD(LOG_TAG, "discovery complete; reason=%d", event->disc_complete.reason);
273291

274292
pScan->m_pScanCallbacks->onScanEnd(pScan->m_scanResults, event->disc_complete.reason);
@@ -437,6 +455,8 @@ void NimBLEScan::setPeriod(uint32_t periodMs) {
437455
* @return True if scan started or false if there was an error.
438456
*/
439457
bool NimBLEScan::start(uint32_t duration, bool isContinue, bool restart) {
458+
m_stats.reset();
459+
440460
NIMBLE_LOGD(LOG_TAG, ">> start: duration=%" PRIu32, duration);
441461
if (isScanning()) {
442462
if (restart) {

src/NimBLEScan.h

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
# endif
3232

3333
# include <vector>
34+
# include <cinttypes>
35+
# include <cstdio>
3436

3537
class NimBLEDevice;
3638
class NimBLEScan;
@@ -83,6 +85,7 @@ class NimBLEScan {
8385
void erase(const NimBLEAddress& address);
8486
void erase(const NimBLEAdvertisedDevice* device);
8587
void setScanResponseTimeout(uint32_t timeoutMs);
88+
std::string getStatsString() const { return m_stats.toString(); }
8689

8790
# if MYNEWT_VAL(BLE_EXT_ADV)
8891
enum Phy { SCAN_1M = 0x01, SCAN_CODED = 0x02, SCAN_ALL = 0x03 };
@@ -93,11 +96,93 @@ class NimBLEScan {
9396
private:
9497
friend class NimBLEDevice;
9598

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.data(),
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+
srMinMs,
142+
srMaxMs,
143+
srCount ? srTotalMs / srCount : 0,
144+
orphanedSrCount,
145+
missedSrCount);
146+
147+
return out;
148+
}
149+
150+
// Records scan-response round-trip time. Returns false if the timing is abnormal
151+
// (>= 5x the scan window) and should be excluded from stats.
152+
bool recordSrTime(uint32_t ticks, uint16_t window) {
153+
uint32_t ms;
154+
ble_npl_time_ticks_to_ms(ticks, &ms);
155+
if (ms >= (window ? window : BLE_GAP_SCAN_FAST_WINDOW) * 5) {
156+
return false;
157+
}
158+
159+
if (ms < srMinMs) {
160+
srMinMs = ms;
161+
}
162+
if (ms > srMaxMs) {
163+
srMaxMs = ms;
164+
}
165+
srTotalMs += ms;
166+
srCount++;
167+
return true;
168+
}
169+
# else
170+
void reset() {}
171+
void incDevCount() {}
172+
void incDupCount() {}
173+
void incMissedSrCount() {}
174+
void incOrphanedSrCount() {}
175+
std::string toString() const { return ""; }
176+
bool recordSrTime(uint32_t ticks, uint16_t window) { return true; }
177+
# endif
178+
} m_stats;
179+
96180
NimBLEScan();
97181
~NimBLEScan();
98182
static int handleGapEvent(ble_gap_event* event, void* arg);
99183
void onHostSync();
100184
static void srTimerCb(ble_npl_event* event);
185+
static void sendDummyScanResponse(ble_npl_event* ev);
101186

102187
NimBLEScanCallbacks* m_pScanCallbacks;
103188
ble_gap_disc_params m_scanParams;

src/nimconfig.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,6 @@
6969
/** @brief Un-comment to change the stack size for the NimBLE host task */
7070
// #define MYNEWT_VAL_NIMBLE_HOST_TASK_STACK_SIZE 4096
7171

72-
/**
73-
* @brief Un-comment to change the default scan response timeout, in milliseconds.
74-
* @details This is the time to wait for a scan response before calling the onResult scan callback,
75-
* lower values increase callback rates but will lose data more often, higher values give full data more
76-
* often. Setting this to 0 will disable the scan response timeout.
77-
*/
78-
// #define MYNEWT_VAL_NIMBLE_CPP_SCAN_RSP_TIMEOUT (200)
79-
8072
/**
8173
* @brief Un-comment to change the bit used to block tasks during BLE operations
8274
* that call NimBLEUtils::taskWait. This should be different than any other

src/syscfg/syscfg.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2023,8 +2023,4 @@
20232023
#define MYNEWT_VAL_NIMBLE_CPP_ENABLE_ADVERTISEMENT_TYPE_TEXT (0)
20242024
#endif
20252025

2026-
#ifndef MYNEWT_VAL_NIMBLE_CPP_SCAN_RSP_TIMEOUT
2027-
#define MYNEWT_VAL_NIMBLE_CPP_SCAN_RSP_TIMEOUT (30)
2028-
#endif
2029-
20302026
#endif /* H_SYSCFG_ */

0 commit comments

Comments
 (0)