Skip to content

Commit aa53457

Browse files
authored
Add feature: remove service (#84)
* Get service handles on server start * remove service + indicate service changed * Reset gatt services when no connections active and services changed. * NimBLEServer::createService can now be used any time and will send service changed indication if server was already active. * Add ability to remove advertised serviceUUIDS * Adds addService() method to server to be allow user to re-add a service previously removed * Add destructior to NimBLEServer, NimBLEService and NimBLECharacteristic to release allocated resources.
1 parent f24a111 commit aa53457

File tree

8 files changed

+279
-79
lines changed

8 files changed

+279
-79
lines changed

docs/Improvements_and_updates.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ as a type specified by the user.
4343
A new method `NimBLEServer::advertiseOnDisconnect(bool)` has been implemented to control this, true(default) = enabled.
4444
<br/>
4545

46+
`NimBLEServer::removeService` takes an additional parameter `bool deleteSvc` that if true will delete the service
47+
and all characteristics / descriptors belonging to it and invalidating any pointers to them.
48+
49+
If false the service is only removed from visibility by clients. The pointers to the service and
50+
it's characteristics / descriptors will remain valid and the service can be re-added in the future
51+
using `NimBLEServer::addService`.
52+
<br/>
53+
4654
# Client
4755

4856
NimBLERemoteCharacteristic::readValue(time_t\*, bool)

src/NimBLEAdvertising.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ NimBLEAdvertising::NimBLEAdvertising() {
6363
*/
6464
void NimBLEAdvertising::addServiceUUID(const NimBLEUUID &serviceUUID) {
6565
m_serviceUUIDs.push_back(serviceUUID);
66+
m_advDataSet = false;
6667
} // addServiceUUID
6768

6869

@@ -75,6 +76,22 @@ void NimBLEAdvertising::addServiceUUID(const char* serviceUUID) {
7576
} // addServiceUUID
7677

7778

79+
/**
80+
* @brief Add a service uuid to exposed list of services.
81+
* @param [in] serviceUUID The UUID of the service to expose.
82+
*/
83+
void NimBLEAdvertising::removeServiceUUID(const NimBLEUUID &serviceUUID) {
84+
//m_serviceUUIDs.erase(std::remove_if(m_serviceUUIDs.begin(), m_serviceUUIDs.end(),[serviceUUID](const NimBLEUUID &s) {return serviceUUID == s;}), m_serviceUUIDs.end());
85+
for(auto it = m_serviceUUIDs.begin(); it != m_serviceUUIDs.end(); ++it) {
86+
if((*it) == serviceUUID) {
87+
m_serviceUUIDs.erase(it);
88+
break;
89+
}
90+
}
91+
m_advDataSet = false;
92+
} // addServiceUUID
93+
94+
7895
/**
7996
* @brief Set the device appearance in the advertising data.
8097
* The codes for distinct appearances can be found here:\n

src/NimBLEAdvertising.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class NimBLEAdvertising {
7575
NimBLEAdvertising();
7676
void addServiceUUID(const NimBLEUUID &serviceUUID);
7777
void addServiceUUID(const char* serviceUUID);
78+
void removeServiceUUID(const NimBLEUUID &serviceUUID);
7879
void start();
7980
void stop();
8081
void setAppearance(uint16_t appearance);

src/NimBLECharacteristic.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t prop
5858
* @brief Destructor.
5959
*/
6060
NimBLECharacteristic::~NimBLECharacteristic() {
61+
for(auto &it : m_dscVec) {
62+
delete it;
63+
}
6164
} // ~NimBLECharacteristic
6265

6366

src/NimBLEServer.cpp

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
#include "NimBLEDevice.h"
2323
#include "NimBLELog.h"
2424

25+
#include "services/gap/ble_svc_gap.h"
26+
#include "services/gatt/ble_svc_gatt.h"
27+
28+
2529
static const char* LOG_TAG = "NimBLEServer";
2630
static NimBLEServerCallbacks defaultCallbacks;
2731

@@ -37,9 +41,20 @@ NimBLEServer::NimBLEServer() {
3741
m_pServerCallbacks = &defaultCallbacks;
3842
m_gattsStarted = false;
3943
m_advertiseOnDisconnect = true;
44+
m_svcChanged = false;
4045
} // NimBLEServer
4146

4247

48+
/**
49+
* @brief Destructor: frees all resources / attributes created.
50+
*/
51+
NimBLEServer::~NimBLEServer() {
52+
for(auto &it : m_svcVec) {
53+
delete it;
54+
}
55+
}
56+
57+
4358
/**
4459
* @brief Create a %BLE Service.
4560
* @param [in] uuid The UUID of the new service.
@@ -71,6 +86,12 @@ NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid, uint32_t numH
7186
NimBLEService* pService = new NimBLEService(uuid, numHandles, this);
7287
m_svcVec.push_back(pService); // Save a reference to this service being on this server.
7388

89+
if(m_gattsStarted) {
90+
ble_svc_gatt_changed(0x0001, 0xffff);
91+
m_svcChanged = true;
92+
resetGATT();
93+
}
94+
7495
NIMBLE_LOGD(LOG_TAG, "<< createService");
7596
return pService;
7697
} // createService
@@ -146,8 +167,16 @@ void NimBLEServer::start() {
146167
147168
NIMBLE_LOGI(LOG_TAG, "Service changed characterisic handle: %d", m_svcChgChrHdl);
148169
*/
149-
// Build a vector of characteristics with Notify / Indicate capabilities for event handling
170+
// Get the assigned service handles and build a vector of characteristics
171+
// with Notify / Indicate capabilities for event handling
150172
for(auto &svc : m_svcVec) {
173+
if(svc->m_removed == 0) {
174+
rc = ble_gatts_find_svc(&svc->getUUID().getNative()->u, &svc->m_handle);
175+
if(rc != 0) {
176+
abort();
177+
}
178+
}
179+
151180
for(auto &chr : svc->m_chrVec) {
152181
// if Notify / Indicate is enabled but we didn't create the descriptor
153182
// we do it now.
@@ -260,6 +289,11 @@ size_t NimBLEServer::getConnectedCount() {
260289
server->m_connectedPeersVec.end(),
261290
event->disconnect.conn.conn_handle),
262291
server->m_connectedPeersVec.end());
292+
293+
if(server->m_svcChanged) {
294+
server->resetGATT();
295+
}
296+
263297
server->m_pServerCallbacks->onDisconnect(server);
264298

265299
if(server->m_advertiseOnDisconnect) {
@@ -445,6 +479,111 @@ void NimBLEServer::setCallbacks(NimBLEServerCallbacks* pCallbacks) {
445479
} // setCallbacks
446480

447481

482+
/**
483+
* @brief Remove a service from the server.
484+
*
485+
* @details Immediately removes access to the service by clients, sends a service changed indication,
486+
* and removes the service (if applicable) from the advertisments.
487+
* The service is not deleted unless the deleteSvc parameter is true, otherwise the service remains
488+
* available and can be re-added in the future. If desired a removed but not deleted service can
489+
* be deleted later by calling this method with deleteSvc set to true.
490+
*
491+
* @note The service will not be removed from the database until all open connections are closed
492+
* as it requires resetting the GATT server. In the interim the service will have it's visibility disabled.
493+
*
494+
* @note Advertising will need to be restarted by the user after calling this as we must stop
495+
* advertising in order to remove the service.
496+
*
497+
* @param [in] service The service object to remove.
498+
* @param [in] deleteSvc true if the service should be deleted.
499+
*/
500+
void NimBLEServer::removeService(NimBLEService* service, bool deleteSvc) {
501+
// Check if the service was already removed and if so check if this
502+
// is being called to delete the object and do so if requested.
503+
// Otherwise, ignore the call and return.
504+
if(service->m_removed > 0) {
505+
if(deleteSvc) {
506+
for(auto it = m_svcVec.begin(); it != m_svcVec.end(); ++it) {
507+
if ((*it)->getUUID() == service->getUUID()) {
508+
delete *it;
509+
m_svcVec.erase(it);
510+
break;
511+
}
512+
}
513+
}
514+
515+
return;
516+
}
517+
518+
int rc = ble_gatts_svc_set_visibility(service->getHandle(), 0);
519+
if(rc !=0) {
520+
return;
521+
}
522+
523+
service->m_removed = deleteSvc ? 2 : 1;
524+
m_svcChanged = true;
525+
526+
ble_svc_gatt_changed(0x0001, 0xffff);
527+
resetGATT();
528+
NimBLEDevice::getAdvertising()->removeServiceUUID(service->getUUID());
529+
}
530+
531+
532+
/**
533+
* @brief Adds a service which was already created, but removed from availability.
534+
*
535+
* @note If it is desired to advertise the service it must be added by
536+
* calling NimBLEAdvertising::addServiceUUID.
537+
*
538+
* @param [in} service The service object to add.
539+
*/
540+
void NimBLEServer::addService(NimBLEService* service) {
541+
// If adding a service that was not removed just return.
542+
if(service->m_removed == 0) {
543+
return;
544+
}
545+
546+
service->m_removed = 0;
547+
m_svcChanged = true;
548+
549+
ble_svc_gatt_changed(0x0001, 0xffff);
550+
resetGATT();
551+
}
552+
553+
554+
/**
555+
* @brief Resets the GATT server, used when services are added/removed after initialization.
556+
*/
557+
void NimBLEServer::resetGATT() {
558+
if(getConnectedCount() > 0) {
559+
return;
560+
}
561+
562+
NimBLEDevice::stopAdvertising();
563+
ble_gatts_reset();
564+
ble_svc_gap_init();
565+
ble_svc_gatt_init();
566+
567+
for(auto it = m_svcVec.begin(); it != m_svcVec.end(); ) {
568+
if ((*it)->m_removed > 0) {
569+
if ((*it)->m_removed == 2) {
570+
delete *it;
571+
it = m_svcVec.erase(it);
572+
} else {
573+
++it;
574+
}
575+
continue;
576+
}
577+
578+
(*it)->start();
579+
++it;
580+
}
581+
582+
m_svcChanged = false;
583+
m_gattsStarted = false;
584+
}
585+
586+
448587
/**
449588
* @brief Start advertising.
450589
*

src/NimBLEServer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ class NimBLEServer {
4141
NimBLEService* createService(const char* uuid);
4242
NimBLEService* createService(const NimBLEUUID &uuid, uint32_t numHandles=15,
4343
uint8_t inst_id=0);
44+
void removeService(NimBLEService* service, bool deleteSvc = false);
45+
void addService(NimBLEService* service);
4446
NimBLEAdvertising* getAdvertising();
4547
void setCallbacks(NimBLEServerCallbacks* pCallbacks);
4648
void startAdvertising();
@@ -59,12 +61,14 @@ class NimBLEServer {
5961

6062
private:
6163
NimBLEServer();
64+
~NimBLEServer();
6265
friend class NimBLECharacteristic;
6366
friend class NimBLEDevice;
6467
friend class NimBLEAdvertising;
6568

6669
bool m_gattsStarted;
6770
bool m_advertiseOnDisconnect;
71+
bool m_svcChanged;
6872
NimBLEServerCallbacks* m_pServerCallbacks;
6973
std::vector<uint16_t> m_connectedPeersVec;
7074

@@ -74,6 +78,7 @@ class NimBLEServer {
7478
std::vector<NimBLECharacteristic*> m_notifyChrVec;
7579

7680
static int handleGapEvent(struct ble_gap_event *event, void *arg);
81+
void resetGATT();
7782
}; // NimBLEServer
7883

7984

0 commit comments

Comments
 (0)