mirror of
https://github.com/h2zero/esp-nimble-cpp.git
synced 2024-11-22 05:00:55 +01:00
Add feature: remove service (#17)
* 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.
This commit is contained in:
parent
5857879612
commit
2a5df0c905
8 changed files with 275 additions and 75 deletions
|
@ -43,6 +43,14 @@ as a type specified by the user.
|
|||
A new method `NimBLEServer::advertiseOnDisconnect(bool)` has been implemented to control this, true(default) = enabled.
|
||||
<br/>
|
||||
|
||||
`NimBLEServer::removeService` takes an additional parameter `bool deleteSvc` that if true will delete the service
|
||||
and all characteristics / descriptors belonging to it and invalidating any pointers to them.
|
||||
|
||||
If false the service is only removed from visibility by clients. The pointers to the service and
|
||||
it's characteristics / descriptors will remain valid and the service can be re-added in the future
|
||||
using `NimBLEServer::addService`.
|
||||
<br/>
|
||||
|
||||
# Client
|
||||
|
||||
NimBLERemoteCharacteristic::readValue(time_t\*, bool)
|
||||
|
|
|
@ -63,6 +63,7 @@ NimBLEAdvertising::NimBLEAdvertising() {
|
|||
*/
|
||||
void NimBLEAdvertising::addServiceUUID(const NimBLEUUID &serviceUUID) {
|
||||
m_serviceUUIDs.push_back(serviceUUID);
|
||||
m_advDataSet = false;
|
||||
} // addServiceUUID
|
||||
|
||||
|
||||
|
@ -75,6 +76,22 @@ void NimBLEAdvertising::addServiceUUID(const char* serviceUUID) {
|
|||
} // addServiceUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Add a service uuid to exposed list of services.
|
||||
* @param [in] serviceUUID The UUID of the service to expose.
|
||||
*/
|
||||
void NimBLEAdvertising::removeServiceUUID(const NimBLEUUID &serviceUUID) {
|
||||
//m_serviceUUIDs.erase(std::remove_if(m_serviceUUIDs.begin(), m_serviceUUIDs.end(),[serviceUUID](const NimBLEUUID &s) {return serviceUUID == s;}), m_serviceUUIDs.end());
|
||||
for(auto it = m_serviceUUIDs.begin(); it != m_serviceUUIDs.end(); ++it) {
|
||||
if((*it) == serviceUUID) {
|
||||
m_serviceUUIDs.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_advDataSet = false;
|
||||
} // addServiceUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the device appearance in the advertising data.
|
||||
* The codes for distinct appearances can be found here:\n
|
||||
|
|
|
@ -75,6 +75,7 @@ public:
|
|||
NimBLEAdvertising();
|
||||
void addServiceUUID(const NimBLEUUID &serviceUUID);
|
||||
void addServiceUUID(const char* serviceUUID);
|
||||
void removeServiceUUID(const NimBLEUUID &serviceUUID);
|
||||
void start();
|
||||
void stop();
|
||||
void setAppearance(uint16_t appearance);
|
||||
|
|
|
@ -58,6 +58,9 @@ NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t prop
|
|||
* @brief Destructor.
|
||||
*/
|
||||
NimBLECharacteristic::~NimBLECharacteristic() {
|
||||
for(auto &it : m_dscVec) {
|
||||
delete it;
|
||||
}
|
||||
} // ~NimBLECharacteristic
|
||||
|
||||
|
||||
|
|
|
@ -22,6 +22,10 @@
|
|||
#include "NimBLEDevice.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "services/gatt/ble_svc_gatt.h"
|
||||
|
||||
|
||||
static const char* LOG_TAG = "NimBLEServer";
|
||||
static NimBLEServerCallbacks defaultCallbacks;
|
||||
|
||||
|
@ -37,9 +41,20 @@ NimBLEServer::NimBLEServer() {
|
|||
m_pServerCallbacks = &defaultCallbacks;
|
||||
m_gattsStarted = false;
|
||||
m_advertiseOnDisconnect = true;
|
||||
m_svcChanged = false;
|
||||
} // NimBLEServer
|
||||
|
||||
|
||||
/**
|
||||
* @brief Destructor: frees all resources / attributes created.
|
||||
*/
|
||||
NimBLEServer::~NimBLEServer() {
|
||||
for(auto &it : m_svcVec) {
|
||||
delete it;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a %BLE Service.
|
||||
* @param [in] uuid The UUID of the new service.
|
||||
|
@ -71,6 +86,12 @@ NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid, uint32_t numH
|
|||
NimBLEService* pService = new NimBLEService(uuid, numHandles, this);
|
||||
m_svcVec.push_back(pService); // Save a reference to this service being on this server.
|
||||
|
||||
if(m_gattsStarted) {
|
||||
ble_svc_gatt_changed(0x0001, 0xffff);
|
||||
m_svcChanged = true;
|
||||
resetGATT();
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< createService");
|
||||
return pService;
|
||||
} // createService
|
||||
|
@ -146,8 +167,16 @@ 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
|
||||
// Get the assigned service handles and build a vector of characteristics
|
||||
// with Notify / Indicate capabilities for event handling
|
||||
for(auto &svc : m_svcVec) {
|
||||
if(svc->m_removed == 0) {
|
||||
rc = ble_gatts_find_svc(&svc->getUUID().getNative()->u, &svc->m_handle);
|
||||
if(rc != 0) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &chr : svc->m_chrVec) {
|
||||
// if Notify / Indicate is enabled but we didn't create the descriptor
|
||||
// we do it now.
|
||||
|
@ -260,6 +289,11 @@ size_t NimBLEServer::getConnectedCount() {
|
|||
server->m_connectedPeersVec.end(),
|
||||
event->disconnect.conn.conn_handle),
|
||||
server->m_connectedPeersVec.end());
|
||||
|
||||
if(server->m_svcChanged) {
|
||||
server->resetGATT();
|
||||
}
|
||||
|
||||
server->m_pServerCallbacks->onDisconnect(server);
|
||||
|
||||
if(server->m_advertiseOnDisconnect) {
|
||||
|
@ -445,6 +479,111 @@ void NimBLEServer::setCallbacks(NimBLEServerCallbacks* pCallbacks) {
|
|||
} // setCallbacks
|
||||
|
||||
|
||||
/**
|
||||
* @brief Remove a service from the server.
|
||||
*
|
||||
* @details Immediately removes access to the service by clients, sends a service changed indication,
|
||||
* and removes the service (if applicable) from the advertisments.
|
||||
* The service is not deleted unless the deleteSvc parameter is true, otherwise the service remains
|
||||
* available and can be re-added in the future. If desired a removed but not deleted service can
|
||||
* be deleted later by calling this method with deleteSvc set to true.
|
||||
*
|
||||
* @note The service will not be removed from the database until all open connections are closed
|
||||
* as it requires resetting the GATT server. In the interim the service will have it's visibility disabled.
|
||||
*
|
||||
* @note Advertising will need to be restarted by the user after calling this as we must stop
|
||||
* advertising in order to remove the service.
|
||||
*
|
||||
* @param [in] service The service object to remove.
|
||||
* @param [in] deleteSvc true if the service should be deleted.
|
||||
*/
|
||||
void NimBLEServer::removeService(NimBLEService* service, bool deleteSvc) {
|
||||
// Check if the service was already removed and if so check if this
|
||||
// is being called to delete the object and do so if requested.
|
||||
// Otherwise, ignore the call and return.
|
||||
if(service->m_removed > 0) {
|
||||
if(deleteSvc) {
|
||||
for(auto it = m_svcVec.begin(); it != m_svcVec.end(); ++it) {
|
||||
if ((*it)->getUUID() == service->getUUID()) {
|
||||
delete *it;
|
||||
m_svcVec.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int rc = ble_gatts_svc_set_visibility(service->getHandle(), 0);
|
||||
if(rc !=0) {
|
||||
return;
|
||||
}
|
||||
|
||||
service->m_removed = deleteSvc ? 2 : 1;
|
||||
m_svcChanged = true;
|
||||
|
||||
ble_svc_gatt_changed(0x0001, 0xffff);
|
||||
resetGATT();
|
||||
NimBLEDevice::getAdvertising()->removeServiceUUID(service->getUUID());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Adds a service which was already created, but removed from availability.
|
||||
*
|
||||
* @note If it is desired to advertise the service it must be added by
|
||||
* calling NimBLEAdvertising::addServiceUUID.
|
||||
*
|
||||
* @param [in} service The service object to add.
|
||||
*/
|
||||
void NimBLEServer::addService(NimBLEService* service) {
|
||||
// If adding a service that was not removed just return.
|
||||
if(service->m_removed == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
service->m_removed = 0;
|
||||
m_svcChanged = true;
|
||||
|
||||
ble_svc_gatt_changed(0x0001, 0xffff);
|
||||
resetGATT();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Resets the GATT server, used when services are added/removed after initialization.
|
||||
*/
|
||||
void NimBLEServer::resetGATT() {
|
||||
if(getConnectedCount() > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
NimBLEDevice::stopAdvertising();
|
||||
ble_gatts_reset();
|
||||
ble_svc_gap_init();
|
||||
ble_svc_gatt_init();
|
||||
|
||||
for(auto it = m_svcVec.begin(); it != m_svcVec.end(); ) {
|
||||
if ((*it)->m_removed > 0) {
|
||||
if ((*it)->m_removed == 2) {
|
||||
delete *it;
|
||||
it = m_svcVec.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
(*it)->start();
|
||||
++it;
|
||||
}
|
||||
|
||||
m_svcChanged = false;
|
||||
m_gattsStarted = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Start advertising.
|
||||
*
|
||||
|
|
|
@ -41,6 +41,8 @@ public:
|
|||
NimBLEService* createService(const char* uuid);
|
||||
NimBLEService* createService(const NimBLEUUID &uuid, uint32_t numHandles=15,
|
||||
uint8_t inst_id=0);
|
||||
void removeService(NimBLEService* service, bool deleteSvc = false);
|
||||
void addService(NimBLEService* service);
|
||||
NimBLEAdvertising* getAdvertising();
|
||||
void setCallbacks(NimBLEServerCallbacks* pCallbacks);
|
||||
void startAdvertising();
|
||||
|
@ -59,12 +61,14 @@ public:
|
|||
|
||||
private:
|
||||
NimBLEServer();
|
||||
~NimBLEServer();
|
||||
friend class NimBLECharacteristic;
|
||||
friend class NimBLEDevice;
|
||||
friend class NimBLEAdvertising;
|
||||
|
||||
bool m_gattsStarted;
|
||||
bool m_advertiseOnDisconnect;
|
||||
bool m_svcChanged;
|
||||
NimBLEServerCallbacks* m_pServerCallbacks;
|
||||
std::vector<uint16_t> m_connectedPeersVec;
|
||||
|
||||
|
@ -74,6 +78,7 @@ private:
|
|||
std::vector<NimBLECharacteristic*> m_notifyChrVec;
|
||||
|
||||
static int handleGapEvent(struct ble_gap_event *event, void *arg);
|
||||
void resetGATT();
|
||||
}; // NimBLEServer
|
||||
|
||||
|
||||
|
|
|
@ -53,9 +53,31 @@ NimBLEService::NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLE
|
|||
m_handle = NULL_HANDLE;
|
||||
m_pServer = pServer;
|
||||
m_numHandles = numHandles;
|
||||
m_pSvcDef = nullptr;
|
||||
m_removed = 0;
|
||||
|
||||
} // NimBLEService
|
||||
|
||||
|
||||
NimBLEService::~NimBLEService() {
|
||||
if(m_pSvcDef != nullptr) {
|
||||
if(m_pSvcDef->characteristics != nullptr) {
|
||||
for(int i=0; m_pSvcDef->characteristics[i].uuid != NULL; ++i) {
|
||||
if(m_pSvcDef->characteristics[i].descriptors) {
|
||||
delete(m_pSvcDef->characteristics[i].descriptors);
|
||||
}
|
||||
}
|
||||
delete(m_pSvcDef->characteristics);
|
||||
}
|
||||
|
||||
delete(m_pSvcDef);
|
||||
}
|
||||
|
||||
for(auto &it : m_chrVec) {
|
||||
delete it;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Dump details of this BLE GATT service.
|
||||
* @return N/A.
|
||||
|
@ -94,10 +116,11 @@ NimBLEUUID NimBLEService::getUUID() {
|
|||
* and registers it with the NimBLE stack.
|
||||
* @return bool success/failure .
|
||||
*/
|
||||
|
||||
bool NimBLEService::start() {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> start(): Starting service: %s", toString().c_str());
|
||||
int rc = 0;
|
||||
|
||||
if(m_pSvcDef == nullptr) {
|
||||
// Nimble requires an array of services to be sent to the api
|
||||
// Since we are adding 1 at a time we create an array of 2 and set the type
|
||||
// of the second service to 0 to indicate the end of the array.
|
||||
|
@ -178,14 +201,16 @@ bool NimBLEService::start() {
|
|||
|
||||
// end of services must indicate to api with type = 0
|
||||
svc[1].type = 0;
|
||||
m_pSvcDef = svc;
|
||||
}
|
||||
|
||||
rc = ble_gatts_count_cfg((const ble_gatt_svc_def*)svc);
|
||||
rc = ble_gatts_count_cfg((const ble_gatt_svc_def*)m_pSvcDef);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gatts_count_cfg failed, rc= %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = ble_gatts_add_svcs((const ble_gatt_svc_def*)svc);
|
||||
rc = ble_gatts_add_svcs((const ble_gatt_svc_def*)m_pSvcDef);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gatts_add_svcs, rc= %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
return false;
|
||||
|
|
|
@ -57,6 +57,7 @@ public:
|
|||
private:
|
||||
NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer);
|
||||
NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLEServer* pServer);
|
||||
~NimBLEService();
|
||||
|
||||
friend class NimBLEServer;
|
||||
friend class NimBLEDevice;
|
||||
|
@ -65,7 +66,8 @@ private:
|
|||
NimBLEServer* m_pServer;
|
||||
NimBLEUUID m_uuid;
|
||||
uint16_t m_numHandles;
|
||||
|
||||
ble_gatt_svc_def* m_pSvcDef;
|
||||
uint8_t m_removed;
|
||||
std::vector<NimBLECharacteristic*> m_chrVec;
|
||||
|
||||
}; // NimBLEService
|
||||
|
|
Loading…
Reference in a new issue