Skip to content

Commit 45ff5a8

Browse files
committed
fix(nimble): Fix Client and tasks
1 parent ce4a891 commit 45ff5a8

17 files changed

+368
-447
lines changed

libraries/BLE/src/BLEAdvertising.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "BLEAdvertising.h"
3535
#include <esp_err.h>
3636
#include "BLEUtils.h"
37+
#include "BLEDevice.h"
3738
#include "GeneralUtils.h"
3839
#include "esp32-hal-log.h"
3940

libraries/BLE/src/BLEClient.cpp

Lines changed: 83 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ BLEClient::BLEClient() {
9898
m_connectTimeout = 30000;
9999
m_pTaskData = nullptr;
100100
m_lastErr = 0;
101+
m_terminateFailCount = 0;
101102

102103
m_pConnParams.scan_itvl = 16; // Scan interval in 0.625ms units (NimBLE Default)
103104
m_pConnParams.scan_window = 16; // Scan window in 0.625ms units (NimBLE Default)
@@ -107,9 +108,6 @@ BLEClient::BLEClient() {
107108
m_pConnParams.supervision_timeout = BLE_GAP_INITIAL_SUPERVISION_TIMEOUT; // timeout = 400*10ms = 4000ms
108109
m_pConnParams.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; // Minimum length of connection event in 0.625ms units
109110
m_pConnParams.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units
110-
111-
memset(&m_dcTimer, 0, sizeof(m_dcTimer));
112-
ble_npl_callout_init(&m_dcTimer, nimble_port_get_dflt_eventq(), BLEClient::dcTimerCb, this);
113111
#endif
114112
} // BLEClient
115113

@@ -124,10 +122,6 @@ BLEClient::~BLEClient() {
124122
}
125123
m_servicesMap.clear();
126124
m_servicesMapByInstID.clear();
127-
128-
#if defined(CONFIG_NIMBLE_ENABLED)
129-
ble_npl_callout_deinit(&m_dcTimer);
130-
#endif
131125
} // ~BLEClient
132126

