From e987ad58b2f59a3642494b9e2c5aea92b7ee2c57 Mon Sep 17 00:00:00 2001 From: h2zero Date: Sun, 7 Jun 2020 18:42:28 -0600 Subject: [PATCH] Refactor server code to use vectors instead of maps. * Use critical sections to access characteristic/descriptor value data. * Remove unnecessary code * Create characteristic semaphore only if needed for indications. * Fix advertising when not broadcasting a service. --- CMakeLists.txt | 4 - src/NimBLE2902.h | 9 +- src/NimBLE2904.h | 1 + src/NimBLEAdvertising.cpp | 59 +++--- src/NimBLEAdvertising.h | 2 +- src/NimBLECharacteristic.cpp | 342 ++++++++++++-------------------- src/NimBLECharacteristic.h | 135 +++++-------- src/NimBLECharacteristicMap.cpp | 132 ------------ src/NimBLEDescriptor.cpp | 40 ++-- src/NimBLEDescriptor.h | 50 +++-- src/NimBLEDescriptorMap.cpp | 149 -------------- src/NimBLEServer.cpp | 294 ++++++++++----------------- src/NimBLEServer.h | 108 +++------- src/NimBLEService.cpp | 117 +++++------ src/NimBLEService.h | 59 ++---- src/NimBLEServiceMap.cpp | 145 -------------- src/NimBLEValue.cpp | 143 ------------- src/NimBLEValue.h | 52 ----- 18 files changed, 471 insertions(+), 1370 deletions(-) delete mode 100644 src/NimBLECharacteristicMap.cpp delete mode 100644 src/NimBLEDescriptorMap.cpp delete mode 100644 src/NimBLEServiceMap.cpp delete mode 100644 src/NimBLEValue.cpp delete mode 100644 src/NimBLEValue.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1eb9d2e..53efc6a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,10 +12,8 @@ idf_component_register(SRCS "src/FreeRTOS.cpp" "src/NimBLEAdvertising.cpp" "src/NimBLEBeacon.cpp" "src/NimBLECharacteristic.cpp" - "src/NimBLECharacteristicMap.cpp" "src/NimBLEClient.cpp" "src/NimBLEDescriptor.cpp" - "src/NimBLEDescriptorMap.cpp" "src/NimBLEDevice.cpp" "src/NimBLEEddystoneTLM.cpp" "src/NimBLEEddystoneURL.cpp" @@ -26,9 +24,7 @@ idf_component_register(SRCS "src/FreeRTOS.cpp" "src/NimBLESecurity.cpp" "src/NimBLEServer.cpp" "src/NimBLEService.cpp" - "src/NimBLEServiceMap.cpp" "src/NimBLEUtils.cpp" "src/NimBLEUUID.cpp" - "src/NimBLEValue.cpp" INCLUDE_DIRS "src" REQUIRES bt) diff --git a/src/NimBLE2902.h b/src/NimBLE2902.h index f7fc555..2d84b73 100644 --- a/src/NimBLE2902.h +++ b/src/NimBLE2902.h @@ -22,11 +22,16 @@ #include "NimBLEDescriptor.h" -#include +#include #define NIMBLE_DESC_FLAG_NOTIFY 0x0001 #define NIMBLE_DESC_FLAG_INDICATE 0x0002 +typedef struct { + uint16_t conn_id; + uint16_t sub_val; +} chr_sub_status_t; + /** * @brief Descriptor for Client Characteristic Configuration. @@ -45,7 +50,7 @@ public: private: NimBLE2902(NimBLECharacteristic* pCharacterisitic); friend class NimBLECharacteristic; - std::map m_subscribedMap; + std::vector m_subscribedVec; }; // NimBLE2902 diff --git a/src/NimBLE2904.h b/src/NimBLE2904.h index dd665a2..0a6d036 100644 --- a/src/NimBLE2904.h +++ b/src/NimBLE2904.h @@ -31,6 +31,7 @@ struct BLE2904_Data { } __attribute__((packed)); + /** * @brief Descriptor for Characteristic Presentation Format. * diff --git a/src/NimBLEAdvertising.cpp b/src/NimBLEAdvertising.cpp index 7c930bf..7e1e07a 100644 --- a/src/NimBLEAdvertising.cpp +++ b/src/NimBLEAdvertising.cpp @@ -100,7 +100,8 @@ void NimBLEAdvertising::setMaxInterval(uint16_t maxinterval) { m_advParams.itvl_max = maxinterval; } // setMaxInterval -// These are dummy functions for now for compatibility + +/* These are dummy functions for now for compatibility */ void NimBLEAdvertising::setMinPreferred(uint16_t mininterval) { //m_advData.min_interval = mininterval; } // @@ -108,7 +109,8 @@ void NimBLEAdvertising::setMinPreferred(uint16_t mininterval) { void NimBLEAdvertising::setMaxPreferred(uint16_t maxinterval) { //m_advData.max_interval = maxinterval; } // -////////////////////////////////////////////////////////// +/*******************************************************/ + void NimBLEAdvertising::setScanResponse(bool set) { m_scanResp = set; @@ -204,19 +206,19 @@ void NimBLEAdvertising::start() { } #endif - int numServices = m_serviceUUIDs.size(); - int rc = 0; - uint8_t addressType; - uint8_t payloadLen = 3; //start with 3 bytes for the flags data - // If already advertising just return if(ble_gap_adv_active()) { return; } - if (!m_customAdvData && !m_advSvcsSet && numServices > 0) { - for (int i = 0; i < numServices; i++) { - if(m_serviceUUIDs[i].getNative()->u.type == BLE_UUID_TYPE_16) { + int rc = 0; + + if (!m_customAdvData && !m_advDataSet) { + //start with 3 bytes for the flags data + uint8_t payloadLen = 3; + + for(auto &it : m_serviceUUIDs) { + if(it.getNative()->u.type == BLE_UUID_TYPE_16) { int add = (m_advData.num_uuids16 > 0) ? 2 : 4; if((payloadLen + add) > 31){ m_advData.uuids16_is_complete = 0; @@ -225,19 +227,19 @@ void NimBLEAdvertising::start() { payloadLen += add; if(nullptr == (m_advData.uuids16 = (ble_uuid16_t*)realloc(m_advData.uuids16, - (m_advData.num_uuids16 + 1) * sizeof(ble_uuid16_t)))) + (m_advData.num_uuids16 + 1) * sizeof(ble_uuid16_t)))) { NIMBLE_LOGE(LOG_TAG, "Error, no mem"); abort(); } memcpy(&m_advData.uuids16[m_advData.num_uuids16].value, - &m_serviceUUIDs[i].getNative()->u16.value, sizeof(uint16_t)); + &it.getNative()->u16.value, 2); m_advData.uuids16[m_advData.num_uuids16].u.type = BLE_UUID_TYPE_16; m_advData.uuids16_is_complete = 1; m_advData.num_uuids16++; } - if(m_serviceUUIDs[i].getNative()->u.type == BLE_UUID_TYPE_32) { + if(it.getNative()->u.type == BLE_UUID_TYPE_32) { int add = (m_advData.num_uuids32 > 0) ? 4 : 6; if((payloadLen + add) > 31){ m_advData.uuids32_is_complete = 0; @@ -246,19 +248,19 @@ void NimBLEAdvertising::start() { payloadLen += add; if(nullptr == (m_advData.uuids32 = (ble_uuid32_t*)realloc(m_advData.uuids32, - (m_advData.num_uuids32 + 1) * sizeof(ble_uuid32_t)))) + (m_advData.num_uuids32 + 1) * sizeof(ble_uuid32_t)))) { NIMBLE_LOGE(LOG_TAG, "Error, no mem"); abort(); } memcpy(&m_advData.uuids32[m_advData.num_uuids32].value, - &m_serviceUUIDs[i].getNative()->u32.value, sizeof(uint32_t)); + &it.getNative()->u32.value, 4); m_advData.uuids32[m_advData.num_uuids32].u.type = BLE_UUID_TYPE_32; m_advData.uuids32_is_complete = 1; m_advData.num_uuids32++; } - if(m_serviceUUIDs[i].getNative()->u.type == BLE_UUID_TYPE_128){ + if(it.getNative()->u.type == BLE_UUID_TYPE_128){ int add = (m_advData.num_uuids128 > 0) ? 16 : 18; if((payloadLen + add) > 31){ m_advData.uuids128_is_complete = 0; @@ -267,12 +269,13 @@ void NimBLEAdvertising::start() { payloadLen += add; if(nullptr == (m_advData.uuids128 = (ble_uuid128_t*)realloc(m_advData.uuids128, - (m_advData.num_uuids128 + 1) * sizeof(ble_uuid128_t)))) { + (m_advData.num_uuids128 + 1) * sizeof(ble_uuid128_t)))) + { NIMBLE_LOGE(LOG_TAG, "Error, no mem"); abort(); } memcpy(&m_advData.uuids128[m_advData.num_uuids128].value, - &m_serviceUUIDs[i].getNative()->u128.value, 16); + &it.getNative()->u128.value, 16); m_advData.uuids128[m_advData.num_uuids128].u.type = BLE_UUID_TYPE_128; m_advData.uuids128_is_complete = 1; @@ -315,11 +318,11 @@ void NimBLEAdvertising::start() { rc = ble_gap_adv_rsp_set_fields(&m_scanData); if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "error setting scan response data; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc)); + NIMBLE_LOGC(LOG_TAG, "error setting scan response data; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc)); abort(); } // if not using scan response and there is room, - // throw the tx power data into the advertisment + // put the tx power data into the advertisment } else if (payloadLen < 29) { m_advData.tx_pwr_lvl_is_present = 1; m_advData.tx_pwr_lvl = NimBLEDevice::getPower(); @@ -327,7 +330,7 @@ void NimBLEAdvertising::start() { rc = ble_gap_adv_set_fields(&m_advData); if (rc != 0) { - NIMBLE_LOGE(LOG_TAG, "error setting advertisement data; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc)); + NIMBLE_LOGC(LOG_TAG, "error setting advertisement data; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc)); abort(); } @@ -349,22 +352,16 @@ void NimBLEAdvertising::start() { m_advData.num_uuids16 = 0; } - m_advSvcsSet = true; - } - - rc = ble_hs_id_infer_auto(0, &addressType); - if (rc != 0) { - NIMBLE_LOGC(LOG_TAG, "Error determining address type; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc)); - abort(); + m_advDataSet = true; } #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - rc = ble_gap_adv_start(addressType, NULL, BLE_HS_FOREVER, + rc = ble_gap_adv_start(0, NULL, BLE_HS_FOREVER, &m_advParams, (pServer != nullptr) ? NimBLEServer::handleGapEvent : NULL, pServer); #else - rc = ble_gap_adv_start(addressType, NULL, BLE_HS_FOREVER, + rc = ble_gap_adv_start(0, NULL, BLE_HS_FOREVER, &m_advParams, NULL,NULL); #endif if (rc != 0) { @@ -398,7 +395,7 @@ void NimBLEAdvertising::stop() { * we need clear the flag so it reloads it. */ void NimBLEAdvertising::onHostReset() { - m_advSvcsSet = false; + m_advDataSet = false; } diff --git a/src/NimBLEAdvertising.h b/src/NimBLEAdvertising.h index f30b158..1d25b81 100644 --- a/src/NimBLEAdvertising.h +++ b/src/NimBLEAdvertising.h @@ -103,7 +103,7 @@ private: bool m_customAdvData = false; // Are we using custom advertising data? bool m_customScanResponseData = false; // Are we using custom scan response data? bool m_scanResp = true; - bool m_advSvcsSet = false; + bool m_advDataSet = false; }; diff --git a/src/NimBLECharacteristic.cpp b/src/NimBLECharacteristic.cpp index dd1be3b..82c3183 100644 --- a/src/NimBLECharacteristic.cpp +++ b/src/NimBLECharacteristic.cpp @@ -22,18 +22,16 @@ #include "NimBLEUtils.h" #include "NimBLELog.h" -#include - #define NULL_HANDLE (0xffff) static NimBLECharacteristicCallbacks defaultCallback; - static const char* LOG_TAG = "NimBLECharacteristic"; /** * @brief Construct a characteristic * @param [in] uuid - UUID (const char*) for the characteristic. * @param [in] properties - Properties for the characteristic. + * @param [in] pService - pointer to the service instance this characteristic belongs to. */ NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties, NimBLEService* pService) : NimBLECharacteristic(NimBLEUUID(uuid), properties, pService) { @@ -43,6 +41,7 @@ NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties * @brief Construct a characteristic * @param [in] uuid - UUID for the characteristic. * @param [in] properties - Properties for the characteristic. + * @param [in] pService - pointer to the service instance this characteristic belongs to. */ NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t properties, NimBLEService* pService) { m_uuid = uuid; @@ -50,39 +49,24 @@ NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t prop m_properties = properties; m_pCallbacks = &defaultCallback; m_pService = pService; -// Backward Compatibility - to be removed -/* setBroadcastProperty((properties & PROPERTY_BROADCAST) != 0); - setReadProperty((properties & PROPERTY_READ) != 0); - setWriteProperty((properties & PROPERTY_WRITE) != 0); - setNotifyProperty((properties & PROPERTY_NOTIFY) != 0); - setIndicateProperty((properties & PROPERTY_INDICATE) != 0); - setWriteNoResponseProperty((properties & PROPERTY_WRITE_NR) != 0); -*/ -/////////////////////////////////////////// + m_value = ""; + m_valMux = portMUX_INITIALIZER_UNLOCKED; + + if(properties & NIMBLE_PROPERTY::INDICATE){ + m_pIndSemaphore = new FreeRTOS::Semaphore("ConfEvt"); + } else { + m_pIndSemaphore = nullptr; + } } // NimBLECharacteristic /** * @brief Destructor. */ NimBLECharacteristic::~NimBLECharacteristic() { -} // ~NimBLECharacteristic - - -/** - * @brief Associate a descriptor with this characteristic. - * @param [in] pDescriptor - * @return N/A. - */ -void NimBLECharacteristic::addDescriptor(NimBLEDescriptor* pDescriptor) { - NIMBLE_LOGD(LOG_TAG, ">> addDescriptor(): Adding %s to %s", pDescriptor->toString().c_str(), toString().c_str()); - // Check that we don't add the same descriptor twice. - if (m_descriptorMap.getByUUID(pDescriptor->getUUID()) != nullptr) { - NIMBLE_LOGW(LOG_TAG, "<< Adding a new descriptor with the same UUID as a previous one"); - //return; + if(m_pIndSemaphore != nullptr) { + delete(m_pIndSemaphore); } - m_descriptorMap.setByUUID(pDescriptor->getUUID(), pDescriptor); - NIMBLE_LOGD(LOG_TAG, "<< addDescriptor()"); -} // addDescriptor +} // ~NimBLECharacteristic /** @@ -104,25 +88,26 @@ NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const char* uuid, uint3 */ NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID &uuid, uint32_t properties, uint16_t max_len) { NimBLEDescriptor* pDescriptor = nullptr; - if(uuid.equals(NimBLEUUID((uint16_t)0x2902))) { + if(uuid == NimBLEUUID(uint16_t(0x2902))) { if(!(m_properties & BLE_GATT_CHR_F_NOTIFY) && !(m_properties & BLE_GATT_CHR_F_INDICATE)) { assert(0 && "Cannot create 2902 descriptior without characteristic notification or indication property set"); } // We cannot have more than one 2902 descriptor, if it's already been created just return a pointer to it. - pDescriptor = m_descriptorMap.getByUUID(uuid); + pDescriptor = getDescriptorByUUID(uuid); if(pDescriptor == nullptr) { pDescriptor = new NimBLE2902(this); } else { return pDescriptor; } - } else if (uuid.equals(NimBLEUUID((uint16_t)0x2904))) { + } else if (uuid == NimBLEUUID(uint16_t(0x2904))) { pDescriptor = new NimBLE2904(this); } else { pDescriptor = new NimBLEDescriptor(uuid, properties, max_len, this); } - addDescriptor(pDescriptor); + + m_dscVec.push_back(pDescriptor); return pDescriptor; } // createCharacteristic @@ -132,8 +117,8 @@ NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID &uuid, * @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve. * @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned. */ -NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* descriptorUUID) { - return m_descriptorMap.getByUUID(NimBLEUUID(descriptorUUID)); +NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* uuid) { + return getDescriptorByUUID(NimBLEUUID(uuid)); } // getDescriptorByUUID @@ -142,8 +127,13 @@ NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* descript * @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve. * @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned. */ -NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &descriptorUUID) { - return m_descriptorMap.getByUUID(descriptorUUID); +NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &uuid) { + for (auto &it : m_dscVec) { + if (it->getUUID() == uuid) { + return it; + } + } + return nullptr; } // getDescriptorByUUID @@ -155,11 +145,6 @@ uint16_t NimBLECharacteristic::getHandle() { return m_handle; } // getHandle -/* -void NimBLECharacteristic::setAccessPermissions(uint16_t perm) { - m_permissions = perm; -} -*/ uint8_t NimBLECharacteristic::getProperties() { return m_properties; @@ -188,25 +173,24 @@ NimBLEUUID NimBLECharacteristic::getUUID() { * @return A pointer to storage containing the current characteristic value. */ std::string NimBLECharacteristic::getValue() { - return m_value.getValue(); + portENTER_CRITICAL(&m_valMux); + std::string retVal = m_value; + portEXIT_CRITICAL(&m_valMux); + + return retVal; } // getValue -/** - * @brief Retrieve the current raw data of the characteristic. - * @return A pointer to storage containing the current characteristic data. - */ -uint8_t* NimBLECharacteristic::getData() { - return m_value.getData(); -} // getData - - /** * @brief Retrieve the the current data length of the characteristic. * @return The length of the current characteristic data. */ -size_t NimBLECharacteristic:: getDataLength() { - return m_value.getLength(); +size_t NimBLECharacteristic::getDataLength() { + portENTER_CRITICAL(&m_valMux); + size_t len = m_value.length(); + portEXIT_CRITICAL(&m_valMux); + + return len; } @@ -225,32 +209,41 @@ int NimBLECharacteristic::handleGapEvent(uint16_t conn_handle, uint16_t attr_han if(ble_uuid_cmp(uuid, &pCharacteristic->getUUID().getNative()->u) == 0){ switch(ctxt->op) { case BLE_GATT_ACCESS_OP_READ_CHR: { - //NIMBLE_LOGD(LOG_TAG, "read char pkthdr len:%d flags:%d", ctxt->om->om_pkthdr_len, ctxt->om->om_flags); // If the packet header is only 8 bytes this is a follow up of a long read // so we don't want to call the onRead() callback again. if(ctxt->om->om_pkthdr_len > 8) { pCharacteristic->m_pCallbacks->onRead(pCharacteristic); } - rc = os_mbuf_append(ctxt->om, pCharacteristic->getData(), pCharacteristic->m_value.getLength()); + + portENTER_CRITICAL(&pCharacteristic->m_valMux); + rc = os_mbuf_append(ctxt->om, (uint8_t*)pCharacteristic->m_value.data(), + pCharacteristic->m_value.length()); + portEXIT_CRITICAL(&pCharacteristic->m_valMux); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; } case BLE_GATT_ACCESS_OP_WRITE_CHR: { - //NIMBLE_LOGD(LOG_TAG, "write char pkthdr len:%d datalen:%d", ctxt->om->om_pkthdr_len, ctxt->om->om_len); if (ctxt->om->om_len > BLE_ATT_ATTR_MAX_LEN) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } - //pCharacteristic->setValue(ctxt->om->om_data, ctxt->om->om_len); - pCharacteristic->m_value.addPart(ctxt->om->om_data, ctxt->om->om_len); + uint8_t buf[BLE_ATT_ATTR_MAX_LEN]; + size_t len = ctxt->om->om_len; + memcpy(buf, ctxt->om->om_data,len); + os_mbuf *next; next = SLIST_NEXT(ctxt->om, om_next); while(next != NULL){ - //NIMBLE_LOGD(LOG_TAG, "Found long write data, len:%d", next->om_len); - pCharacteristic->m_value.addPart(next->om_data, next->om_len); + if((len + next->om_len) > BLE_ATT_ATTR_MAX_LEN) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + memcpy(&buf[len-1], next->om_data, next->om_len); + len += next->om_len; next = SLIST_NEXT(next, om_next); } - pCharacteristic->m_value.commit(); + + pCharacteristic->setValue(buf, len); pCharacteristic->m_pCallbacks->onWrite(pCharacteristic); return 0; @@ -278,14 +271,18 @@ void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) { subVal |= NIMBLE_DESC_FLAG_INDICATE; } - m_semaphoreConfEvt.give((subVal | NIMBLE_DESC_FLAG_INDICATE) ? 0 : - NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_DISABLED); + if(m_pIndSemaphore != nullptr) { + m_pIndSemaphore->give((subVal & NIMBLE_DESC_FLAG_INDICATE) ? 0 : + NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_DISABLED); + } - NIMBLE_LOGI(LOG_TAG, "New subscribe value for conn: %d val: %d", event->subscribe.conn_handle, subVal); + NIMBLE_LOGI(LOG_TAG, "New subscribe value for conn: %d val: %d", + event->subscribe.conn_handle, subVal); - NimBLE2902* p2902 = (NimBLE2902*)getDescriptorByUUID((uint16_t)0x2902); + NimBLE2902* p2902 = (NimBLE2902*)getDescriptorByUUID(uint16_t(0x2902)); if(p2902 == nullptr){ - ESP_LOGE(LOG_TAG, "No 2902 descriptor found for %s", getUUID().toString().c_str()); + ESP_LOGE(LOG_TAG, "No 2902 descriptor found for %s", + std::string(getUUID()).c_str()); return; } @@ -294,21 +291,28 @@ void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) { p2902->m_pCallbacks->onWrite(p2902); - auto it = p2902->m_subscribedMap.find(event->subscribe.conn_handle); - if(subVal > 0 && it == p2902->m_subscribedMap.cend()) { - p2902->m_subscribedMap.insert(std::pair(event->subscribe.conn_handle, subVal)); - return; - } else if(it != p2902->m_subscribedMap.cend()) { - p2902->m_subscribedMap.erase(event->subscribe.conn_handle); - return; + auto it = p2902->m_subscribedVec.begin(); + for(;it != p2902->m_subscribedVec.end(); ++it) { + if((*it).conn_id == event->subscribe.conn_handle) { + break; + } } -/* - if(event->subscribe.reason == BLE_GAP_SUBSCRIBE_REASON_TERM) { - p2902->m_subscribedMap.erase(event->subscribe.conn_handle); - return; + + if(subVal > 0) { + if(it == p2902->m_subscribedVec.end()) { + chr_sub_status_t client_sub; + client_sub.conn_id = event->subscribe.conn_handle; + client_sub.sub_val = subVal; + p2902->m_subscribedVec.push_back(client_sub); + return; + } + + (*it).sub_val = subVal; + + } else if(it != p2902->m_subscribedVec.end()) { + p2902->m_subscribedVec.erase(it); + p2902->m_subscribedVec.shrink_to_fit(); } -*/ - (*it).second = subVal; } @@ -319,7 +323,7 @@ void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) { * @return N/A */ void NimBLECharacteristic::indicate() { - NIMBLE_LOGD(LOG_TAG, ">> indicate: length: %d", m_value.getValue().length()); + NIMBLE_LOGD(LOG_TAG, ">> indicate: length: %d", getDataLength()); notify(false); NIMBLE_LOGD(LOG_TAG, "<< indicate"); } // indicate @@ -331,36 +335,38 @@ void NimBLECharacteristic::indicate() { * @return N/A. */ void NimBLECharacteristic::notify(bool is_notification) { - NIMBLE_LOGD(LOG_TAG, ">> notify: length: %d", m_value.getValue().length()); + NIMBLE_LOGD(LOG_TAG, ">> notify: length: %d", getDataLength()); - assert(getService() != nullptr); - assert(getService()->getServer() != nullptr); + NimBLE2902* p2902 = (NimBLE2902*)getDescriptorByUUID(uint16_t(0x2902)); + if(p2902 == nullptr) { + NIMBLE_LOGE(LOG_TAG, + "<< notify-Error; Notify/indicate not enabled for characterisitc: %s", + std::string(getUUID()).c_str()); + } - if (getService()->getServer()->getConnectedCount() == 0) { - NIMBLE_LOGD(LOG_TAG, "<< notify: No connected clients."); + if (p2902->m_subscribedVec.size() == 0) { + NIMBLE_LOGD(LOG_TAG, "<< notify: No clients subscribed."); return; } m_pCallbacks->onNotify(this); + std::string value = getValue(); + size_t length = value.length(); int rc = 0; - NimBLE2902* p2902 = (NimBLE2902*)getDescriptorByUUID((uint16_t)0x2902); - for (auto it = p2902->m_subscribedMap.cbegin(); it != p2902->m_subscribedMap.cend(); ++it) { - uint16_t _mtu = getService()->getServer()->getPeerMTU((*it).first); - // Must rebuild the data on each loop iteration as NimBLE will release it. - size_t length = m_value.getValue().length(); - uint8_t* data = (uint8_t*)m_value.getValue().data(); + for (auto &it : p2902->m_subscribedVec) { + uint16_t _mtu = getService()->getServer()->getPeerMTU(it.conn_id); os_mbuf *om; if(_mtu == 0) { - //NIMBLE_LOGD(LOG_TAG, "peer not connected, removing from map"); - p2902->m_subscribedMap.erase((*it).first); - it = p2902->m_subscribedMap.cbegin(); - if(it == p2902->m_subscribedMap.cend()) { - return; - } + //NIMBLE_LOGD(LOG_TAG, "peer not connected"); + continue; + } + + if(it.sub_val == 0) { + //NIMBLE_LOGD(LOG_TAG, "Skipping unsubscribed client"); continue; } @@ -368,54 +374,52 @@ void NimBLECharacteristic::notify(bool is_notification) { NIMBLE_LOGW(LOG_TAG, "- Truncating to %d bytes (maximum notify size)", _mtu - 3); } - if((*it).second == 0) { - //NIMBLE_LOGI(LOG_TAG, "Skipping unsubscribed client"); - continue; - } - - if(is_notification && (!((*it).second & NIMBLE_DESC_FLAG_NOTIFY))) { + if(is_notification && (!(it.sub_val & NIMBLE_DESC_FLAG_NOTIFY))) { NIMBLE_LOGW(LOG_TAG, "Sending notification to client subscribed to indications, sending indication instead"); is_notification = false; } - if(!is_notification && (!((*it).second & NIMBLE_DESC_FLAG_INDICATE))) { + if(!is_notification && (!(it.sub_val & NIMBLE_DESC_FLAG_INDICATE))) { NIMBLE_LOGW(LOG_TAG, - "Sending indication to client subscribed to notifications, sending notifications instead"); + "Sending indication to client subscribed to notification, sending notification instead"); is_notification = true; } // don't create the m_buf until we are sure to send the data or else // we could be allocating a buffer that doesn't get released. // We also must create it in each loop iteration because it is consumed with each host call. - om = ble_hs_mbuf_from_flat(data, length); + om = ble_hs_mbuf_from_flat((uint8_t*)value.data(), length); - if(!is_notification) { - m_semaphoreConfEvt.take("indicate"); - rc = ble_gattc_indicate_custom((*it).first, m_handle, om); + NimBLECharacteristicCallbacks::Status statusRC; + if(m_pIndSemaphore != nullptr && !is_notification) { + m_pIndSemaphore->take("indicate"); + rc = ble_gattc_indicate_custom(it.conn_id, m_handle, om); if(rc != 0){ - m_semaphoreConfEvt.give(); - m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::ERROR_GATT, rc); - return; + m_pIndSemaphore->give(); + statusRC = NimBLECharacteristicCallbacks::Status::ERROR_GATT; + } else { + rc = m_pIndSemaphore->wait(); } - rc = m_semaphoreConfEvt.wait(); - - if(rc == BLE_HS_ETIMEOUT) { - m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT, rc); - } else if(rc == BLE_HS_EDONE) { - m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::SUCCESS_INDICATE, rc); + if(rc == 0 || rc == BLE_HS_EDONE) { + rc = 0; + statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_INDICATE; + } else if(rc == BLE_HS_ETIMEOUT) { + statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT; } else { - m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE, rc); + statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE; } } else { - rc = ble_gattc_notify_custom((*it).first, m_handle, om); + rc = ble_gattc_notify_custom(it.conn_id, m_handle, om); if(rc == 0) { - m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::SUCCESS_NOTIFY, 0); + statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_NOTIFY; } else { - m_pCallbacks->onStatus(this, NimBLECharacteristicCallbacks::Status::ERROR_GATT, rc); + statusRC = NimBLECharacteristicCallbacks::Status::ERROR_GATT; } } + + m_pCallbacks->onStatus(this, statusRC, rc); } NIMBLE_LOGD(LOG_TAG, "<< notify"); @@ -434,87 +438,6 @@ void NimBLECharacteristic::setCallbacks(NimBLECharacteristicCallbacks* pCallback } } // setCallbacks -// Backward compatibility - to be removed //////////////////////////////// -/** - * @brief Set the permission to broadcast. - * A characteristics has properties associated with it which define what it is capable of doing. - * One of these is the broadcast flag. - * @param [in] value The flag value of the property. - * @return N/A - */ -void NimBLECharacteristic::setBroadcastProperty(bool value) { - if (value) { - m_properties = (m_properties | BLE_GATT_CHR_F_BROADCAST); - } else { - m_properties = (m_properties & ~BLE_GATT_CHR_F_BROADCAST); - } -} // setBroadcastProperty - - -/** - * @brief Set the Indicate property value. - * @param [in] value Set to true if we are to allow indicate messages. - */ -void NimBLECharacteristic::setIndicateProperty(bool value) { - if (value) { - m_properties = (m_properties | BLE_GATT_CHR_F_INDICATE); - } else { - m_properties = (m_properties & ~BLE_GATT_CHR_F_INDICATE); - } -} // setIndicateProperty - - -/** - * @brief Set the Notify property value. - * @param [in] value Set to true if we are to allow notification messages. - */ -void NimBLECharacteristic::setNotifyProperty(bool value) { - if (value) { - m_properties = (m_properties | BLE_GATT_CHR_F_NOTIFY); - } else { - m_properties = (m_properties & ~BLE_GATT_CHR_F_NOTIFY); - } -} // setNotifyProperty - - -/** - * @brief Set the Read property value. - * @param [in] value Set to true if we are to allow reads. - */ -void NimBLECharacteristic::setReadProperty(bool value) { - if (value) { - m_properties = (m_properties | BLE_GATT_CHR_F_READ); - } else { - m_properties = (m_properties & ~BLE_GATT_CHR_F_READ); - } -} // setReadProperty - - -/** - * @brief Set the Write No Response property value. - * @param [in] value Set to true if we are to allow writes with no response. - */ -void NimBLECharacteristic::setWriteNoResponseProperty(bool value) { - if (value) { - m_properties = (m_properties | BLE_GATT_CHR_F_WRITE_NO_RSP); - } else { - m_properties = (m_properties & ~BLE_GATT_CHR_F_WRITE_NO_RSP); - } -} // setWriteNoResponseProperty - - -/** - * @brief Set the Write property value. - * @param [in] value Set to true if we are to allow writes. - */ -void NimBLECharacteristic::setWriteProperty(bool value) { - if (value) { - m_properties = (m_properties | BLE_GATT_CHR_F_WRITE ); - } else { - m_properties = (m_properties & ~BLE_GATT_CHR_F_WRITE ); - } -} // setWriteProperty -////////////////////////////////////////////////////////////////////////////////// /** * @brief Set the value of the characteristic. @@ -522,21 +445,20 @@ void NimBLECharacteristic::setWriteProperty(bool value) { * @param [in] length The length of the data in bytes. */ void NimBLECharacteristic::setValue(const uint8_t* data, size_t length) { +#if CONFIG_LOG_DEFAULT_LEVEL > 3 || (ARDUINO_ARCH_ESP32 && CORE_DEBUG_LEVEL >= 4) char* pHex = NimBLEUtils::buildHexData(nullptr, data, length); NIMBLE_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str()); free(pHex); +#endif if (length > BLE_ATT_ATTR_MAX_LEN) { NIMBLE_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, BLE_ATT_ATTR_MAX_LEN); return; } - m_value.setValue(data, length); - - // if(m_handle != NULL_HANDLE) { - //ble_gatts_chr_updated(m_handle); - // ble_gattc_notify(getService()->getServer()->m_connId, m_handle); - // } + portENTER_CRITICAL(&m_valMux); + m_value = std::string((char*)data, length); + portEXIT_CRITICAL(&m_valMux); NIMBLE_LOGD(LOG_TAG, "<< setValue"); } // setValue diff --git a/src/NimBLECharacteristic.h b/src/NimBLECharacteristic.h index 25e1ec7..1a15c5c 100644 --- a/src/NimBLECharacteristic.h +++ b/src/NimBLECharacteristic.h @@ -42,42 +42,16 @@ typedef enum { #include "NimBLEService.h" #include "NimBLEDescriptor.h" -#include "NimBLEUUID.h" -#include "NimBLEValue.h" #include "FreeRTOS.h" #include -#include - +#include class NimBLEService; class NimBLEDescriptor; class NimBLECharacteristicCallbacks; -/** - * @brief A management structure for %BLE descriptors. - */ -class NimBLEDescriptorMap { -public: - void setByUUID(const char* uuid, NimBLEDescriptor* pDescriptor); - void setByUUID(const NimBLEUUID &uuid, NimBLEDescriptor* pDescriptor); -// void setByHandle(uint16_t handle, NimBLEDescriptor* pDescriptor); - NimBLEDescriptor* getByUUID(const char* uuid); - NimBLEDescriptor* getByUUID(const NimBLEUUID &uuid); -// NimBLEDescriptor* getByHandle(uint16_t handle); - std::string toString(); - NimBLEDescriptor* getFirst(); - NimBLEDescriptor* getNext(); - uint8_t getSize(); - -private: - std::map m_uuidMap; -// std::map m_handleMap; - std::map::iterator m_iterator; -}; - - /** * @brief The model of a %BLE Characteristic. * @@ -87,84 +61,67 @@ private: class NimBLECharacteristic { public: NimBLEDescriptor* createDescriptor(const char* uuid, - uint32_t properties = NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE, - uint16_t max_len = 100); + uint32_t properties = + NIMBLE_PROPERTY::READ | + NIMBLE_PROPERTY::WRITE, + uint16_t max_len = 100); NimBLEDescriptor* createDescriptor(const NimBLEUUID &uuid, - uint32_t properties = NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE, - uint16_t max_len = 100); + uint32_t properties = + NIMBLE_PROPERTY::READ | + NIMBLE_PROPERTY::WRITE, + uint16_t max_len = 100); - NimBLEDescriptor* getDescriptorByUUID(const char* descriptorUUID); - NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &descriptorUUID); + NimBLEDescriptor* getDescriptorByUUID(const char* uuid); + NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &uuid); NimBLEUUID getUUID(); std::string getValue(); - uint8_t* getData(); size_t getDataLength(); - - void indicate(); - void notify(bool is_notification = true); - void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks); -// Backward Compatibility - to be removed - void setBroadcastProperty(bool value); - void setIndicateProperty(bool value); - void setNotifyProperty(bool value); - void setReadProperty(bool value); - void setWriteProperty(bool value); - void setWriteNoResponseProperty(bool value); -////////////////////////////////////////////////////// - void setValue(const uint8_t* data, size_t size); - void setValue(const std::string &value); - void setValue(uint16_t& data16); - void setValue(uint32_t& data32); - void setValue(int& data32); - void setValue(float& data32); - void setValue(double& data64); - - std::string toString(); - uint16_t getHandle(); -// void setAccessPermissions(uint16_t perm); - -// Backward Compatibility - to be removed -/* static const uint32_t PROPERTY_READ = 1<<0; - static const uint32_t PROPERTY_WRITE = 1<<1; - static const uint32_t PROPERTY_NOTIFY = 1<<2; - static const uint32_t PROPERTY_BROADCAST = 1<<3; - static const uint32_t PROPERTY_INDICATE = 1<<4; - static const uint32_t PROPERTY_WRITE_NR = 1<<5; -*/ -////////////////////////////////////////////////////// + void indicate(); + void notify(bool is_notification = true); + void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks); + void setValue(const uint8_t* data, size_t size); + void setValue(const std::string &value); + void setValue(uint16_t& data16); + void setValue(uint32_t& data32); + void setValue(int& data32); + void setValue(float& data32); + void setValue(double& data64); + std::string toString(); + uint16_t getHandle(); private: - friend class NimBLEServer; - friend class NimBLEService; -// friend class NimBLEDescriptor; -// friend class NimBLECharacteristicMap; + friend class NimBLEServer; + friend class NimBLEService; - NimBLECharacteristic(const char* uuid, uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE, - NimBLEService* pService = nullptr); - NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE, - NimBLEService* pService = nullptr); - virtual ~NimBLECharacteristic(); + NimBLECharacteristic(const char* uuid, + uint16_t properties = + NIMBLE_PROPERTY::READ | + NIMBLE_PROPERTY::WRITE, + NimBLEService* pService = nullptr); + NimBLECharacteristic(const NimBLEUUID &uuid, + uint16_t properties = + NIMBLE_PROPERTY::READ | + NIMBLE_PROPERTY::WRITE, + NimBLEService* pService = nullptr); - NimBLEUUID m_uuid; - NimBLEDescriptorMap m_descriptorMap; - uint16_t m_handle; - uint16_t m_properties; - NimBLECharacteristicCallbacks* m_pCallbacks; - NimBLEService* m_pService; - NimBLEValue m_value; -// uint16_t m_permissions; + ~NimBLECharacteristic(); - void addDescriptor(NimBLEDescriptor* pDescriptor); NimBLEService* getService(); uint8_t getProperties(); void setSubscribe(struct ble_gap_event *event); static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, void *arg); + struct ble_gatt_access_ctxt *ctxt, void *arg); - FreeRTOS::Semaphore m_semaphoreConfEvt = FreeRTOS::Semaphore("ConfEvt"); + NimBLEUUID m_uuid; + uint16_t m_handle; + uint16_t m_properties; + NimBLECharacteristicCallbacks* m_pCallbacks; + NimBLEService* m_pService; + std::string m_value; + std::vector m_dscVec; + FreeRTOS::Semaphore *m_pIndSemaphore; + portMUX_TYPE m_valMux; }; // NimBLECharacteristic diff --git a/src/NimBLECharacteristicMap.cpp b/src/NimBLECharacteristicMap.cpp deleted file mode 100644 index b3cdcf9..0000000 --- a/src/NimBLECharacteristicMap.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - * NimBLECharacteristicMap.cpp - * - * Created: on March 3, 2020 - * Author H2zero - * - * BLECharacteristicMap.cpp - * - * Created on: Jun 22, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include "nimconfig.h" -#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - -#include "NimBLEService.h" -#include "NimBLELog.h" - - -/** - * @brief Return the characteristic by handle. - * @param [in] handle The handle to look up the characteristic. - * @return The characteristic. - */ -NimBLECharacteristic* NimBLECharacteristicMap::getByHandle(uint16_t handle) { - return m_handleMap.at(handle); -} // getByHandle - - -/** - * @brief Return the characteristic by UUID. - * @param [in] UUID The UUID to look up the characteristic. - * @return The characteristic. - */ -NimBLECharacteristic* NimBLECharacteristicMap::getByUUID(const char* uuid) { - return getByUUID(NimBLEUUID(uuid)); -} - - -/** - * @brief Return the characteristic by UUID. - * @param [in] UUID The UUID to look up the characteristic. - * @return The characteristic. - */ -NimBLECharacteristic* NimBLECharacteristicMap::getByUUID(const NimBLEUUID &uuid) { - for (auto &myPair : m_uuidMap) { - if (myPair.first->getUUID().equals(uuid)) { - return myPair.first; - } - } - - return nullptr; -} // getByUUID - -/** - * @brief Get the number of characteristics in the map. - */ -uint8_t NimBLECharacteristicMap::getSize() { - return (uint8_t)m_uuidMap.size(); -} // getSize - -/** - * @brief Get the first characteristic in the map. - * @return The first characteristic in the map. - */ -NimBLECharacteristic* NimBLECharacteristicMap::getFirst() { - m_iterator = m_uuidMap.begin(); - if (m_iterator == m_uuidMap.end()) return nullptr; - NimBLECharacteristic* pRet = m_iterator->first; - m_iterator++; - return pRet; -} // getFirst - - -/** - * @brief Get the next characteristic in the map. - * @return The next characteristic in the map. - */ -NimBLECharacteristic* NimBLECharacteristicMap::getNext() { - if (m_iterator == m_uuidMap.end()) return nullptr; - NimBLECharacteristic* pRet = m_iterator->first; - m_iterator++; - return pRet; -} // getNext - - -/** - * @brief Set the characteristic by handle. - * @param [in] handle The handle of the characteristic. - * @param [in] characteristic The characteristic to cache. - * @return N/A. - */ -void NimBLECharacteristicMap::setByHandle(uint16_t handle, NimBLECharacteristic* characteristic) { - m_handleMap.insert(std::pair(handle, characteristic)); -} // setByHandle - - -/** - * @brief Set the characteristic by UUID. - * @param [in] uuid The uuid of the characteristic. - * @param [in] characteristic The characteristic to cache. - * @return N/A. - */ -void NimBLECharacteristicMap::setByUUID(NimBLECharacteristic* pCharacteristic, const NimBLEUUID &uuid) { - m_uuidMap.insert(std::pair(pCharacteristic, uuid.toString())); -} // setByUUID - - -/** - * @brief Return a string representation of the characteristic map. - * @return A string representation of the characteristic map. - */ -std::string NimBLECharacteristicMap::toString() { - std::string res; - int count = 0; - char hex[5]; - for (auto &myPair: m_uuidMap) { - if (count > 0) {res += "\n";} - snprintf(hex, sizeof(hex), "%04x", myPair.first->getHandle()); - count++; - res += "handle: 0x"; - res += hex; - res += ", uuid: " + myPair.first->getUUID().toString(); - } - return res; -} // toString - - -#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) -#endif /* CONFIG_BT_ENABLED */ diff --git a/src/NimBLEDescriptor.cpp b/src/NimBLEDescriptor.cpp index 0d414d3..e8f7f9f 100644 --- a/src/NimBLEDescriptor.cpp +++ b/src/NimBLEDescriptor.cpp @@ -50,6 +50,7 @@ NimBLEDescriptor::NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties, uint16_ m_pCharacteristic = nullptr; // No initial characteristic. m_pCallbacks = &defaultCallbacks; // No initial callback. m_value.attr_value = (uint8_t*) calloc(max_len,1); // Allocate storage for the value. + m_valMux = portMUX_INITIALIZER_UNLOCKED; m_properties = 0; if (properties & BLE_GATT_CHR_F_READ) { // convert uint16_t properties to uint8_t @@ -137,17 +138,37 @@ int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle, if(ble_uuid_cmp(uuid, &pDescriptor->getUUID().getNative()->u) == 0){ switch(ctxt->op) { case BLE_GATT_ACCESS_OP_READ_DSC: { - pDescriptor->m_pCallbacks->onRead(pDescriptor); + // If the packet header is only 8 bytes this is a follow up of a long read + // so we don't want to call the onRead() callback again. + if(ctxt->om->om_pkthdr_len > 8) { + pDescriptor->m_pCallbacks->onRead(pDescriptor); + } + portENTER_CRITICAL(&pDescriptor->m_valMux); rc = os_mbuf_append(ctxt->om, pDescriptor->getValue(), pDescriptor->getLength()); + portEXIT_CRITICAL(&pDescriptor->m_valMux); return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; } case BLE_GATT_ACCESS_OP_WRITE_DSC: { - if (ctxt->om->om_len > BLE_ATT_ATTR_MAX_LEN) { + if (ctxt->om->om_len > pDescriptor->m_value.attr_max_len) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } - pDescriptor->setValue(ctxt->om->om_data, ctxt->om->om_len); + uint8_t buf[pDescriptor->m_value.attr_max_len]; + size_t len = ctxt->om->om_len; + memcpy(buf, ctxt->om->om_data,len); + os_mbuf *next; + next = SLIST_NEXT(ctxt->om, om_next); + while(next != NULL){ + if((len + next->om_len) > pDescriptor->m_value.attr_max_len) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + memcpy(&buf[len-1], next->om_data, next->om_len); + len += next->om_len; + next = SLIST_NEXT(next, om_next); + } + + pDescriptor->setValue(buf, len); pDescriptor->m_pCallbacks->onWrite(pDescriptor); return 0; } @@ -191,12 +212,14 @@ void NimBLEDescriptor::setHandle(uint16_t handle) { * @param [in] length The length of the data in bytes. */ void NimBLEDescriptor::setValue(const uint8_t* data, size_t length) { - if (length > BLE_ATT_ATTR_MAX_LEN) { - NIMBLE_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, BLE_ATT_ATTR_MAX_LEN); + if (length > m_value.attr_max_len) { + NIMBLE_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, m_value.attr_max_len); return; } + portENTER_CRITICAL(&m_valMux); m_value.attr_len = length; memcpy(m_value.attr_value, data, length); + portEXIT_CRITICAL(&m_valMux); } // setValue @@ -209,13 +232,6 @@ void NimBLEDescriptor::setValue(const std::string &value) { } // setValue -/* -void NimBLEDescriptor::setAccessPermissions(uint8_t perm) { - m_permissions = perm; -} -*/ - - /** * @brief Return a string representation of the descriptor. * @return A string representation of the descriptor. diff --git a/src/NimBLEDescriptor.h b/src/NimBLEDescriptor.h index 8af3560..870fc65 100644 --- a/src/NimBLEDescriptor.h +++ b/src/NimBLEDescriptor.h @@ -29,13 +29,11 @@ typedef struct { - uint16_t attr_max_len; /*!< attribute max value length */ - uint16_t attr_len; /*!< attribute current value length */ - uint8_t *attr_value; /*!< the pointer to attribute value */ + uint16_t attr_max_len; /*!< attribute max value length */ + uint16_t attr_len; /*!< attribute current value length */ + uint8_t *attr_value; /*!< the pointer to attribute value */ } attr_value_t; -typedef attr_value_t esp_attr_value_t; /*!< compatibility for esp32 */ - class NimBLEService; class NimBLECharacteristic; class NimBLEDescriptorCallbacks; @@ -46,32 +44,34 @@ class NimBLEDescriptorCallbacks; */ class NimBLEDescriptor { public: - virtual ~NimBLEDescriptor(); - uint16_t getHandle(); // Get the handle of the descriptor. - size_t getLength(); // Get the length of the value of the descriptor. - NimBLEUUID getUUID(); // Get the UUID of the descriptor. - uint8_t* getValue(); // Get a pointer to the value of the descriptor. -// void setAccessPermissions(uint8_t perm); // Set the permissions of the descriptor. - void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks); // Set callbacks to be invoked for the descriptor. - void setValue(const uint8_t* data, size_t size); // Set the value of the descriptor as a pointer to data. - void setValue(const std::string &value); // Set the value of the descriptor as a data buffer. - - std::string toString(); // Convert the descriptor to a string representation. + uint16_t getHandle(); + size_t getLength(); + NimBLEUUID getUUID(); + uint8_t* getValue(); + void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks); + void setValue(const uint8_t* data, size_t size); + void setValue(const std::string &value); + std::string toString(); private: - friend class NimBLEDescriptorMap; friend class NimBLECharacteristic; friend class NimBLEService; friend class NimBLE2902; friend class NimBLE2904; NimBLEDescriptor(const char* uuid, uint16_t properties, - uint16_t max_len, - NimBLECharacteristic* pCharacteristic); + uint16_t max_len, + NimBLECharacteristic* pCharacteristic); NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties, - uint16_t max_len, - NimBLECharacteristic* pCharacteristic); + uint16_t max_len, + NimBLECharacteristic* pCharacteristic); + + ~NimBLEDescriptor(); + + static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg); + void setHandle(uint16_t handle); NimBLEUUID m_uuid; uint16_t m_handle; @@ -79,12 +79,8 @@ private: NimBLECharacteristic* m_pCharacteristic; uint8_t m_properties; attr_value_t m_value; - - static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, void *arg); - - void setHandle(uint16_t handle); -}; // BLEDescriptor + portMUX_TYPE m_valMux; +}; // NimBLEDescriptor /** diff --git a/src/NimBLEDescriptorMap.cpp b/src/NimBLEDescriptorMap.cpp deleted file mode 100644 index 0ca1cbe..0000000 --- a/src/NimBLEDescriptorMap.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * NimBLEDescriptorMap.cpp - * - * Created: on March 10, 2020 - * Author H2zero - * - * Originally: - * - * BLEDescriptorMap.cpp - * - * Created on: Jun 22, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include "nimconfig.h" -#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - -#include "NimBLECharacteristic.h" -#include "NimBLEDescriptor.h" - - -/** - * @brief Return the descriptor by UUID. - * @param [in] UUID The UUID to look up the descriptor. - * @return The descriptor. If not present, then nullptr is returned. - */ -NimBLEDescriptor* NimBLEDescriptorMap::getByUUID(const char* uuid) { - return getByUUID(NimBLEUUID(uuid)); -} - - -/** - * @brief Return the descriptor by UUID. - * @param [in] UUID The UUID to look up the descriptor. - * @return The descriptor. If not present, then nullptr is returned. - */ -NimBLEDescriptor* NimBLEDescriptorMap::getByUUID(const NimBLEUUID &uuid) { - for (auto &myPair : m_uuidMap) { - if (myPair.first->getUUID().equals(uuid)) { - return myPair.first; - } - } - return nullptr; -} // getByUUID - - -/** - * @brief Return the descriptor by handle. - * @param [in] handle The handle to look up the descriptor. - * @return The descriptor. - */ - /* -NimBLEDescriptor* NimBLEDescriptorMap::getByHandle(uint16_t handle) { - return m_handleMap.at(handle); -} // getByHandle -*/ - -/** - * @brief Set the descriptor by UUID. - * @param [in] uuid The uuid of the descriptor. - * @param [in] characteristic The descriptor to cache. - * @return N/A. - */ -void NimBLEDescriptorMap::setByUUID(const char* uuid, NimBLEDescriptor* pDescriptor){ - m_uuidMap.insert(std::pair(pDescriptor, uuid)); -} // setByUUID - - - -/** - * @brief Set the descriptor by UUID. - * @param [in] uuid The uuid of the descriptor. - * @param [in] characteristic The descriptor to cache. - * @return N/A. - */ -void NimBLEDescriptorMap::setByUUID(const NimBLEUUID &uuid, NimBLEDescriptor* pDescriptor) { - m_uuidMap.insert(std::pair(pDescriptor, uuid.toString())); -} // setByUUID - - -/** - * @brief Set the descriptor by handle. - * @param [in] handle The handle of the descriptor. - * @param [in] descriptor The descriptor to cache. - * @return N/A. - */ - /* -void NimBLEDescriptorMap::setByHandle(uint16_t handle, NimBLEDescriptor* pDescriptor) { - m_handleMap.insert(std::pair(handle, pDescriptor)); -} // setByHandle -*/ - - -/** - * @brief Get the number of descriptors in the map. - */ -uint8_t NimBLEDescriptorMap::getSize() { - return (uint8_t)m_uuidMap.size(); -} // getSize - - -/** - * @brief Return a string representation of the descriptor map. - * @return A string representation of the descriptor map. - */ -std::string NimBLEDescriptorMap::toString() { - std::string res; - char hex[5]; - int count = 0; - for (auto &myPair : m_uuidMap) { - if (count > 0) {res += "\n";} - snprintf(hex, sizeof(hex), "%04x", myPair.first->getHandle()); - count++; - res += "handle: 0x"; - res += hex; - res += ", uuid: " + myPair.first->getUUID().toString(); - } - return res; -} // toString - - -/** - * @brief Get the first descriptor in the map. - * @return The first descriptor in the map. - */ -NimBLEDescriptor* NimBLEDescriptorMap::getFirst() { - m_iterator = m_uuidMap.begin(); - if (m_iterator == m_uuidMap.end()) return nullptr; - NimBLEDescriptor* pRet = m_iterator->first; - m_iterator++; - return pRet; -} // getFirst - - -/** - * @brief Get the next descriptor in the map. - * @return The next descriptor in the map. - */ -NimBLEDescriptor* NimBLEDescriptorMap::getNext() { - if (m_iterator == m_uuidMap.end()) return nullptr; - NimBLEDescriptor* pRet = m_iterator->first; - m_iterator++; - return pRet; -} // getNext - -#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) -#endif /* CONFIG_BT_ENABLED */ diff --git a/src/NimBLEServer.cpp b/src/NimBLEServer.cpp index d731bad..f914bc5 100644 --- a/src/NimBLEServer.cpp +++ b/src/NimBLEServer.cpp @@ -19,7 +19,6 @@ #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) #include "NimBLEServer.h" -#include "NimBLE2902.h" #include "NimBLEUtils.h" #include "NimBLEDevice.h" #include "NimBLELog.h" @@ -32,51 +31,46 @@ static NimBLEServerCallbacks defaultCallbacks; * @brief Construct a %BLE Server * * This class is not designed to be individually instantiated. Instead one should create a server by asking - * the BLEDevice class. + * the NimBLEDevice class. */ NimBLEServer::NimBLEServer() { - m_connId = BLE_HS_CONN_HANDLE_NONE; - m_svcChgChrHdl = 0xffff; - m_pServerCallbacks = &defaultCallbacks; - m_gattsStarted = false; -} // BLEServer +// m_svcChgChrHdl = 0xffff; // Future Use + m_pServerCallbacks = &defaultCallbacks; + m_gattsStarted = false; + m_advertiseOnDisconnect = true; +} // NimBLEServer /** * @brief Create a %BLE Service. - * - * With a %BLE server, we can host one or more services. Invoking this function causes the creation of a definition - * of a new service. Every service must have a unique UUID. * @param [in] uuid The UUID of the new service. * @return A reference to the new service object. */ NimBLEService* NimBLEServer::createService(const char* uuid) { return createService(NimBLEUUID(uuid)); -} +} // createService /** * @brief Create a %BLE Service. - * - * With a %BLE server, we can host one or more services. Invoking this function causes the creation of a definition - * of a new service. Every service must have a unique UUID. * @param [in] uuid The UUID of the new service. * @param [in] numHandles The maximum number of handles associated with this service. - * @param [in] inst_id With multiple services with the same UUID we need to provide inst_id value different for each service. + * @param [in] inst_id if we have multiple services with the same UUID we need + * to provide inst_id value different for each service. * @return A reference to the new service object. */ NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid, uint32_t numHandles, uint8_t inst_id) { NIMBLE_LOGD(LOG_TAG, ">> createService - %s", uuid.toString().c_str()); - + // TODO: add functionality to use inst_id for multiple services with same uuid + (void)inst_id; // Check that a service with the supplied UUID does not already exist. - if (m_serviceMap.getByUUID(uuid) != nullptr) { - NIMBLE_LOGW(LOG_TAG, "<< Attempt to create a new service with uuid %s but a service with that UUID already exists.", - uuid.toString().c_str()); + if(getServiceByUUID(uuid) != nullptr) { + NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s", + std::string(uuid).c_str()); } NimBLEService* pService = new NimBLEService(uuid, numHandles, this); - pService->m_instId = inst_id; - m_serviceMap.setByUUID(uuid, pService); // Save a reference to this service being on this server. + m_svcVec.push_back(pService); // Save a reference to this service being on this server. NIMBLE_LOGD(LOG_TAG, "<< createService"); return pService; @@ -89,8 +83,8 @@ NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid, uint32_t numH * @return A reference to the service object. */ NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid) { - return m_serviceMap.getByUUID(uuid); -} + return getServiceByUUID(NimBLEUUID(uuid)); +} // getServiceByUUID /** @@ -99,8 +93,13 @@ NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid) { * @return A reference to the service object. */ NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid) { - return m_serviceMap.getByUUID(uuid); -} + for (auto &it : m_svcVec) { + if (it->getUUID() == uuid) { + return it; + } + } + return nullptr; +} // getServiceByUUID /** @@ -109,18 +108,8 @@ NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid) { * @return An advertising object. */ NimBLEAdvertising* NimBLEServer::getAdvertising() { - return BLEDevice::getAdvertising(); -} - - -/** - * @brief Retrieve the connection id of the last connected client. - * @todo Not very useful, should refactor or remove. - * @return Client connection id. - */ -uint16_t NimBLEServer::getConnId() { - return m_connId; -} + return NimBLEDevice::getAdvertising(); +} // getAdvertising /** @@ -143,6 +132,8 @@ void NimBLEServer::start() { #if CONFIG_LOG_DEFAULT_LEVEL > 3 || (ARDUINO_ARCH_ESP32 && CORE_DEBUG_LEVEL >= 4) ble_gatts_show_local(); #endif +/*** Future use *** + * TODO: implement service changed handling ble_uuid16_t svc = {BLE_UUID_TYPE_16, 0x1801}; ble_uuid16_t chr = {BLE_UUID_TYPE_16, 0x2a05}; @@ -155,36 +146,25 @@ void NimBLEServer::start() { } NIMBLE_LOGI(LOG_TAG, "Service changed characterisic handle: %d", m_svcChgChrHdl); +*/ + // Build a vector of characteristics with Notify / Indicate capabilities for event handling + for(auto &svc : m_svcVec) { + for(auto &chr : svc->m_chrVec) { + // if Notify / Indicate is enabled but we didn't create the descriptor + // we do it now. + if((chr->m_properties & BLE_GATT_CHR_F_INDICATE) || + (chr->m_properties & BLE_GATT_CHR_F_NOTIFY)) { - // Build a map of characteristics with Notify / Indicate capabilities for event handling - uint8_t numSvcs = m_serviceMap.getRegisteredServiceCount(); - NimBLEService* pService = m_serviceMap.getFirst(); - - for(int i = 0; i < numSvcs; i++) { - uint8_t numChrs = pService->m_characteristicMap.getSize(); - NimBLECharacteristic* pChr = pService->m_characteristicMap.getFirst(); - - if(pChr != nullptr) { - for( int d = 0; d < numChrs; d++) { - // if Notify / Indicate is enabled but we didn't create the descriptor - // we do it now. - if((pChr->m_properties & BLE_GATT_CHR_F_INDICATE) || - (pChr->m_properties & BLE_GATT_CHR_F_NOTIFY)) { - - if(nullptr == pChr->getDescriptorByUUID("2902")) { - pChr->createDescriptor("2902"); - } - m_notifyChrMap.insert(std::pair - (pChr->getHandle(), pChr)); + if(nullptr == chr->getDescriptorByUUID(uint16_t(0x2902))) { + chr->createDescriptor(uint16_t(0x2902)); } - pChr = pService->m_characteristicMap.getNext(); + m_notifyChrVec.push_back(chr); } } - pService = m_serviceMap.getNext(); } m_gattsStarted = true; -} +} // start /** @@ -204,15 +184,24 @@ int NimBLEServer::disconnect(uint16_t connId, uint8_t reason) { return rc; NIMBLE_LOGD(LOG_TAG, "<< disconnect()"); -} +} // disconnect + + +/** + * @brief Set the server to automatically start advertising when a client disconnects. + * @param [in] bool true == advertise, false == don't advertise. + */ +void NimBLEServer::advertiseOnDisconnect(bool aod) { + m_advertiseOnDisconnect = aod; +} // advertiseOnDisconnect /** * @brief Return the number of connected clients. * @return The number of connected clients. */ -uint32_t NimBLEServer::getConnectedCount() { - return m_connectedServersMap.size(); +size_t NimBLEServer::getConnectedCount() { + return m_connectedPeersVec.size(); } // getConnectedCount @@ -227,7 +216,7 @@ uint32_t NimBLEServer::getConnectedCount() { /*STATIC*/int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) { NimBLEServer* server = (NimBLEServer*)arg; NIMBLE_LOGD(LOG_TAG, ">> handleGapEvent: %s", - NimBLEUtils::gapEventToString(event->type)); + NimBLEUtils::gapEventToString(event->type)); int rc = 0; struct ble_gap_conn_desc desc; @@ -236,13 +225,11 @@ uint32_t NimBLEServer::getConnectedCount() { case BLE_GAP_EVENT_CONNECT: { if (event->connect.status != 0) { /* Connection failed; resume advertising */ - NIMBLE_LOGC(LOG_TAG, "Connection failed"); + NIMBLE_LOGE(LOG_TAG, "Connection failed"); NimBLEDevice::startAdvertising(); - server->m_connId = BLE_HS_CONN_HANDLE_NONE; } else { - server->m_connId = event->connect.conn_handle; - server->addPeerDevice((void*)server, false, server->m_connId); + server->m_connectedPeersVec.push_back(event->connect.conn_handle); ble_gap_conn_desc desc; rc = ble_gap_conn_find(event->connect.conn_handle, &desc); @@ -271,10 +258,15 @@ uint32_t NimBLEServer::getConnectedCount() { break; } - server->removePeerDevice(event->disconnect.conn.conn_handle, false); - server->m_connId = BLE_HS_CONN_HANDLE_NONE; + server->m_connectedPeersVec.erase(std::remove(server->m_connectedPeersVec.begin(), + server->m_connectedPeersVec.end(), + event->disconnect.conn.conn_handle), + server->m_connectedPeersVec.end()); server->m_pServerCallbacks->onDisconnect(server); + if(server->m_advertiseOnDisconnect) { + server->startAdvertising(); + } return 0; } // BLE_GAP_EVENT_DISCONNECT @@ -283,9 +275,11 @@ uint32_t NimBLEServer::getConnectedCount() { "val_handle=%d\n", event->subscribe.cur_notify, event->subscribe.attr_handle); - auto it = server->m_notifyChrMap.find(event->subscribe.attr_handle); - if(it != server->m_notifyChrMap.cend()) { - (*it).second->setSubscribe(event); + for(auto &it : server->m_notifyChrVec) { + if(it->getHandle() == event->subscribe.attr_handle) { + it->setSubscribe(event); + break; + } } return 0; @@ -295,15 +289,18 @@ uint32_t NimBLEServer::getConnectedCount() { NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d", event->mtu.conn_handle, event->mtu.value); - server->updatePeerMTU(event->mtu.conn_handle, event->mtu.value); return 0; } // BLE_GAP_EVENT_MTU case BLE_GAP_EVENT_NOTIFY_TX: { if(event->notify_tx.indication && event->notify_tx.status != 0) { - auto it = server->m_notifyChrMap.find(event->notify_tx.attr_handle); - if(it != server->m_notifyChrMap.cend()) { - (*it).second->m_semaphoreConfEvt.give(event->notify_tx.status); + for(auto &it : server->m_notifyChrVec) { + if(it->getHandle() == event->notify_tx.attr_handle) { + if(it->m_pIndSemaphore != nullptr) { + it->m_pIndSemaphore->give(event->notify_tx.status); + } + break; + } } } @@ -349,7 +346,7 @@ uint32_t NimBLEServer::getConnectedCount() { } // BLE_GAP_EVENT_ENC_CHANGE case BLE_GAP_EVENT_PASSKEY_ACTION: { - struct ble_sm_io pkey = {0}; + struct ble_sm_io pkey = {0,0}; if (event->passkey.params.action == BLE_SM_IOACT_DISP) { pkey.action = event->passkey.params.action; @@ -416,7 +413,7 @@ uint32_t NimBLEServer::getConnectedCount() { NIMBLE_LOGD(LOG_TAG, "<< handleGATTServerEvent"); return 0; -} // handleGATTServerEvent +} // handleGapEvent /** @@ -437,18 +434,6 @@ void NimBLEServer::setCallbacks(NimBLEServerCallbacks* pCallbacks) { } // setCallbacks -/* - * Remove service - */ -/* -void BLEServer::removeService(BLEService* service) { - service->stop(); - service->executeDelete(); - m_serviceMap.removeService(service); -} -*/ - - /** * @brief Start advertising. * @@ -456,9 +441,7 @@ void BLEServer::removeService(BLEService* service) { * retrieving the advertising object and invoking start upon it. */ void NimBLEServer::startAdvertising() { - NIMBLE_LOGD(LOG_TAG, ">> startAdvertising"); NimBLEDevice::startAdvertising(); - NIMBLE_LOGD(LOG_TAG, "<< startAdvertising"); } // startAdvertising @@ -466,38 +449,43 @@ void NimBLEServer::startAdvertising() { * @brief Stop advertising. */ void NimBLEServer::stopAdvertising() { - NIMBLE_LOGD(LOG_TAG, ">> stopAdvertising"); NimBLEDevice::stopAdvertising(); - NIMBLE_LOGD(LOG_TAG, "<< stopAdvertising"); } // startAdvertising /** - * Allow to connect GATT server to peer device - * Probably can be used in ANCS for iPhone + * @brief Get the MTU of the client. + * @returns The client MTU or 0 if not found/connected. */ - /* -bool BLEServer::connect(BLEAddress address) { - esp_bd_addr_t addr; - memcpy(&addr, address.getNative(), 6); - // Perform the open connection request against the target BLE Server. - m_semaphoreOpenEvt.take("connect"); - esp_err_t errRc = ::esp_ble_gatts_open( - getGattsIf(), - addr, // address - 1 // direct connection - ); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gattc_open: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return false; +uint16_t NimBLEServer::getPeerMTU(uint16_t conn_id) { + return ble_att_mtu(conn_id); +} //getPeerMTU + + +/** + * Update connection parameters can be called only after connection has been established + */ +void NimBLEServer::updateConnParams(uint16_t conn_handle, + uint16_t minInterval, uint16_t maxInterval, + uint16_t latency, uint16_t timeout) +{ + ble_gap_upd_params params; + + params.latency = latency; + params.itvl_max = maxInterval; // max_int = 0x20*1.25ms = 40ms + params.itvl_min = minInterval; // min_int = 0x10*1.25ms = 20ms + params.supervision_timeout = timeout; // timeout = 400*10ms = 4000ms + params.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; // Minimum length of connection event in 0.625ms units + params.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units + + int rc = ble_gap_update_params(conn_handle, ¶ms); + if(rc != 0) { + NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc)); } +} // updateConnParams - uint32_t rc = m_semaphoreOpenEvt.wait("connect"); // Wait for the connection to complete. - ESP_LOGD(LOG_TAG, "<< connect(), rc=%d", rc==ESP_GATT_OK); - return rc == ESP_GATT_OK; -} // connect -*/ +/** Default callback handlers */ void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer) { NIMBLE_LOGD("NimBLEServerCallbacks", "onConnect(): Default"); @@ -534,80 +522,6 @@ bool NimBLEServerCallbacks::onConfirmPIN(uint32_t pin){ return true; } -/* multi connect support */ -void NimBLEServer::updatePeerMTU(uint16_t conn_id, uint16_t mtu) { - const std::map::iterator it = m_connectedServersMap.find(conn_id); - if (it != m_connectedServersMap.end()) { - it->second.mtu = mtu; - } -} - -std::map NimBLEServer::getPeerDevices() { - return m_connectedServersMap; -} - - -/** - * @brief Get the MTU of the client. - * @returns The client MTU or 0 if not found/connected. - */ -uint16_t NimBLEServer::getPeerMTU(uint16_t conn_id) { - auto it = m_connectedServersMap.find(conn_id); - if(it != m_connectedServersMap.cend()) { - return (*it).second.mtu; - } else { - return 0; - } -} - -void NimBLEServer::addPeerDevice(void* peer, bool _client, uint16_t conn_id) { - conn_status_t status = { - .peer_device = peer, - .connected = true, - .mtu = 23 - }; - - m_connectedServersMap.insert(std::pair(conn_id, status)); -} - -void NimBLEServer::removePeerDevice(uint16_t conn_id, bool _client) { - m_connectedServersMap.erase(conn_id); -} -/* multi connect support */ - - -/** - * Update connection parameters can be called only after connection has been established - */ -void NimBLEServer::updateConnParams(uint16_t conn_handle, - uint16_t minInterval, uint16_t maxInterval, - uint16_t latency, uint16_t timeout, - uint16_t minConnTime, uint16_t maxConnTime) -{ - ble_gap_upd_params params; - - params.latency = latency; - params.itvl_max = maxInterval; // max_int = 0x20*1.25ms = 40ms - params.itvl_min = minInterval; // min_int = 0x10*1.25ms = 20ms - params.supervision_timeout = timeout; // timeout = 400*10ms = 4000ms - params.min_ce_len = minConnTime; // Minimum length of connection event in 0.625ms units - params.max_ce_len = maxConnTime; // Maximum length of connection event in 0.625ms units - - int rc = ble_gap_update_params(conn_handle, ¶ms); - if(rc != 0) { - NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc)); - } -} - -/* Don't think this is needed - -void NimBLEServer::onHostReset() { - for(auto it = m_notifyChrMap.cbegin(); it != m_notifyChrMap.cend(); ++it) { - (*it).second->m_semaphoreConfEvt.give(0); - } - -} -*/ #endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) #endif // CONFIG_BT_ENABLED diff --git a/src/NimBLEServer.h b/src/NimBLEServer.h index 903eb23..1f95c4a 100644 --- a/src/NimBLEServer.h +++ b/src/NimBLEServer.h @@ -21,102 +21,58 @@ #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) #include "NimBLEAddress.h" -#include "NimBLEUUID.h" #include "NimBLEAdvertising.h" #include "NimBLEService.h" #include "NimBLESecurity.h" #include "FreeRTOS.h" -#include - class NimBLEService; class NimBLECharacteristic; class NimBLEServerCallbacks; -/* TODO possibly refactor this struct */ -typedef struct { - void *peer_device; // peer device BLEClient or BLEServer - maybe its better to have 2 structures or union here - bool connected; // do we need it? - uint16_t mtu; // every peer device negotiate own mtu -} conn_status_t; - - -/** - * @brief A data structure that manages the %BLE servers owned by a BLE server. - */ -class NimBLEServiceMap { -public: -// NimBLEService* getByHandle(uint16_t handle); - NimBLEService* getByUUID(const char* uuid); - NimBLEService* getByUUID(const NimBLEUUID &uuid, uint8_t inst_id = 0); -// void setByHandle(uint16_t handle, NimBLEService* service); - void setByUUID(const char* uuid, NimBLEService* service); - void setByUUID(const NimBLEUUID &uuid, NimBLEService* service); - std::string toString(); - NimBLEService* getFirst(); - NimBLEService* getNext(); - void removeService(NimBLEService *service); - int getRegisteredServiceCount(); - -private: -// std::map m_handleMap; - std::map m_uuidMap; - std::map::iterator m_iterator; -}; - /** * @brief The model of a %BLE server. */ class NimBLEServer { public: - uint32_t getConnectedCount(); - NimBLEService* createService(const char* uuid); - NimBLEService* createService(const NimBLEUUID &uuid, uint32_t numHandles=15, uint8_t inst_id=0); - NimBLEAdvertising* getAdvertising(); - void setCallbacks(NimBLEServerCallbacks* pCallbacks); - void startAdvertising(); - void stopAdvertising(); - void start(); -// void removeService(BLEService* service); - NimBLEService* getServiceByUUID(const char* uuid); - NimBLEService* getServiceByUUID(const NimBLEUUID &uuid); - int disconnect(uint16_t connID, uint8_t reason = BLE_ERR_REM_USER_CONN_TERM); -// bool connect(BLEAddress address); - void updateConnParams(uint16_t conn_handle, - uint16_t minInterval, uint16_t maxInterval, - uint16_t latency, uint16_t timeout, - uint16_t minConnTime=0, uint16_t maxConnTime=0); - - /* multi connection support */ - std::map getPeerDevices(); - void addPeerDevice(void* peer, bool is_client, uint16_t conn_id); - void removePeerDevice(uint16_t conn_id, bool client); - NimBLEServer* getServerByConnId(uint16_t conn_id); - void updatePeerMTU(uint16_t connId, uint16_t mtu); - uint16_t getPeerMTU(uint16_t conn_id); - uint16_t getConnId(); - + size_t getConnectedCount(); + NimBLEService* createService(const char* uuid); + NimBLEService* createService(const NimBLEUUID &uuid, uint32_t numHandles=15, + uint8_t inst_id=0); + NimBLEAdvertising* getAdvertising(); + void setCallbacks(NimBLEServerCallbacks* pCallbacks); + void startAdvertising(); + void stopAdvertising(); + void start(); + NimBLEService* getServiceByUUID(const char* uuid); + NimBLEService* getServiceByUUID(const NimBLEUUID &uuid); + int disconnect(uint16_t connID, + uint8_t reason = BLE_ERR_REM_USER_CONN_TERM); + void updateConnParams(uint16_t conn_handle, + uint16_t minInterval, uint16_t maxInterval, + uint16_t latency, uint16_t timeout); + uint16_t getPeerMTU(uint16_t conn_id); + std::vector getPeerDevices(); + void advertiseOnDisconnect(bool); private: NimBLEServer(); - //friend class BLEService; - friend class NimBLECharacteristic; - friend class NimBLEDevice; - friend class NimBLEAdvertising; - // void onHostReset(); - // BLEAdvertising m_bleAdvertising; - uint16_t m_connId; - uint16_t m_svcChgChrHdl; + friend class NimBLECharacteristic; + friend class NimBLEDevice; + friend class NimBLEAdvertising; + bool m_gattsStarted; - - std::map m_connectedServersMap; - std::map m_notifyChrMap; - - NimBLEServiceMap m_serviceMap; + bool m_advertiseOnDisconnect; NimBLEServerCallbacks* m_pServerCallbacks; + std::vector m_connectedPeersVec; - static int handleGapEvent(struct ble_gap_event *event, void *arg); +// uint16_t m_svcChgChrHdl; // Future use + + std::vector m_svcVec; + std::vector m_notifyChrVec; + + static int handleGapEvent(struct ble_gap_event *event, void *arg); }; // NimBLEServer @@ -149,7 +105,7 @@ public: virtual bool onSecurityRequest(); //{return true;} virtual void onAuthenticationComplete(ble_gap_conn_desc* desc);//{}; virtual bool onConfirmPIN(uint32_t pin);//{return true;} -}; // BLEServerCallbacks +}; // NimBLEServerCallbacks #endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) diff --git a/src/NimBLEService.cpp b/src/NimBLEService.cpp index 6036a38..c2631ab 100644 --- a/src/NimBLEService.cpp +++ b/src/NimBLEService.cpp @@ -32,9 +32,10 @@ static const char* LOG_TAG = "NimBLEService"; // Tag for logging. /** - * @brief Construct an instance of the BLEService + * @brief Construct an instance of the NimBLEService * @param [in] uuid The UUID of the service. * @param [in] numHandles The maximum number of handles associated with the service. + * @param [in] a pointer to the server instance that this service belongs to. */ NimBLEService::NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer) : NimBLEService(NimBLEUUID(uuid), numHandles, pServer) { @@ -45,11 +46,12 @@ NimBLEService::NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer * @brief Construct an instance of the BLEService * @param [in] uuid The UUID of the service. * @param [in] numHandles The maximum number of handles associated with the service. + * @param [in] a pointer to the server instance that this service belongs to. */ NimBLEService::NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLEServer* pServer) { - m_uuid = uuid; - m_handle = NULL_HANDLE; - m_pServer = pServer; + m_uuid = uuid; + m_handle = NULL_HANDLE; + m_pServer = pServer; m_numHandles = numHandles; } // NimBLEService @@ -59,10 +61,22 @@ NimBLEService::NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLE * @return N/A. */ void NimBLEService::dump() { - NIMBLE_LOGD(LOG_TAG, "Service: uuid:%s, handle: 0x%.2x", + NIMBLE_LOGD(LOG_TAG, "Service: uuid:%s, handle: 0x%2x", m_uuid.toString().c_str(), m_handle); - NIMBLE_LOGD(LOG_TAG, "Characteristics:\n%s", m_characteristicMap.toString().c_str()); + + std::string res; + int count = 0; + char hex[5]; + for (auto &it: m_chrVec) { + if (count > 0) {res += "\n";} + snprintf(hex, sizeof(hex), "%04x", it->getHandle()); + count++; + res += "handle: 0x"; + res += hex; + res += ", uuid: " + std::string(it->getUUID()); + } + NIMBLE_LOGD(LOG_TAG, "Characteristics:\n%s", res.c_str()); } // dump @@ -76,10 +90,9 @@ NimBLEUUID NimBLEService::getUUID() { /** - * @brief Start the service. - * Here we wish to start the service which means that we will respond to partner requests about it. - * Starting a service also means that we can create the corresponding characteristics. - * @return Start the service. + * @brief Builds the database of characteristics/descriptors for the service + * and registers it with the NimBLE stack. + * @return bool success/failure . */ bool NimBLEService::start() { @@ -96,7 +109,7 @@ bool NimBLEService::start() { svc[0].uuid = &m_uuid.getNative()->u; svc[0].includes = NULL; - uint8_t numChrs = m_characteristicMap.getSize(); + size_t numChrs = m_chrVec.size(); NIMBLE_LOGD(LOG_TAG,"Adding %d characteristics for service %s", numChrs, toString().c_str()); @@ -107,16 +120,17 @@ bool NimBLEService::start() { // of the characteristics for the service. We create 1 extra and set it to null // for this purpose. pChr_a = new ble_gatt_chr_def[numChrs+1]; - NimBLECharacteristic* pCharacteristic = m_characteristicMap.getFirst(); + NimBLECharacteristic* pCharacteristic = *m_chrVec.begin(); - for(uint8_t i=0; i < numChrs; i++) { - uint8_t numDscs = pCharacteristic->m_descriptorMap.getSize(); + for(uint8_t i=0; i < numChrs;) { + uint8_t numDscs = pCharacteristic->m_dscVec.size(); if(numDscs) { // skip 2902 as it's automatically created by NimBLE // if Indicate or Notify flags are set if(((pCharacteristic->m_properties & BLE_GATT_CHR_F_INDICATE) || (pCharacteristic->m_properties & BLE_GATT_CHR_F_NOTIFY)) && - pCharacteristic->getDescriptorByUUID("2902") != nullptr) { + pCharacteristic->getDescriptorByUUID("2902") != nullptr) + { numDscs--; } } @@ -127,12 +141,12 @@ bool NimBLEService::start() { // Must have last descriptor uuid = 0 so we have to create 1 extra //NIMBLE_LOGD(LOG_TAG, "Adding %d descriptors", numDscs); pDsc_a = new ble_gatt_dsc_def[numDscs+1]; - NimBLEDescriptor* pDescriptor = pCharacteristic->m_descriptorMap.getFirst(); + NimBLEDescriptor* pDescriptor = *pCharacteristic->m_dscVec.begin(); for(uint8_t d=0; d < numDscs;) { // skip 2902 - if(pDescriptor->m_uuid.equals(NimBLEUUID((uint16_t)0x2902))) { + if(pDescriptor->m_uuid == NimBLEUUID(uint16_t(0x2902))) { //NIMBLE_LOGD(LOG_TAG, "Skipped 0x2902"); - pDescriptor = pCharacteristic->m_descriptorMap.getNext(); + pDescriptor = *(pCharacteristic->m_dscVec.begin()+d+1); continue; } pDsc_a[d].uuid = &pDescriptor->m_uuid.getNative()->u; @@ -140,8 +154,8 @@ bool NimBLEService::start() { pDsc_a[d].min_key_size = 0; pDsc_a[d].access_cb = NimBLEDescriptor::handleGapEvent; pDsc_a[d].arg = pDescriptor; - pDescriptor = pCharacteristic->m_descriptorMap.getNext(); d++; + pDescriptor = *(pCharacteristic->m_dscVec.begin() + d); } pDsc_a[numDscs].uuid = NULL; @@ -154,7 +168,8 @@ bool NimBLEService::start() { pChr_a[i].flags = pCharacteristic->m_properties; pChr_a[i].min_key_size = 0; pChr_a[i].val_handle = &pCharacteristic->m_handle; - pCharacteristic = m_characteristicMap.getNext(); + i++; + pCharacteristic = *(m_chrVec.begin() + i); } pChr_a[numChrs].uuid = NULL; @@ -182,21 +197,6 @@ bool NimBLEService::start() { } // start -/** - * @brief Set the handle associated with this service. - * @param [in] handle The handle associated with the service. - */ -void NimBLEService::setHandle(uint16_t handle) { - NIMBLE_LOGD(LOG_TAG, ">> setHandle - Handle=0x%.2x, service UUID=%s)", handle, getUUID().toString().c_str()); - if (m_handle != NULL_HANDLE) { - NIMBLE_LOGE(LOG_TAG, "!!! Handle is already set %.2x", m_handle); - return; - } - m_handle = handle; - NIMBLE_LOGD(LOG_TAG, "<< setHandle"); -} // setHandle - - /** * @brief Get the handle associated with this service. * @return The handle associated with this service. @@ -206,34 +206,6 @@ uint16_t NimBLEService::getHandle() { } // getHandle -/** - * @brief Add a characteristic to the service. - * @param [in] pCharacteristic A pointer to the characteristic to be added. - */ -void NimBLEService::addCharacteristic(NimBLECharacteristic* pCharacteristic) { - // We maintain a mapping of characteristics owned by this service. These are managed by the - // BLECharacteristicMap class instance found in m_characteristicMap. We add the characteristic - // to the map and then ask the service to add the characteristic at the BLE level (ESP-IDF). - - NIMBLE_LOGD(LOG_TAG, ">> addCharacteristic()"); - NIMBLE_LOGD(LOG_TAG, "Adding characteristic: uuid=%s to service: %s", - pCharacteristic->getUUID().toString().c_str(), - toString().c_str()); - - // Check that we don't add the same characteristic twice. - if (m_characteristicMap.getByUUID(pCharacteristic->getUUID()) != nullptr) { - NIMBLE_LOGW(LOG_TAG, "<< Adding a new characteristic with the same UUID as a previous one"); - //return; - } - - // Remember this characteristic in our map of characteristics. At this point, we can lookup by UUID - // but not by handle. The handle is allocated to us on the ESP_GATTS_ADD_CHAR_EVT. - m_characteristicMap.setByUUID(pCharacteristic, pCharacteristic->getUUID()); - - NIMBLE_LOGD(LOG_TAG, "<< addCharacteristic()"); -} // addCharacteristic - - /** * @brief Create a new BLE Characteristic associated with this service. * @param [in] uuid - The UUID of the characteristic. @@ -253,8 +225,15 @@ NimBLECharacteristic* NimBLEService::createCharacteristic(const char* uuid, uint */ NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid, uint32_t properties) { NimBLECharacteristic* pCharacteristic = new NimBLECharacteristic(uuid, properties, this); - addCharacteristic(pCharacteristic); - //pCharacteristic->executeCreate(this); + // Check that we don't add the same characteristic twice. + if (getCharacteristic(uuid) != nullptr) { + NIMBLE_LOGW(LOG_TAG, "<< Adding a duplicate characteristic with UUID: %s", + std::string(uuid).c_str()); + } + + // Remember this characteristic in our vector of characteristics. + m_chrVec.push_back(pCharacteristic); + return pCharacteristic; } // createCharacteristic @@ -265,7 +244,13 @@ NimBLECharacteristic* NimBLEService::getCharacteristic(const char* uuid) { NimBLECharacteristic* NimBLEService::getCharacteristic(const NimBLEUUID &uuid) { - return m_characteristicMap.getByUUID(uuid); + for (auto &it : m_chrVec) { + if (it->getUUID() == uuid) { + return it; + } + } + + return nullptr; } diff --git a/src/NimBLEService.h b/src/NimBLEService.h index 1cb0f61..1b496f4 100644 --- a/src/NimBLEService.h +++ b/src/NimBLEService.h @@ -29,28 +29,6 @@ class NimBLEServer; class NimBLECharacteristic; -/** - * @brief A data mapping used to manage the set of %BLE characteristics known to the server. - */ -class NimBLECharacteristicMap { -public: - void setByUUID(NimBLECharacteristic* pCharacteristic, const char* uuid); - void setByUUID(NimBLECharacteristic* pCharacteristic, const NimBLEUUID &uuid); - void setByHandle(uint16_t handle, NimBLECharacteristic* pCharacteristic); - NimBLECharacteristic* getByUUID(const char* uuid); - NimBLECharacteristic* getByUUID(const NimBLEUUID &uuid); - NimBLECharacteristic* getByHandle(uint16_t handle); - NimBLECharacteristic* getFirst(); - NimBLECharacteristic* getNext(); - uint8_t getSize(); - std::string toString(); - -private: - std::map m_uuidMap; - std::map m_handleMap; - std::map::iterator m_iterator; -}; - /** * @brief The model of a %BLE service. @@ -59,40 +37,39 @@ private: class NimBLEService { public: NimBLECharacteristic* createCharacteristic(const char* uuid, - uint32_t properties = NIMBLE_PROPERTY::READ | + uint32_t properties = + NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE); NimBLECharacteristic* createCharacteristic(const NimBLEUUID &uuid, - uint32_t properties = NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::WRITE); + uint32_t properties = + NIMBLE_PROPERTY::READ | + NIMBLE_PROPERTY::WRITE); - void dump(); + void dump(); NimBLECharacteristic* getCharacteristic(const char* uuid); NimBLECharacteristic* getCharacteristic(const NimBLEUUID &uuid); NimBLEUUID getUUID(); NimBLEServer* getServer(); - bool start(); -// void stop(); - std::string toString(); - uint16_t getHandle(); - uint8_t m_instId = 0; + bool start(); + std::string toString(); + uint16_t getHandle(); private: NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer); NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLEServer* pServer); - friend class NimBLEServer; - friend class NimBLEDevice; - void addCharacteristic(NimBLECharacteristic* pCharacteristic); + friend class NimBLEServer; + friend class NimBLEDevice; - NimBLECharacteristicMap m_characteristicMap; - uint16_t m_handle; - NimBLEServer* m_pServer = nullptr; - NimBLEUUID m_uuid; + uint16_t m_handle; + NimBLEServer* m_pServer; + NimBLEUUID m_uuid; + uint16_t m_numHandles; - uint16_t m_numHandles; - void setHandle(uint16_t handle); -}; // BLEService + std::vector m_chrVec; + +}; // NimBLEService #endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) diff --git a/src/NimBLEServiceMap.cpp b/src/NimBLEServiceMap.cpp deleted file mode 100644 index e5b96e6..0000000 --- a/src/NimBLEServiceMap.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/* - * NimBLEService.cpp - * - * Created: on March 7, 2020 - * Author H2zero - * - * Originally: - * - * BLEServiceMap.cpp - * - * Created on: Jun 22, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include "nimconfig.h" -#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - -#include "NimBLEService.h" - - -/** - * @brief Return the service by UUID. - * @param [in] UUID The UUID to look up the service. - * @return The characteristic. - */ -NimBLEService* NimBLEServiceMap::getByUUID(const char* uuid) { - return getByUUID(NimBLEUUID(uuid)); -} - -/** - * @brief Return the service by UUID. - * @param [in] UUID The UUID to look up the service. - * @return The characteristic. - */ -NimBLEService* NimBLEServiceMap::getByUUID(const NimBLEUUID &uuid, uint8_t inst_id) { - for (auto &myPair : m_uuidMap) { - if (myPair.first->getUUID().equals(uuid)) { - return myPair.first; - } - } - //return m_uuidMap.at(uuid.toString()); - return nullptr; -} // getByUUID - - -/** - * @brief Return the service by handle. - * @param [in] handle The handle to look up the service. - * @return The service. - */ -/* -NimBLEService* NimBLEServiceMap::getByHandle(uint16_t handle) { - return m_handleMap.at(handle); -} // getByHandle -*/ - -/** - * @brief Set the service by UUID. - * @param [in] uuid The uuid of the service. - * @param [in] characteristic The service to cache. - * @return N/A. - */ -void NimBLEServiceMap::setByUUID(const NimBLEUUID &uuid, NimBLEService* service) { - m_uuidMap.insert(std::pair(service, uuid.toString())); -} // setByUUID - - -/** - * @brief Set the service by handle. - * @param [in] handle The handle of the service. - * @param [in] service The service to cache. - * @return N/A. - */ - /* -void NimBLEServiceMap::setByHandle(uint16_t handle, NimBLEService* service) { - m_handleMap.insert(std::pair(handle, service)); -} // setByHandle -*/ - -/** - * @brief Return a string representation of the service map. - * @return A string representation of the service map. - */ -std::string NimBLEServiceMap::toString() { - std::string res; - //char hex[5]; - for (auto &myPair: m_uuidMap) { - // res += "handle: 0x"; - // snprintf(hex, sizeof(hex), "%04x", myPair.first); - // res += hex; - res += ", uuid: " + myPair.second + "\n"; - } - return res; -} // toString - - -/** - * @brief Get the first service in the map. - * @return The first service in the map. - */ -NimBLEService* NimBLEServiceMap::getFirst() { - m_iterator = m_uuidMap.begin(); - if (m_iterator == m_uuidMap.end()) return nullptr; - NimBLEService* pRet = m_iterator->first; - m_iterator++; - return pRet; -} // getFirst - - -/** - * @brief Get the next service in the map. - * @return The next service in the map. - */ -NimBLEService* NimBLEServiceMap::getNext() { - if (m_iterator == m_uuidMap.end()) return nullptr; - NimBLEService* pRet = m_iterator->first; - m_iterator++; - return pRet; -} // getNext - - -/** - * @brief Removes service from maps. - * @return N/A. - */ -void NimBLEServiceMap::removeService(NimBLEService* service) { - //m_handleMap.erase(service->getHandle()); - m_uuidMap.erase(service); -} // removeService - - -/** - * @brief Returns the amount of registered services - * @return amount of registered services - */ -int NimBLEServiceMap::getRegisteredServiceCount(){ - //return m_handleMap.size(); - return m_uuidMap.size(); -} - - -#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) -#endif /* CONFIG_BT_ENABLED */ diff --git a/src/NimBLEValue.cpp b/src/NimBLEValue.cpp deleted file mode 100644 index aa437c6..0000000 --- a/src/NimBLEValue.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * NimNimBLEValue.cpp - * - * Created: on March 6, 2020 - * Author H2zero - * - * Originally: - * - * BLEValue.cpp - * - * Created on: Jul 17, 2017 - * Author: kolban - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include "nimconfig.h" -#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - -#include "NimBLEValue.h" -#include "NimBLELog.h" - -static const char* LOG_TAG="NimBLEValue"; - -NimBLEValue::NimBLEValue() { - m_accumulation = ""; - m_value = ""; - m_readOffset = 0; -} // NimBLEValue - - -/** - * @brief Add a message part to the accumulation. - * The accumulation is a growing set of data that is added to until a commit or cancel. - * @param [in] part A message part being added. - */ -void NimBLEValue::addPart(const std::string &part) { - NIMBLE_LOGD(LOG_TAG, ">> addPart: length=%d", part.length()); - m_accumulation += part; -} // addPart - - -/** - * @brief Add a message part to the accumulation. - * The accumulation is a growing set of data that is added to until a commit or cancel. - * @param [in] pData A message part being added. - * @param [in] length The number of bytes being added. - */ -void NimBLEValue::addPart(const uint8_t* pData, size_t length) { - NIMBLE_LOGD(LOG_TAG, ">> addPart: length=%d", length); - m_accumulation += std::string((char*) pData, length); -} // addPart - - -/** - * @brief Cancel the current accumulation. - */ -void NimBLEValue::cancel() { - NIMBLE_LOGD(LOG_TAG, ">> cancel"); - m_accumulation = ""; - m_readOffset = 0; -} // cancel - - -/** - * @brief Commit the current accumulation. - * When writing a value, we may find that we write it in "parts" meaning that the writes come in in pieces - * of the overall message. After the last part has been received, we may perform a commit which means that - * we now have the complete message and commit the change as a unit. - */ -void NimBLEValue::commit() { - NIMBLE_LOGD(LOG_TAG, ">> commit"); - // If there is nothing to commit, do nothing. - if (m_accumulation.length() == 0) return; - setValue(m_accumulation); - m_accumulation = ""; - m_readOffset = 0; -} // commit - - -/** - * @brief Get a pointer to the data. - * @return A pointer to the data. - */ -uint8_t* NimBLEValue::getData() { - return (uint8_t*) m_value.data(); -} - - -/** - * @brief Get the length of the data in bytes. - * @return The length of the data in bytes. - */ -size_t NimBLEValue::getLength() { - return m_value.length(); -} // getLength - - -/** - * @brief Get the read offset. - * @return The read offset into the read. - */ -uint16_t NimBLEValue::getReadOffset() { - return m_readOffset; -} // getReadOffset - - -/** - * @brief Get the current value. - */ -std::string NimBLEValue::getValue() { - return m_value; -} // getValue - - -/** - * @brief Set the read offset - * @param [in] readOffset The offset into the read. - */ -void NimBLEValue::setReadOffset(uint16_t readOffset) { - m_readOffset = readOffset; -} // setReadOffset - - -/** - * @brief Set the current value. - */ -void NimBLEValue::setValue(const std::string &value) { - m_value = value; -} // setValue - - -/** - * @brief Set the current value. - * @param [in] pData The data for the current value. - * @param [in] The length of the new current value. - */ -void NimBLEValue::setValue(const uint8_t* pData, size_t length) { - m_value = std::string((char*) pData, length); -} // setValue - -#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) -#endif // CONFIG_BT_ENABLED diff --git a/src/NimBLEValue.h b/src/NimBLEValue.h deleted file mode 100644 index 4fdeb9b..0000000 --- a/src/NimBLEValue.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * NimBLEValue.h - * - * Created: on March 6, 2020 - * Author H2zero - * - * Originally: - * - * BLEValue.h - * - * Created on: Jul 17, 2017 - * Author: kolban - */ - -#ifndef MAIN_BLEVALUE_H_ -#define MAIN_BLEVALUE_H_ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) - -#include "nimconfig.h" -#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) - -#include - -/** - * @brief The model of a %BLE value. - */ -class NimBLEValue { -public: - NimBLEValue(); - void addPart(const std::string &part); - void addPart(const uint8_t* pData, size_t length); - void cancel(); - void commit(); - uint8_t* getData(); - size_t getLength(); - uint16_t getReadOffset(); - std::string getValue(); - void setReadOffset(uint16_t readOffset); - void setValue(const std::string &value); - void setValue(const uint8_t* pData, size_t length); - -private: - std::string m_accumulation; - uint16_t m_readOffset; - std::string m_value; - -}; - -#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) -#endif // CONFIG_BT_ENABLED -#endif /* MAIN_BLEVALUE_H_ */