From 0957d7f6adac3a1a1686f87896ce6deb3c3eb9f4 Mon Sep 17 00:00:00 2001 From: h2zero Date: Sun, 9 Jan 2022 19:04:41 -0700 Subject: [PATCH] The latest versions of IDF include a new esp_timer library that seems to be incrementing the task notification values in unexpected places depending on other tasks in operation. This causes task blocking to fail in client operations leading to exceptions and crashing. This is a workaround for this situation and will need to be reworked properly in the future. --- src/NimBLEClient.cpp | 22 +++++++++++++++++++--- src/NimBLERemoteCharacteristic.cpp | 25 ++++++++++++++++++++++--- src/NimBLERemoteDescriptor.cpp | 14 ++++++++++++-- src/NimBLERemoteService.cpp | 7 ++++++- src/NimBLEScan.cpp | 7 ++++++- 5 files changed, 65 insertions(+), 10 deletions(-) diff --git a/src/NimBLEClient.cpp b/src/NimBLEClient.cpp index 9f4e08f..536626f 100644 --- a/src/NimBLEClient.cpp +++ b/src/NimBLEClient.cpp @@ -207,7 +207,8 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) { m_peerAddress = address; } - ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr}; + TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); + ble_task_data_t taskData = {this, cur_task, 0, nullptr}; m_pTaskData = &taskData; int rc = 0; @@ -260,6 +261,10 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) { return false; } +#ifdef ulTaskNotifyValueClear + // Clear the task notification value to ensure we block + ulTaskNotifyValueClear(cur_task, ULONG_MAX); +#endif // Wait for the connect timeout time +1 second for the connection to complete if(ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(m_connectTimeout + 1000)) == pdFALSE) { m_pTaskData = nullptr; @@ -310,7 +315,8 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) { * @return True on success. */ bool NimBLEClient::secureConnection() { - ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr}; + TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); + ble_task_data_t taskData = {this, cur_task, 0, nullptr}; int retryCount = 1; @@ -324,6 +330,10 @@ bool NimBLEClient::secureConnection() { return false; } +#ifdef ulTaskNotifyValueClear + // Clear the task notification value to ensure we block + ulTaskNotifyValueClear(cur_task, ULONG_MAX); +#endif ulTaskNotifyTake(pdTRUE, portMAX_DELAY); } while (taskData.rc == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING) && retryCount--); @@ -670,7 +680,8 @@ bool NimBLEClient::retrieveServices(const NimBLEUUID *uuid_filter) { } int rc = 0; - ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr}; + TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); + ble_task_data_t taskData = {this, cur_task, 0, nullptr}; if(uuid_filter == nullptr) { rc = ble_gattc_disc_all_svcs(m_conn_id, NimBLEClient::serviceDiscoveredCB, &taskData); @@ -685,6 +696,11 @@ bool NimBLEClient::retrieveServices(const NimBLEUUID *uuid_filter) { return false; } +#ifdef ulTaskNotifyValueClear + // Clear the task notification value to ensure we block + ulTaskNotifyValueClear(cur_task, ULONG_MAX); +#endif + // wait until we have all the services ulTaskNotifyTake(pdTRUE, portMAX_DELAY); m_lastErr = taskData.rc; diff --git a/src/NimBLERemoteCharacteristic.cpp b/src/NimBLERemoteCharacteristic.cpp index 9390c18..23b253b 100644 --- a/src/NimBLERemoteCharacteristic.cpp +++ b/src/NimBLERemoteCharacteristic.cpp @@ -237,7 +237,8 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt } int rc = 0; - ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr}; + TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); + ble_task_data_t taskData = {this, cur_task, 0, nullptr}; // If we don't know the end handle of this characteristic retrieve the next one in the service // The end handle is the next characteristic definition handle -1. @@ -252,6 +253,10 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt return false; } +#ifdef ulTaskNotifyValueClear + // Clear the task notification value to ensure we block + ulTaskNotifyValueClear(cur_task, ULONG_MAX); +#endif ulTaskNotifyTake(pdTRUE, portMAX_DELAY); if (taskData.rc != 0) { @@ -273,6 +278,10 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt return false; } +#ifdef ulTaskNotifyValueClear + // Clear the task notification value to ensure we block + ulTaskNotifyValueClear(cur_task, ULONG_MAX); +#endif ulTaskNotifyTake(pdTRUE, portMAX_DELAY); if (taskData.rc != 0) { @@ -473,7 +482,8 @@ std::string NimBLERemoteCharacteristic::readValue(time_t *timestamp) { int rc = 0; int retryCount = 1; - ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(),0, &value}; + TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); + ble_task_data_t taskData = {this, cur_task, 0, &value}; do { rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0, @@ -485,6 +495,10 @@ std::string NimBLERemoteCharacteristic::readValue(time_t *timestamp) { return value; } +#ifdef ulTaskNotifyValueClear + // Clear the task notification value to ensure we block + ulTaskNotifyValueClear(cur_task, ULONG_MAX); +#endif ulTaskNotifyTake(pdTRUE, portMAX_DELAY); rc = taskData.rc; @@ -742,7 +756,8 @@ bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length, return (rc==0); } - ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr}; + TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); + ble_task_data_t taskData = {this, cur_task, 0, nullptr}; do { if(length > mtu) { @@ -762,6 +777,10 @@ bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length, return false; } +#ifdef ulTaskNotifyValueClear + // Clear the task notification value to ensure we block + ulTaskNotifyValueClear(cur_task, ULONG_MAX); +#endif ulTaskNotifyTake(pdTRUE, portMAX_DELAY); rc = taskData.rc; diff --git a/src/NimBLERemoteDescriptor.cpp b/src/NimBLERemoteDescriptor.cpp index e3db26c..b86b106 100644 --- a/src/NimBLERemoteDescriptor.cpp +++ b/src/NimBLERemoteDescriptor.cpp @@ -137,7 +137,8 @@ std::string NimBLERemoteDescriptor::readValue() { int rc = 0; int retryCount = 1; - ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(),0, &value}; + TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); + ble_task_data_t taskData = {this, cur_task, 0, &value}; do { rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0, @@ -149,6 +150,10 @@ std::string NimBLERemoteDescriptor::readValue() { return value; } +#ifdef ulTaskNotifyValueClear + // Clear the task notification value to ensure we block + ulTaskNotifyValueClear(cur_task, ULONG_MAX); +#endif ulTaskNotifyTake(pdTRUE, portMAX_DELAY); rc = taskData.rc; @@ -289,7 +294,8 @@ bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool return (rc == 0); } - ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr}; + TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); + ble_task_data_t taskData = {this, cur_task, 0, nullptr}; do { if(length > mtu) { @@ -310,6 +316,10 @@ bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool return false; } +#ifdef ulTaskNotifyValueClear + // Clear the task notification value to ensure we block + ulTaskNotifyValueClear(cur_task, ULONG_MAX); +#endif ulTaskNotifyTake(pdTRUE, portMAX_DELAY); rc = taskData.rc; diff --git a/src/NimBLERemoteService.cpp b/src/NimBLERemoteService.cpp index b8ae4fc..77567bf 100644 --- a/src/NimBLERemoteService.cpp +++ b/src/NimBLERemoteService.cpp @@ -196,7 +196,8 @@ bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID *uuid_filter) NIMBLE_LOGD(LOG_TAG, ">> retrieveCharacteristics() for service: %s", getUUID().toString().c_str()); int rc = 0; - ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr}; + TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); + ble_task_data_t taskData = {this, cur_task, 0, nullptr}; if(uuid_filter == nullptr) { rc = ble_gattc_disc_all_chrs(m_pClient->getConnId(), @@ -218,6 +219,10 @@ bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID *uuid_filter) return false; } +#ifdef ulTaskNotifyValueClear + // Clear the task notification value to ensure we block + ulTaskNotifyValueClear(cur_task, ULONG_MAX); +#endif ulTaskNotifyTake(pdTRUE, portMAX_DELAY); if(taskData.rc == 0){ diff --git a/src/NimBLEScan.cpp b/src/NimBLEScan.cpp index d9dcb7d..dd82cf5 100644 --- a/src/NimBLEScan.cpp +++ b/src/NimBLEScan.cpp @@ -356,10 +356,15 @@ NimBLEScanResults NimBLEScan::start(uint32_t duration, bool is_continue) { NIMBLE_LOGW(LOG_TAG, "Blocking scan called with duration = forever"); } - ble_task_data_t taskData = {nullptr, xTaskGetCurrentTaskHandle(),0, nullptr}; + TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); + ble_task_data_t taskData = {nullptr, cur_task, 0, nullptr}; m_pTaskData = &taskData; if(start(duration, nullptr, is_continue)) { +#ifdef ulTaskNotifyValueClear + // Clear the task notification value to ensure we block + ulTaskNotifyValueClear(cur_task, ULONG_MAX); +#endif ulTaskNotifyTake(pdTRUE, portMAX_DELAY); }