133127
/**
@@ -186,34 +180,27 @@ bool BLEClient::secureConnection() {
186180
#endif
187181

188182
#if defined(CONFIG_NIMBLE_ENABLED)
189-
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
190-
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
191-
192183
int retryCount = 1;
184+
BLETaskData taskData(const_cast<BLEClient*>(this), BLE_HS_ENOTCONN);
185+
m_pTaskData = &taskData;
193186

194187
do {
195-
m_pTaskData = &taskData;
196-
197-
int rc = BLESecurity::startSecurity(m_conn_id);
198-
if (rc != 0) {
199-
m_lastErr = rc;
200-
m_pTaskData = nullptr;
201-
return false;
188+
if (BLESecurity::startSecurity(m_conn_id)) {
189+
BLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER);
202190
}
203191

204-
#ifdef ulTaskNotifyValueClear
205-
// Clear the task notification value to ensure we block
206-
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
207-
#endif
208-
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
209-
} while (taskData.rc == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING) && retryCount--);
192+
} while (taskData.m_flags == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING) && retryCount--);
210193

211-
if (taskData.rc != 0) {
212-
m_lastErr = taskData.rc;
213-
return false;
194+
m_pTaskData = nullptr;
195+
196+
if (taskData.m_flags == 0) {
197+
log_d("<< secureConnection: success");
198+
return true;
214199
}
215200

216-
return true;
201+
m_lastErr = taskData.m_flags;
202+
log_e("secureConnection: failed rc=%d", taskData.m_flags);
203+
return false;
217204
#endif
218205
} // secureConnection
219206

@@ -376,7 +363,7 @@ bool BLEClient::setMTU(uint16_t mtu) {
376363
#endif
377364

378365
#if defined(CONFIG_NIMBLE_ENABLED)
379-
err = ble_gattc_exchange_mtu(m_conn_id, nullptr, nullptr);
366+
//err = ble_gattc_exchange_mtu(m_conn_id, nullptr, nullptr);
380367
#endif
381368

382369
if (err != ESP_OK) {
@@ -799,9 +786,6 @@ bool BLEClient::connect(BLEAddress address, uint8_t type, uint32_t timeoutMs) {
799786
m_appId = BLEDevice::m_appId++;
800787
m_peerAddress = address;
801788

802-
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
803-
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
804-
m_pTaskData = &taskData;
805789
int rc = 0;
806790

807791
/* Try to connect the the advertiser. Allow 30 seconds (30000 ms) for
@@ -837,45 +821,34 @@ bool BLEClient::connect(BLEAddress address, uint8_t type, uint32_t timeoutMs) {
837821

838822
} while (rc == BLE_HS_EBUSY);
839823

840-
m_lastErr = rc;
841-
842824
if (rc != 0) {
843-
m_pTaskData = nullptr;
825+
m_lastErr = rc;
844826
return false;
845827
}
846828

847-
#ifdef ulTaskNotifyValueClear
848-
// Clear the task notification value to ensure we block
849-
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
850-
#endif
829+
BLETaskData taskData(this);
830+
m_pTaskData = &taskData;
851831

852832
// Wait for the connect timeout time +1 second for the connection to complete
853-
if (ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(m_connectTimeout + 1000)) == pdFALSE) {
854-
m_pTaskData = nullptr;
855-
// If a connection was made but no response from MTU exchange; disconnect
833+
if (!BLEUtils::taskWait(taskData, m_connectTimeout + 1000)) {
834+
// If a connection was made but no response from MTU exchange proceed anyway
856835
if (isConnected()) {
857-
log_e("Connect timeout - no response");
858-
disconnect();
836+
taskData.m_flags = 0;
859837
} else {
860-
// workaround; if the controller doesn't cancel the connection
861-
// at the timeout, cancel it here.
862-
log_e("Connect timeout - canceling");
838+
// workaround; if the controller doesn't cancel the connection at the timeout, cancel it here.
839+
log_e("Connect timeout - cancelling");
863840
ble_gap_conn_cancel();
841+
taskData.m_flags = BLE_HS_ETIMEOUT;
864842
}
843+
}
865844

866-
return false;
845+
m_pTaskData = nullptr;
846+
rc = taskData.m_flags;
867847

868-
} else if (taskData.rc != 0) {
869-
m_lastErr = taskData.rc;
870-
log_e("Connection failed; status=%d %s", taskData.rc, BLEUtils::returnCodeToString(taskData.rc));
871-
// If the failure was not a result of a disconnection
872-
// make sure we disconnect now to avoid dangling connections
873-
if (isConnected()) {
874-
disconnect();
875-
}
848+
if (rc != 0) {
849+
log_e("Connection failed; status=%d %s", rc, BLEUtils::returnCodeToString(rc));
850+
m_lastErr = rc;
876851
return false;
877-
} else {
878-
log_i("Connection established");
879852
}
880853

881854
m_isConnected = true;
@@ -895,15 +868,16 @@ bool BLEClient::connect(BLEAddress address, uint8_t type, uint32_t timeoutMs) {
895868
*/
896869
int BLEClient::serviceDiscoveredCB(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, void *arg)
897870
{
898-
if (error == nullptr || service == nullptr) {
899-
log_e("serviceDiscoveredCB: error or service is nullptr");
900-
return 0;
901-
}
902-
903871
log_d("Service Discovered >> status: %d handle: %d", error->status, (error->status == 0) ? service->start_handle : -1);
904872

905-
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
906-
BLEClient *client = (BLEClient*)pTaskData->pATT;
873+
BLETaskData *pTaskData = (BLETaskData*)arg;
874+
BLEClient *client = (BLEClient*)pTaskData->m_pInstance;
875+
876+
if (error->status == BLE_HS_ENOTCONN) {
877+
log_e("<< Service Discovered; Disconnected");
878+
BLEUtils::taskRelease(*pTaskData, error->status);
879+
return error->status;
880+
}
907881

908882
// Make sure the service discovery is for this device
909883
if(client->getConnId() != conn_handle){
@@ -918,53 +892,50 @@ int BLEClient::serviceDiscoveredCB(uint16_t conn_handle, const struct ble_gatt_e
918892
return 0;
919893
}
920894

921-
if(error->status == BLE_HS_EDONE) {
922-
pTaskData->rc = 0;
923-
} else {
924-
log_e("serviceDiscoveredCB() rc=%d %s", error->status, BLEUtils::returnCodeToString(error->status));
925-
pTaskData->rc = error->status;
926-
}
927-
928-
xTaskNotifyGive(pTaskData->task);
929-
895+
BLEUtils::taskRelease(*pTaskData, error->status);
930896
log_d("<< Service Discovered");
931897
return error->status;
932898
}
933899

934900
std::map<std::string, BLERemoteService *> *BLEClient::getServices() {
935-
/*
936-
* Design
937-
* ------
938-
* We invoke esp_ble_gattc_search_service. This will request a list of the service exposed by the
939-
* peer BLE partner to be returned as events. Each event will be an an instance of ESP_GATTC_SEARCH_RES_EVT
940-
* and will culminate with an ESP_GATTC_SEARCH_CMPL_EVT when all have been received.
941-
*/
942901
log_v(">> getServices");
943-
// TODO implement retrieving services from cache
944-
//m_semaphoreSearchCmplEvt.take("getServices");
902+
945903
clearServices(); // Clear any services that may exist.
946904

905+
if (!isConnected()) {
906+
log_e("Disconnected, could not retrieve services -aborting");
907+
return &m_servicesMap;
908+
}
909+
947910
int errRc = 0;
948-
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
949-
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
911+
BLETaskData taskData(this);
950912

951913
errRc = ble_gattc_disc_all_svcs(m_conn_id, BLEClient::serviceDiscoveredCB, &taskData);
914+
952915
if (errRc != 0) {
953916
log_e("ble_gattc_disc_all_svcs: rc=%d %s", errRc, BLEUtils::returnCodeToString(errRc));
954917
m_lastErr = errRc;
955-
//m_semaphoreSearchCmplEvt.give();
956918
return &m_servicesMap;
957919
}
958-
// If successful, remember that we now have services.
959-
m_haveServices = m_servicesMap.size() > 0;
960-
//m_semaphoreSearchCmplEvt.give();
961-
log_v("<< getServices");
920+
921+
BLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER);
922+
errRc = taskData.m_flags;
923+
if (errRc == 0 || errRc == BLE_HS_EDONE) {
924+
// If successful, remember that we now have services.
925+
m_haveServices = m_servicesMap.size() > 0;
926+
log_v("<< getServices");
927+
return &m_servicesMap;
928+
}
929+
930+
m_lastErr = errRc;
931+
log_e("Could not retrieve services, rc=%d %s", errRc, BLEUtils::returnCodeToString(errRc));
962932
return &m_servicesMap;
963933
} // getServices
964934

