Remove automatic discovery in NimBLEClient::connect().

Instead of discovering the peripheral database on connection and consuming
the associated resources this will give the user more control over the
discovery operation.

* Adds void NimBLEClient::discoverAtrributes() for the user to discover all
the peripheral attributes as a replacement for the former functionality.

* getServices(), getCharacteristics(), getDescriptors() now take an
optional bool parameter (default false).
If true it will clear the respective vector and retrieve all the respective
attributes from the peripheral. If false it will retrieve the attributes
only if the vector is empty, otherwise the vector is returned with the
currently stored attributes.

* getService(NimBLEUUID), getCharacteristic(NimBLEUUID), getDescriptor(NimBLEUUID)
will now check the respective vectors for the attribute object and, if not
found, will retrieve (only) the specified attribute from the peripheral.
This commit is contained in:
h2zero
2020-05-23 10:27:32 -06:00
parent 10e50a8791
commit c5c9423893
9 changed files with 368 additions and 254 deletions

View File

@@ -53,7 +53,6 @@ NimBLEClient::NimBLEClient()
{
m_pClientCallbacks = &defaultCallbacks;
m_conn_id = BLE_HS_CONN_HANDLE_NONE;
m_haveServices = false;
m_isConnected = false;
m_connectTimeout = 30000;
@@ -95,7 +94,6 @@ void NimBLEClient::clearServices() {
}
m_servicesVector.clear();
m_haveServices = false;
NIMBLE_LOGD(LOG_TAG, "<< clearServices");
} // clearServices
@@ -183,18 +181,6 @@ bool NimBLEClient::connect(const NimBLEAddress &address, uint8_t type, bool refr
clearServices();
}
if (!m_haveServices) {
if (!retrieveServices()) {
// error getting services, make sure we disconnect and release any resources before returning
disconnect();
clearServices();
return false;
}
else{
NIMBLE_LOGD(LOG_TAG, "Found %d services", getServices()->size());
}
}
m_pClientCallbacks->onConnect(this);
NIMBLE_LOGD(LOG_TAG, "<< connect()");
@@ -384,10 +370,6 @@ NimBLERemoteService* NimBLEClient::getService(const char* uuid) {
NimBLERemoteService* NimBLEClient::getService(const NimBLEUUID &uuid) {
NIMBLE_LOGD(LOG_TAG, ">> getService: uuid: %s", uuid.toString().c_str());
if (!m_haveServices) {
return nullptr;
}
for(auto &it: m_servicesVector) {
if(it->getUUID() == uuid) {
NIMBLE_LOGD(LOG_TAG, "<< getService: found the service with uuid: %s", uuid.toString().c_str());
@@ -395,6 +377,13 @@ NimBLERemoteService* NimBLEClient::getService(const NimBLEUUID &uuid) {
}
}
size_t prev_size = m_servicesVector.size();
if(retrieveServices(&uuid)) {
if(m_servicesVector.size() > prev_size) {
return m_servicesVector.back();
}
}
NIMBLE_LOGD(LOG_TAG, "<< getService: not found");
return nullptr;
} // getService
@@ -402,12 +391,41 @@ NimBLERemoteService* NimBLEClient::getService(const NimBLEUUID &uuid) {
/**
* @Get a pointer to the vector of found services.
* @param [in] bool value to indicate if the current vector should be cleared and
* subsequently all services retrieved from the peripheral.
* If false the vector will be returned with the currently stored services,
* if vector is empty it will retrieve all services from the peripheral.
* @return a pointer to the vector of available services.
*/
std::vector<NimBLERemoteService*>* NimBLEClient::getServices() {
std::vector<NimBLERemoteService*>* NimBLEClient::getServices(bool refresh) {
if(refresh) {
clearServices();
}
if(m_servicesVector.empty()) {
if (!retrieveServices()) {
NIMBLE_LOGE(LOG_TAG, "Error: Failed to get services");
}
else{
NIMBLE_LOGI(LOG_TAG, "Found %d services", m_servicesVector.size());
}
}
return &m_servicesVector;
}
/**
* @ Retrieves the full database of attributes that the peripheral has available.
*/
void NimBLEClient::discoverAttributes() {
for(auto svc: *getServices(true)) {
for(auto chr: *svc->getCharacteristics(true)) {
chr->getDescriptors(true);
}
}
}
/**
* @brief Ask the remote %BLE server for its services.
* A %BLE Server exposes a set of services for its partners. Here we ask the server for its set of
@@ -415,7 +433,7 @@ std::vector<NimBLERemoteService*>* NimBLEClient::getServices() {
* We then ask for the characteristics for each service found and their desciptors.
* @return true on success otherwise false if an error occurred
*/
bool NimBLEClient::retrieveServices() {
bool NimBLEClient::retrieveServices(const NimBLEUUID *uuid_filter) {
/**
* Design
* ------
@@ -424,6 +442,7 @@ bool NimBLEClient::retrieveServices() {
*/
NIMBLE_LOGD(LOG_TAG, ">> retrieveServices");
int rc = 0;
if(!m_isConnected){
NIMBLE_LOGE(LOG_TAG, "Disconnected, could not retrieve services -aborting");
@@ -432,26 +451,21 @@ bool NimBLEClient::retrieveServices() {
m_semaphoreSearchCmplEvt.take("retrieveServices");
int rc = ble_gattc_disc_all_svcs(m_conn_id, NimBLEClient::serviceDiscoveredCB, this);
if(uuid_filter == nullptr) {
rc = ble_gattc_disc_all_svcs(m_conn_id, NimBLEClient::serviceDiscoveredCB, this);
} else {
rc = ble_gattc_disc_svc_by_uuid(m_conn_id, &uuid_filter->getNative()->u,
NimBLEClient::serviceDiscoveredCB, this);
}
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_svcs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
m_haveServices = false;
m_semaphoreSearchCmplEvt.give();
return false;
}
// wait until we have all the services
// If sucessful, remember that we now have services.
m_haveServices = (m_semaphoreSearchCmplEvt.wait("retrieveServices") == 0);
if(m_haveServices){
for (auto &it: m_servicesVector) {
if(!m_isConnected || !it->retrieveCharacteristics()) {
NIMBLE_LOGE(LOG_TAG, "Disconnected, could not retrieve characteristics -aborting");
return false;
}
}
if(m_semaphoreSearchCmplEvt.wait("retrieveServices") == 0){
NIMBLE_LOGD(LOG_TAG, "<< retrieveServices");
return true;
}
@@ -472,7 +486,9 @@ int NimBLEClient::serviceDiscoveredCB(
const struct ble_gatt_error *error,
const struct ble_gatt_svc *service, void *arg)
{
NIMBLE_LOGD(LOG_TAG,"Service Discovered >> status: %d handle: %d", error->status, conn_handle);
NIMBLE_LOGD(LOG_TAG,"Service Discovered >> status: %d handle: %d",
error->status, (error->status == 0) ? service->start_handle : -1);
NimBLEClient *peer = (NimBLEClient*)arg;
int rc=0;
@@ -518,7 +534,8 @@ int NimBLEClient::serviceDiscoveredCB(
* @returns characteristic value or an empty string if not found
*/
std::string NimBLEClient::getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID) {
NIMBLE_LOGD(LOG_TAG, ">> getValue: serviceUUID: %s, characteristicUUID: %s", serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
NIMBLE_LOGD(LOG_TAG, ">> getValue: serviceUUID: %s, characteristicUUID: %s",
serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
std::string ret = "";
NimBLERemoteService* pService = getService(serviceUUID);
@@ -541,8 +558,11 @@ std::string NimBLEClient::getValue(const NimBLEUUID &serviceUUID, const NimBLEUU
* @param [in] characteristicUUID The characteristic whose value we wish to write.
* @returns true if successful otherwise false
*/
bool NimBLEClient::setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID, const std::string &value) {
NIMBLE_LOGD(LOG_TAG, ">> setValue: serviceUUID: %s, characteristicUUID: %s", serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
bool NimBLEClient::setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID,
const std::string &value)
{
NIMBLE_LOGD(LOG_TAG, ">> setValue: serviceUUID: %s, characteristicUUID: %s",
serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
bool ret = false;
NimBLERemoteService* pService = getService(serviceUUID);
@@ -679,8 +699,6 @@ uint16_t NimBLEClient::getMTU() {
return 0;
NIMBLE_LOGD(LOG_TAG, "Notify Recieved for handle: %d",event->notify_rx.attr_handle);
if(!client->m_haveServices)
return 0;
for(auto &it: client->m_servicesVector) {
// Dont waste cycles searching services without this handle in their range
@@ -688,19 +706,26 @@ uint16_t NimBLEClient::getMTU() {
continue;
}
auto cVector = it->getCharacteristics();
NIMBLE_LOGD(LOG_TAG, "checking service %s for handle: %d", it->getUUID().toString().c_str(),event->notify_rx.attr_handle);
auto cVector = &it->m_characteristicVector;
NIMBLE_LOGD(LOG_TAG, "checking service %s for handle: %d",
it->getUUID().toString().c_str(),
event->notify_rx.attr_handle);
auto characteristic = cVector->cbegin();
for(; characteristic != cVector->cend(); ++characteristic) {
if((*characteristic)->m_handle == event->notify_rx.attr_handle) break;
if((*characteristic)->m_handle == event->notify_rx.attr_handle)
break;
}
if(characteristic != cVector->cend()) {
NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", (*characteristic)->toString().c_str());
if ((*characteristic)->m_notifyCallback != nullptr) {
NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s", (*characteristic)->toString().c_str());
(*characteristic)->m_notifyCallback(*characteristic, event->notify_rx.om->om_data, event->notify_rx.om->om_len, !event->notify_rx.indication);
NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s",
(*characteristic)->toString().c_str());
(*characteristic)->m_notifyCallback(*characteristic, event->notify_rx.om->om_data,
event->notify_rx.om->om_len,
!event->notify_rx.indication);
}
break;
@@ -778,7 +803,6 @@ uint16_t NimBLEClient::getMTU() {
event->mtu.conn_handle,
event->mtu.value);
client->m_semaphoreOpenEvt.give(0);
//client->m_mtu = event->mtu.value;
return 0;
} // BLE_GAP_EVENT_MTU