/** * @brief Populate the descriptors (if any) for this characteristic. */ void BLERemoteCharacteristic::retrieveDescriptors() { ESP_LOGD(LOG_TAG, ">> retrieveDescriptors() for characteristic: %s", getUUID().toString().c_str()); removeDescriptors(); // Remove any existing descriptors. // Loop over each of the descriptors within the service associated with this characteristic. // For each descriptor we find, create a BLERemoteDescriptor instance. uint16_t offset = 0; esp_gattc_descr_elem_t result; while(1) { uint16_t count = 1; esp_gatt_status_t status = ::esp_ble_gattc_get_all_descr( getRemoteService()->getClient()->getGattcIf(), getRemoteService()->getClient()->getConnId(), getHandle(), &result, &count, offset ); if (status == ESP_GATT_INVALID_OFFSET) { // We have reached the end of the entries. break; } if (status != ESP_GATT_OK) { ESP_LOGE(LOG_TAG, "esp_ble_gattc_get_all_descr: %s", BLEUtils::gattStatusToString(status).c_str()); break; } if (count == 0) { break; } ESP_LOGE(LOG_TAG, ""); ESP_LOGD(LOG_TAG, "Found a descriptor: Handle: %d, UUID: %s", result.handle, BLEUUID(result.uuid).toString().c_str()); // We now have a new characteristic ... let us add that to our set of known characteristics BLERemoteDescriptor *pNewRemoteDescriptor = new BLERemoteDescriptor( result.handle, BLEUUID(result.uuid), this ); m_descriptorMap.insert(std::pair<std::string, BLERemoteDescriptor*>(pNewRemoteDescriptor->getUUID().toString(), pNewRemoteDescriptor)); offset++; } // while true //m_haveCharacteristics = true; // Remember that we have received the characteristics. ESP_LOGD(LOG_TAG, "<< retrieveDescriptors(): Found %d descriptors.", offset); } // getDescriptors
static void run() { BLEDevice::init("MYDEVICE"); BLEServer *pServer = BLEDevice::createServer(); BLEService *pService = pServer->createService(BLEUUID(SERVICE_UUID_BIN, 16, true)); BLECharacteristic *pCharacteristic = pService->createCharacteristic( BLEUUID(CHARACTERISTIC_UUID), BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE ); pCharacteristic->setCallbacks(new MyCallbackHandler()); pCharacteristic->setValue("Hello World"); pService->start(); BLEAdvertising *pAdvertising = pServer->getAdvertising(); pAdvertising->start(); }
/** * @brief Retrieve all the characteristics for this service. * This function will not return until we have all the characteristics. * @return N/A */ void BLERemoteService::retrieveCharacteristics() { ESP_LOGD(LOG_TAG, ">> getCharacteristics() for service: %s", getUUID().toString().c_str()); removeCharacteristics(); // Forget any previous characteristics. uint16_t offset = 0; esp_gattc_char_elem_t result; while(1) { uint16_t count = 1; esp_gatt_status_t status = ::esp_ble_gattc_get_all_char( getClient()->getGattcIf(), getClient()->getConnId(), m_startHandle, m_endHandle, &result, &count, offset ); if (status == ESP_GATT_INVALID_OFFSET) { // We have reached the end of the entries. break; } if (status != ESP_GATT_OK) { // If we got an error, end. ESP_LOGE(LOG_TAG, "esp_ble_gattc_get_all_char: %s", BLEUtils::gattStatusToString(status).c_str()); break; } if (count == 0) { // If we failed to get any new records, end. break; } ESP_LOGD(LOG_TAG, "Found a characteristic: Handle: %d, UUID: %s", result.char_handle, BLEUUID(result.uuid).toString().c_str()); // We now have a new characteristic ... let us add that to our set of known characteristics BLERemoteCharacteristic *pNewRemoteCharacteristic = new BLERemoteCharacteristic( result.char_handle, BLEUUID(result.uuid), result.properties, this ); m_characteristicMap.insert(std::pair<std::string, BLERemoteCharacteristic*>(pNewRemoteCharacteristic->getUUID().toString(), pNewRemoteCharacteristic)); offset++; // Increment our count of number of descriptors found. } // Loop forever (until we break inside the loop). m_haveCharacteristics = true; // Remember that we have received the characteristics. ESP_LOGD(LOG_TAG, "<< getCharacteristics()"); } // getCharacteristics
BLERemoteService::BLERemoteService( esp_gatt_id_t srvcId, BLEClient* pClient, uint16_t startHandle, uint16_t endHandle ) { ESP_LOGD(LOG_TAG, ">> BLERemoteService()"); m_srvcId = srvcId; m_pClient = pClient; m_uuid = BLEUUID(m_srvcId); m_haveCharacteristics = false; m_startHandle = startHandle; m_endHandle = endHandle; ESP_LOGD(LOG_TAG, "<< BLERemoteService()"); }
/** * @brief Set the Service UUID for this device. * @param [in] serviceUUID The discovered serviceUUID */ void BLEAdvertisedDevice::setServiceUUID(const char* serviceUUID) { return setServiceUUID(BLEUUID(serviceUUID)); } // setServiceUUID
/** * @brief Parse the advertising pay load. * * The pay load is a buffer of bytes that is either 31 bytes long or terminated by * a 0 length value. Each entry in the buffer has the format: * [length][type][data...] * * The length does not include itself but does include everything after it until the next record. A record * with a length value of 0 indicates a terminator. * * https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile */ void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload, size_t total_len) { uint8_t length; uint8_t ad_type; uint8_t sizeConsumed = 0; bool finished = false; m_payload = payload; m_payloadLength = total_len; while(!finished) { length = *payload; // Retrieve the length of the record. payload++; // Skip to type sizeConsumed += 1 + length; // increase the size consumed. if (length != 0) { // A length of 0 indicates that we have reached the end. ad_type = *payload; payload++; length--; char* pHex = BLEUtils::buildHexData(nullptr, payload, length); ESP_LOGD(LOG_TAG, "Type: 0x%.2x (%s), length: %d, data: %s", ad_type, BLEUtils::advTypeToString(ad_type), length, pHex); free(pHex); switch(ad_type) { case ESP_BLE_AD_TYPE_NAME_CMPL: { // Adv Data Type: 0x09 setName(std::string(reinterpret_cast<char*>(payload), length)); break; } // ESP_BLE_AD_TYPE_NAME_CMPL case ESP_BLE_AD_TYPE_TX_PWR: { // Adv Data Type: 0x0A setTXPower(*payload); break; } // ESP_BLE_AD_TYPE_TX_PWR case ESP_BLE_AD_TYPE_APPEARANCE: { // Adv Data Type: 0x19 setAppearance(*reinterpret_cast<uint16_t*>(payload)); break; } // ESP_BLE_AD_TYPE_APPEARANCE case ESP_BLE_AD_TYPE_FLAG: { // Adv Data Type: 0x01 setAdFlag(*payload); break; } // ESP_BLE_AD_TYPE_FLAG case ESP_BLE_AD_TYPE_16SRV_CMPL: case ESP_BLE_AD_TYPE_16SRV_PART: { // Adv Data Type: 0x02 for (int var = 0; var < length/2; ++var) { setServiceUUID(BLEUUID(*reinterpret_cast<uint16_t*>(payload + var * 2))); } break; } // ESP_BLE_AD_TYPE_16SRV_PART case ESP_BLE_AD_TYPE_32SRV_CMPL: case ESP_BLE_AD_TYPE_32SRV_PART: { // Adv Data Type: 0x04 for (int var = 0; var < length/4; ++var) { setServiceUUID(BLEUUID(*reinterpret_cast<uint32_t*>(payload + var * 4))); } break; } // ESP_BLE_AD_TYPE_32SRV_PART case ESP_BLE_AD_TYPE_128SRV_CMPL: { // Adv Data Type: 0x07 setServiceUUID(BLEUUID(payload, 16, false)); break; } // ESP_BLE_AD_TYPE_128SRV_CMPL case ESP_BLE_AD_TYPE_128SRV_PART: { // Adv Data Type: 0x06 setServiceUUID(BLEUUID(payload, 16, false)); break; } // ESP_BLE_AD_TYPE_128SRV_PART // See CSS Part A 1.4 Manufacturer Specific Data case ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE: { setManufacturerData(std::string(reinterpret_cast<char*>(payload), length)); break; } // ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE case ESP_BLE_AD_TYPE_SERVICE_DATA: { // Adv Data Type: 0x16 (Service Data) - 2 byte UUID if (length < 2) { ESP_LOGE(LOG_TAG, "Length too small for ESP_BLE_AD_TYPE_SERVICE_DATA"); break; } uint16_t uuid = *(uint16_t*)payload; setServiceDataUUID(BLEUUID(uuid)); if (length > 2) { setServiceData(std::string(reinterpret_cast<char*>(payload + 2), length - 2)); } break; } //ESP_BLE_AD_TYPE_SERVICE_DATA case ESP_BLE_AD_TYPE_32SERVICE_DATA: { // Adv Data Type: 0x20 (Service Data) - 4 byte UUID if (length < 4) { ESP_LOGE(LOG_TAG, "Length too small for ESP_BLE_AD_TYPE_32SERVICE_DATA"); break; } uint32_t uuid = *(uint32_t*) payload; setServiceDataUUID(BLEUUID(uuid)); if (length > 4) { setServiceData(std::string(reinterpret_cast<char*>(payload + 4), length - 4)); } break; } //ESP_BLE_AD_TYPE_32SERVICE_DATA case ESP_BLE_AD_TYPE_128SERVICE_DATA: { // Adv Data Type: 0x21 (Service Data) - 16 byte UUID if (length < 16) { ESP_LOGE(LOG_TAG, "Length too small for ESP_BLE_AD_TYPE_128SERVICE_DATA"); break; } setServiceDataUUID(BLEUUID(payload, (size_t)16, false)); if (length > 16) { setServiceData(std::string(reinterpret_cast<char*>(payload + 16), length - 16)); } break; } //ESP_BLE_AD_TYPE_32SERVICE_DATA default: { ESP_LOGD(LOG_TAG, "Unhandled type: adType: %d - 0x%.2x", ad_type, ad_type); break; } } // switch payload += length; } // Length <> 0 if (sizeConsumed >= total_len) finished = true; } // !finished } // parseAdvertisement
/** * @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. */ BLEService* BLEServer::createService(const char* uuid) { return createService(BLEUUID(uuid)); }
/** * @brief Construct an instance of the BLEService * @param [in] uuid The UUID of the service. */ BLEService::BLEService(const char* uuid) : BLEService(BLEUUID(uuid)) { }
BLECharacteristic* BLEService::getCharacteristic(const char* uuid) { return getCharacteristic(BLEUUID(uuid)); }
/** * @brief Get the remote characteristic object for the characteristic UUID. * @param [in] uuid Remote characteristic uuid. * @return Reference to the remote characteristic object. * @throws BLEUuidNotFoundException */ BLERemoteCharacteristic* BLERemoteService::getCharacteristic(const char* uuid) { return getCharacteristic(BLEUUID(uuid)); } // getCharacteristic
/** * @brief Create a new BLE Characteristic associated with this service. * @param [in] uuid - The UUID of the characteristic. * @param [in] properties - The properties of the characteristic. * @return The new BLE characteristic. */ BLECharacteristic* BLEService::createCharacteristic(const char* uuid, uint32_t properties) { return createCharacteristic(BLEUUID(uuid), properties); }
/** * @brief Get the service BLE Remote Service instance corresponding to the uuid. * @param [in] uuid The UUID of the service being sought. * @return A reference to the Service or nullptr if don't know about it. */ BLERemoteService* BLEClient::getService(const char* uuid) { return getService(BLEUUID(uuid)); } // getService
/** * @brief Handle GATT Client events */ void BLEClient::gattClientEventHandler( esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t* evtParam) { ESP_LOGD(LOG_TAG, "gattClientEventHandler [esp_gatt_if: %d] ... %s", gattc_if, BLEUtils::gattClientEventTypeToString(event).c_str()); // Execute handler code based on the type of event received. switch(event) { case ESP_GATTC_SRVC_CHG_EVT: ESP_LOGI(LOG_TAG, "SERVICE CHANGED"); break; case ESP_GATTC_CLOSE_EVT: { // esp_ble_gattc_app_unregister(m_appId); // BLEDevice::removePeerDevice(m_gattc_if, true); break; } // // ESP_GATTC_DISCONNECT_EVT // // disconnect: // - esp_gatt_status_t status // - uint16_t conn_id // - esp_bd_addr_t remote_bda case ESP_GATTC_DISCONNECT_EVT: { // If we receive a disconnect event, set the class flag that indicates that we are // no longer connected. m_isConnected = false; if (m_pClientCallbacks != nullptr) { m_pClientCallbacks->onDisconnect(this); } BLEDevice::removePeerDevice(m_appId, true); esp_ble_gattc_app_unregister(m_gattc_if); m_semaphoreRssiCmplEvt.give(); m_semaphoreSearchCmplEvt.give(1); break; } // ESP_GATTC_DISCONNECT_EVT // // ESP_GATTC_OPEN_EVT // // open: // - esp_gatt_status_t status // - uint16_t conn_id // - esp_bd_addr_t remote_bda // case ESP_GATTC_OPEN_EVT: { m_conn_id = evtParam->open.conn_id; if (m_pClientCallbacks != nullptr) { m_pClientCallbacks->onConnect(this); } if (evtParam->open.status == ESP_GATT_OK) { m_isConnected = true; // Flag us as connected. } m_semaphoreOpenEvt.give(evtParam->open.status); break; } // ESP_GATTC_OPEN_EVT // // ESP_GATTC_REG_EVT // // reg: // esp_gatt_status_t status // uint16_t app_id // case ESP_GATTC_REG_EVT: { m_gattc_if = gattc_if; m_semaphoreRegEvt.give(); break; } // ESP_GATTC_REG_EVT case ESP_GATTC_CFG_MTU_EVT: if(evtParam->cfg_mtu.status != ESP_GATT_OK) { ESP_LOGE(LOG_TAG,"Config mtu failed"); } m_mtu = evtParam->cfg_mtu.mtu; break; case ESP_GATTC_CONNECT_EVT: { BLEDevice::updatePeerDevice(this, true, m_gattc_if); esp_err_t errRc = esp_ble_gattc_send_mtu_req(gattc_if, evtParam->connect.conn_id); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "esp_ble_gattc_send_mtu_req: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); } #ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig if(BLEDevice::m_securityLevel){ esp_ble_set_encryption(evtParam->connect.remote_bda, BLEDevice::m_securityLevel); } #endif // CONFIG_BLE_SMP_ENABLE break; } // ESP_GATTC_CONNECT_EVT // // ESP_GATTC_SEARCH_CMPL_EVT // // search_cmpl: // - esp_gatt_status_t status // - uint16_t conn_id // case ESP_GATTC_SEARCH_CMPL_EVT: { esp_ble_gattc_cb_param_t* p_data = (esp_ble_gattc_cb_param_t*)evtParam; if (p_data->search_cmpl.status != ESP_GATT_OK){ ESP_LOGE(LOG_TAG, "search service failed, error status = %x", p_data->search_cmpl.status); break; } #ifndef ARDUINO_ARCH_ESP32 // commented out just for now to keep backward compatibility // if(p_data->search_cmpl.searched_service_source == ESP_GATT_SERVICE_FROM_REMOTE_DEVICE) { // ESP_LOGI(LOG_TAG, "Get service information from remote device"); // } else if (p_data->search_cmpl.searched_service_source == ESP_GATT_SERVICE_FROM_NVS_FLASH) { // ESP_LOGI(LOG_TAG, "Get service information from flash"); // } else { // ESP_LOGI(LOG_TAG, "unknown service source"); // } #endif m_semaphoreSearchCmplEvt.give(0); break; } // ESP_GATTC_SEARCH_CMPL_EVT // // ESP_GATTC_SEARCH_RES_EVT // // search_res: // - uint16_t conn_id // - uint16_t start_handle // - uint16_t end_handle // - esp_gatt_id_t srvc_id // case ESP_GATTC_SEARCH_RES_EVT: { BLEUUID uuid = BLEUUID(evtParam->search_res.srvc_id); BLERemoteService* pRemoteService = new BLERemoteService( evtParam->search_res.srvc_id, this, evtParam->search_res.start_handle, evtParam->search_res.end_handle ); m_servicesMap.insert(std::pair<std::string, BLERemoteService*>(uuid.toString(), pRemoteService)); m_servicesMapByInstID.insert(std::pair<BLERemoteService *, uint16_t>(pRemoteService, evtParam->search_res.srvc_id.inst_id)); break; } // ESP_GATTC_SEARCH_RES_EVT default: { break; } } // Switch // Pass the request on to all services. for (auto &myPair : m_servicesMap) { myPair.second->gattClientEventHandler(event, gattc_if, evtParam); } } // gattClientEventHandler
/** * @brief Handle GATT server events for the descripttor. * @param [in] event * @param [in] gatts_if * @param [in] param */ void BLEDescriptor::handleGATTServerEvent( esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { switch(event) { // ESP_GATTS_ADD_CHAR_DESCR_EVT // // add_char_descr: // - esp_gatt_status_t status // - uint16_t attr_handle // - uint16_t service_handle // - esp_bt_uuid_t char_uuid case ESP_GATTS_ADD_CHAR_DESCR_EVT: { /* ESP_LOGD(LOG_TAG, "DEBUG: m_pCharacteristic: %x", (uint32_t)m_pCharacteristic); ESP_LOGD(LOG_TAG, "DEBUG: m_bleUUID: %s, add_char_descr.char_uuid: %s, equals: %d", m_bleUUID.toString().c_str(), BLEUUID(param->add_char_descr.char_uuid).toString().c_str(), m_bleUUID.equals(BLEUUID(param->add_char_descr.char_uuid))); ESP_LOGD(LOG_TAG, "DEBUG: service->getHandle: %x, add_char_descr.service_handle: %x", m_pCharacteristic->getService()->getHandle(), param->add_char_descr.service_handle); ESP_LOGD(LOG_TAG, "DEBUG: service->lastCharacteristic: %x", (uint32_t)m_pCharacteristic->getService()->getLastCreatedCharacteristic()); */ if (m_pCharacteristic != nullptr && m_bleUUID.equals(BLEUUID(param->add_char_descr.descr_uuid)) && m_pCharacteristic->getService()->getHandle() == param->add_char_descr.service_handle && m_pCharacteristic == m_pCharacteristic->getService()->getLastCreatedCharacteristic()) { setHandle(param->add_char_descr.attr_handle); m_semaphoreCreateEvt.give(); } break; } // ESP_GATTS_ADD_CHAR_DESCR_EVT // ESP_GATTS_WRITE_EVT - A request to write the value of a descriptor has arrived. // // write: // - uint16_t conn_id // - uint16_t trans_id // - esp_bd_addr_t bda // - uint16_t handle // - uint16_t offset // - bool need_rsp // - bool is_prep // - uint16_t len // - uint8_t *value case ESP_GATTS_WRITE_EVT: { if (param->write.handle == m_handle) { setValue(param->write.value, param->write.len); // Set the value of the descriptor. esp_gatt_rsp_t rsp; // Build a response. rsp.attr_value.len = getLength(); rsp.attr_value.handle = m_handle; rsp.attr_value.offset = 0; rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE; memcpy(rsp.attr_value.value, getValue(), rsp.attr_value.len); esp_err_t errRc = ::esp_ble_gatts_send_response( gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, &rsp); if (errRc != ESP_OK) { // Check the return code from the send of the response. ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); } if (m_pCallback != nullptr) { // We have completed the write, if there is a user supplied callback handler, invoke it now. m_pCallback->onWrite(this); // Invoke the onWrite callback handler. } } // End of ... this is our handle. break; } // ESP_GATTS_WRITE_EVT // ESP_GATTS_READ_EVT - A request to read the value of a descriptor has arrived. // // read: // - uint16_t conn_id // - uint32_t trans_id // - esp_bd_addr_t bda // - uint16_t handle // - uint16_t offset // - bool is_long // - bool need_rsp // case ESP_GATTS_READ_EVT: { if (param->read.handle == m_handle) { // If this event is for this descriptor ... process it if (m_pCallback != nullptr) { // If we have a user supplied callback, invoke it now. m_pCallback->onRead(this); // Invoke the onRead callback method in the callback handler. } if (param->read.need_rsp) { // Do we need a response ESP_LOGD(LOG_TAG, "Sending a response (esp_ble_gatts_send_response)"); esp_gatt_rsp_t rsp; rsp.attr_value.len = getLength(); rsp.attr_value.handle = param->read.handle; rsp.attr_value.offset = 0; rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE; memcpy(rsp.attr_value.value, getValue(), rsp.attr_value.len); esp_err_t errRc = ::esp_ble_gatts_send_response( gatts_if, param->read.conn_id, param->read.trans_id, ESP_GATT_OK, &rsp); if (errRc != ESP_OK) { // Check the return code from the send of the response. ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); } } // End of need a response. } // End of this is our handle break; } // ESP_GATTS_READ_EVT default: { break; } }// switch event } // handleGATTServerEvent
/** * @brief Handle a GATTS server event. */ void BLEService::handleGATTServerEvent( esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { switch(event) { // ESP_GATTS_ADD_CHAR_EVT - Indicate that a characteristic was added to the service. // add_char: // - esp_gatt_status_t status // - uint16_t attr_handle // - uint16_t service_handle // - esp_bt_uuid_t char_uuid // If we have reached the correct service, then locate the characteristic and remember the handle // for that characteristic. case ESP_GATTS_ADD_CHAR_EVT: { if (m_handle == param->add_char.service_handle) { BLECharacteristic *pCharacteristic = getCharacteristic(BLEUUID(param->add_char.char_uuid)); if (pCharacteristic == nullptr) { ESP_LOGE(LOG_TAG, "Expected to find characteristic with UUID: %s, but didnt!", BLEUUID(param->add_char.char_uuid).toString().c_str()); dump(); m_semaphoreAddCharEvt.give(); break; } pCharacteristic->setHandle(param->add_char.attr_handle); m_characteristicMap.setByHandle(param->add_char.attr_handle, pCharacteristic); //ESP_LOGD(tag, "Characteristic map: %s", m_characteristicMap.toString().c_str()); m_semaphoreAddCharEvt.give(); break; } // Reached the correct service. break; } // ESP_GATTS_ADD_CHAR_EVT // ESP_GATTS_START_EVT // // start: // esp_gatt_status_t status // uint16_t service_handle case ESP_GATTS_START_EVT: { if (param->start.service_handle == getHandle()) { m_semaphoreStartEvt.give(); } break; } // ESP_GATTS_START_EVT // ESP_GATTS_CREATE_EVT // Called when a new service is registered as having been created. // // create: // * esp_gatt_status_t status // * uint16_t service_handle // * esp_gatt_srvc_id_t service_id // * - esp_gatt_id id // * - esp_bt_uuid uuid // * - uint8_t inst_id // * - bool is_primary // case ESP_GATTS_CREATE_EVT: { if (getUUID().equals(BLEUUID(param->create.service_id.id.uuid))) { setHandle(param->create.service_handle); m_semaphoreCreateEvt.give(); } break; } // ESP_GATTS_CREATE_EVT default: { break; } // Default } // Switch m_characteristicMap.handleGATTServerEvent(event, gatts_if, param); } // handleGATTServerEvent
/** * @brief BLEDescriptor constructor. */ BLEDescriptor::BLEDescriptor(const char* uuid) : BLEDescriptor(BLEUUID(uuid)) { }
/** * @brief Return the characteristic by UUID. * @param [in] UUID The UUID to look up the characteristic. * @return The characteristic. */ BLECharacteristic* BLECharacteristicMap::getByUUID(const char* uuid) { return getByUUID(BLEUUID(uuid)); }