Skip to content

Commit 242c0ab

Browse files
Copiloth2zero
andauthored
Fix: onDisconnect not called when central powers off with 0x3E reason after established connection
When a BLE connection was established (BLE_GAP_EVENT_CONNECT with status 0) and then disconnects with BLE_ERR_CONN_ESTABLISHMENT (0x3E) - which can happen when the peer powers off within the first 6 connection events - the 2.5.0 retry logic incorrectly suppressed onDisconnect and called onConnectFail after retries (up to 60+ seconds later). Fix: only retry on 0x3E if the connection was never established (m_connStatus != CONNECTED). When the connection was previously established, call onDisconnect (not onConnectFail) so user reconnect logic fires correctly. Agent-Logs-Url: https://github.com/h2zero/NimBLE-Arduino/sessions/ca79e82b-2ceb-4ae8-83d3-c6344ed13cea Co-authored-by: h2zero <32826625+h2zero@users.noreply.github.com>
1 parent 9273857 commit 242c0ab

2 files changed

Lines changed: 18 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file.
55

66
## Fixed
77
- `NimBLEClient` connection state tracking.
8+
- `NimBLEClient` no longer retries connection or calls `onConnectFail` when a disconnect with error code `0x3E` (Connection Failed to be Established) occurs after the connection was previously confirmed; instead `onDisconnect` is called correctly.
89
- Calling disconnect will no longer return false if the HCI response is "Unknown ID".
910
- Remote descriptors not found when characteristic vector handles out of order.
1011
- `setValue` with char inputs now calculates the data length correctly.

src/NimBLEClient.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,8 +1059,17 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
10591059
// set this incase the client instance was changed due to incorrect event arg bug above
10601060
pTaskData = pClient->m_pTaskData;
10611061

1062+
// Save the connection status before any modifications to determine if the connection
1063+
// was previously established. This is used to differentiate between a genuine
1064+
// connection establishment failure and a disconnect after a successful connection.
1065+
const bool wasConnected = (pClient->m_connStatus == CONNECTED);
1066+
10621067
const int connEstablishFailReason = BLE_HS_HCI_ERR(BLE_ERR_CONN_ESTABLISHMENT);
1063-
if (rc == connEstablishFailReason && pClient->m_connectFailRetryCount < pClient->m_config.connectFailRetries) {
1068+
// Only retry connection establishment failures if the connection was not previously
1069+
// established. If the connection was established (wasConnected), this is a genuine
1070+
// disconnect (e.g., peer powered off), so we should not retry.
1071+
if (rc == connEstablishFailReason && !wasConnected &&
1072+
pClient->m_connectFailRetryCount < pClient->m_config.connectFailRetries) {
10641073
pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
10651074
++pClient->m_connectFailRetryCount;
10661075
pClient->m_connStatus = CONNECTING;
@@ -1078,7 +1087,11 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
10781087
NIMBLE_LOGE(LOG_TAG, "Retry connect start failed, rc=%d %s", retryRc, NimBLEUtils::returnCodeToString(retryRc));
10791088
}
10801089

1081-
if (rc == connEstablishFailReason) {
1090+
// Treat as a connect failure only if the connection was never established.
1091+
// If the connection was established (wasConnected), call onDisconnect even for 0x3E,
1092+
// since the peer was already connected and then disconnected.
1093+
const bool isConnectFail = (rc == connEstablishFailReason && !wasConnected);
1094+
if (isConnectFail) {
10821095
pClient->m_pClientCallbacks->onConnectFail(pClient, rc);
10831096
} else {
10841097
pClient->m_pClientCallbacks->onDisconnect(pClient, rc);
@@ -1088,10 +1101,10 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
10881101
pClient->m_connStatus = DISCONNECTED;
10891102

10901103
if (pClient->m_config.deleteOnDisconnect ||
1091-
(rc == connEstablishFailReason && pClient->m_config.deleteOnConnectFail)) {
1104+
(isConnectFail && pClient->m_config.deleteOnConnectFail)) {
10921105
// If we are set to self delete on disconnect but we have a task waiting on the connection
10931106
// completion we will set the flag to delete on connect fail instead of deleting here
1094-
if (pTaskData != nullptr && rc == connEstablishFailReason) {
1107+
if (pTaskData != nullptr && isConnectFail) {
10951108
pClient->m_config.deleteOnConnectFail = true;
10961109
break;
10971110
}

0 commit comments

Comments
 (0)