Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 45ff5a8

Browse files
committedJun 15, 2025··
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

‎libraries/BLE/src/BLEClient.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ typedef uint16_t esp_gatt_if_t;
6868
class BLERemoteService;
6969
class BLEClientCallbacks;
7070
class BLEAdvertisedDevice;
71+
struct BLETaskData;
7172

7273
/**
7374
* @brief A model of a %BLE client.
@@ -164,9 +165,9 @@ class BLEClient {
164165
#if defined(CONFIG_NIMBLE_ENABLED)
165166
int m_lastErr;
166167
int32_t m_connectTimeout;
168+
uint8_t m_terminateFailCount;
167169
ble_gap_conn_params m_pConnParams;
168-
ble_task_data_t *m_pTaskData;
169-
ble_npl_callout m_dcTimer;
170+
mutable BLETaskData *m_pTaskData;
170171
#endif
171172

172173
/***************************************************************************

‎libraries/BLE/src/BLEDevice.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
#include "BLEAdvertising.h"
3232
#include "BLESecurity.h"
3333
#include "BLEAddress.h"
34-
#include "BLETypes.h"
34+
#include "BLEUtils.h"
3535

3636
/***************************************************************************
3737
* Bluedroid includes *

‎libraries/BLE/src/BLERemoteCharacteristic.cpp

Lines changed: 83 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -679,74 +679,26 @@ int BLERemoteCharacteristic::descriptorDiscCB(
679679

680680
desc_filter_t *filter = (desc_filter_t *)arg;
681681
const BLEUUID *uuid_filter = filter->uuid;
682-
ble_task_data_t *pTaskData = (ble_task_data_t *)filter->task_data;
683-
BLERemoteCharacteristic *characteristic = (BLERemoteCharacteristic *)pTaskData->pATT;
682+
BLETaskData *pTaskData = (BLETaskData *)filter->task_data;
683+
BLERemoteCharacteristic *characteristic = (BLERemoteCharacteristic *)pTaskData->m_pInstance;
684684

685685
if (characteristic->getRemoteService()->getClient()->getConnId() != conn_handle) {
686686
return 0;
687687
}
688688

689-
switch (rc) {
690-
case 0:
691-
{
692-
if (uuid_filter != nullptr) {
693-
if (ble_uuid_cmp(&uuid_filter->getNative()->u, &dsc->uuid.u) != 0) {
694-
return 0;
695-
} else {
696-
rc = BLE_HS_EDONE;
697-
}
698-
}
699-
700-
BLERemoteDescriptor *pNewRemoteDescriptor = new BLERemoteDescriptor(characteristic, dsc);
701-
characteristic->m_descriptorMap.insert(
702-
std::pair<std::string, BLERemoteDescriptor *>(pNewRemoteDescriptor->getUUID().toString().c_str(), pNewRemoteDescriptor)
703-
);
704-
break;
705-
}
706-
default: break;
707-
}
708-
709-
/* If rc == BLE_HS_EDONE, resume the task with a success error code and stop the discovery process.
710-
* Else if rc == 0, just return 0 to continue the discovery until we get BLE_HS_EDONE.
711-
* If we get any other error code tell the application to abort by returning non-zero in the rc.
712-
*/
713-
if (rc == BLE_HS_EDONE) {
714-
pTaskData->rc = 0;
715-
xTaskNotifyGive(pTaskData->task);
716-
} else if (rc != 0) {
717-
// Error; abort discovery.
718-
pTaskData->rc = rc;
719-
xTaskNotifyGive(pTaskData->task);
720-
}
721-
722-
log_d("<< Descriptor Discovered. status: %d", pTaskData->rc);
723-
return rc;
724-
}
725-
726-
/**
727-
* @brief callback from NimBLE when the next characteristic of the service is discovered.
728-
*/
729-
int BLERemoteCharacteristic::nextCharCB(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_chr *chr, void *arg) {
730-
int rc = error->status;
731-
log_d("Next Characteristic >> status: %d handle: %d", rc, (rc == 0) ? chr->val_handle : -1);
732-
733-
ble_task_data_t *pTaskData = (ble_task_data_t *)arg;
734-
BLERemoteCharacteristic *pChar = (BLERemoteCharacteristic *)pTaskData->pATT;
735-
736-
if (pChar->getRemoteService()->getClient()->getConnId() != conn_handle) {
737-
return 0;
689+
if (rc == 0 && characteristic->getHandle() == chr_val_handle && (!uuid_filter || ble_uuid_cmp(&uuid_filter->getNative()->u, &dsc->uuid.u) == 0)) {
690+
BLERemoteDescriptor *pNewRemoteDescriptor = new BLERemoteDescriptor(characteristic, dsc);
691+
characteristic->m_descriptorMap.insert(
692+
std::pair<std::string, BLERemoteDescriptor *>(pNewRemoteDescriptor->getUUID().toString().c_str(), pNewRemoteDescriptor)
693+
);
694+
rc = !!uuid_filter * BLE_HS_EDONE;
738695
}
739696

740-
if (rc == 0) {
741-
pChar->m_endHandle = chr->def_handle - 1;
742-
rc = BLE_HS_EDONE;
743-
} else if (rc == BLE_HS_EDONE) {
744-
pChar->m_endHandle = pChar->getRemoteService()->getEndHandle();
745-
} else {
746-
pTaskData->rc = rc;
697+
if (rc != 0) {
698+
BLEUtils::taskRelease(*pTaskData, rc);
699+
log_d("<< Descriptor Discovery");
747700
}
748701

749-
xTaskNotifyGive(pTaskData->task);
750702
return rc;
751703
}
752704

@@ -755,18 +707,23 @@ int BLERemoteCharacteristic::nextCharCB(uint16_t conn_handle, const struct ble_g
755707
* @return success == 0 or error code.
756708
*/
757709
int BLERemoteCharacteristic::onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) {
758-
ble_task_data_t *pTaskData = (ble_task_data_t *)arg;
759-
BLERemoteCharacteristic *characteristic = (BLERemoteCharacteristic *)pTaskData->pATT;
760-
uint16_t conn_id = characteristic->getRemoteService()->getClient()->getConnId();
710+
BLETaskData *pTaskData = static_cast<BLETaskData *>(arg);
711+
BLERemoteCharacteristic *characteristic = static_cast<BLERemoteCharacteristic *>(pTaskData->m_pInstance);
761712

762-
if (conn_id != conn_handle) {
763-
return 0;
713+
if (error->status == BLE_HS_ENOTCONN) {
714+
log_e("<< Characteristic Read; Not connected");
715+
BLEUtils::taskRelease(*pTaskData, error->status);
716+
return error->status;
764717
}
765718

766-
log_i("Read complete; status=%d conn_handle=%d", error->status, conn_handle);
719+
if (characteristic->getRemoteService()->getClient()->getConnId() != conn_handle) {
720+
return 0;
721+
}
767722

768-
String *strBuf = (String *)pTaskData->buf;
769723
int rc = error->status;
724+
log_i("Read complete; status=%d conn_handle=%d", rc, conn_handle);
725+
726+
String *strBuf = (String *)pTaskData->m_pBuf;
770727

771728
if (rc == 0) {
772729
if (attr) {
@@ -781,9 +738,7 @@ int BLERemoteCharacteristic::onReadCB(uint16_t conn_handle, const struct ble_gat
781738
}
782739
}
783740

784-
pTaskData->rc = rc;
785-
xTaskNotifyGive(pTaskData->task);
786-
741+
BLEUtils::taskRelease(*pTaskData, rc);
787742
return rc;
788743
}
789744

@@ -792,18 +747,21 @@ int BLERemoteCharacteristic::onReadCB(uint16_t conn_handle, const struct ble_gat
792747
* @return success == 0 or error code.
793748
*/
794749
int BLERemoteCharacteristic::onWriteCB(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) {
795-
ble_task_data_t *pTaskData = (ble_task_data_t *)arg;
796-
BLERemoteCharacteristic *characteristic = (BLERemoteCharacteristic *)pTaskData->pATT;
750+
BLETaskData *pTaskData = static_cast<BLETaskData *>(arg);
751+
BLERemoteCharacteristic *characteristic = static_cast<BLERemoteCharacteristic *>(pTaskData->m_pInstance);
752+
753+
if (error->status == BLE_HS_ENOTCONN) {
754+
log_e("<< Characteristic Write; Not connected");
755+
BLEUtils::taskRelease(*pTaskData, error->status);
756+
return error->status;
757+
}
797758

798759
if (characteristic->getRemoteService()->getClient()->getConnId() != conn_handle) {
799760
return 0;
800761
}
801762

802763
log_i("Write complete; status=%d conn_handle=%d", error->status, conn_handle);
803-
804-
pTaskData->rc = error->status;
805-
xTaskNotifyGive(pTaskData->task);
806-
764+
BLEUtils::taskRelease(*pTaskData, error->status);
807765
return 0;
808766
}
809767

@@ -816,41 +774,13 @@ bool BLERemoteCharacteristic::retrieveDescriptors(const BLEUUID *uuid_filter) {
816774

817775
// If this is the last handle then there are no descriptors
818776
if (m_handle == getRemoteService()->getEndHandle()) {
777+
log_d("<< retrieveDescriptors(): No descriptors found");
819778
return true;
820779
}
821780

822-
int rc = 0;
823-
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
824-
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
825-
826-
// If we don't know the end handle of this characteristic retrieve the next one in the service
827-
// The end handle is the next characteristic definition handle -1.
828-
if (m_endHandle == 0) {
829-
rc = ble_gattc_disc_all_chrs(
830-
getRemoteService()->getClient()->getConnId(), m_handle, getRemoteService()->getEndHandle(), BLERemoteCharacteristic::nextCharCB, &taskData
831-
);
832-
if (rc != 0) {
833-
log_e("Error getting end handle rc=%d", rc);
834-
return false;
835-
}
836-
837-
#ifdef ulTaskNotifyValueClear
838-
// Clear the task notification value to ensure we block
839-
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
840-
#endif
841-
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
842-
843-
if (taskData.rc != 0) {
844-
log_e("Could not retrieve end handle rc=%d", taskData.rc);
845-
return false;
846-
}
847-
}
848-
849-
if (m_handle == m_endHandle) {
850-
return true;
851-
}
852-
781+
BLETaskData taskData(const_cast<BLERemoteCharacteristic*>(this));
853782
desc_filter_t filter = {uuid_filter, &taskData};
783+
int rc = 0;
854784

855785
rc = ble_gattc_disc_all_dscs(getRemoteService()->getClient()->getConnId(), m_handle, m_endHandle, BLERemoteCharacteristic::descriptorDiscCB, &filter);
856786

@@ -859,18 +789,17 @@ bool BLERemoteCharacteristic::retrieveDescriptors(const BLEUUID *uuid_filter) {
859789
return false;
860790
}
861791

862-
#ifdef ulTaskNotifyValueClear
863-
// Clear the task notification value to ensure we block
864-
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
865-
#endif
866-
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
792+
size_t prevDscCount = m_descriptorMap.size();
793+
BLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER);
794+
rc = ((BLETaskData*)filter.task_data)->m_flags;
867795

868-
if (taskData.rc != 0) {
869-
log_e("Failed to retrieve descriptors; startHandle:%d endHandle:%d taskData.rc=%d", m_handle, m_endHandle, taskData.rc);
796+
if (rc != BLE_HS_EDONE) {
797+
log_e("<< retrieveDescriptors(): failed: rc=%d %s", rc, BLEUtils::returnCodeToString(rc));
798+
return false;
870799
}
871800

872-
log_d("<< retrieveDescriptors(): Found %d descriptors.", m_descriptorMap.size());
873-
return (taskData.rc == 0);
801+
log_d("<< retrieveDescriptors(): Found %d descriptors.", m_descriptorMap.size() - prevDscCount);
802+
return true;
874803
} // retrieveDescriptors
875804

876805
/**
@@ -881,7 +810,7 @@ String BLERemoteCharacteristic::readValue() {
881810
log_d(">> readValue(): uuid: %s, handle: %d 0x%.2x", getUUID().toString().c_str(), getHandle(), getHandle());
882811

883812
BLEClient *pClient = getRemoteService()->getClient();
884-
String value;
813+
String value{};
885814

886815
if (!pClient->isConnected()) {
887816
log_e("Disconnected");
@@ -890,30 +819,30 @@ String BLERemoteCharacteristic::readValue() {
890819

891820
int rc = 0;
892821
int retryCount = 1;
893-
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
894-
ble_task_data_t taskData = {this, cur_task, 0, &value};
822+
BLETaskData taskData(const_cast<BLERemoteCharacteristic*>(this), 0, &value);
895823

896824
do {
897825
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0, BLERemoteCharacteristic::onReadCB, &taskData);
898826
if (rc != 0) {
899-
log_e("Error: Failed to read characteristic; rc=%d, %s", rc, BLEUtils::returnCodeToString(rc));
900-
return value;
827+
goto exit;
901828
}
902829

903-
#ifdef ulTaskNotifyValueClear
904-
// Clear the task notification value to ensure we block
905-
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
906-
#endif
907-
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
908-
rc = taskData.rc;
830+
BLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER);
831+
rc = taskData.m_flags;
909832

910833
switch (rc) {
911834
case 0:
912-
case BLE_HS_EDONE: rc = 0; break;
835+
case BLE_HS_EDONE:
836+
rc = 0;
837+
break;
913838
// Characteristic is not long-readable, return with what we have.
914839
case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
915840
log_i("Attribute not long");
916-
rc = 0;
841+
rc = ble_gattc_read(pClient->getConnId(), m_handle, BLERemoteCharacteristic::onReadCB, &taskData);
842+
if (rc != 0) {
843+
goto exit;
844+
}
845+
retryCount++;
917846
break;
918847
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
919848
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR):
@@ -922,7 +851,8 @@ String BLERemoteCharacteristic::readValue() {
922851
break;
923852
}
924853
/* Else falls through. */
925-
default: log_e("<< readValue rc=%d", rc); return value;
854+
default:
855+
goto exit;
926856
}
927857
} while (rc != 0 && retryCount--);
928858

@@ -934,7 +864,13 @@ String BLERemoteCharacteristic::readValue() {
934864
}
935865
m_semaphoreReadCharEvt.give();
936866

937-
log_d("<< readValue length: %d rc=%d", value.length(), rc);
867+
exit:
868+
if (rc != 0) {
869+
log_e("<< readValue failed rc=%d, %s", rc, BLEUtils::returnCodeToString(rc));
870+
} else {
871+
log_d("<< readValue length: %d rc=%d", value.length(), rc);
872+
}
873+
938874
return value;
939875
} // readValue
940876

@@ -958,17 +894,15 @@ bool BLERemoteCharacteristic::writeValue(uint8_t *data, size_t length, bool resp
958894
int rc = 0;
959895
int retryCount = 1;
960896
uint16_t mtu = ble_att_mtu(pClient->getConnId()) - 3;
897+
BLETaskData taskData(const_cast<BLERemoteCharacteristic*>(this));
961898

962899
// Check if the data length is longer than we can write in one connection event.
963900
// If so we must do a long write which requires a response.
964901
if (length <= mtu && !response) {
965902
rc = ble_gattc_write_no_rsp_flat(pClient->getConnId(), m_handle, data, length);
966-
return (rc == 0);
903+
goto exit;
967904
}
968905

969-
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
970-
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
971-
972906
do {
973907
if (length > mtu) {
974908
log_i("long write %d bytes", length);
@@ -978,20 +912,17 @@ bool BLERemoteCharacteristic::writeValue(uint8_t *data, size_t length, bool resp
978912
rc = ble_gattc_write_flat(pClient->getConnId(), m_handle, data, length, BLERemoteCharacteristic::onWriteCB, &taskData);
979913
}
980914
if (rc != 0) {
981-
log_e("Error: Failed to write characteristic; rc=%d", rc);
982-
return false;
915+
goto exit;
983916
}
984917

985-
#ifdef ulTaskNotifyValueClear
986-
// Clear the task notification value to ensure we block
987-
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
988-
#endif
989-
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
990-
rc = taskData.rc;
918+
BLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER);
919+
rc = taskData.m_flags;
991920

992921
switch (rc) {
993922
case 0:
994-
case BLE_HS_EDONE: rc = 0; break;
923+
case BLE_HS_EDONE:
924+
rc = 0;
925+
break;
995926
case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
996927
log_e("Long write not supported by peer; Truncating length to %d", mtu);
997928
retryCount++;
@@ -1005,11 +936,18 @@ bool BLERemoteCharacteristic::writeValue(uint8_t *data, size_t length, bool resp
1005936
break;
1006937
}
1007938
/* Else falls through. */
1008-
default: log_e("<< writeValue, rc: %d", rc); return false;
939+
default:
940+
goto exit;
1009941
}
1010942
} while (rc != 0 && retryCount--);
1011943

1012-
log_d("<< writeValue, rc: %d", rc);
944+
exit:
945+
if (rc != 0) {
946+
log_e("<< writeValue failed rc=%d, %s", rc, BLEUtils::returnCodeToString(rc));
947+
} else {
948+
log_d("<< writeValue success. length: %d rc=%d", length, rc);
949+
}
950+
1013951
return (rc == 0);
1014952
} // writeValue
1015953

‎libraries/BLE/src/BLERemoteCharacteristic.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,6 @@ class BLERemoteCharacteristic {
182182
static int onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg);
183183
static int onWriteCB(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg);
184184
static int descriptorDiscCB(uint16_t conn_handle, const struct ble_gatt_error *error, uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc, void *arg);
185-
static int nextCharCB(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_chr *chr, void *arg);
186185
#endif
187186
}; // BLERemoteCharacteristic
188187

‎libraries/BLE/src/BLERemoteDescriptor.cpp

Lines changed: 58 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ String BLERemoteDescriptor::readValue() {
279279
log_d(">> Descriptor readValue: %s", toString().c_str());
280280

281281
BLEClient *pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
282-
String value;
282+
String value{};
283283

284284
if (!pClient->isConnected()) {
285285
log_e("Disconnected");
@@ -288,30 +288,28 @@ String BLERemoteDescriptor::readValue() {
288288

289289
int rc = 0;
290290
int retryCount = 1;
291-
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
292-
ble_task_data_t taskData = {this, cur_task, 0, &value};
291+
BLETaskData taskData(const_cast<BLERemoteDescriptor*>(this), 0, &value);
293292

294293
do {
295294
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0, BLERemoteDescriptor::onReadCB, &taskData);
296295
if (rc != 0) {
297-
log_e("Error: Failed to read descriptor; rc=%d, %s", rc, BLEUtils::returnCodeToString(rc));
298-
return value;
296+
goto exit;
299297
}
300298

301-
#ifdef ulTaskNotifyValueClear
302-
// Clear the task notification value to ensure we block
303-
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
304-
#endif
305-
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
306-
rc = taskData.rc;
299+
BLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER);
300+
rc = taskData.m_flags;
307301

308302
switch (rc) {
309303
case 0:
310304
case BLE_HS_EDONE: rc = 0; break;
311305
// Descriptor is not long-readable, return with what we have.
312306
case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
313307
log_i("Attribute not long");
314-
rc = 0;
308+
rc = ble_gattc_read(pClient->getConnId(), m_handle, BLERemoteDescriptor::onReadCB, &taskData);
309+
if (rc != 0) {
310+
goto exit;
311+
}
312+
retryCount++;
315313
break;
316314
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
317315
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR):
@@ -320,11 +318,22 @@ String BLERemoteDescriptor::readValue() {
320318
break;
321319
}
322320
/* Else falls through. */
323-
default: return value;
321+
default:
322+
goto exit;
324323
}
325324
} while (rc != 0 && retryCount--);
326325

327-
log_d("<< Descriptor readValue(): length: %d rc=%d", value.length(), rc);
326+
m_semaphoreReadDescrEvt.take("readValue");
327+
m_value = value;
328+
m_semaphoreReadDescrEvt.give();
329+
330+
exit:
331+
if (rc != 0) {
332+
log_e("<< readValue failed rc=%d, %s", rc, BLEUtils::returnCodeToString(rc));
333+
} else {
334+
log_d("<< Descriptor readValue(): length: %d rc=%d", value.length(), rc);
335+
}
336+
328337
return value;
329338
} // readValue
330339