965935
int BLEClient::handleGAPEvent(struct ble_gap_event *event, void *arg) {
966936
BLEClient *client = (BLEClient *)arg;
967-
int rc;
937+
int rc = 0;
938+
BLETaskData *pTaskData = client->m_pTaskData;
968939

969940
log_d("BLEClient", "Got Client event %s", BLEUtils::gapEventToString(event->type));
970941

@@ -979,7 +950,7 @@ int BLEClient::handleGAPEvent(struct ble_gap_event *event, void *arg) {
979950
case BLE_HS_ETIMEOUT_HCI:
980951
case BLE_HS_ENOTSYNCED:
981952
case BLE_HS_EOS:
982-
log_d("BLEClient", "Disconnect - host reset, rc=%d", rc);
953+
log_e("BLEClient", "Disconnect - host reset, rc=%d", rc);
983954
BLEDevice::onReset(rc);
984955
break;
985956
default:
@@ -990,14 +961,12 @@ int BLEClient::handleGAPEvent(struct ble_gap_event *event, void *arg) {
990961
break;
991962
}
992963

993-
// Stop the disconnect timer since we are now disconnected.
994-
ble_npl_callout_stop(&client->m_dcTimer);
995-
996964
// Remove the device from ignore list so we will scan it again
997965
// BLEDevice::removeIgnored(client->m_peerAddress);
998966

999967
// No longer connected, clear the connection ID.
1000968
client->m_conn_id = BLE_HS_CONN_HANDLE_NONE;
969+
client->m_terminateFailCount = 0;
1001970

1002971
// If we received a connected event but did not get established (no PDU)
1003972
// then a disconnect event will be sent but we should not send it to the
@@ -1028,11 +997,11 @@ int BLEClient::handleGAPEvent(struct ble_gap_event *event, void *arg) {
1028997

1029998
rc = event->connect.status;
1030999
if (rc == 0) {
1031-
log_i("BLEClient", "Connected event");
1000+
log_i("BLEClient: Connected event. Handle: %d", event->connect.conn_handle);
10321001

10331002
client->m_conn_id = event->connect.conn_handle;
10341003

1035-
rc = ble_gattc_exchange_mtu(client->m_conn_id, NULL, NULL);
1004+
rc = ble_gattc_exchange_mtu(client->m_conn_id, nullptr, nullptr);
10361005
if (rc != 0) {
10371006
log_e("BLEClient", "MTU exchange error; rc=%d %s", rc, BLEUtils::returnCodeToString(rc));
10381007
break;
@@ -1049,6 +1018,20 @@ int BLEClient::handleGAPEvent(struct ble_gap_event *event, void *arg) {
10491018
return 0;
10501019
} // BLE_GAP_EVENT_CONNECT
10511020

1021+
case BLE_GAP_EVENT_TERM_FAILURE: {
1022+
if (client->m_conn_id != event->term_failure.conn_handle) {
1023+
return 0;
1024+
}
1025+
1026+
log_e("Connection termination failure; rc=%d - retrying", event->term_failure.status);
1027+
if (++client->m_terminateFailCount > 2) {
1028+
ble_hs_sched_reset(BLE_HS_ECONTROLLER);
1029+
} else {
1030+
ble_gap_terminate(event->term_failure.conn_handle, BLE_ERR_REM_USER_CONN_TERM);
1031+
}
1032+
return 0;
1033+
} // BLE_GAP_EVENT_TERM_FAILURE
1034+
10521035
case BLE_GAP_EVENT_NOTIFY_RX:
10531036
{
10541037
if (client->m_conn_id != event->notify_rx.conn_handle) {
@@ -1236,12 +1219,8 @@ int BLEClient::handleGAPEvent(struct ble_gap_event *event, void *arg) {
12361219
}
12371220
} // Switch
12381221

1239-
if (client->m_pTaskData != nullptr) {
1240-
client->m_pTaskData->rc = rc;
1241-
if (client->m_pTaskData->task) {
1242-
xTaskNotifyGive(client->m_pTaskData->task);
1243-
}
1244-
client->m_pTaskData = nullptr;
1222+
if (pTaskData != nullptr) {
1223+
BLEUtils::taskRelease(*pTaskData, rc);
12451224
}
12461225

12471226
return 0;
@@ -1256,41 +1235,16 @@ int BLEClient::disconnect(uint8_t reason) {
12561235
int rc = 0;
12571236

12581237
if(isConnected()) {
1259-
// If the timer was already started, ignore this call.
1260-
if(ble_npl_callout_is_active(&m_dcTimer)) {
1261-
log_i("Already disconnecting, timer started");
1262-
return BLE_HS_EALREADY;
1263-
}
1264-
1265-
ble_gap_conn_desc desc;
1266-
if(ble_gap_conn_find(m_conn_id, &desc) != 0){
1267-
log_i("Connection ID not found");
1268-
return BLE_HS_EALREADY;
1269-
}
1270-
1271-
// We use a timer to detect a controller error in the event that it does
1272-
// not inform the stack when disconnection is complete.
1273-
// This is a common error in certain esp-idf versions.
1274-
// The disconnect timeout time is the supervison timeout time + 1 second.
1275-
// In the case that the event happenss shortly after the supervision timeout
1276-
// we don't want to prematurely reset the host.
1277-
ble_npl_time_t ticks;
1278-
ble_npl_time_ms_to_ticks((desc.supervision_timeout + 100) * 10, &ticks);
1279-
ble_npl_callout_reset(&m_dcTimer, ticks);
1280-
12811238
rc = ble_gap_terminate(m_conn_id, reason);
1282-
if (rc != 0) {
1283-
if(rc != BLE_HS_EALREADY) {
1284-
ble_npl_callout_stop(&m_dcTimer);
1285-
}
1239+
if (rc != 0 && rc != BLE_HS_ENOTCONN && rc != BLE_HS_EALREADY) {
1240+
m_lastErr = rc;
12861241
log_e("ble_gap_terminate failed: rc=%d %s", rc, BLEUtils::returnCodeToString(rc));
12871242
}
12881243
} else {
12891244
log_d("Not connected to any peers");
12901245
}
12911246

12921247
log_d("<< disconnect()");
1293-
m_lastErr = rc;
12941248
return rc;
12951249
} // disconnect
12961250

0 commit comments

Comments
 (0)