2020-03-30 01:44:20 +02:00
|
|
|
/*
|
|
|
|
* NimBLERemoteService.cpp
|
|
|
|
*
|
|
|
|
* Created: on Jan 27 2020
|
|
|
|
* Author H2zero
|
2020-05-14 06:03:56 +02:00
|
|
|
*
|
2020-03-30 01:44:20 +02:00
|
|
|
* Originally:
|
|
|
|
*
|
|
|
|
* BLERemoteService.cpp
|
|
|
|
*
|
|
|
|
* Created on: Jul 8, 2017
|
|
|
|
* Author: kolban
|
|
|
|
*/
|
|
|
|
|
2020-05-14 06:03:56 +02:00
|
|
|
#include "nimconfig.h"
|
2021-09-07 05:14:43 +02:00
|
|
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2024-07-26 22:47:36 +02:00
|
|
|
# include "NimBLERemoteService.h"
|
|
|
|
# include "NimBLERemoteCharacteristic.h"
|
|
|
|
# include "NimBLEClient.h"
|
|
|
|
# include "NimBLEAttValue.h"
|
|
|
|
# include "NimBLEUtils.h"
|
|
|
|
# include "NimBLELog.h"
|
2020-03-30 01:44:20 +02:00
|
|
|
|
2024-07-26 22:47:36 +02:00
|
|
|
# include <climits>
|
2022-01-15 04:45:24 +01:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
static const char* LOG_TAG = "NimBLERemoteService";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Remote Service constructor.
|
2020-07-09 03:27:26 +02:00
|
|
|
* @param [in] pClient A pointer to the client this belongs to.
|
|
|
|
* @param [in] service A pointer to the structure with the service information.
|
2020-05-14 06:03:56 +02:00
|
|
|
*/
|
2024-07-26 22:47:36 +02:00
|
|
|
NimBLERemoteService::NimBLERemoteService(NimBLEClient* pClient, const ble_gatt_svc* service)
|
|
|
|
: NimBLEAttribute{service->uuid, service->start_handle}, m_pClient{pClient}, m_endHandle{service->end_handle} {}
|
2020-03-30 01:44:20 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief When deleting the service make sure we delete all characteristics and descriptors.
|
2020-05-14 06:03:56 +02:00
|
|
|
*/
|
2020-03-30 01:44:20 +02:00
|
|
|
NimBLERemoteService::~NimBLERemoteService() {
|
2020-05-30 05:21:56 +02:00
|
|
|
deleteCharacteristics();
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
|
|
|
|
Add iterators to client remote attributes.
Add iterators for NimBLEScan: NimBLEadvertisedDevice, NimBLEClient: NimBLERemoteService, NimBLERemoteService: NimBLERemoteCharacteristic and NimBLERemoteCharacteristic: NimBLERemoteDescriptor
This is handy e.g. for showing every address of the advertised devices from a scan. To do so, first get a new scan and next:
```
for(auto pAdvertisedDevice: pBLEScan->getResults()) {
Serial.printf("Address is %s\n", std::string(pAdvertisedDevice->getAddress()).c_str());
}
```
Of course any other property of the advertised device can be shown (or looked up, if that is your use case)
Also this is handy e.g. for showing every UUID in a peripheral. To do so, first connect to a peripheral and next:
```
for(auto pService: *pClient) {
Serial.printf("Service UUID is %s\n", std::string(pService->getUUID()).c_str());
for(auto pCharacteristic: *pService) {
Serial.printf("Characteristic UUID is %s\n", std::string(pCharacteristic->getUUID()).c_str());
for(auto pDescriptor: *pCharacteristic) {
Serial.printf("Descriptor UUID is %s\n", std::string(pDescriptor->getUUID()).c_str());
}
}
}
```
Again of course any other property can be shown, or looked up.
2020-05-23 04:13:52 +02:00
|
|
|
/**
|
|
|
|
* @brief Get iterator to the beginning of the vector of remote characteristic pointers.
|
|
|
|
* @return An iterator to the beginning of the vector of remote characteristic pointers.
|
|
|
|
*/
|
2024-07-26 22:47:36 +02:00
|
|
|
std::vector<NimBLERemoteCharacteristic*>::iterator NimBLERemoteService::begin() const {
|
|
|
|
return m_vChars.begin();
|
Add iterators to client remote attributes.
Add iterators for NimBLEScan: NimBLEadvertisedDevice, NimBLEClient: NimBLERemoteService, NimBLERemoteService: NimBLERemoteCharacteristic and NimBLERemoteCharacteristic: NimBLERemoteDescriptor
This is handy e.g. for showing every address of the advertised devices from a scan. To do so, first get a new scan and next:
```
for(auto pAdvertisedDevice: pBLEScan->getResults()) {
Serial.printf("Address is %s\n", std::string(pAdvertisedDevice->getAddress()).c_str());
}
```
Of course any other property of the advertised device can be shown (or looked up, if that is your use case)
Also this is handy e.g. for showing every UUID in a peripheral. To do so, first connect to a peripheral and next:
```
for(auto pService: *pClient) {
Serial.printf("Service UUID is %s\n", std::string(pService->getUUID()).c_str());
for(auto pCharacteristic: *pService) {
Serial.printf("Characteristic UUID is %s\n", std::string(pCharacteristic->getUUID()).c_str());
for(auto pDescriptor: *pCharacteristic) {
Serial.printf("Descriptor UUID is %s\n", std::string(pDescriptor->getUUID()).c_str());
}
}
}
```
Again of course any other property can be shown, or looked up.
2020-05-23 04:13:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get iterator to the end of the vector of remote characteristic pointers.
|
|
|
|
* @return An iterator to the end of the vector of remote characteristic pointers.
|
|
|
|
*/
|
2024-07-26 22:47:36 +02:00
|
|
|
std::vector<NimBLERemoteCharacteristic*>::iterator NimBLERemoteService::end() const {
|
|
|
|
return m_vChars.end();
|
Add iterators to client remote attributes.
Add iterators for NimBLEScan: NimBLEadvertisedDevice, NimBLEClient: NimBLERemoteService, NimBLERemoteService: NimBLERemoteCharacteristic and NimBLERemoteCharacteristic: NimBLERemoteDescriptor
This is handy e.g. for showing every address of the advertised devices from a scan. To do so, first get a new scan and next:
```
for(auto pAdvertisedDevice: pBLEScan->getResults()) {
Serial.printf("Address is %s\n", std::string(pAdvertisedDevice->getAddress()).c_str());
}
```
Of course any other property of the advertised device can be shown (or looked up, if that is your use case)
Also this is handy e.g. for showing every UUID in a peripheral. To do so, first connect to a peripheral and next:
```
for(auto pService: *pClient) {
Serial.printf("Service UUID is %s\n", std::string(pService->getUUID()).c_str());
for(auto pCharacteristic: *pService) {
Serial.printf("Characteristic UUID is %s\n", std::string(pCharacteristic->getUUID()).c_str());
for(auto pDescriptor: *pCharacteristic) {
Serial.printf("Descriptor UUID is %s\n", std::string(pDescriptor->getUUID()).c_str());
}
}
}
```
Again of course any other property can be shown, or looked up.
2020-05-23 04:13:52 +02:00
|
|
|
}
|
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
/**
|
|
|
|
* @brief Get the remote characteristic object for the characteristic UUID.
|
|
|
|
* @param [in] uuid Remote characteristic uuid.
|
2020-07-09 03:27:26 +02:00
|
|
|
* @return A pointer to the remote characteristic object.
|
2020-05-14 06:03:56 +02:00
|
|
|
*/
|
2024-07-26 22:47:36 +02:00
|
|
|
NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const char* uuid) const {
|
2020-03-30 01:44:20 +02:00
|
|
|
return getCharacteristic(NimBLEUUID(uuid));
|
|
|
|
} // getCharacteristic
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get the characteristic object for the UUID.
|
|
|
|
* @param [in] uuid Characteristic uuid.
|
2020-07-09 03:27:26 +02:00
|
|
|
* @return A pointer to the characteristic object, or nullptr if not found.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-07-26 22:47:36 +02:00
|
|
|
NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const NimBLEUUID& uuid) const {
|
2020-12-28 23:40:01 +01:00
|
|
|
NIMBLE_LOGD(LOG_TAG, ">> getCharacteristic: uuid: %s", uuid.toString().c_str());
|
2024-07-26 22:47:36 +02:00
|
|
|
NimBLERemoteCharacteristic* pChar = nullptr;
|
|
|
|
size_t prev_size = m_vChars.size();
|
2020-12-28 23:40:01 +01:00
|
|
|
|
2024-07-26 22:47:36 +02:00
|
|
|
for (const auto& it : m_vChars) {
|
|
|
|
if (it->getUUID() == uuid) {
|
|
|
|
pChar = it;
|
|
|
|
goto Done;
|
2020-05-23 18:27:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-26 22:47:36 +02:00
|
|
|
if (retrieveCharacteristics(&uuid)) {
|
|
|
|
if (m_vChars.size() > prev_size) {
|
|
|
|
pChar = m_vChars.back();
|
|
|
|
goto Done;
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
2020-12-28 23:40:01 +01:00
|
|
|
|
2022-01-18 22:48:07 +01:00
|
|
|
// If the request was successful but 16/32 bit uuid not found
|
2020-12-28 23:40:01 +01:00
|
|
|
// try again with the 128 bit uuid.
|
2024-07-26 22:47:36 +02:00
|
|
|
if (uuid.bitSize() == BLE_UUID_TYPE_16 || uuid.bitSize() == BLE_UUID_TYPE_32) {
|
2020-12-28 23:40:01 +01:00
|
|
|
NimBLEUUID uuid128(uuid);
|
|
|
|
uuid128.to128();
|
2022-02-15 04:18:18 +01:00
|
|
|
if (retrieveCharacteristics(&uuid128)) {
|
2024-07-26 22:47:36 +02:00
|
|
|
if (m_vChars.size() > prev_size) {
|
|
|
|
pChar = m_vChars.back();
|
2022-02-15 04:18:18 +01:00
|
|
|
}
|
|
|
|
}
|
2022-01-18 22:48:07 +01:00
|
|
|
} else {
|
|
|
|
// If the request was successful but the 128 bit uuid not found
|
|
|
|
// try again with the 16 bit uuid.
|
|
|
|
NimBLEUUID uuid16(uuid);
|
|
|
|
uuid16.to16();
|
|
|
|
// if the uuid was 128 bit but not of the BLE base type this check will fail
|
|
|
|
if (uuid16.bitSize() == BLE_UUID_TYPE_16) {
|
2024-07-26 22:47:36 +02:00
|
|
|
if (retrieveCharacteristics(&uuid16)) {
|
|
|
|
if (m_vChars.size() > prev_size) {
|
|
|
|
pChar = m_vChars.back();
|
2022-02-15 04:18:18 +01:00
|
|
|
}
|
|
|
|
}
|
2022-01-18 22:48:07 +01:00
|
|
|
}
|
2020-12-28 23:40:01 +01:00
|
|
|
}
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
|
|
|
|
2024-07-26 22:47:36 +02:00
|
|
|
Done:
|
|
|
|
NIMBLE_LOGD(LOG_TAG, "<< Characteristic %sfound", pChar ? "" : "not ");
|
|
|
|
return pChar;
|
2020-03-30 01:44:20 +02:00
|
|
|
} // getCharacteristic
|
|
|
|
|
2020-05-23 18:27:32 +02:00
|
|
|
/**
|
2020-07-09 03:27:26 +02:00
|
|
|
* @brief Get a pointer to the vector of found characteristics.
|
|
|
|
* @param [in] refresh If true the current characteristics vector will cleared and
|
|
|
|
* all characteristics for this service retrieved from the peripheral.
|
|
|
|
* If false the vector will be returned with the currently stored characteristics of this service.
|
2024-07-26 22:47:36 +02:00
|
|
|
* @return A read-only reference to the vector of characteristics retrieved for this service.
|
2020-05-23 18:27:32 +02:00
|
|
|
*/
|
2024-07-26 22:47:36 +02:00
|
|
|
const std::vector<NimBLERemoteCharacteristic*>& NimBLERemoteService::getCharacteristics(bool refresh) const {
|
|
|
|
if (refresh) {
|
2020-05-30 05:21:56 +02:00
|
|
|
deleteCharacteristics();
|
2024-07-26 22:47:36 +02:00
|
|
|
retrieveCharacteristics();
|
2020-05-23 18:27:32 +02:00
|
|
|
}
|
|
|
|
|
2024-07-26 22:47:36 +02:00
|
|
|
return m_vChars;
|
|
|
|
} // getCharacteristics
|
2020-05-23 18:27:32 +02:00
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
/**
|
2022-07-31 19:00:12 +02:00
|
|
|
* @brief Callback for Characteristic discovery.
|
2020-07-09 03:27:26 +02:00
|
|
|
* @return success == 0 or error code.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-07-26 22:47:36 +02:00
|
|
|
int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle,
|
|
|
|
const ble_gatt_error* error,
|
|
|
|
const ble_gatt_chr* chr,
|
|
|
|
void* arg) {
|
|
|
|
NIMBLE_LOGD(LOG_TAG, "Characteristic Discovery >>");
|
2024-11-10 21:31:37 +01:00
|
|
|
auto pTaskData = (NimBLETaskData*)arg;
|
|
|
|
const auto pSvc = (NimBLERemoteService*)pTaskData->m_pInstance;
|
2020-03-30 01:44:20 +02:00
|
|
|
|
2024-11-14 23:55:09 +01:00
|
|
|
|
|
|
|
if (error->status == BLE_HS_ENOTCONN) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "<< Characteristic Discovery; Not connected");
|
|
|
|
NimBLEUtils::taskRelease(*pTaskData, error->status);
|
|
|
|
return error->status;
|
|
|
|
}
|
|
|
|
|
2020-03-30 01:44:20 +02:00
|
|
|
// Make sure the discovery is for this device
|
2024-11-03 02:00:07 +01:00
|
|
|
if (pSvc->getClient()->getConnHandle() != conn_handle) {
|
2020-06-22 06:07:01 +02:00
|
|
|
return 0;
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
2020-06-22 06:07:01 +02:00
|
|
|
|
2024-07-26 22:47:36 +02:00
|
|
|
if (error->status == 0) {
|
|
|
|
pSvc->m_vChars.push_back(new NimBLERemoteCharacteristic(pSvc, chr));
|
2024-11-10 21:31:37 +01:00
|
|
|
return 0;
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
2020-06-22 06:07:01 +02:00
|
|
|
|
2024-11-10 21:31:37 +01:00
|
|
|
NimBLEUtils::taskRelease(*pTaskData, error->status);
|
|
|
|
NIMBLE_LOGD(LOG_TAG, "<< Characteristic Discovery");
|
2020-06-22 06:07:01 +02:00
|
|
|
return error->status;
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Retrieve all the characteristics for this service.
|
|
|
|
* This function will not return until we have all the characteristics.
|
2020-07-09 03:27:26 +02:00
|
|
|
* @return True if successful.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-07-26 22:47:36 +02:00
|
|
|
bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID* uuidFilter) const {
|
|
|
|
NIMBLE_LOGD(LOG_TAG, ">> retrieveCharacteristics()");
|
2024-11-10 21:31:37 +01:00
|
|
|
int rc = 0;
|
|
|
|
NimBLETaskData taskData(const_cast<NimBLERemoteService*>(this));
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2024-07-26 22:47:36 +02:00
|
|
|
if (uuidFilter == nullptr) {
|
2024-11-03 02:00:07 +01:00
|
|
|
rc = ble_gattc_disc_all_chrs(m_pClient->getConnHandle(),
|
2024-07-26 22:47:36 +02:00
|
|
|
getHandle(),
|
|
|
|
getEndHandle(),
|
|
|
|
NimBLERemoteService::characteristicDiscCB,
|
|
|
|
&taskData);
|
2020-05-23 18:27:32 +02:00
|
|
|
} else {
|
2024-11-03 02:00:07 +01:00
|
|
|
rc = ble_gattc_disc_chrs_by_uuid(m_pClient->getConnHandle(),
|
2024-07-26 22:47:36 +02:00
|
|
|
getHandle(),
|
|
|
|
getEndHandle(),
|
|
|
|
uuidFilter->getBase(),
|
|
|
|
NimBLERemoteService::characteristicDiscCB,
|
|
|
|
&taskData);
|
2020-05-23 18:27:32 +02:00
|
|
|
}
|
|
|
|
|
2024-11-10 21:31:37 +01:00
|
|
|
if (rc != 0) {
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_chrs rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
|
|
return false;
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2024-11-10 21:31:37 +01:00
|
|
|
NimBLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER);
|
|
|
|
rc = taskData.m_flags;
|
|
|
|
if (rc == 0 || rc == BLE_HS_EDONE) {
|
2020-03-30 01:44:20 +02:00
|
|
|
NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics()");
|
2024-11-10 21:31:37 +01:00
|
|
|
return true;
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2024-11-10 21:31:37 +01:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "<< retrieveCharacteristics() rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
|
|
return false;
|
2020-03-30 01:44:20 +02:00
|
|
|
} // retrieveCharacteristics
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get the client associated with this service.
|
|
|
|
* @return A reference to the client associated with this service.
|
|
|
|
*/
|
2024-07-26 22:47:36 +02:00
|
|
|
NimBLEClient* NimBLERemoteService::getClient() const {
|
2020-03-30 01:44:20 +02:00
|
|
|
return m_pClient;
|
|
|
|
} // getClient
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Read the value of a characteristic associated with this service.
|
2024-07-26 22:47:36 +02:00
|
|
|
* @param [in] uuid The characteristic to read.
|
2020-03-30 01:44:20 +02:00
|
|
|
* @returns a string containing the value or an empty string if not found or error.
|
|
|
|
*/
|
2024-07-26 22:47:36 +02:00
|
|
|
NimBLEAttValue NimBLERemoteService::getValue(const NimBLEUUID& uuid) const {
|
|
|
|
const auto pChar = getCharacteristic(uuid);
|
|
|
|
if (pChar) {
|
|
|
|
return pChar->readValue();
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
|
|
|
|
2024-07-26 22:47:36 +02:00
|
|
|
return NimBLEAttValue{};
|
2020-03-30 01:44:20 +02:00
|
|
|
} // readValue
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the value of a characteristic.
|
2024-07-26 22:47:36 +02:00
|
|
|
* @param [in] uuid The characteristic UUID to set.
|
2020-03-30 01:44:20 +02:00
|
|
|
* @param [in] value The value to set.
|
|
|
|
* @returns true on success, false if not found or error
|
|
|
|
*/
|
2024-07-26 22:47:36 +02:00
|
|
|
bool NimBLERemoteService::setValue(const NimBLEUUID& uuid, const NimBLEAttValue& value) const {
|
|
|
|
const auto pChar = getCharacteristic(uuid);
|
|
|
|
if (pChar) {
|
|
|
|
return pChar->writeValue(value);
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
|
|
|
|
2024-07-26 22:47:36 +02:00
|
|
|
return false;
|
2020-03-30 01:44:20 +02:00
|
|
|
} // setValue
|
|
|
|
|
|
|
|
/**
|
2020-05-18 04:21:35 +02:00
|
|
|
* @brief Delete the characteristics in the characteristics vector.
|
2020-07-09 03:27:26 +02:00
|
|
|
* @details We maintain a vector called m_characteristicsVector that contains pointers to BLERemoteCharacteristic
|
2020-05-18 04:21:35 +02:00
|
|
|
* object references. Since we allocated these in this class, we are also responsible for deleting
|
|
|
|
* them. This method does just that.
|
2020-03-30 01:44:20 +02:00
|
|
|
*/
|
2024-07-26 22:47:36 +02:00
|
|
|
void NimBLERemoteService::deleteCharacteristics() const {
|
|
|
|
for (const auto& it : m_vChars) {
|
2020-05-18 04:21:35 +02:00
|
|
|
delete it;
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
2024-07-26 22:47:36 +02:00
|
|
|
std::vector<NimBLERemoteCharacteristic*>{}.swap(m_vChars);
|
2020-05-30 05:21:56 +02:00
|
|
|
} // deleteCharacteristics
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Delete characteristic by UUID
|
2020-07-09 03:27:26 +02:00
|
|
|
* @param [in] uuid The UUID of the characteristic to be removed from the local database.
|
2020-05-30 05:21:56 +02:00
|
|
|
* @return Number of characteristics left.
|
|
|
|
*/
|
2024-07-26 22:47:36 +02:00
|
|
|
size_t NimBLERemoteService::deleteCharacteristic(const NimBLEUUID& uuid) const {
|
|
|
|
for (auto it = m_vChars.begin(); it != m_vChars.end(); ++it) {
|
|
|
|
if ((*it)->getUUID() == uuid) {
|
|
|
|
delete (*it);
|
|
|
|
m_vChars.erase(it);
|
2020-05-30 05:21:56 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-26 22:47:36 +02:00
|
|
|
return m_vChars.size();
|
2020-05-30 05:21:56 +02:00
|
|
|
} // deleteCharacteristic
|
2020-03-30 01:44:20 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Create a string representation of this remote service.
|
|
|
|
* @return A string representation of this remote service.
|
|
|
|
*/
|
2024-07-26 22:47:36 +02:00
|
|
|
std::string NimBLERemoteService::toString() const {
|
|
|
|
std::string res = "Service: uuid: " + m_uuid.toString() + ", start_handle: 0x";
|
|
|
|
char val[5];
|
|
|
|
snprintf(val, sizeof(val), "%04x", getHandle());
|
2020-03-30 01:44:20 +02:00
|
|
|
res += val;
|
2024-07-26 22:47:36 +02:00
|
|
|
res += ", end_handle: 0x";
|
|
|
|
snprintf(val, sizeof(val), "%04x", getEndHandle());
|
2020-03-30 01:44:20 +02:00
|
|
|
res += val;
|
2020-05-14 06:03:56 +02:00
|
|
|
|
2024-07-26 22:47:36 +02:00
|
|
|
for (const auto& chr : m_vChars) {
|
|
|
|
res += "\n" + chr->toString();
|
2020-03-30 01:44:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
} // toString
|
|
|
|
|
2021-09-07 05:14:43 +02:00
|
|
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|