From f5541d18dee44f7b4f45b6991ecd1a3c1cdc9c69 Mon Sep 17 00:00:00 2001 From: h2zero <32826625+h2zero@users.noreply.github.com> Date: Sun, 21 Jun 2020 22:07:01 -0600 Subject: [PATCH] Replace semaphores with task notifications. (#9) * Replace all semaphores with task notifications. * use critical sections to prevent concurrent data access. * Ensure scan stop has been called before connecting. * Optimize and cleanup * Add template casting to NimBLERemoteDescriptor::readValue() * Removed storage of the descriptor value read as it did not serve any purpose. --- src/NimBLEClient.cpp | 167 ++++++++++----------- src/NimBLEClient.h | 18 +-- src/NimBLERemoteCharacteristic.cpp | 187 ++++++++++++------------ src/NimBLERemoteCharacteristic.h | 11 +- src/NimBLERemoteDescriptor.cpp | 225 ++++++++++++++--------------- src/NimBLERemoteDescriptor.h | 24 +-- src/NimBLERemoteService.cpp | 77 ++++------ src/NimBLERemoteService.h | 2 - src/NimBLEScan.cpp | 45 +++--- src/NimBLEScan.h | 6 +- src/NimBLEUtils.cpp | 7 +- 11 files changed, 368 insertions(+), 401 deletions(-) diff --git a/src/NimBLEClient.cpp b/src/NimBLEClient.cpp index 0589ed9..71f1c9a 100644 --- a/src/NimBLEClient.cpp +++ b/src/NimBLEClient.cpp @@ -18,7 +18,6 @@ #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL) #include "NimBLEClient.h" -#include "NimBLEUtils.h" #include "NimBLEDevice.h" #include "NimBLELog.h" @@ -54,7 +53,10 @@ NimBLEClient::NimBLEClient() m_pClientCallbacks = &defaultCallbacks; m_conn_id = BLE_HS_CONN_HANDLE_NONE; m_isConnected = false; + m_waitingToConnect = false; m_connectTimeout = 30000; + m_deleteCallbacks = false; + m_pTaskData = nullptr; m_pConnParams.scan_itvl = 16; // Scan interval in 0.625ms units (NimBLE Default) m_pConnParams.scan_window = 16; // Scan window in 0.625ms units (NimBLE Default) @@ -157,6 +159,10 @@ bool NimBLEClient::connect(const NimBLEAddress &address, uint8_t type, bool refr return false; } + if(!NimBLEDevice::getScan()->stop()) { + return false; + } + int rc = 0; m_peerAddress = address; @@ -164,7 +170,8 @@ bool NimBLEClient::connect(const NimBLEAddress &address, uint8_t type, bool refr memcpy(&peerAddrt.val, address.getNative(),6); peerAddrt.type = type; - m_semaphoreOpenEvt.take("connect"); + ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr}; + m_pTaskData = &taskData; /** Try to connect the the advertiser. Allow 30 seconds (30000 ms) for * timeout (default value of m_connectTimeout). @@ -174,7 +181,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, uint8_t type, bool refr rc = ble_gap_connect(BLE_OWN_ADDR_PUBLIC, &peerAddrt, m_connectTimeout, &m_pConnParams, NimBLEClient::handleGapEvent, this); if(rc == BLE_HS_EBUSY) { - vTaskDelay(1); + vTaskDelay(1 / portTICK_PERIOD_MS); } }while(rc == BLE_HS_EBUSY); @@ -184,17 +191,17 @@ bool NimBLEClient::connect(const NimBLEAddress &address, uint8_t type, bool refr type, m_peerAddress.toString().c_str(), rc, NimBLEUtils::returnCodeToString(rc)); - - m_semaphoreOpenEvt.give(); + m_pTaskData = nullptr; m_waitingToConnect = false; return false; } m_waitingToConnect = true; - rc = m_semaphoreOpenEvt.wait("connect"); // Wait for the connection to complete. + // Wait for the connection to complete. + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - if(rc != 0){ + if(taskData.rc != 0){ return false; } @@ -216,17 +223,18 @@ bool NimBLEClient::connect(const NimBLEAddress &address, uint8_t type, bool refr * @return True on success. */ bool NimBLEClient::secureConnection() { - - m_semeaphoreSecEvt.take("secureConnection"); + ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr}; + m_pTaskData = &taskData; int rc = NimBLEDevice::startSecurity(m_conn_id); if(rc != 0){ - m_semeaphoreSecEvt.give(); + m_pTaskData = nullptr; return false; } - rc = m_semeaphoreSecEvt.wait("secureConnection"); - if(rc != 0){ + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + if(taskData.rc != 0){ return false; } @@ -458,30 +466,31 @@ bool NimBLEClient::retrieveServices(const NimBLEUUID *uuid_filter) { */ NIMBLE_LOGD(LOG_TAG, ">> retrieveServices"); - int rc = 0; if(!m_isConnected){ NIMBLE_LOGE(LOG_TAG, "Disconnected, could not retrieve services -aborting"); return false; } - m_semaphoreSearchCmplEvt.take("retrieveServices"); + int rc = 0; + ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr}; if(uuid_filter == nullptr) { - rc = ble_gattc_disc_all_svcs(m_conn_id, NimBLEClient::serviceDiscoveredCB, this); + rc = ble_gattc_disc_all_svcs(m_conn_id, NimBLEClient::serviceDiscoveredCB, &taskData); } else { rc = ble_gattc_disc_svc_by_uuid(m_conn_id, &uuid_filter->getNative()->u, - NimBLEClient::serviceDiscoveredCB, this); + NimBLEClient::serviceDiscoveredCB, &taskData); } if (rc != 0) { NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_svcs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); - m_semaphoreSearchCmplEvt.give(); return false; } // wait until we have all the services - if(m_semaphoreSearchCmplEvt.wait("retrieveServices") == 0){ + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + if(taskData.rc == 0){ NIMBLE_LOGD(LOG_TAG, "<< retrieveServices"); return true; } @@ -505,41 +514,34 @@ int NimBLEClient::serviceDiscoveredCB( NIMBLE_LOGD(LOG_TAG,"Service Discovered >> status: %d handle: %d", error->status, (error->status == 0) ? service->start_handle : -1); - NimBLEClient *peer = (NimBLEClient*)arg; - int rc=0; + ble_task_data_t *pTaskData = (ble_task_data_t*)arg; + NimBLEClient *client = (NimBLEClient*)pTaskData->pATT; // Make sure the service discovery is for this device - if(peer->getConnId() != conn_handle){ + if(client->getConnId() != conn_handle){ return 0; } - switch (error->status) { - case 0: { - // Found a service - add it to the vector - NimBLERemoteService* pRemoteService = new NimBLERemoteService(peer, service); - peer->m_servicesVector.push_back(pRemoteService); - break; - } - case BLE_HS_EDONE:{ - // All services discovered; start discovering characteristics. - - //NIMBLE_LOGD(LOG_TAG,"Giving search semaphore - completed"); - peer->m_semaphoreSearchCmplEvt.give(0); - rc = 0; - break; - } - default: - // Error; abort discovery. - rc = error->status; - break; + if(error->status == 0) { + // Found a service - add it to the vector + NimBLERemoteService* pRemoteService = new NimBLERemoteService(client, service); + client->m_servicesVector.push_back(pRemoteService); + return 0; } - if (rc != 0) { - // pass non-zero to semaphore on error to indicate an error finding services - peer->m_semaphoreSearchCmplEvt.give(1); + if(error->status == BLE_HS_EDONE) { + pTaskData->rc = 0; + } else { + NIMBLE_LOGE(LOG_TAG, "characteristicDiscCB() rc=%d %s", + error->status, + NimBLEUtils::returnCodeToString(error->status)); + pTaskData->rc = error->status; } - NIMBLE_LOGD(LOG_TAG,"<< Service Discovered. status: %d", rc); - return rc; + + xTaskNotifyGive(pTaskData->task); + + NIMBLE_LOGD(LOG_TAG,"<< << Service Discovered"); + return error->status; } @@ -611,15 +613,11 @@ uint16_t NimBLEClient::getMTU() { * @param [in] arg = pointer to the client instance */ /*STATIC*/ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) { - NimBLEClient* client = (NimBLEClient*)arg; - //struct ble_gap_conn_desc desc; - //struct ble_hs_adv_fields fields; int rc; NIMBLE_LOGD(LOG_TAG, "Got Client event %s", NimBLEUtils::gapEventToString(event->type)); - // Execute handler code based on the type of event received. switch(event->type) { case BLE_GAP_EVENT_DISCONNECT: { @@ -636,9 +634,6 @@ uint16_t NimBLEClient::getMTU() { NIMBLE_LOGI(LOG_TAG, "disconnect; reason=%d, %s", event->disconnect.reason, NimBLEUtils::returnCodeToString(event->disconnect.reason)); - //print_conn_desc(&event->disconnect.conn); - //MODLOG_DFLT(INFO, "\n"); - // If Host reset tell the device now before returning to prevent // any errors caused by calling host functions before resyncing. @@ -655,15 +650,9 @@ uint16_t NimBLEClient::getMTU() { } //client->m_conn_id = BLE_HS_CONN_HANDLE_NONE; - - // Indicate a non-success return value to any semaphores waiting - client->m_semaphoreOpenEvt.give(1); - client->m_semaphoreSearchCmplEvt.give(1); - client->m_semeaphoreSecEvt.give(1); - client->m_pClientCallbacks->onDisconnect(client); - - return 0; + rc = event->disconnect.reason; + break; } // BLE_GAP_EVENT_DISCONNECT case BLE_GAP_EVENT_CONNECT: { @@ -683,31 +672,24 @@ uint16_t NimBLEClient::getMTU() { client->m_conn_id = event->connect.conn_handle; - // rc = ble_gap_conn_find(event->connect.conn_handle, &desc); - // assert(rc == 0); - // print_conn_desc(&desc); - // MODLOG_DFLT(INFO, "\n"); - - - // In the case of a multiconnecting device we ignore this device when - // scanning since we are already connected to it - NimBLEDevice::addIgnored(client->m_peerAddress); - rc = ble_gattc_exchange_mtu(client->m_conn_id, NULL,NULL); if(rc != 0) { NIMBLE_LOGE(LOG_TAG, "ble_gattc_exchange_mtu: rc=%d %s",rc, NimBLEUtils::returnCodeToString(rc)); - // if error getting mtu indicate a connection error. - client->m_semaphoreOpenEvt.give(rc); + break; } + + // In the case of a multiconnecting device we ignore this device when + // scanning since we are already connected to it + NimBLEDevice::addIgnored(client->m_peerAddress); } else { - // Connection attempt failed NIMBLE_LOGE(LOG_TAG, "Error: Connection failed; status=%d %s", event->connect.status, NimBLEUtils::returnCodeToString(event->connect.status)); client->m_isConnected = false; - client->m_semaphoreOpenEvt.give(event->connect.status); + rc = event->connect.status; + break; } return 0; } // BLE_GAP_EVENT_CONNECT @@ -719,7 +701,7 @@ uint16_t NimBLEClient::getMTU() { NIMBLE_LOGD(LOG_TAG, "Notify Recieved for handle: %d",event->notify_rx.attr_handle); for(auto &it: client->m_servicesVector) { - // Dont waste cycles searching services without this handle in their range + // Dont waste cycles searching services without this handle in its range if(it->getEndHandle() < event->notify_rx.attr_handle) { continue; } @@ -738,11 +720,10 @@ uint16_t NimBLEClient::getMTU() { if(characteristic != cVector->cend()) { NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", (*characteristic)->toString().c_str()); - if((*characteristic)->m_semaphoreReadCharEvt.take(0, "notifyValue")) { - (*characteristic)->m_value = std::string((char *)event->notify_rx.om->om_data, event->notify_rx.om->om_len); - (*characteristic)->m_timestamp = time(nullptr); - (*characteristic)->m_semaphoreReadCharEvt.give(); - } + portENTER_CRITICAL(&(*characteristic)->m_valMux); + (*characteristic)->m_value = std::string((char *)event->notify_rx.om->om_data, event->notify_rx.om->om_len); + (*characteristic)->m_timestamp = time(nullptr); + portEXIT_CRITICAL(&(*characteristic)->m_valMux); if ((*characteristic)->m_notifyCallback != nullptr) { NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s", @@ -761,7 +742,7 @@ uint16_t NimBLEClient::getMTU() { case BLE_GAP_EVENT_CONN_UPDATE_REQ: case BLE_GAP_EVENT_L2CAP_UPDATE_REQ: { if(client->m_conn_id != event->conn_update_req.conn_handle){ - return 0; //BLE_HS_ENOTCONN BLE_ATT_ERR_INVALID_HANDLE + return 0; } NIMBLE_LOGD(LOG_TAG, "Peer requesting to update connection parameters"); NIMBLE_LOGD(LOG_TAG, "MinInterval: %d, MaxInterval: %d, Latency: %d, Timeout: %d", @@ -787,7 +768,7 @@ uint16_t NimBLEClient::getMTU() { case BLE_GAP_EVENT_CONN_UPDATE: { if(client->m_conn_id != event->conn_update.conn_handle){ - return 0; //BLE_HS_ENOTCONN BLE_ATT_ERR_INVALID_HANDLE + return 0; } if(event->conn_update.status == 0) { NIMBLE_LOGI(LOG_TAG, "Connection parameters updated."); @@ -799,7 +780,7 @@ uint16_t NimBLEClient::getMTU() { case BLE_GAP_EVENT_ENC_CHANGE: { if(client->m_conn_id != event->enc_change.conn_handle){ - return 0; //BLE_HS_ENOTCONN BLE_ATT_ERR_INVALID_HANDLE + return 0; } if(event->enc_change.status == 0) { @@ -814,23 +795,23 @@ uint16_t NimBLEClient::getMTU() { } } - client->m_semeaphoreSecEvt.give(event->enc_change.status); - return 0; + rc = event->enc_change.status; + break; } //BLE_GAP_EVENT_ENC_CHANGE case BLE_GAP_EVENT_MTU: { if(client->m_conn_id != event->mtu.conn_handle){ - return 0; //BLE_HS_ENOTCONN BLE_ATT_ERR_INVALID_HANDLE + return 0; } NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d", event->mtu.conn_handle, event->mtu.value); - client->m_semaphoreOpenEvt.give(0); - return 0; + rc = 0; + break; } // BLE_GAP_EVENT_MTU case BLE_GAP_EVENT_PASSKEY_ACTION: { - struct ble_sm_io pkey = {0}; + struct ble_sm_io pkey = {0,0}; if(client->m_conn_id != event->passkey.conn_handle) return 0; @@ -891,6 +872,14 @@ uint16_t NimBLEClient::getMTU() { return 0; } } // Switch + + if(client->m_pTaskData != nullptr) { + client->m_pTaskData->rc = rc; + xTaskNotifyGive(client->m_pTaskData->task); + client->m_pTaskData = nullptr; + } + + return 0; } // handleGapEvent diff --git a/src/NimBLEClient.h b/src/NimBLEClient.h index 289c739..888b42d 100644 --- a/src/NimBLEClient.h +++ b/src/NimBLEClient.h @@ -22,17 +22,13 @@ #include "NimBLEAddress.h" #include "NimBLEUUID.h" +#include "NimBLEUtils.h" #include "NimBLEAdvertisedDevice.h" #include "NimBLERemoteService.h" #include #include -typedef struct { - const NimBLEUUID *uuid; - const void *attribute; -} disc_filter_t; - class NimBLERemoteService; class NimBLEClientCallbacks; class NimBLEAdvertisedDevice; @@ -89,14 +85,12 @@ private: NimBLEAddress m_peerAddress = NimBLEAddress(""); uint16_t m_conn_id; - bool m_isConnected = false; - bool m_waitingToConnect =false; - bool m_deleteCallbacks = true; + bool m_isConnected; + bool m_waitingToConnect; + bool m_deleteCallbacks; int32_t m_connectTimeout; - NimBLEClientCallbacks* m_pClientCallbacks = nullptr; - FreeRTOS::Semaphore m_semaphoreOpenEvt = FreeRTOS::Semaphore("OpenEvt"); - FreeRTOS::Semaphore m_semaphoreSearchCmplEvt = FreeRTOS::Semaphore("SearchCmplEvt"); - FreeRTOS::Semaphore m_semeaphoreSecEvt = FreeRTOS::Semaphore("Security"); + NimBLEClientCallbacks* m_pClientCallbacks; + ble_task_data_t *m_pTaskData; std::vector m_servicesVector; diff --git a/src/NimBLERemoteCharacteristic.cpp b/src/NimBLERemoteCharacteristic.cpp index 493def4..9d3bb1e 100644 --- a/src/NimBLERemoteCharacteristic.cpp +++ b/src/NimBLERemoteCharacteristic.cpp @@ -60,6 +60,7 @@ static const char* LOG_TAG = "NimBLERemoteCharacteristic"; m_pRemoteService = pRemoteService; m_notifyCallback = nullptr; m_timestamp = 0; + m_valMux = portMUX_INITIALIZER_UNLOCKED; } // NimBLERemoteCharacteristic @@ -67,7 +68,7 @@ static const char* LOG_TAG = "NimBLERemoteCharacteristic"; *@brief Destructor. */ NimBLERemoteCharacteristic::~NimBLERemoteCharacteristic() { - deleteDescriptors(); // Release resources for any descriptor information we may have allocated. + deleteDescriptors(); } // ~NimBLERemoteCharacteristic /* @@ -147,12 +148,12 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle, NIMBLE_LOGD(LOG_TAG,"Descriptor Discovered >> status: %d handle: %d", error->status, (error->status == 0) ? dsc->handle : -1); - disc_filter_t *filter = (disc_filter_t*)arg; - NimBLEUUID *uuid_filter = (NimBLEUUID*)filter->uuid; - NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)filter->attribute; + desc_filter_t *filter = (desc_filter_t*)arg; + const NimBLEUUID *uuid_filter = filter->uuid; + ble_task_data_t *pTaskData = (ble_task_data_t*)filter->task_data; + NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)pTaskData->pATT; int rc=0; - // Make sure the discovery is for this device if(characteristic->getRemoteService()->getClient()->getConnId() != conn_handle){ return 0; } @@ -172,7 +173,7 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle, rc = BLE_HS_EDONE; } } - // Found a descriptor - add it to the vector + NimBLERemoteDescriptor* pNewRemoteDescriptor = new NimBLERemoteDescriptor(characteristic, dsc); characteristic->m_descriptorVector.push_back(pNewRemoteDescriptor); break; @@ -182,18 +183,20 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle, break; } - /** If rc == BLE_HS_EDONE, release the semaphore with a success error code and stop the discovery process. + /** If rc == BLE_HS_EDONE, resume the task with a success error code and stop the discovery process. * Else if rc == 0, just return 0 to continue the discovery until we get BLE_HS_EDONE. - * If we get any other error code tell the application to abort by returning non-zero in the semaphore rc. + * If we get any other error code tell the application to abort by returning non-zero in the rc. */ if (rc == BLE_HS_EDONE) { - characteristic->m_semaphoreGetDescEvt.give(0); + pTaskData->rc = 0; + xTaskNotifyGive(pTaskData->task); } else if(rc != 0) { - /* Error; abort discovery. */ - // pass error code to semaphore waiting - characteristic->m_semaphoreGetDescEvt.give(rc); + // Error; abort discovery. + pTaskData->rc = rc; + xTaskNotifyGive(pTaskData->task); } - NIMBLE_LOGD(LOG_TAG,"<< Descriptor Discovered. status: %d", rc); + + NIMBLE_LOGD(LOG_TAG,"<< Descriptor Discovered. status: %d", pTaskData->rc); return rc; } @@ -206,11 +209,8 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt NIMBLE_LOGD(LOG_TAG, ">> retrieveDescriptors() for characteristic: %s", getUUID().toString().c_str()); int rc = 0; - disc_filter_t filter; - filter.uuid = uuid_filter; - filter.attribute = this; - - m_semaphoreGetDescEvt.take("retrieveDescriptors"); + ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr}; + desc_filter_t filter = {uuid_filter, &taskData}; rc = ble_gattc_disc_all_dscs(getRemoteService()->getClient()->getConnId(), m_handle, @@ -219,11 +219,12 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt &filter); if (rc != 0) { NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_chrs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); - m_semaphoreGetDescEvt.give(); return false; } - if(m_semaphoreGetDescEvt.wait("retrieveDescriptors") != 0) { + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + if(taskData.rc != 0) { return false; } @@ -337,6 +338,22 @@ NimBLEUUID NimBLERemoteCharacteristic::getUUID() { } // getUUID +/** + * @brief Get the value of the remote characteristic. + * @return The value of the remote characteristic. + */ +std::string NimBLERemoteCharacteristic::getValue(time_t *timestamp) { + portENTER_CRITICAL(&m_valMux); + std::string value = m_value; + if(timestamp != nullptr) { + *timestamp = m_timestamp; + } + portEXIT_CRITICAL(&m_valMux); + + return value; +} + + /** * @brief Read an unsigned 16 bit value * @return The unsigned 16 bit value. @@ -384,33 +401,31 @@ std::string NimBLERemoteCharacteristic::readValue(time_t *timestamp) { NIMBLE_LOGD(LOG_TAG, ">> readValue(): uuid: %s, handle: %d 0x%.2x", getUUID().toString().c_str(), getHandle(), getHandle()); - int rc = 0; - int retryCount = 1; - NimBLEClient* pClient = getRemoteService()->getClient(); + std::string value; - // Check to see that we are connected. if (!pClient->isConnected()) { NIMBLE_LOGE(LOG_TAG, "Disconnected"); - return ""; + return value; } - do { - m_semaphoreReadCharEvt.take("readValue"); - // Clear the value before reading. - m_value = ""; + int rc = 0; + int retryCount = 1; + ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(),0, &value}; + do { rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0, NimBLERemoteCharacteristic::onReadCB, - this); + &taskData); if (rc != 0) { NIMBLE_LOGE(LOG_TAG, "Error: Failed to read characteristic; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc)); - m_semaphoreReadCharEvt.give(0); - return ""; + return value; } - rc = m_semaphoreReadCharEvt.wait("readValue"); + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + rc = taskData.rc; + switch(rc){ case 0: case BLE_HS_EDONE: @@ -428,39 +443,24 @@ std::string NimBLERemoteCharacteristic::readValue(time_t *timestamp) { break; /* Else falls through. */ default: - return ""; + NIMBLE_LOGE(LOG_TAG, "<< readValue rc=%d", rc); + return value; } } while(rc != 0 && retryCount--); - NIMBLE_LOGD(LOG_TAG, "<< readValue(): length: %d", m_value.length()); - - m_semaphoreReadCharEvt.take("returnValue"); - std::string value = m_value; + portENTER_CRITICAL(&m_valMux); + m_value = value; + m_timestamp = time(nullptr); if(timestamp != nullptr) { *timestamp = m_timestamp; } - m_semaphoreReadCharEvt.give(); + portEXIT_CRITICAL(&m_valMux); + NIMBLE_LOGD(LOG_TAG, "<< readValue length: %d rc=%d", value.length(), rc); return value; } // readValue -/** - * @brief Get the value of the remote characteristic. - * @return The value of the remote characteristic. - */ -std::string NimBLERemoteCharacteristic::getValue(time_t *timestamp) { - m_semaphoreReadCharEvt.take("getValue"); - std::string value = m_value; - if(timestamp != nullptr) { - *timestamp = m_timestamp; - } - - m_semaphoreReadCharEvt.give(); - return value; -} - - /** * @brief Callback for characteristic read operation. * @return 0 or error code. @@ -469,27 +469,35 @@ int NimBLERemoteCharacteristic::onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { - NimBLERemoteCharacteristic* characteristic = (NimBLERemoteCharacteristic*)arg; + ble_task_data_t *pTaskData = (ble_task_data_t*)arg; + NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)pTaskData->pATT; uint16_t conn_id = characteristic->getRemoteService()->getClient()->getConnId(); - // Make sure the read is for this client if(conn_id != conn_handle) { return 0; } + NIMBLE_LOGI(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle); - if(error->status == 0) { - if(attr) { - NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len); + std::string *strBuf = (std::string*)pTaskData->buf; + int rc = error->status; - characteristic->m_value += std::string((char*) attr->om->om_data, attr->om->om_len); - characteristic->m_timestamp = time(nullptr); - return 0; + if(rc == 0) { + if(attr) { + if(((*strBuf).length() + attr->om->om_len) > BLE_ATT_ATTR_MAX_LEN) { + rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } else { + NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len); + (*strBuf) += std::string((char*) attr->om->om_data, attr->om->om_len); + return 0; + } } } - // Read complete release semaphore and let the app can continue. - characteristic->m_semaphoreReadCharEvt.give(error->status); - return 0; + + pTaskData->rc = rc; + xTaskNotifyGive(pTaskData->task); + + return rc; } @@ -509,7 +517,7 @@ bool NimBLERemoteCharacteristic::setNotify(uint16_t val, bool response, notify_c return false; } - m_notifyCallback = notifyCallback; // Save the notification callback. + m_notifyCallback = notifyCallback; NIMBLE_LOGD(LOG_TAG, "<< setNotify()"); @@ -572,7 +580,7 @@ bool NimBLERemoteCharacteristic::registerForNotify(notify_callback notifyCallbac */ void NimBLERemoteCharacteristic::deleteDescriptors() { NIMBLE_LOGD(LOG_TAG, ">> deleteDescriptors"); - // Iterate through all the descriptors releasing their storage and erasing them from the vector. + for(auto &it: m_descriptorVector) { delete it; } @@ -588,7 +596,7 @@ void NimBLERemoteCharacteristic::deleteDescriptors() { */ size_t NimBLERemoteCharacteristic::deleteDescriptor(const NimBLEUUID &uuid) { NIMBLE_LOGD(LOG_TAG, ">> deleteDescriptor"); - // Delete the requested descriptor. + for(auto it = m_descriptorVector.begin(); it != m_descriptorVector.end(); ++it) { if((*it)->getUUID() == uuid) { delete *it; @@ -665,47 +673,45 @@ bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length, NIMBLE_LOGD(LOG_TAG, ">> writeValue(), length: %d", length); NimBLEClient* pClient = getRemoteService()->getClient(); - int rc = 0; - int retryCount = 1; - uint16_t mtu; - // Check to see that we are connected. if (!pClient->isConnected()) { NIMBLE_LOGE(LOG_TAG, "Disconnected"); return false; } - mtu = ble_att_mtu(pClient->getConnId()) - 3; + int rc = 0; + int retryCount = 1; + uint16_t mtu = ble_att_mtu(pClient->getConnId()) - 3; - // Check if the data length is longer than we can write in 1 connection event. + // Check if the data length is longer than we can write in one connection event. // If so we must do a long write which requires a response. if(length <= mtu && !response) { rc = ble_gattc_write_no_rsp_flat(pClient->getConnId(), m_handle, data, length); return (rc==0); } - do { - m_semaphoreWriteCharEvt.take("writeValue"); + ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr}; + do { if(length > mtu) { NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length); os_mbuf *om = ble_hs_mbuf_from_flat(data, length); rc = ble_gattc_write_long(pClient->getConnId(), m_handle, 0, om, NimBLERemoteCharacteristic::onWriteCB, - this); + &taskData); } else { rc = ble_gattc_write_flat(pClient->getConnId(), m_handle, data, length, NimBLERemoteCharacteristic::onWriteCB, - this); + &taskData); } if (rc != 0) { NIMBLE_LOGE(LOG_TAG, "Error: Failed to write characteristic; rc=%d", rc); - m_semaphoreWriteCharEvt.give(); return false; } - rc = m_semaphoreWriteCharEvt.wait("writeValue"); + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + rc = taskData.rc; switch(rc){ case 0: @@ -725,11 +731,12 @@ bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length, break; /* Else falls through. */ default: + NIMBLE_LOGE(LOG_TAG, "<< writeValue, rc: %d", rc); return false; } } while(rc != 0 && retryCount--); - NIMBLE_LOGD(LOG_TAG, "<< writeValue, rc: %d",rc); + NIMBLE_LOGD(LOG_TAG, "<< writeValue, rc: %d", rc); return (rc == 0); } // writeValue @@ -742,29 +749,21 @@ int NimBLERemoteCharacteristic::onWriteCB(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { - NimBLERemoteCharacteristic* characteristic = (NimBLERemoteCharacteristic*)arg; + ble_task_data_t *pTaskData = (ble_task_data_t*)arg; + NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)pTaskData->pATT; - // Make sure the discovery is for this device if(characteristic->getRemoteService()->getClient()->getConnId() != conn_handle){ return 0; } NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle); - characteristic->m_semaphoreWriteCharEvt.give(error->status); + pTaskData->rc = error->status; + xTaskNotifyGive(pTaskData->task); return 0; } -void NimBLERemoteCharacteristic::releaseSemaphores() { - for (auto &it: m_descriptorVector) { - it->releaseSemaphores(); - } - m_semaphoreWriteCharEvt.give(1); - m_semaphoreGetDescEvt.give(1); - m_semaphoreReadCharEvt.give(1); -} - #endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL) #endif /* CONFIG_BT_ENABLED */ diff --git a/src/NimBLERemoteCharacteristic.h b/src/NimBLERemoteCharacteristic.h index ab67cd1..657eaf0 100644 --- a/src/NimBLERemoteCharacteristic.h +++ b/src/NimBLERemoteCharacteristic.h @@ -32,6 +32,12 @@ class NimBLERemoteDescriptor; typedef void (*notify_callback)(NimBLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify); +typedef struct { + const NimBLEUUID *uuid; + void *task_data; +} desc_filter_t; + + /** * @brief A model of a remote %BLE characteristic. */ @@ -110,7 +116,6 @@ private: struct ble_gatt_attr *attr, void *arg); static int onWriteCB(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg); - void releaseSemaphores(); 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); @@ -121,12 +126,10 @@ private: uint16_t m_handle; uint16_t m_defHandle; NimBLERemoteService* m_pRemoteService; - FreeRTOS::Semaphore m_semaphoreGetDescEvt = FreeRTOS::Semaphore("GetDescEvt"); - FreeRTOS::Semaphore m_semaphoreReadCharEvt = FreeRTOS::Semaphore("ReadCharEvt"); - FreeRTOS::Semaphore m_semaphoreWriteCharEvt = FreeRTOS::Semaphore("WriteCharEvt"); std::string m_value; notify_callback m_notifyCallback; time_t m_timestamp; + portMUX_TYPE m_valMux; // We maintain a vector of descriptors owned by this characteristic. std::vector m_descriptorVector; diff --git a/src/NimBLERemoteDescriptor.cpp b/src/NimBLERemoteDescriptor.cpp index 057a68a..3c2f9d0 100644 --- a/src/NimBLERemoteDescriptor.cpp +++ b/src/NimBLERemoteDescriptor.cpp @@ -45,9 +45,9 @@ NimBLERemoteDescriptor::NimBLERemoteDescriptor(NimBLERemoteCharacteristic* pRemo m_uuid = nullptr; break; } + m_handle = dsc->handle; m_pRemoteCharacteristic = pRemoteCharacteristic; - } @@ -78,96 +78,6 @@ NimBLEUUID NimBLERemoteDescriptor::getUUID() { } // getUUID -/** - * @brief Callback for Descriptor read operation. - * @return 0 or error code. - */ -int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle, - const struct ble_gatt_error *error, - struct ble_gatt_attr *attr, void *arg) -{ - NimBLERemoteDescriptor* desc = (NimBLERemoteDescriptor*)arg; - uint16_t conn_id = desc->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId(); - - // Make sure the discovery is for this device - if(conn_id != conn_handle){ - return 0; - } - - NIMBLE_LOGD(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle); - - if(error->status == 0){ - if(attr){ - NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len); - - desc->m_value += std::string((char*) attr->om->om_data, attr->om->om_len); - return 0; - } - } - - // Read complete release semaphore and let the app can continue. - desc->m_semaphoreReadDescrEvt.give(error->status); - return 0; -} - - -std::string NimBLERemoteDescriptor::readValue() { - NIMBLE_LOGD(LOG_TAG, ">> Descriptor readValue: %s", toString().c_str()); - - int rc = 0; - int retryCount = 1; - // Clear the value before reading. - m_value = ""; - - NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient(); - - // Check to see that we are connected. - if (!pClient->isConnected()) { - NIMBLE_LOGE(LOG_TAG, "Disconnected"); - return ""; - } - - do { - m_semaphoreReadDescrEvt.take("ReadDescriptor"); - - rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0, - NimBLERemoteDescriptor::onReadCB, - this); - if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Error: Failed to read descriptor; rc=%d, %s", - rc, NimBLEUtils::returnCodeToString(rc)); - m_semaphoreReadDescrEvt.give(0); - return ""; - } - - rc = m_semaphoreReadDescrEvt.wait("ReadDescriptor"); - - switch(rc){ - case 0: - case BLE_HS_EDONE: - rc = 0; - break; - // Descriptor is not long-readable, return with what we have. - case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG): - NIMBLE_LOGI(LOG_TAG, "Attribute not long"); - rc = 0; - break; - case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN): - case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR): - case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC): - if (retryCount && pClient->secureConnection()) - break; - /* Else falls through. */ - default: - return ""; - } - } while(rc != 0 && retryCount--); - - NIMBLE_LOGD(LOG_TAG, "<< Descriptor readValue(): length: %d", m_value.length()); - return m_value; -} // readValue - - uint8_t NimBLERemoteDescriptor::readUInt8() { std::string value = readValue(); if (value.length() >= 1) { @@ -195,6 +105,100 @@ uint32_t NimBLERemoteDescriptor::readUInt32() { } // readUInt32 +std::string NimBLERemoteDescriptor::readValue() { + NIMBLE_LOGD(LOG_TAG, ">> Descriptor readValue: %s", toString().c_str()); + + NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient(); + std::string value; + + if (!pClient->isConnected()) { + NIMBLE_LOGE(LOG_TAG, "Disconnected"); + return value; + } + + int rc = 0; + int retryCount = 1; + ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(),0, &value}; + + do { + rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0, + NimBLERemoteDescriptor::onReadCB, + &taskData); + if (rc != 0) { + NIMBLE_LOGE(LOG_TAG, "Error: Failed to read descriptor; rc=%d, %s", + rc, NimBLEUtils::returnCodeToString(rc)); + return value; + } + + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + rc = taskData.rc; + + switch(rc){ + case 0: + case BLE_HS_EDONE: + rc = 0; + break; + // Descriptor is not long-readable, return with what we have. + case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG): + NIMBLE_LOGI(LOG_TAG, "Attribute not long"); + rc = 0; + break; + case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN): + case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR): + case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC): + if (retryCount && pClient->secureConnection()) + break; + /* Else falls through. */ + default: + return value; + } + } while(rc != 0 && retryCount--); + + NIMBLE_LOGD(LOG_TAG, "<< Descriptor readValue(): length: %d rc=%d", value.length(), rc); + return value; +} // readValue + + +/** + * @brief Callback for Descriptor read operation. + * @return 0 or error code. + */ +int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, void *arg) +{ + ble_task_data_t *pTaskData = (ble_task_data_t*)arg; + NimBLERemoteDescriptor* desc = (NimBLERemoteDescriptor*)pTaskData->pATT; + uint16_t conn_id = desc->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId(); + + if(conn_id != conn_handle){ + return 0; + } + + NIMBLE_LOGD(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle); + + std::string *strBuf = (std::string*)pTaskData->buf; + int rc = error->status; + + if(rc == 0) { + if(attr) { + if(((*strBuf).length() + attr->om->om_len) > BLE_ATT_ATTR_MAX_LEN) { + rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } else { + NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len); + (*strBuf) += std::string((char*) attr->om->om_data, attr->om->om_len); + return 0; + } + } + } + + pTaskData->rc = rc; + xTaskNotifyGive(pTaskData->task); + + return rc; +} + + /** * @brief Return a string representation of this BLE Remote Descriptor. * @retun A string representation of this BLE Remote Descriptor. @@ -218,16 +222,17 @@ int NimBLERemoteDescriptor::onWriteCB(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { - NimBLERemoteDescriptor* descriptor = (NimBLERemoteDescriptor*)arg; + ble_task_data_t *pTaskData = (ble_task_data_t*)arg; + NimBLERemoteDescriptor* descriptor = (NimBLERemoteDescriptor*)pTaskData->pATT; - // Make sure the discovery is for this device if(descriptor->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId() != conn_handle){ return 0; } - NIMBLE_LOGD(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle); + NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle); - descriptor->m_semaphoreDescWrite.give(error->status); + pTaskData->rc = error->status; + xTaskNotifyGive(pTaskData->task); return 0; } @@ -245,17 +250,15 @@ bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient(); - int rc = 0; - int retryCount = 1; - uint16_t mtu; - // Check to see that we are connected. if (!pClient->isConnected()) { NIMBLE_LOGE(LOG_TAG, "Disconnected"); return false; } - mtu = ble_att_mtu(pClient->getConnId()) - 3; + int rc = 0; + int retryCount = 1; + uint16_t mtu = ble_att_mtu(pClient->getConnId()) - 3; // Check if the data length is longer than we can write in 1 connection event. // If so we must do a long write which requires a response. @@ -264,31 +267,31 @@ bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool return (rc == 0); } - do { - m_semaphoreDescWrite.take("WriteDescriptor"); + ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr}; + do { if(length > mtu) { NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length); os_mbuf *om = ble_hs_mbuf_from_flat(data, length); rc = ble_gattc_write_long(pClient->getConnId(), m_handle, 0, om, NimBLERemoteDescriptor::onWriteCB, - this); + &taskData); } else { rc = ble_gattc_write_flat(pClient->getConnId(), m_handle, data, length, NimBLERemoteDescriptor::onWriteCB, - this); + &taskData); } if (rc != 0) { NIMBLE_LOGE(LOG_TAG, "Error: Failed to write descriptor; rc=%d", rc); - m_semaphoreDescWrite.give(); return false; } - rc = m_semaphoreDescWrite.wait("WriteDescriptor"); + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + rc = taskData.rc; - switch(rc){ + switch(rc) { case 0: case BLE_HS_EDONE: rc = 0; @@ -335,13 +338,5 @@ bool NimBLERemoteDescriptor::writeValue(uint8_t newValue, bool response) { } // writeValue -/** - * @brief In the event of an error this is called to make sure we don't block. - */ -void NimBLERemoteDescriptor::releaseSemaphores() { - m_semaphoreDescWrite.give(1); - m_semaphoreReadDescrEvt.give(1); -} - #endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL) #endif /* CONFIG_BT_ENABLED */ diff --git a/src/NimBLERemoteDescriptor.h b/src/NimBLERemoteDescriptor.h index 23fe13f..b320781 100644 --- a/src/NimBLERemoteDescriptor.h +++ b/src/NimBLERemoteDescriptor.h @@ -31,16 +31,24 @@ public: uint16_t getHandle(); NimBLERemoteCharacteristic* getRemoteCharacteristic(); NimBLEUUID getUUID(); - std::string readValue(void); - uint8_t readUInt8(void); - uint16_t readUInt16(void); - uint32_t readUInt32(void); + std::string readValue(); + + template + T readValue(bool skipSizeCheck = false) { + std::string value = readValue(); + if(!skipSizeCheck && value.size() < sizeof(T)) return T(); + const char *pData = value.data(); + return *((T *)pData); + } + + uint8_t readUInt8() __attribute__ ((deprecated)); + uint16_t readUInt16() __attribute__ ((deprecated)); + uint32_t readUInt32() __attribute__ ((deprecated)); std::string toString(void); bool writeValue(const uint8_t* data, size_t length, bool response = false); bool writeValue(const std::string &newValue, bool response = false); bool writeValue(uint8_t newValue, bool response = false); - private: friend class NimBLERemoteCharacteristic; @@ -50,16 +58,10 @@ private: struct ble_gatt_attr *attr, void *arg); static int onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg); - void releaseSemaphores(); uint16_t m_handle; NimBLEUUID m_uuid; - std::string m_value; NimBLERemoteCharacteristic* m_pRemoteCharacteristic; - FreeRTOS::Semaphore m_semaphoreReadDescrEvt = FreeRTOS::Semaphore("ReadDescrEvt"); - FreeRTOS::Semaphore m_semaphoreDescWrite = FreeRTOS::Semaphore("WriteDescEvt"); - - }; #endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL) diff --git a/src/NimBLERemoteService.cpp b/src/NimBLERemoteService.cpp index 6a1031e..db9eabc 100644 --- a/src/NimBLERemoteService.cpp +++ b/src/NimBLERemoteService.cpp @@ -148,43 +148,34 @@ int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle, NIMBLE_LOGD(LOG_TAG,"Characteristic Discovered >> status: %d handle: %d", error->status, (error->status == 0) ? chr->val_handle : -1); - NimBLERemoteService *service = (NimBLERemoteService*)arg; - int rc=0; + ble_task_data_t *pTaskData = (ble_task_data_t*)arg; + NimBLERemoteService *service = (NimBLERemoteService*)pTaskData->pATT; // Make sure the discovery is for this device if(service->getClient()->getConnId() != conn_handle){ return 0; } - switch (error->status) { - case 0: { - // Found a service - add it to the vector - NimBLERemoteCharacteristic* pRemoteCharacteristic = new NimBLERemoteCharacteristic(service, chr); - service->m_characteristicVector.push_back(pRemoteCharacteristic); - break; - } - case BLE_HS_EDONE:{ - /** All characteristics in this service discovered; start discovering - * characteristics in the next service. - */ - service->m_semaphoreGetCharEvt.give(0); - rc = 0; - break; - } - default: - rc = error->status; - break; + if(error->status == 0) { + // Found a service - add it to the vector + NimBLERemoteCharacteristic* pRemoteCharacteristic = new NimBLERemoteCharacteristic(service, chr); + service->m_characteristicVector.push_back(pRemoteCharacteristic); + return 0; } - if (rc != 0) { - /* Error; abort discovery. */ - // pass non-zero to semaphore on error to indicate an error finding characteristics - // release memory from any characteristics we created - //service->deleteCharacteristics(); --this will now be done when we clear services on returning with error - NIMBLE_LOGE(LOG_TAG, "characteristicDiscCB() rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); - service->m_semaphoreGetCharEvt.give(1); + + if(error->status == BLE_HS_EDONE) { + pTaskData->rc = 0; + } else { + NIMBLE_LOGE(LOG_TAG, "characteristicDiscCB() rc=%d %s", + error->status, + NimBLEUtils::returnCodeToString(error->status)); + pTaskData->rc = error->status; } - NIMBLE_LOGD(LOG_TAG,"<< Characteristic Discovered. status: %d", rc); - return rc; + + xTaskNotifyGive(pTaskData->task); + + NIMBLE_LOGD(LOG_TAG,"<< Characteristic Discovered"); + return error->status; } @@ -197,32 +188,31 @@ bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID *uuid_filter) NIMBLE_LOGD(LOG_TAG, ">> retrieveCharacteristics() for service: %s", getUUID().toString().c_str()); int rc = 0; - //deleteCharacteristics(); // Forget any previous characteristics. - - m_semaphoreGetCharEvt.take("retrieveCharacteristics"); + ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr}; if(uuid_filter == nullptr) { rc = ble_gattc_disc_all_chrs(m_pClient->getConnId(), m_startHandle, m_endHandle, NimBLERemoteService::characteristicDiscCB, - this); + &taskData); } else { rc = ble_gattc_disc_chrs_by_uuid(m_pClient->getConnId(), m_startHandle, m_endHandle, &uuid_filter->getNative()->u, NimBLERemoteService::characteristicDiscCB, - this); + &taskData); } if (rc != 0) { NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_chrs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); - m_semaphoreGetCharEvt.give(); return false; } - if(m_semaphoreGetCharEvt.wait("retrieveCharacteristics") == 0){ + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + if(taskData.rc == 0){ NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics()"); return true; } @@ -319,7 +309,7 @@ void NimBLERemoteService::deleteCharacteristics() { for(auto &it: m_characteristicVector) { delete it; } - m_characteristicVector.clear(); // Clear the vector + m_characteristicVector.clear(); NIMBLE_LOGD(LOG_TAG, "<< deleteCharacteristics"); } // deleteCharacteristics @@ -331,7 +321,7 @@ void NimBLERemoteService::deleteCharacteristics() { */ size_t NimBLERemoteService::deleteCharacteristic(const NimBLEUUID &uuid) { NIMBLE_LOGD(LOG_TAG, ">> deleteCharacteristic"); - // Delete the requested characteristic. + for(auto it = m_characteristicVector.begin(); it != m_characteristicVector.end(); ++it) { if((*it)->getUUID() == uuid) { delete *it; @@ -374,16 +364,5 @@ std::string NimBLERemoteService::toString() { } // toString -/** - * @brief called when an error occurrs and we need to release the semaphores to resume operations. - * Will release all characteristic and subsequently all descriptor semaphores for this service. - */ -void NimBLERemoteService::releaseSemaphores() { - for(auto &it: m_characteristicVector) { - it->releaseSemaphores(); - } - m_semaphoreGetCharEvt.give(1); -} - #endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL) #endif /* CONFIG_BT_ENABLED */ diff --git a/src/NimBLERemoteService.h b/src/NimBLERemoteService.h index 12bd3ff..2d63c5d 100644 --- a/src/NimBLERemoteService.h +++ b/src/NimBLERemoteService.h @@ -22,7 +22,6 @@ #include "NimBLEClient.h" #include "NimBLEUUID.h" -#include "FreeRTOS.h" #include "NimBLERemoteCharacteristic.h" #include @@ -79,7 +78,6 @@ private: std::vector m_characteristicVector; NimBLEClient* m_pClient; - FreeRTOS::Semaphore m_semaphoreGetCharEvt = FreeRTOS::Semaphore("GetCharEvt"); NimBLEUUID m_uuid; uint16_t m_startHandle; uint16_t m_endHandle; diff --git a/src/NimBLEScan.cpp b/src/NimBLEScan.cpp index eedc39a..5effeb1 100644 --- a/src/NimBLEScan.cpp +++ b/src/NimBLEScan.cpp @@ -18,7 +18,6 @@ #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) #include "NimBLEScan.h" -#include "NimBLEUtils.h" #include "NimBLEDevice.h" #include "NimBLELog.h" @@ -70,6 +69,7 @@ NimBLEScan::NimBLEScan() { m_pAdvertisedDeviceCallbacks = nullptr; m_stopped = true; m_wantDuplicates = false; + m_pTaskData = nullptr; } @@ -101,14 +101,6 @@ NimBLEScan::NimBLEScan() { NimBLEAddress advertisedAddress(event->disc.addr); - // Print advertisement data - // print_adv_fields(&fields); - - // If we are not scanning, nothing to do with the extra results. - if (pScan->m_stopped) { - return 0; - } - // Examine our list of ignored addresses and stop processing if we don't want to see it or are already connected if(NimBLEDevice::isIgnored(advertisedAddress)) { NIMBLE_LOGI(LOG_TAG, "Ignoring device: address: %s", advertisedAddress.toString().c_str()); @@ -131,7 +123,6 @@ NimBLEScan::NimBLEScan() { advertisedDevice = new NimBLEAdvertisedDevice(); advertisedDevice->setAddressType(event->disc.addr.type); advertisedDevice->setAddress(advertisedAddress); - //NIMBLE_LOGE(LOG_TAG, "advertisement type: %d, %s",event->disc.event_type, NimBLEUtils::advTypeToString(event->disc.event_type)); advertisedDevice->setAdvType(event->disc.event_type); pScan->m_scanResults.m_advertisedDevicesVector.push_back(advertisedDevice); NIMBLE_LOGI(LOG_TAG, "NEW DEVICE FOUND: %s", advertisedAddress.toString().c_str()); @@ -153,7 +144,6 @@ NimBLEScan::NimBLEScan() { } else if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) { pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice); } - //m_pAdvertisedDeviceCallbacks->onResult(*advertisedDevice); } return 0; @@ -167,7 +157,11 @@ NimBLEScan::NimBLEScan() { } pScan->m_stopped = true; - pScan->m_semaphoreScanEnd.give(); + if(pScan->m_pTaskData != nullptr) { + pScan->m_pTaskData->rc = event->disc_complete.reason; + xTaskNotifyGive(pScan->m_pTaskData->task); + } + return 0; } @@ -249,7 +243,6 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul } m_stopped = false; - m_semaphoreScanEnd.take("start"); // Save the callback to be invoked when the scan completes. m_scanCompleteCB = scanCompleteCB; @@ -275,7 +268,7 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul rc = ble_gap_disc(m_own_addr_type, duration, &m_scan_params, NimBLEScan::handleGapEvent, this); if(rc == BLE_HS_EBUSY) { - vTaskDelay(2); + vTaskDelay(1 / portTICK_PERIOD_MS); } } while(rc == BLE_HS_EBUSY); @@ -283,7 +276,6 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul NIMBLE_LOGE(LOG_TAG, "Error initiating GAP discovery procedure; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc)); m_stopped = true; - m_semaphoreScanEnd.give(); return false; } @@ -298,9 +290,18 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul * @return The BLEScanResults. */ NimBLEScanResults NimBLEScan::start(uint32_t duration, bool is_continue) { - if(start(duration, nullptr, is_continue)) { - m_semaphoreScanEnd.wait("start"); // Wait for the semaphore to release. + if(duration == 0) { + NIMBLE_LOGW(LOG_TAG, "Blocking scan called with duration = forever"); } + + ble_task_data_t taskData = {nullptr, xTaskGetCurrentTaskHandle(),0, nullptr}; + m_pTaskData = &taskData; + + if(start(duration, nullptr, is_continue)) { + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + } + + m_pTaskData = nullptr; return m_scanResults; } // start @@ -309,13 +310,13 @@ NimBLEScanResults NimBLEScan::start(uint32_t duration, bool is_continue) { * @brief Stop an in progress scan. * @return N/A. */ -void NimBLEScan::stop() { +bool NimBLEScan::stop() { NIMBLE_LOGD(LOG_TAG, ">> stop()"); int rc = ble_gap_disc_cancel(); if (rc != 0 && rc != BLE_HS_EALREADY) { NIMBLE_LOGE(LOG_TAG, "Failed to cancel scan; rc=%d\n", rc); - return; + return false; } m_stopped = true; @@ -324,9 +325,12 @@ void NimBLEScan::stop() { m_scanCompleteCB(m_scanResults); } - m_semaphoreScanEnd.give(); + if(m_pTaskData != nullptr) { + xTaskNotifyGive(m_pTaskData->task); + } NIMBLE_LOGD(LOG_TAG, "<< stop()"); + return true; } // stop @@ -350,7 +354,6 @@ void NimBLEScan::erase(const NimBLEAddress &address) { */ void NimBLEScan::onHostReset() { m_stopped = true; - m_semaphoreScanEnd.give(); } diff --git a/src/NimBLEScan.h b/src/NimBLEScan.h index 3cab257..06359f9 100644 --- a/src/NimBLEScan.h +++ b/src/NimBLEScan.h @@ -20,7 +20,7 @@ #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) #include "NimBLEAdvertisedDevice.h" -#include "FreeRTOS.h" +#include "NimBLEUtils.h" #include "host/ble_gap.h" @@ -66,7 +66,7 @@ public: void setActiveScan(bool active); void setInterval(uint16_t intervalMSecs); void setWindow(uint16_t windowMSecs); - void stop(); + bool stop(); void clearResults(); NimBLEScanResults getResults(); void erase(const NimBLEAddress &address); @@ -85,8 +85,8 @@ private: bool m_stopped; bool m_wantDuplicates; NimBLEScanResults m_scanResults; - FreeRTOS::Semaphore m_semaphoreScanEnd = FreeRTOS::Semaphore("ScanEnd"); uint32_t m_duration; + ble_task_data_t *m_pTaskData; }; #endif // #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) diff --git a/src/NimBLEUtils.cpp b/src/NimBLEUtils.cpp index 9036d4d..1f1f22c 100644 --- a/src/NimBLEUtils.cpp +++ b/src/NimBLEUtils.cpp @@ -502,8 +502,13 @@ void print_bytes(const uint8_t *bytes, int len) int i; for (i = 0; i < len; i++) { - MODLOG_DFLT(DEBUG, "%s0x%02x", i != 0 ? ":" : "", bytes[i]); + MODLOG_DFLT(ERROR, "%s0x%02x", i != 0 ? ":" : "", bytes[i]); + if(i % 30 == 0){ + MODLOG_DFLT(ERROR, "\n"); + } } + + MODLOG_DFLT(ERROR, "\n"); } void print_mbuf(const struct os_mbuf *om)