@@ -333,17 +342,23 @@ String BLERemoteDescriptor::readValue() {
333342
* @return success == 0 or error code.
334343
*/
335344
int BLERemoteDescriptor::onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) {
336-
ble_task_data_t *pTaskData = (ble_task_data_t *)arg;
337-
BLERemoteDescriptor *desc = (BLERemoteDescriptor *)pTaskData->pATT;
345+
BLETaskData *pTaskData = static_cast<BLETaskData *>(arg);
346+
BLERemoteDescriptor *desc = static_cast<BLERemoteDescriptor *>(pTaskData->m_pInstance);
338347
uint16_t conn_id = desc->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId();
339348

349+
if (error->status == BLE_HS_ENOTCONN) {
350+
log_e("<< Descriptor Read; Not connected");
351+
BLEUtils::taskRelease(*pTaskData, error->status);
352+
return error->status;
353+
}
354+
340355
if (conn_id != conn_handle) {
341356
return 0;
342357
}
343358

344359
log_d("Read complete; status=%d conn_handle=%d", error->status, conn_handle);
345360

346-
String *strBuf = (String *)pTaskData->buf;
361+
String *strBuf = static_cast<String *>(pTaskData->m_pBuf);
347362
int rc = error->status;
348363

349364
if (rc == 0) {
@@ -359,9 +374,7 @@ int BLERemoteDescriptor::onReadCB(uint16_t conn_handle, const struct ble_gatt_er
359374
}
360375
}
361376

362-
pTaskData->rc = rc;
363-
xTaskNotifyGive(pTaskData->task);
364-
377+
BLEUtils::taskRelease(*pTaskData, rc);
365378
return rc;
366379
}
367380

