diff --git a/src/NimBLEClient.cpp b/src/NimBLEClient.cpp index c8760240..d273d04e 100644 --- a/src/NimBLEClient.cpp +++ b/src/NimBLEClient.cpp @@ -270,6 +270,12 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes, goto error; } + if (!asyncConnect && NimBLEUtils::inHostTask()) { + NIMBLE_LOGE(LOG_TAG, "Cannot connect synchronously from host task"); + rc = BLE_HS_EREJECT; + goto error; + } + m_connStatus = CONNECTING; m_peerAddress = address; m_config.asyncConnect = asyncConnect; @@ -334,6 +340,11 @@ bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes, */ bool NimBLEClient::secureConnection(bool async) const { NIMBLE_LOGD(LOG_TAG, ">> secureConnection()"); + if (!async && NimBLEUtils::inHostTask()) { + NIMBLE_LOGE(LOG_TAG, "Cannot secure connection synchronously from host task"); + m_lastErr = BLE_HS_EREJECT; + return false; + } int rc = 0; if (async && !NimBLEDevice::startSecurity(m_connHandle, &rc)) { @@ -669,6 +680,10 @@ NimBLERemoteService* NimBLEClient::getService(const char* uuid) { */ NimBLERemoteService* NimBLEClient::getService(const NimBLEUUID& uuid) { NIMBLE_LOGD(LOG_TAG, ">> getService: uuid: %s", uuid.toString().c_str()); + if (NimBLEUtils::inHostTask()) { + NIMBLE_LOGE(LOG_TAG, "getService cannot be called from host task"); + return nullptr; + } for (auto& it : m_svcVec) { if (it->getUUID() == uuid) { diff --git a/src/NimBLEDevice.cpp b/src/NimBLEDevice.cpp index 13504fe7..9f7c64c4 100644 --- a/src/NimBLEDevice.cpp +++ b/src/NimBLEDevice.cpp @@ -879,6 +879,7 @@ void NimBLEDevice::onSync(void) { */ void NimBLEDevice::host_task(void* param) { NIMBLE_LOGI(LOG_TAG, "NimBLE Started!"); + NimBLEUtils::m_hostTaskHandle = ble_npl_get_current_task_id(); nimble_port_run(); // This function will return only when nimble_port_stop() is executed nimble_port_freertos_deinit(); } // host_task diff --git a/src/NimBLERemoteCharacteristic.cpp b/src/NimBLERemoteCharacteristic.cpp index 64a1f308..54cf2666 100644 --- a/src/NimBLERemoteCharacteristic.cpp +++ b/src/NimBLERemoteCharacteristic.cpp @@ -155,6 +155,11 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(NimBLEDescriptorFilter* pFi */ NimBLERemoteDescriptor* NimBLERemoteCharacteristic::getDescriptor(const NimBLEUUID& uuid) const { NIMBLE_LOGD(LOG_TAG, ">> getDescriptor: uuid: %s", uuid.toString().c_str()); + if (NimBLEUtils::inHostTask()) { + NIMBLE_LOGE(LOG_TAG, "getDescriptor cannot be called from host task"); + return nullptr; + } + NimBLEUUID uuidTmp{uuid}; NimBLETaskData taskData(const_cast(this)); NimBLEDescriptorFilter filter{nullptr, &uuidTmp, &taskData}; diff --git a/src/NimBLERemoteService.cpp b/src/NimBLERemoteService.cpp index f15a9a31..afc5df68 100644 --- a/src/NimBLERemoteService.cpp +++ b/src/NimBLERemoteService.cpp @@ -75,6 +75,11 @@ NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const char* u */ NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const NimBLEUUID& uuid) const { NIMBLE_LOGD(LOG_TAG, ">> getCharacteristic: uuid: %s", uuid.toString().c_str()); + if (NimBLEUtils::inHostTask()) { + NIMBLE_LOGE(LOG_TAG, "getCharacteristic cannot be called from host task"); + return nullptr; + } + NimBLERemoteCharacteristic* pChar = nullptr; for (const auto& it : m_vChars) { @@ -116,6 +121,11 @@ NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const NimBLEU * @return A read-only reference to the vector of characteristics retrieved for this service. */ const std::vector& NimBLERemoteService::getCharacteristics(bool refresh) const { + if (refresh && NimBLEUtils::inHostTask()) { + NIMBLE_LOGE(LOG_TAG, "cannot refresh characteristics from host task"); + return m_vChars; + } + if (refresh) { deleteCharacteristics(); retrieveCharacteristics(); diff --git a/src/NimBLERemoteValueAttribute.cpp b/src/NimBLERemoteValueAttribute.cpp index c2ef17dd..380ba8c8 100644 --- a/src/NimBLERemoteValueAttribute.cpp +++ b/src/NimBLERemoteValueAttribute.cpp @@ -42,6 +42,11 @@ bool NimBLERemoteValueAttribute::writeValue(const uint8_t* data, size_t length, goto Done; } + if (NimBLEUtils::inHostTask()) { + NIMBLE_LOGE(LOG_TAG, "writeValue cannot be called from the host task"); + return false; + } + do { if (length > mtu) { NIMBLE_LOGI(LOG_TAG, "writeValue: long write"); @@ -123,6 +128,10 @@ int NimBLERemoteValueAttribute::onWriteCB(uint16_t conn_handle, const ble_gatt_e */ NimBLEAttValue NimBLERemoteValueAttribute::readValue(time_t* timestamp) { NIMBLE_LOGD(LOG_TAG, ">> readValue()"); + if (NimBLEUtils::inHostTask()) { + NIMBLE_LOGE(LOG_TAG, "readValue cannot be called from the host task"); + return NimBLEAttValue(); + } NimBLEAttValue value{}; const NimBLEClient* pClient = getClient(); diff --git a/src/NimBLEScan.cpp b/src/NimBLEScan.cpp index 063f3215..a3a45d0c 100644 --- a/src/NimBLEScan.cpp +++ b/src/NimBLEScan.cpp @@ -678,6 +678,11 @@ NimBLEScanResults NimBLEScan::getResults(uint32_t duration, bool is_continue) { return m_scanResults; } + if (NimBLEUtils::inHostTask()) { + NIMBLE_LOGE(LOG_TAG, "Cannot call blocking getResults from NimBLE host task"); + return m_scanResults; + } + NimBLETaskData taskData; m_pTaskData = &taskData; diff --git a/src/NimBLEUtils.cpp b/src/NimBLEUtils.cpp index 1156eb88..f971dabe 100644 --- a/src/NimBLEUtils.cpp +++ b/src/NimBLEUtils.cpp @@ -72,6 +72,8 @@ constexpr uint32_t TASK_BLOCK_BIT = (1 << MYNEWT_VAL(NIMBLE_CPP_FREERTOS_TASK_BLOCK_BIT)); static const char* LOG_TAG = "NimBLEUtils"; +void* NimBLEUtils::m_hostTaskHandle = nullptr; + /** * @brief Construct a NimBLETaskData instance. * @param [in] pInstance An instance of the class that will be waiting. @@ -604,4 +606,21 @@ NimBLEAddress NimBLEUtils::generateAddr(bool nrpa) { return NimBLEAddress{addr}; } // generateAddr + +/** + * @brief Get the handle of the task that is running the NimBLE host. + * @return The task handle or nullptr if there was an error. + */ +void* NimBLEUtils::getHostTaskHandle() { + return m_hostTaskHandle; +} // getHostTaskHandle + +/** + * @brief Check if the current task is the NimBLE host task. + * @return True if the current task is the host task, false otherwise. + */ +bool NimBLEUtils::inHostTask() { + return ble_npl_get_current_task_id() == NimBLEUtils::getHostTaskHandle(); +} + #endif // CONFIG_BT_NIMBLE_ENABLED diff --git a/src/NimBLEUtils.h b/src/NimBLEUtils.h index 63b7f199..96b36878 100644 --- a/src/NimBLEUtils.h +++ b/src/NimBLEUtils.h @@ -29,17 +29,18 @@ # endif # endif -#if MYNEWT_VAL(NIMBLE_CPP_DEBUG_ASSERT_ENABLED) && !defined NDEBUG -void nimble_cpp_assert(const char *file, unsigned line) __attribute((weak, noreturn)); -# define NIMBLE_ATT_VAL_FILE (__builtin_strrchr(__FILE__, '/') ? \ - __builtin_strrchr (__FILE__, '/') + 1 : __FILE__) -# define NIMBLE_CPP_DEBUG_ASSERT(cond) \ - if (!(cond)) { \ - nimble_cpp_assert(NIMBLE_ATT_VAL_FILE, __LINE__); \ - } -#else -# define NIMBLE_CPP_DEBUG_ASSERT(cond) (void(0)) -#endif +# if MYNEWT_VAL(NIMBLE_CPP_DEBUG_ASSERT_ENABLED) && !defined NDEBUG +void nimble_cpp_assert(const char* file, unsigned line) __attribute__((weak, noreturn)); +# define NIMBLE_ATT_VAL_FILE (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__) +# define NIMBLE_CPP_DEBUG_ASSERT(cond) \ + do { \ + if (!(cond)) { \ + nimble_cpp_assert(NIMBLE_ATT_VAL_FILE, __LINE__); \ + } \ + } while (0) +# else +# define NIMBLE_CPP_DEBUG_ASSERT(cond) (void(0)) +# endif # include @@ -74,6 +75,12 @@ class NimBLEUtils { static NimBLEAddress generateAddr(bool nrpa); static bool taskWait(const NimBLETaskData& taskData, uint32_t timeout); static void taskRelease(const NimBLETaskData& taskData, int rc = 0); + static void* getHostTaskHandle(); + static bool inHostTask(); + + private: + friend class NimBLEDevice; + static void* m_hostTaskHandle; }; #endif // CONFIG_BT_NIMBLE_ENABLED