Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file.

## Fixed
- `NimBLEClient` connection state tracking.
- `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.
- Calling disconnect will no longer return false if the HCI response is "Unknown ID".
- Remote descriptors not found when characteristic vector handles out of order.
- `setValue` with char inputs now calculates the data length correctly.
Expand Down
21 changes: 17 additions & 4 deletions src/NimBLEClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1059,8 +1059,17 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
// set this incase the client instance was changed due to incorrect event arg bug above
pTaskData = pClient->m_pTaskData;

// Save the connection status before any modifications to determine if the connection
// was previously established. This is used to differentiate between a genuine
// connection establishment failure and a disconnect after a successful connection.
const bool wasConnected = (pClient->m_connStatus == CONNECTED);

const int connEstablishFailReason = BLE_HS_HCI_ERR(BLE_ERR_CONN_ESTABLISHMENT);
if (rc == connEstablishFailReason && pClient->m_connectFailRetryCount < pClient->m_config.connectFailRetries) {
// Only retry connection establishment failures if the connection was not previously
// established. If the connection was established (wasConnected), this is a genuine
// disconnect (e.g., peer powered off), so we should not retry.
if (rc == connEstablishFailReason && !wasConnected &&
pClient->m_connectFailRetryCount < pClient->m_config.connectFailRetries) {
pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
++pClient->m_connectFailRetryCount;
pClient->m_connStatus = CONNECTING;
Expand All @@ -1078,7 +1087,11 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
NIMBLE_LOGE(LOG_TAG, "Retry connect start failed, rc=%d %s", retryRc, NimBLEUtils::returnCodeToString(retryRc));
}

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

if (pClient->m_config.deleteOnDisconnect ||
(rc == connEstablishFailReason && pClient->m_config.deleteOnConnectFail)) {
(isConnectFail && pClient->m_config.deleteOnConnectFail)) {
// If we are set to self delete on disconnect but we have a task waiting on the connection
// completion we will set the flag to delete on connect fail instead of deleting here
if (pTaskData != nullptr && rc == connEstablishFailReason) {
if (pTaskData != nullptr && isConnectFail) {
pClient->m_config.deleteOnConnectFail = true;
break;
}
Expand Down