@@ -370,18 +383,23 @@ int BLERemoteDescriptor::onReadCB(uint16_t conn_handle, const struct ble_gatt_er
370383
* @return success == 0 or error code.
371384
*/
372385
int BLERemoteDescriptor::onWriteCB(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) {
373-
ble_task_data_t *pTaskData = (ble_task_data_t *)arg;
374-
BLERemoteDescriptor *descriptor = (BLERemoteDescriptor *)pTaskData->pATT;
386+
BLETaskData *pTaskData = static_cast<BLETaskData *>(arg);
387+
BLERemoteDescriptor *descriptor = static_cast<BLERemoteDescriptor *>(pTaskData->m_pInstance);
388+
int rc = error->status;
389+
390+
if (rc == BLE_HS_ENOTCONN) {
391+
log_e("<< Descriptor Write; Not connected");
392+
BLEUtils::taskRelease(*pTaskData, rc);
393+
return rc;
394+
}
375395

376396
if (descriptor->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId() != conn_handle) {
377397
return 0;
378398
}
379399

380-
log_i("Write complete; status=%d conn_handle=%d", error->status, conn_handle);
381-
382-
pTaskData->rc = error->status;
383-
xTaskNotifyGive(pTaskData->task);
400+
log_i("Write complete; status=%d conn_handle=%d", rc, conn_handle);
384401

402+
BLEUtils::taskRelease(*pTaskData, rc);
385403
return 0;
386404
}
387405

@@ -406,17 +424,15 @@ bool BLERemoteDescriptor::writeValue(uint8_t *data, size_t length, bool response
406424
int rc = 0;
407425
int retryCount = 1;
408426
uint16_t mtu = ble_att_mtu(pClient->getConnId()) - 3;
427+
BLETaskData taskData(const_cast<BLERemoteDescriptor*>(this));
409428

410429
// Check if the data length is longer than we can write in 1 connection event.
411430
// If so we must do a long write which requires a response.
412431
if (length <= mtu && !response) {
413432
rc = ble_gattc_write_no_rsp_flat(pClient->getConnId(), m_handle, data, length);
414-
return (rc == 0);
433+
goto exit;
415434
}
416435

417-
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
418-
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
419-
420436
do {
421437
if (length > mtu) {
422438
log_i("long write %d bytes", length);
@@ -427,16 +443,11 @@ bool BLERemoteDescriptor::writeValue(uint8_t *data, size_t length, bool response
427443
}
428444

429445
if (rc != 0) {
430-
log_e("Error: Failed to write descriptor; rc=%d", rc);
431-
return false;
446+
goto exit;
432447
}
433448

434-
#ifdef ulTaskNotifyValueClear
435-
// Clear the task notification value to ensure we block
436-
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
437-
#endif
438-
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
439-
rc = taskData.rc;
449+
BLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER);
450+
rc = taskData.m_flags;
440451

441452
switch (rc) {
442453
case 0:
@@ -454,11 +465,18 @@ bool BLERemoteDescriptor::writeValue(uint8_t *data, size_t length, bool response
454465
break;
455466
}
456467
/* Else falls through. */
457-
default: return false;
468+
default:
469+
goto exit;
458470
}
459471
} while (rc != 0 && retryCount--);
460472

461-
log_d("<< Descriptor writeValue, rc: %d", rc);
473+
exit:
474+
if (rc != 0) {
475+
log_e("<< writeValue failed rc=%d, %s", rc, BLEUtils::returnCodeToString(rc));
476+
} else {
477+
log_d("<< writeValue success. length: %d rc=%d", length, rc);
478+
}
479+
462480
return (rc == 0);
463481
} // writeValue
464482

‎libraries/BLE/src/BLERemoteService.cpp

Lines changed: 22 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -355,60 +355,35 @@ BLERemoteService::BLERemoteService(BLEClient *pClient, const struct ble_gatt_svc
355355
}
356356
m_startHandle = service->start_handle;
357357
m_endHandle = service->end_handle;
358+
m_haveCharacteristics = false;
358359
log_v("<< BLERemoteService(): %s", m_uuid.toString().c_str());
359360
}
360361

