Skip to content

Commit f2a63fa

Browse files
Fix NimbleBluetooth reliability and performance (#8385)
* Initial work to get NimbleBluetooth working reliably, and cross-task mutexes cleaned up * Pre-fill toPhoneQueue when safe (during config/nodeinfo): runOnceToPhoneCanPreloadNextPacket * Handle 0-byte responses breaking clients during initial config phases * requestLowerPowerConnection * PhoneAPI: onConfigStart and onConfigComplete callbacks for subclasses * NimbleBluetooth: switch to high-throughput BLE mode during config, then lower-power BLE mode for steady-state * Add some documentation to NimbleBluetooth.cpp * make cppcheck happier * Allow runOnceHandleToPhoneQueue to tell runOnce to shouldBreakAndRetryLater, so we don't busy-loop forever in runOnce * Gating some logging behind DEBUG_NIMBLE_ON_READ_TIMING ifdef again; bump retry count * Add check for connected state in NimBLE onRead() --------- Co-authored-by: Jonathan Bennett <[email protected]>
1 parent 05c176c commit f2a63fa

File tree

3 files changed

+512
-61
lines changed

3 files changed

+512
-61
lines changed

src/mesh/PhoneAPI.cpp

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ void PhoneAPI::handleStartConfig()
5757
#endif
5858
}
5959

60+
// Allow subclasses to prepare for high-throughput config traffic
61+
onConfigStart();
62+
6063
// even if we were already connected - restart our state machine
6164
if (config_nonce == SPECIAL_NONCE_ONLY_NODES) {
6265
// If client only wants node info, jump directly to sending nodes
@@ -71,7 +74,7 @@ void PhoneAPI::handleStartConfig()
7174
spiLock->unlock();
7275
LOG_DEBUG("Got %d files in manifest", filesManifest.size());
7376

74-
LOG_INFO("Start API client config");
77+
LOG_INFO("Start API client config millis=%u", millis());
7578
// Protect against concurrent BLE callbacks: they run in NimBLE's FreeRTOS task and also touch nodeInfoQueue.
7679
{
7780
concurrency::LockGuard guard(&nodeInfoMutex);
@@ -453,7 +456,10 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
453456
break;
454457

455458
case STATE_SEND_OTHER_NODEINFOS: {
456-
LOG_DEBUG("Send known nodes");
459+
if (readIndex == 2) { // readIndex==2 will be true for the first non-us node
460+
LOG_INFO("Start sending nodeinfos millis=%u", millis());
461+
}
462+
457463
meshtastic_NodeInfo infoToSend = {};
458464
{
459465
concurrency::LockGuard guard(&nodeInfoMutex);
@@ -470,13 +476,22 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
470476
if (infoToSend.num != 0) {
471477
// Just in case we stored a different user.id in the past, but should never happen going forward
472478
sprintf(infoToSend.user.id, "!%08x", infoToSend.num);
473-
LOG_DEBUG("nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s", infoToSend.num, infoToSend.last_heard,
474-
infoToSend.user.id, infoToSend.user.long_name);
479+
480+
// Logging this really slows down sending nodes on initial connection because the serial console is so slow, so only
481+
// uncomment if you really need to:
482+
// LOG_INFO("nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s", nodeInfoForPhone.num, nodeInfoForPhone.last_heard,
483+
// nodeInfoForPhone.user.id, nodeInfoForPhone.user.long_name);
484+
485+
// Occasional progress logging. (readIndex==2 will be true for the first non-us node)
486+
if (readIndex == 2 || readIndex % 20 == 0) {
487+
LOG_DEBUG("nodeinfo: %d/%d", readIndex, nodeDB->getNumMeshNodes());
488+
}
489+
475490
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_node_info_tag;
476491
fromRadioScratch.node_info = infoToSend;
477492
prefetchNodeInfos();
478493
} else {
479-
LOG_DEBUG("Done sending nodeinfo");
494+
LOG_DEBUG("Done sending %d of %d nodeinfos millis=%u", readIndex, nodeDB->getNumMeshNodes(), millis());
480495
concurrency::LockGuard guard(&nodeInfoMutex);
481496
nodeInfoQueue.clear();
482497
state = STATE_SEND_FILEMANIFEST;
@@ -558,11 +573,15 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
558573

559574
void PhoneAPI::sendConfigComplete()
560575
{
561-
LOG_INFO("Config Send Complete");
576+
LOG_INFO("Config Send Complete millis=%u", millis());
562577
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_config_complete_id_tag;
563578
fromRadioScratch.config_complete_id = config_nonce;
564579
config_nonce = 0;
565580
state = STATE_SEND_PACKETS;
581+
582+
// Allow subclasses to know we've entered steady-state so they can lower power consumption
583+
onConfigComplete();
584+
566585
pauseBluetoothLogging = false;
567586
}
568587

src/mesh/PhoneAPI.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ class PhoneAPI
136136
bool available();
137137

138138
bool isConnected() { return state != STATE_SEND_NOTHING; }
139+
bool isSendingPackets() { return state == STATE_SEND_PACKETS; }
139140

140141
protected:
141142
/// Our fromradio packet while it is being assembled
@@ -158,6 +159,11 @@ class PhoneAPI
158159
*/
159160
virtual void onNowHasData(uint32_t fromRadioNum) {}
160161

162+
/// Subclasses can use these lifecycle hooks for transport-specific behavior around config/steady-state
163+
/// (i.e. BLE connection params)
164+
virtual void onConfigStart() {}
165+
virtual void onConfigComplete() {}
166+
161167
/// begin a new connection
162168
void handleStartConfig();
163169

0 commit comments

Comments
 (0)