Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 50 additions & 4 deletions src/NimBLEServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ struct gattRegisterCallbackArgs {
NimBLEServer::NimBLEServer()
: m_gattsStarted{false},
m_svcChanged{false},
m_registerAppServicesFirst{false},
m_svcChangedSent{false},
# if !MYNEWT_VAL(BLE_EXT_ADV)
# if !MYNEWT_VAL(BLE_EXT_ADV) && MYNEWT_VAL(BLE_ROLE_BROADCASTER)
m_advertiseOnDisconnect{false},
# endif
m_pCallbacks{&defaultCallbacks},
Expand Down Expand Up @@ -397,6 +398,20 @@ void NimBLEServer::advertiseOnDisconnect(bool enable) {
} // advertiseOnDisconnect
# endif

/**
* @brief Register the application's services before the standard GAP/GATT services.
* @param [in] enable true == register the application services first (they take the
* low attribute handles, starting at 0x0001, and GAP/GATT are placed after them);
* false (default) == the standard behavior, GAP/GATT register first and take the low
* handles.
* @details Must be called before the services are started (i.e. before
* NimBLEServer::start()). Useful when a peripheral must expose a fixed attribute-table
* layout that another device relies on by hardcoded handle rather than discovery.
*/
void NimBLEServer::registerAppServicesFirst(bool enable) {
m_registerAppServicesFirst = enable;
} // registerAppServicesFirst

/**
* @brief Return the number of connected clients.
* @return The number of connected clients.
Expand Down Expand Up @@ -954,16 +969,37 @@ bool NimBLEServer::resetGATT() {
# if MYNEWT_VAL(BLE_ROLE_BROADCASTER)
NimBLEDevice::stopAdvertising();
# endif

// esp-idf nimble clears the device name and
// appearance during ble_gatts_reset()
#ifndef CONFIG_USING_NIMBLE_COMPONENT
std::string name(ble_svc_gap_device_name());
uint16_t appearance = ble_svc_gap_device_appearance();
#endif
// A refused reset leaves every attribute registered, so nothing may be freed below; the next
// start() retries, since services stay marked changed.
int rc = ble_gatts_reset();
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "ble_gatts_reset; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
return false;
}
ble_svc_gap_init();
ble_svc_gatt_init();

// Register the standard GAP (0x1800) and GATT (0x1801) services, restoring the
// device name/appearance that ble_gatts_reset() clears. By default this happens
// first, so GAP/GATT take the low attribute handles (0x0001+). When
// registerAppServicesFirst() is enabled, it is deferred until after the application
// services below, so those take the low handles instead.
auto initGapGattServices = [&]() {
ble_svc_gap_init();
#ifndef CONFIG_USING_NIMBLE_COMPONENT
ble_svc_gap_device_name_set(name.c_str());
ble_svc_gap_device_appearance_set(appearance);
#endif
ble_svc_gatt_init();
};

if (!m_registerAppServicesFirst) {
initGapGattServices();
}

for (auto svcIt = m_svcVec.begin(); svcIt != m_svcVec.end();) {
auto* pSvc = *svcIt;
Expand Down Expand Up @@ -1001,13 +1037,23 @@ bool NimBLEServer::resetGATT() {
// connected — a reset, which needs none connected, is the only way to register one.
if (!pSvc->start_internal()) {
NIMBLE_LOGE(LOG_TAG, "Failed to start service: %s", pSvc->getUUID().toString().c_str());
// When deferring GAP/GATT (registerAppServicesFirst), still register
// them on the failure path so the mandatory GAP/GATT services (and
// the restored name/appearance) are never left out of the database.
if (m_registerAppServicesFirst) {
initGapGattServices();
}
return false;
}

pSvc->m_handle = 0;
++svcIt;
}

if (m_registerAppServicesFirst) {
initGapGattServices();
}

return true;
} // resetGATT

Expand Down
2 changes: 2 additions & 0 deletions src/NimBLEServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class NimBLEServer {
NimBLEConnInfo getPeerInfo(const NimBLEAddress& address) const;
NimBLEConnInfo getPeerInfoByHandle(uint16_t connHandle) const;
void advertiseOnDisconnect(bool enable);
void registerAppServicesFirst(bool enable);
void setDataLen(uint16_t connHandle, uint16_t tx_octets) const;
bool updatePhy(uint16_t connHandle, uint8_t txPhysMask, uint8_t rxPhysMask, uint16_t phyOptions);
bool getPhy(uint16_t connHandle, uint8_t* txPhy, uint8_t* rxPhy);
Expand Down Expand Up @@ -130,6 +131,7 @@ class NimBLEServer {

bool m_gattsStarted : 1;
bool m_svcChanged : 1;
bool m_registerAppServicesFirst : 1;
mutable bool m_svcChangedSent : 1;
# if !MYNEWT_VAL(BLE_EXT_ADV) && MYNEWT_VAL(BLE_ROLE_BROADCASTER)
bool m_advertiseOnDisconnect : 1;
Expand Down
Loading