361362
/**
362363
* @brief Retrieve all the characteristics for this service.
363364
* This function will not return until we have all the characteristics.
364365
*/
365-
void BLERemoteService::retrieveCharacteristics(BLEUUID *uuid_filter) {
366+
void BLERemoteService::retrieveCharacteristics() {
366367
log_v(">> retrieveCharacteristics() for service: %s", getUUID().toString().c_str());
367368

368369
int rc = 0;
369-
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
370-
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
371-
372-
if (uuid_filter == nullptr) {
373-
rc = ble_gattc_disc_all_chrs(m_pClient->getConnId(), m_startHandle, m_endHandle, BLERemoteService::characteristicDiscCB, &taskData);
374-
} else {
375-
rc = ble_gattc_disc_chrs_by_uuid(
376-
m_pClient->getConnId(), m_startHandle, m_endHandle, &uuid_filter->getNative()->u, BLERemoteService::characteristicDiscCB, &taskData
377-
);
378-
}
370+
BLETaskData taskData(const_cast<BLERemoteService*>(this));
371+
372+
rc = ble_gattc_disc_all_chrs(m_pClient->getConnId(), m_startHandle, m_endHandle, BLERemoteService::characteristicDiscCB, &taskData);
379373

380374
if (rc != 0) {
381375
log_e("ble_gattc_disc_all_chrs: rc=%d %s", rc, BLEUtils::returnCodeToString(rc));
382376
return;
383377
}
384378

385-
#ifdef ulTaskNotifyValueClear
386-
// Clear the task notification value to ensure we block
387-
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
388-
#endif
389-
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
390-
391-
if (taskData.rc == 0) {
392-
if (uuid_filter == nullptr) {
393-
if (m_characteristicMap.size() > 1) {
394-
for (auto it = m_characteristicMap.begin(); it != m_characteristicMap.end(); ++it) {
395-
auto nx = std::next(it, 1);
396-
if (nx == m_characteristicMap.end()) {
397-
break;
398-
}
399-
it->second->m_endHandle = nx->second->m_defHandle - 1;
400-
}
401-
}
402-
403-
if (m_characteristicMap.size() > 0) {
404-
std::prev(m_characteristicMap.end())->second->m_endHandle = getEndHandle();
405-
}
406-
}
407-
408-
log_v("<< retrieveCharacteristics()");
409-
} else {
410-
log_e("Could not retrieve characteristics");
379+
BLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER);
380+
rc = taskData.m_flags;
381+
if (rc == 0 || rc == BLE_HS_EDONE) {
382+
log_d("<< retrieveCharacteristics()");
383+
return;
411384
}
385+
386+
log_e("<< retrieveCharacteristics() rc=%d %s", rc, BLEUtils::returnCodeToString(rc));
412387
} // retrieveCharacteristics
413388

414389
/**
@@ -418,8 +393,14 @@ void BLERemoteService::retrieveCharacteristics(BLEUUID *uuid_filter) {
418393
int BLERemoteService::characteristicDiscCB(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_chr *chr, void *arg) {
419394
log_d("Characteristic Discovered >> status: %d handle: %d", error->status, (error->status == 0) ? chr->val_handle : -1);
420395

421-
ble_task_data_t *pTaskData = (ble_task_data_t *)arg;
422-
BLERemoteService *service = (BLERemoteService *)pTaskData->pATT;
396+
BLETaskData *pTaskData = (BLETaskData *)arg;
397+
BLERemoteService *service = (BLERemoteService *)pTaskData->m_pInstance;
398+
399+
if (error->status == BLE_HS_ENOTCONN) {
400+
log_e("<< Characteristic Discovery; Not connected");
401+
BLEUtils::taskRelease(*pTaskData, error->status);
402+
return error->status;
403+
}
423404

424405
// Make sure the discovery is for this device
425406
if (service->getClient()->getConnId() != conn_handle) {
@@ -436,15 +417,8 @@ int BLERemoteService::characteristicDiscCB(uint16_t conn_handle, const struct bl
436417
return 0;
437418
}
438419

439-
if (error->status == BLE_HS_EDONE) {
440-
pTaskData->rc = 0;
441-
} else {
442-
log_e("characteristicDiscCB() rc=%d %s", error->status, BLEUtils::returnCodeToString(error->status));
443-
pTaskData->rc = error->status;
444-
}
445-
446-
xTaskNotifyGive(pTaskData->task);
447-
420+
BLEUtils::taskRelease(*pTaskData, error->status);
421+
service->m_haveCharacteristics = true;
448422
log_d("<< Characteristic Discovered");
449423
return error->status;
450424
}

‎libraries/BLE/src/BLERemoteService.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class BLERemoteService {
6060
std::map<std::string, BLERemoteCharacteristic *> *getCharacteristics();
6161
std::map<uint16_t, BLERemoteCharacteristic *> *getCharacteristicsByHandle(); // Get the characteristics map.
6262
void getCharacteristics(std::map<uint16_t, BLERemoteCharacteristic *> **pCharacteristicMap);
63+
void retrieveCharacteristics();
6364

6465
BLEClient *getClient(void); // Get a reference to the client associated with this service.
6566
uint16_t getHandle(); // Get the handle of this service.
@@ -112,8 +113,7 @@ class BLERemoteService {
112113
#if defined(CONFIG_BLUEDROID_ENABLED)
113114
// Private constructor ... never meant to be created by a user application.
114115
BLERemoteService(esp_gatt_id_t srvcId, BLEClient *pClient, uint16_t startHandle, uint16_t endHandle);
115-
esp_gatt_id_t *getSrvcId(void);
116-
void retrieveCharacteristics(void);
116+
esp_gatt_id_t *getSrvcId();
117117
void gattClientEventHandler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *evtParam);
118118
#endif
119119

@@ -123,7 +123,6 @@ class BLERemoteService {
123123

124124
#if defined(CONFIG_NIMBLE_ENABLED)
125125
BLERemoteService(BLEClient *pClient, const struct ble_gatt_svc *service);
126-
void retrieveCharacteristics(BLEUUID *uuid_filter = nullptr);
127126
static int characteristicDiscCB(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_chr *chr, void *arg);
128127
#endif
129128
}; // BLERemoteService

‎libraries/BLE/src/BLEScan.cpp

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -704,8 +704,7 @@ int BLEScan::handleGAPEvent(ble_gap_event *event, void *arg) {
704704
}
705705

706706
if (pScan->m_pTaskData != nullptr) {
707-
pScan->m_pTaskData->rc = event->disc_complete.reason;
708-
xTaskNotifyGive(pScan->m_pTaskData->task);
707+
BLEUtils::taskRelease(*pScan->m_pTaskData, event->disc_complete.reason);
709708
}
710709

711710
return 0;
@@ -785,16 +784,16 @@ BLEScanResults *BLEScan::start(uint32_t duration, bool is_continue) {
785784
log_w("Blocking scan called with duration = forever");
786785
}
787786

788-
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
789-
ble_task_data_t taskData = {nullptr, cur_task, 0, nullptr};
787+
if (m_pTaskData != nullptr) {
788+
log_e("Scan already in progress");
789+
return &m_scanResults;
790+
}
791+
792+
BLETaskData taskData(this);
790793
m_pTaskData = &taskData;
791794

792795
if (start(duration, nullptr, is_continue)) {
793-
#ifdef ulTaskNotifyValueClear
794-
// Clear the task notification value to ensure we block
795-
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
796-
#endif
797-
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
796+
BLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER);
798797
}
799798

800799
m_pTaskData = nullptr;
@@ -823,7 +822,7 @@ bool BLEScan::stop() {
823822
}
824823

825824
if (m_pTaskData != nullptr) {
826-
xTaskNotifyGive(m_pTaskData->task);
825+
BLEUtils::taskRelease(*m_pTaskData);
827826
}
828827

829828
log_d("<< stop()");

‎libraries/BLE/src/BLEScan.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
#include <string>
2525
#include "BLEAdvertisedDevice.h"
2626
#include "BLEClient.h"
27-
#include "BLETypes.h"
27+
#include "BLEUtils.h"
2828
#include "RTOS.h"
2929

3030
/***************************************************************************
@@ -53,6 +53,7 @@ class BLEExtAdvertisingCallbacks;
5353
class BLEClient;
5454
class BLEScan;
5555
class BLEPeriodicScanCallbacks;
56+
struct BLETaskData;
5657

5758
/***************************************************************************
5859
* Bluedroid type definitions *
@@ -179,7 +180,7 @@ class BLEScan {
179180
uint32_t m_duration;
180181
ble_gap_disc_params m_scan_params;
181182
bool m_ignoreResults;
182-
ble_task_data_t *m_pTaskData;
183+
BLETaskData *m_pTaskData;
183184
uint8_t m_maxResults;
184185
#endif
185186

‎libraries/BLE/src/BLESecurity.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include "BLESecurity.h"
2323
#include "BLEUtils.h"
24+
#include "esp32-hal-log.h"
2425

2526
/***************************************************************************
2627
* NimBLE includes *

‎libraries/BLE/src/BLEServer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
#include "RTOS.h"
3434
#include "BLEAddress.h"
3535
#include "BLEUtils.h"
36-
#include "BLETypes.h"
36+
#include "BLEUtils.h"
3737

3838
/*****************************************************************************
3939
* Bluedroid includes *

‎libraries/BLE/src/BLEService.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
#include "BLECharacteristic.h"
2525
#include "BLEServer.h"
2626
#include "BLEUUID.h"
27-
#include "BLETypes.h"
27+
#include "BLEUtils.h"
2828
#include "RTOS.h"
2929

3030
/*****************************************************************************

‎libraries/BLE/src/BLETypes.h

Lines changed: 0 additions & 57 deletions
This file was deleted.

‎libraries/BLE/src/BLEUtils.cpp

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,25 @@
5151
*****************************************************************************/
5252

5353
#if defined(CONFIG_NIMBLE_ENABLED)
54-
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
55-
#define CONFIG_NIMBLE_ENABLE_RETURN_CODE_TEXT
56-
#define CONFIG_NIMBLE_ENABLE_ADVERTISMENT_TYPE_TEXT
57-
#define CONFIG_NIMBLE_ENABLE_GAP_EVENT_CODE_TEXT
58-
#endif
5954
#include <host/ble_gap.h>
6055
#include <host/ble_att.h>
6156
#include <host/ble_hs.h>
6257
#include <host/ble_sm.h>
6358
#include <host/ble_l2cap.h>
6459
#include <nimble/hci_common.h>
6560
#include <nimble/ble.h>
61+
62+
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
63+
#define CONFIG_NIMBLE_ENABLE_RETURN_CODE_TEXT
64+
#define CONFIG_NIMBLE_ENABLE_ADVERTISMENT_TYPE_TEXT
65+
#define CONFIG_NIMBLE_ENABLE_GAP_EVENT_CODE_TEXT
66+
#endif
67+
68+
#ifndef CONFIG_NIMBLE_FREERTOS_TASK_BLOCK_BIT
69+
#define CONFIG_NIMBLE_FREERTOS_TASK_BLOCK_BIT 31
70+
#endif
71+
72+
constexpr uint32_t TASK_BLOCK_BIT = (1 << CONFIG_NIMBLE_FREERTOS_TASK_BLOCK_BIT);
6673
#endif
6774

6875
/*****************************************************************************
@@ -1879,6 +1886,19 @@ const char *BLEUtils::searchEventTypeToString(esp_gap_search_evt_t searchEvt) {
18791886

18801887
#if defined(CONFIG_NIMBLE_ENABLED)
18811888

1889+
/**
1890+
* @brief Construct a BLETaskData instance.
1891+
* @param [in] pInstance An instance of the class that will be waiting.
1892+
* @param [in] flags General purpose flags for the caller.
1893+
* @param [in] buf A buffer for data.
1894+
*/
1895+
BLETaskData::BLETaskData(void* pInstance, int flags, void* buf) : m_pInstance{pInstance}, m_flags{flags}, m_pBuf{buf}, m_pHandle{xTaskGetCurrentTaskHandle()} {}
1896+
1897+
/**
1898+
* @brief Destructor.
1899+
*/
1900+
BLETaskData::~BLETaskData() {}
1901+
18821902
/**
18831903
* @brief A function for checking validity of connection parameters.
18841904
* @param [in] params A pointer to the structure containing the parameters to check.
@@ -2196,6 +2216,41 @@ String BLEUtils::characteristicPropertiesToString(uint8_t prop) {
21962216
return res;
21972217
} // characteristicPropertiesToString
21982218

2219+
/**
2220+
* @brief Blocks the calling task until released or timeout.
2221+
* @param [in] taskData A pointer to the task data structure.
2222+
* @param [in] timeout The time to wait in milliseconds.
2223+
* @return True if the task completed, false if the timeout was reached.
2224+
*/
2225+
bool BLEUtils::taskWait(const BLETaskData& taskData, uint32_t timeout) {
2226+
ble_npl_time_t ticks;
2227+
if (timeout == BLE_NPL_TIME_FOREVER) {
2228+
ticks = BLE_NPL_TIME_FOREVER;
2229+
} else {
2230+
ble_npl_time_ms_to_ticks(timeout, &ticks);
2231+
}
2232+
2233+
uint32_t notificationValue;
2234+
xTaskNotifyWait(0, TASK_BLOCK_BIT, &notificationValue, 0);
2235+
if (notificationValue & TASK_BLOCK_BIT) {
2236+
return true;
2237+
}
2238+
2239+
return xTaskNotifyWait(0, TASK_BLOCK_BIT, nullptr, ticks) == pdTRUE;
2240+
} // taskWait
2241+
2242+
/**
2243+
* @brief Release a task.
2244+
* @param [in] taskData A pointer to the task data structure.
2245+
* @param [in] flags A return value to set in the task data structure.
2246+
*/
2247+
void BLEUtils::taskRelease(const BLETaskData& taskData, int flags) {
2248+
taskData.m_flags = flags;
2249+
if (taskData.m_pHandle != nullptr) {
2250+
xTaskNotify(static_cast<TaskHandle_t>(taskData.m_pHandle), TASK_BLOCK_BIT, eSetBits);
2251+
}
2252+
} // taskRelease
2253+
21992254
#endif // CONFIG_NIMBLE_ENABLED
22002255

22012256
#endif /* CONFIG_BLUEDROID_ENABLED || CONFIG_NIMBLE_ENABLED */

‎libraries/BLE/src/BLEUtils.h

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,8 @@
2323

2424
#include <string>
2525
#include "BLEAddress.h"
26-
#include "BLEClient.h"
27-
#include "BLETypes.h"
2826
#include "WString.h"
27+
#include <freertos/task.h>
2928

3029
/*****************************************************************************
3130
* Bluedroid includes *
@@ -42,9 +41,46 @@
4241
*****************************************************************************/
4342

4443
#if defined(CONFIG_NIMBLE_ENABLED)
44+
#include <stdlib.h>
45+
#include <climits>
4546
#include <host/ble_gap.h>
4647
#endif
4748

49+
/*****************************************************************************
50+
* Common types *
51+
*****************************************************************************/
52+
53+
typedef struct {
54+
void *peer_device; // peer device BLEClient or BLEServer
55+
bool connected; // connection status
56+
uint16_t mtu; // negotiated MTU per peer device
57+
} conn_status_t;
58+
59+
/*****************************************************************************
60+
* NimBLE types *
61+
*****************************************************************************/
62+
63+
#if defined(CONFIG_NIMBLE_ENABLED)
64+
65+
/**
66+
* @brief A structure to hold data for a task that is waiting for a response.
67+
* @details This structure is used in conjunction with BLEUtils::taskWait() and BLEUtils::taskRelease().
68+
* All items are optional, the m_pHandle will be set in taskWait().
69+
*/
70+
struct BLETaskData {
71+
BLETaskData(void* pInstance = nullptr, int flags = 0, void* buf = nullptr);
72+
~BLETaskData();
73+
void* m_pInstance{nullptr};
74+
mutable int m_flags{0};
75+
void* m_pBuf{nullptr};
76+
77+
private:
78+
mutable void* m_pHandle{nullptr}; // semaphore or task handle
79+
friend class BLEUtils;
80+
};
81+
82+
#endif
83+
4884
/*****************************************************************************
4985
* Forward declarations *
5086
*****************************************************************************/
@@ -106,6 +142,8 @@ class BLEUtils {
106142
static const char *gapEventToString(uint8_t eventType);
107143
static const char *returnCodeToString(int rc);
108144
static int checkConnParams(ble_gap_conn_params *params);
145+
static bool taskWait(const BLETaskData& taskData, uint32_t timeout);
146+
static void taskRelease(const BLETaskData& taskData, int rc = 0);
109147
#endif
110148
};
111149

0 commit comments

Comments
 (0)
Please sign in to comment.