[BREAKING] Refactor NimBLEServer

* General code cleanup
* `NimBLEServerCallbacks::onMTUChanged` renamed to `NimBLEServerCallbacks::onMTUChange` to be consistent with the client callback.
* `NimBLEServer::getPeerIDInfo` renamed to `NimBLEServer::getPeerInfoByHandle` to better describe it's use.
* Use a std::array to store client connection handles instead of std::vector to reduce memory allocation.
* `NimBLEServer::disconnect` now returns `bool`, true = success,  instead of `int` to be consistent with the rest of the library.
This commit is contained in:
h2zero 2024-11-24 19:59:56 -07:00 committed by h2zero
parent c4c9f7913a
commit d9178cfa9b
5 changed files with 448 additions and 510 deletions

View file

@ -199,12 +199,7 @@ bool NimBLEAdvertising::start(uint32_t duration, const NimBLEAddress* dirAddr) {
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
NimBLEServer* pServer = NimBLEDevice::getServer();
if (pServer != nullptr) {
if (!pServer->m_gattsStarted) {
pServer->start();
} else if (pServer->getConnectedCount() >= NIMBLE_MAX_CONNECTIONS) {
NIMBLE_LOGE(LOG_TAG, "Unable to advertise; Max connections reached");
return false;
}
pServer->start(); // make sure the GATT server is ready before advertising
}
# endif

View file

@ -62,9 +62,7 @@ bool NimBLEExtAdvertising::setInstanceData(uint8_t instId, NimBLEExtAdvertisemen
# if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
NimBLEServer* pServer = NimBLEDevice::getServer();
if (pServer != nullptr) {
if (!pServer->m_gattsStarted) {
pServer->start();
}
pServer->start(); // make sure the GATT server is ready before advertising
}
int rc = ble_gap_ext_adv_configure(

View file

@ -27,134 +27,119 @@
# include "nimble/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h"
# endif
#include <limits.h>
#include <algorithm>
# define NIMBLE_SERVER_GET_PEER_NAME_ON_CONNECT_CB 0
# define NIMBLE_SERVER_GET_PEER_NAME_ON_AUTH_CB 1
static const char* LOG_TAG = "NimBLEServer";
static NimBLEServerCallbacks defaultCallbacks;
/**
* @brief Construct a %BLE Server
* @brief Construct a BLE Server
*
* This class is not designed to be individually instantiated. Instead one should create a server by asking
* the NimBLEDevice class.
* This class is not designed to be individually instantiated.
* Instead it should be created the NimBLEDevice API.
*/
NimBLEServer::NimBLEServer() {
memset(m_indWait, BLE_HS_CONN_HANDLE_NONE, sizeof(m_indWait));
// m_svcChgChrHdl = 0xffff; // Future Use
m_pServerCallbacks = &defaultCallbacks;
m_gattsStarted = false;
NimBLEServer::NimBLEServer()
: m_gattsStarted{false},
m_getPeerNameOnConnect{false},
m_svcChanged{false},
m_deleteCallbacks{false},
# if !CONFIG_BT_NIMBLE_EXT_ADV
m_advertiseOnDisconnect = true;
m_advertiseOnDisconnect{false},
# endif
m_svcChanged = false;
m_deleteCallbacks = true;
m_getPeerNameOnConnect = false;
m_pServerCallbacks{&defaultCallbacks},
m_svcVec{},
m_notifyChrVec{} {
m_connectedPeers.fill(BLE_HS_CONN_HANDLE_NONE);
m_indWait.fill(BLE_HS_CONN_HANDLE_NONE);
} // NimBLEServer
/**
* @brief Destructor: frees all resources / attributes created.
*/
NimBLEServer::~NimBLEServer() {
for(const auto &it : m_svcVec) {
delete it;
for (const auto& svc : m_svcVec) {
delete svc;
}
if(m_deleteCallbacks && m_pServerCallbacks != &defaultCallbacks) {
if (m_deleteCallbacks) {
delete m_pServerCallbacks;
}
}
/**
* @brief Create a %BLE Service.
* @brief Create a BLE Service.
* @param [in] uuid The UUID of the new service.
* @return A reference to the new service object.
* @return A pointer to the new service object.
*/
NimBLEService* NimBLEServer::createService(const char* uuid) {
return createService(NimBLEUUID(uuid));
} // createService
/**
* @brief Create a %BLE Service.
* @brief Create a BLE Service.
* @param [in] uuid The UUID of the new service.
* @return A reference to the new service object.
* @return A pointer to the new service object.
*/
NimBLEService* NimBLEServer::createService(const NimBLEUUID& uuid) {
NIMBLE_LOGD(LOG_TAG, ">> createService - %s", uuid.toString().c_str());
// Check that a service with the supplied UUID does not already exist.
if(getServiceByUUID(uuid) != nullptr) {
NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s",
std::string(uuid).c_str());
}
NimBLEService* pService = new NimBLEService(uuid);
m_svcVec.push_back(pService);
serviceChanged();
NIMBLE_LOGD(LOG_TAG, "<< createService");
return pService;
} // createService
/**
* @brief Get a %BLE Service by its UUID
* @brief Get a BLE Service by its UUID
* @param [in] uuid The UUID of the service.
* @param instanceId The index of the service to return (used when multiple services have the same UUID).
* @return A pointer to the service object or nullptr if not found.
*/
NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid, uint16_t instanceId) {
NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid, uint16_t instanceId) const {
return getServiceByUUID(NimBLEUUID(uuid), instanceId);
} // getServiceByUUID
/**
* @brief Get a %BLE Service by its UUID
* @brief Get a BLE Service by its UUID
* @param [in] uuid The UUID of the service.
* @param instanceId The index of the service to return (used when multiple services have the same UUID).
* @return A pointer to the service object or nullptr if not found.
*/
NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid, uint16_t instanceId) {
NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID& uuid, uint16_t instanceId) const {
uint16_t position = 0;
for (auto &it : m_svcVec) {
if (it->getUUID() == uuid) {
for (const auto& svc : m_svcVec) {
if (svc->getUUID() == uuid) {
if (position == instanceId) {
return it;
return svc;
}
position++;
}
}
return nullptr;
} // getServiceByUUID
/**
* @brief Get a %BLE Service by its handle
* @brief Get a BLE Service by its handle
* @param handle The handle of the service.
* @return A pointer to the service object or nullptr if not found.
*/
NimBLEService *NimBLEServer::getServiceByHandle(uint16_t handle) {
for (auto &it : m_svcVec) {
if (it->getHandle() == handle) {
return it;
NimBLEService* NimBLEServer::getServiceByHandle(uint16_t handle) const {
for (const auto& svc : m_svcVec) {
if (svc->getHandle() == handle) {
return svc;
}
}
return nullptr;
}
return nullptr;
}
# if CONFIG_BT_NIMBLE_EXT_ADV
/**
* @brief Retrieve the advertising object that can be used to advertise the existence of the server.
* @return An advertising object.
* @return A pinter to an advertising object.
*/
NimBLEExtAdvertising* NimBLEServer::getAdvertising() {
NimBLEExtAdvertising* NimBLEServer::getAdvertising() const {
return NimBLEDevice::getAdvertising();
} // getAdvertising
# endif
@ -162,9 +147,9 @@ NimBLEExtAdvertising* NimBLEServer::getAdvertising() {
# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
/**
* @brief Retrieve the advertising object that can be used to advertise the existence of the server.
* @return An advertising object.
* @return A pointer to an advertising object.
*/
NimBLEAdvertising* NimBLEServer::getAdvertising() {
NimBLEAdvertising* NimBLEServer::getAdvertising() const {
return NimBLEDevice::getAdvertising();
} // getAdvertising
# endif
@ -178,17 +163,16 @@ void NimBLEServer::serviceChanged() {
ble_svc_gatt_changed(0x0001, 0xffff);
resetGATT();
}
}
} // serviceChanged
/**
* @brief Start the GATT server. Required to be called after setup of all
* services and characteristics / descriptors for the NimBLE host to register them.
* @brief Start the GATT server.
* @details Required to be called after setup of all services and characteristics / descriptors
* for the NimBLE host to register them.
*/
void NimBLEServer::start() {
if (m_gattsStarted) {
NIMBLE_LOGW(LOG_TAG, "Gatt server already started");
return;
return; //already started
}
int rc = ble_gatts_start();
@ -200,29 +184,17 @@ void NimBLEServer::start() {
# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 4
ble_gatts_show_local();
# endif
/*** Future use ***
* TODO: implement service changed handling
ble_uuid16_t svc = {BLE_UUID_TYPE_16, 0x1801};
ble_uuid16_t chr = {BLE_UUID_TYPE_16, 0x2a05};
rc = ble_gatts_find_chr(&svc.u, &chr.u, NULL, &m_svcChgChrHdl);
if(rc != 0) {
NIMBLE_LOGE(LOG_TAG, "ble_gatts_find_chr: rc=%d, %s", rc,
NimBLEUtils::returnCodeToString(rc));
abort();
}
NIMBLE_LOGI(LOG_TAG, "Service changed characterisic handle: %d", m_svcChgChrHdl);
*/
// Get the assigned service handles and build a vector of characteristics
// with Notify / Indicate capabilities for event handling
for(auto &svc : m_svcVec) {
for (const auto& svc : m_svcVec) {
if (svc->getRemoved() == 0) {
rc = ble_gatts_find_svc(svc->getUUID().getBase(), &svc->m_handle);
if (rc != 0) {
NIMBLE_LOGW(LOG_TAG, "GATT Server started without service: %s, Service %s",
svc->getUUID().toString().c_str(), svc->isStarted() ? "missing" : "not started");
NIMBLE_LOGW(LOG_TAG,
"GATT Server started without service: %s, Service %s",
svc->getUUID().toString().c_str(),
svc->isStarted() ? "missing" : "not started");
continue; // Skip this service as it was not started
}
}
@ -230,16 +202,12 @@ void NimBLEServer::start() {
for (auto& chr : svc->m_vChars) {
// if Notify / Indicate is enabled but we didn't create the descriptor
// we do it now.
if((chr->m_properties & BLE_GATT_CHR_F_INDICATE) ||
(chr->m_properties & BLE_GATT_CHR_F_NOTIFY)) {
if ((chr->m_properties & BLE_GATT_CHR_F_INDICATE) || (chr->m_properties & BLE_GATT_CHR_F_NOTIFY)) {
m_notifyChrVec.push_back(chr);
}
for (auto& desc : chr->m_vDescriptors) {
ble_gatts_find_dsc(svc->getUUID().getBase(),
chr->getUUID().getBase(),
desc->getUUID().getBase(),
&desc->m_handle);
ble_gatts_find_dsc(svc->getUUID().getBase(), chr->getUUID().getBase(), desc->getUUID().getBase(), &desc->m_handle);
}
}
}
@ -247,24 +215,20 @@ void NimBLEServer::start() {
m_gattsStarted = true;
} // start
/**
* @brief Disconnect the specified client with optional reason.
* @param [in] connId Connection Id of the client to disconnect.
* @param [in] connHandle Connection handle of the client to disconnect.
* @param [in] reason code for disconnecting.
* @return NimBLE host return code.
* @return True if successful.
*/
int NimBLEServer::disconnect(uint16_t connId, uint8_t reason) {
NIMBLE_LOGD(LOG_TAG, ">> disconnect()");
int rc = ble_gap_terminate(connId, reason);
if(rc != 0){
NIMBLE_LOGE(LOG_TAG, "ble_gap_terminate failed: rc=%d %s", rc,
NimBLEUtils::returnCodeToString(rc));
bool NimBLEServer::disconnect(uint16_t connHandle, uint8_t reason) const {
int rc = ble_gap_terminate(connHandle, reason);
if (rc != 0 && rc != BLE_HS_ENOTCONN && rc != BLE_HS_EALREADY) {
NIMBLE_LOGE(LOG_TAG, "ble_gap_terminate failed: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
return false;
}
NIMBLE_LOGD(LOG_TAG, "<< disconnect()");
return rc;
return true;
} // disconnect
/**
@ -273,17 +237,17 @@ int NimBLEServer::disconnect(uint16_t connId, uint8_t reason) {
* @param [in] reason code for disconnecting.
* @return NimBLE host return code.
*/
int NimBLEServer::disconnect(const NimBLEConnInfo &connInfo, uint8_t reason) {
bool NimBLEServer::disconnect(const NimBLEConnInfo& connInfo, uint8_t reason) const {
return disconnect(connInfo.getConnHandle(), reason);
} // disconnect
# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
/**
* @brief Set the server to automatically start advertising when a client disconnects.
* @param [in] aod true == advertise, false == don't advertise.
* @param [in] enable true == advertise, false == don't advertise.
*/
void NimBLEServer::advertiseOnDisconnect(bool aod) {
m_advertiseOnDisconnect = aod;
void NimBLEServer::advertiseOnDisconnect(bool enable) {
m_advertiseOnDisconnect = enable;
} // advertiseOnDisconnect
# endif
@ -300,57 +264,78 @@ void NimBLEServer::getPeerNameOnConnect(bool enable) {
* @brief Return the number of connected clients.
* @return The number of connected clients.
*/
size_t NimBLEServer::getConnectedCount() {
return m_connectedPeersVec.size();
uint8_t NimBLEServer::getConnectedCount() const {
size_t count = 0;
for (const auto& peer : m_connectedPeers) {
if (peer != BLE_HS_CONN_HANDLE_NONE) {
count++;
}
}
return count;
} // getConnectedCount
/**
* @brief Get the vector of the connected client ID's.
* @brief Get a vector of the connected client handles.
* @return A vector of the connected client handles.
*/
std::vector<uint16_t> NimBLEServer::getPeerDevices() {
return m_connectedPeersVec;
} // getPeerDevices
std::vector<uint16_t> NimBLEServer::getPeerDevices() const {
std::vector<uint16_t> peers{};
for (const auto& peer : m_connectedPeers) {
if (peer != BLE_HS_CONN_HANDLE_NONE) {
peers.push_back(peer);
}
}
return peers;
} // getPeerDevices
/**
* @brief Get the connection information of a connected peer by vector index.
* @param [in] index The vector index of the peer.
* @return A NimBLEConnInfo instance with the peer connection information, or an empty instance if not found.
*/
NimBLEConnInfo NimBLEServer::getPeerInfo(size_t index) {
if (index >= m_connectedPeersVec.size()) {
NIMBLE_LOGE(LOG_TAG, "No peer at index %u", index);
return NimBLEConnInfo();
NimBLEConnInfo NimBLEServer::getPeerInfo(uint8_t index) const {
if (index >= m_connectedPeers.size()) {
NIMBLE_LOGE(LOG_TAG, "Invalid index %u", index);
return NimBLEConnInfo{};
}
return getPeerIDInfo(m_connectedPeersVec[index]);
} // getPeerInfo
auto count = 0;
for (const auto& peer : m_connectedPeers) {
if (peer != BLE_HS_CONN_HANDLE_NONE) {
if (count == index) {
return getPeerInfoByHandle(m_connectedPeers[count]);
}
count++;
}
}
return NimBLEConnInfo{};
} // getPeerInfo
/**
* @brief Get the connection information of a connected peer by address.
* @param [in] address The address of the peer.
* @return A NimBLEConnInfo instance with the peer connection information, or an empty instance if not found.
*/
NimBLEConnInfo NimBLEServer::getPeerInfo(const NimBLEAddress& address) {
NimBLEConnInfo peerInfo;
int rc = ble_gap_conn_find_by_addr(address.getBase(), &peerInfo.m_desc);
if (rc != 0) {
NimBLEConnInfo NimBLEServer::getPeerInfo(const NimBLEAddress& address) const {
NimBLEConnInfo peerInfo{};
if (ble_gap_conn_find_by_addr(address.getBase(), &peerInfo.m_desc) != 0) {
NIMBLE_LOGE(LOG_TAG, "Peer info not found");
}
return peerInfo;
} // getPeerInfo
/**
* @brief Get the connection information of a connected peer by connection ID.
* @param [in] id The connection id of the peer.
* @brief Get the connection information of a connected peer by connection handle.
* @param [in] connHandle The connection handle of the peer.
* @return A NimBLEConnInfo instance with the peer connection information, or an empty instance if not found.
*/
NimBLEConnInfo NimBLEServer::getPeerIDInfo(uint16_t id) {
NimBLEConnInfo peerInfo;
int rc = ble_gap_conn_find(id, &peerInfo.m_desc);
if (rc != 0) {
NimBLEConnInfo NimBLEServer::getPeerInfoByHandle(uint16_t connHandle) const {
NimBLEConnInfo peerInfo{};
if (ble_gap_conn_find(connHandle, &peerInfo.m_desc) != 0) {
NIMBLE_LOGE(LOG_TAG, "Peer info not found");
}
@ -361,13 +346,10 @@ NimBLEConnInfo NimBLEServer::getPeerIDInfo(uint16_t id) {
* @brief Callback that is called after reading from the peer name characteristic.
* @details This will check the task pointer in the task data struct to determine
* the action to take once the name has been read. If there is a task waiting then
* it will be woken, if not, the the RC value is checked to determine which callback
* it will be resumed, if not, the the RC value is checked to determine which callback
* should be called.
*/
int NimBLEServer::peerNameCB(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr,
void *arg) {
int NimBLEServer::peerNameCB(uint16_t connHandle, const ble_gatt_error* error, ble_gatt_attr* attr, void* arg) {
NimBLETaskData* pTaskData = (NimBLETaskData*)arg;
std::string* name = (std::string*)pTaskData->m_pBuf;
int rc = error->status;
@ -383,7 +365,7 @@ int NimBLEServer::peerNameCB(uint16_t conn_handle,
if (pTaskData->m_flags != -1) {
NimBLEServer* pServer = (NimBLEServer*)pTaskData->m_pInstance;
NimBLEConnInfo peerInfo{};
ble_gap_conn_find(conn_handle, &peerInfo.m_desc);
ble_gap_conn_find(connHandle, &peerInfo.m_desc);
// check the flag to indicate which callback should be called.
if (pTaskData->m_flags == NIMBLE_SERVER_GET_PEER_NAME_ON_CONNECT_CB) {
@ -408,30 +390,25 @@ int NimBLEServer::peerNameCB(uint16_t conn_handle,
}
/**
* @brief Internal method that sends the read command.
* @brief Implementation of the function that sends the read command.
*/
std::string NimBLEServer::getPeerNameInternal(uint16_t conn_handle, int cb_type) {
std::string NimBLEServer::getPeerNameImpl(uint16_t connHandle, int cbType) const {
std::string* buf = new std::string{};
NimBLETaskData *pTaskData = new NimBLETaskData(this, cb_type, buf);
NimBLETaskData* pTaskData = new NimBLETaskData(const_cast<NimBLEServer*>(this), cbType, buf);
ble_uuid16_t uuid{{BLE_UUID_TYPE_16}, BLE_SVC_GAP_CHR_UUID16_DEVICE_NAME};
int rc = ble_gattc_read_by_uuid(conn_handle,
1,
0xffff,
&uuid.u,
NimBLEServer::peerNameCB,
pTaskData);
int rc = ble_gattc_read_by_uuid(connHandle, 1, 0xffff, &uuid.u, NimBLEServer::peerNameCB, pTaskData);
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "ble_gattc_read_by_uuid rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
NimBLEConnInfo peerInfo{};
ble_gap_conn_find(conn_handle, &peerInfo.m_desc);
if (cb_type == NIMBLE_SERVER_GET_PEER_NAME_ON_CONNECT_CB) {
m_pServerCallbacks->onConnect(this, peerInfo, *buf);
} else if (cb_type == NIMBLE_SERVER_GET_PEER_NAME_ON_AUTH_CB) {
ble_gap_conn_find(connHandle, &peerInfo.m_desc);
if (cbType == NIMBLE_SERVER_GET_PEER_NAME_ON_CONNECT_CB) {
m_pServerCallbacks->onConnect(const_cast<NimBLEServer*>(this), peerInfo, *buf);
} else if (cbType == NIMBLE_SERVER_GET_PEER_NAME_ON_AUTH_CB) {
m_pServerCallbacks->onAuthenticationComplete(peerInfo, *buf);
}
delete buf;
delete pTaskData;
} else if (cb_type == -1) {
} else if (cbType == -1) {
NimBLEUtils::taskWait(*pTaskData, BLE_NPL_TIME_FOREVER);
rc = pTaskData->m_flags;
std::string name{*(std::string*)pTaskData->m_pBuf};
@ -454,29 +431,22 @@ std::string NimBLEServer::getPeerNameInternal(uint16_t conn_handle, int cb_type)
* @returns A string containing the name.
* @note This is a blocking call and should NOT be called from any callbacks!
*/
std::string NimBLEServer::getPeerName(const NimBLEConnInfo& connInfo) {
std::string name = getPeerNameInternal(connInfo.getConnHandle());
std::string NimBLEServer::getPeerName(const NimBLEConnInfo& connInfo) const {
std::string name = getPeerNameImpl(connInfo.getConnHandle());
return name;
}
/**
* @brief Handle a GATT Server Event.
*
* @param [in] event
* @param [in] gatts_if
* @param [in] param
*
* @brief Gap event handler.
*/
/*STATIC*/
int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
int NimBLEServer::handleGapEvent(ble_gap_event* event, void* arg) {
NIMBLE_LOGD(LOG_TAG, ">> handleGapEvent: %s", NimBLEUtils::gapEventToString(event->type));
int rc = 0;
NimBLEConnInfo peerInfo;
NimBLEConnInfo peerInfo{};
NimBLEServer* pServer = NimBLEDevice::getServer();
switch (event->type) {
case BLE_GAP_EVENT_CONNECT: {
if (event->connect.status != 0) {
/* Connection failed; resume advertising */
@ -490,21 +460,23 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
return 0;
}
pServer->m_connectedPeersVec.push_back(event->connect.conn_handle);
for (auto& peer : pServer->m_connectedPeers) {
if (peer == BLE_HS_CONN_HANDLE_NONE) {
peer = event->connect.conn_handle;
break;
}
}
if (pServer->m_getPeerNameOnConnect) {
pServer->getPeerNameInternal(event->connect.conn_handle,
NIMBLE_SERVER_GET_PEER_NAME_ON_CONNECT_CB);
pServer->getPeerNameImpl(event->connect.conn_handle, NIMBLE_SERVER_GET_PEER_NAME_ON_CONNECT_CB);
} else {
pServer->m_pServerCallbacks->onConnect(pServer, peerInfo);
}
}
return 0;
break;
} // BLE_GAP_EVENT_CONNECT
case BLE_GAP_EVENT_DISCONNECT: {
// If Host reset tell the device now before returning to prevent
// any errors caused by calling host functions before resync.
@ -520,73 +492,70 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
break;
}
pServer->m_connectedPeersVec.erase(std::remove(pServer->m_connectedPeersVec.begin(),
pServer->m_connectedPeersVec.end(),
event->disconnect.conn.conn_handle),
pServer->m_connectedPeersVec.end());
for (auto& peer : pServer->m_connectedPeers) {
if (peer == event->disconnect.conn.conn_handle) {
peer = BLE_HS_CONN_HANDLE_NONE;
break;
}
}
if (pServer->m_svcChanged) {
pServer->resetGATT();
}
NimBLEConnInfo peerInfo(event->disconnect.conn);
peerInfo.m_desc = event->disconnect.conn;
pServer->m_pServerCallbacks->onDisconnect(pServer, peerInfo, event->disconnect.reason);
# if !CONFIG_BT_NIMBLE_EXT_ADV
if (pServer->m_advertiseOnDisconnect) {
pServer->startAdvertising();
}
# endif
return 0;
break;
} // BLE_GAP_EVENT_DISCONNECT
case BLE_GAP_EVENT_SUBSCRIBE: {
NIMBLE_LOGI(LOG_TAG, "subscribe event; attr_handle=%d, subscribed: %s",
NIMBLE_LOGI(LOG_TAG,
"subscribe event; attr_handle=%d, subscribed: %s",
event->subscribe.attr_handle,
(event->subscribe.cur_notify ? "true" : "false"));
for(auto &it : pServer->m_notifyChrVec) {
if(it->getHandle() == event->subscribe.attr_handle) {
for (const auto& chr : pServer->m_notifyChrVec) {
if (chr->getHandle() == event->subscribe.attr_handle) {
rc = ble_gap_conn_find(event->subscribe.conn_handle, &peerInfo.m_desc);
if (rc != 0) {
break;
}
if(((it->getProperties() & BLE_GATT_CHR_F_READ_AUTHEN) ||
(it->getProperties() & BLE_GATT_CHR_F_READ_AUTHOR) ||
(it->getProperties() & BLE_GATT_CHR_F_READ_ENC)) &&
!peerInfo.isEncrypted()) {
auto chrProps = chr->getProperties();
if (!peerInfo.isEncrypted() &&
(chrProps & BLE_GATT_CHR_F_READ_AUTHEN || chrProps & BLE_GATT_CHR_F_READ_AUTHOR ||
chrProps & BLE_GATT_CHR_F_READ_ENC)) {
NimBLEDevice::startSecurity(event->subscribe.conn_handle);
}
it->setSubscribe(event, peerInfo);
chr->setSubscribe(event, peerInfo);
break;
}
}
return 0;
break;
} // BLE_GAP_EVENT_SUBSCRIBE
case BLE_GAP_EVENT_MTU: {
NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d",
event->mtu.conn_handle,
event->mtu.value);
rc = ble_gap_conn_find(event->mtu.conn_handle, &peerInfo.m_desc);
if (rc != 0) {
return 0;
NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d", event->mtu.conn_handle, event->mtu.value);
if (ble_gap_conn_find(event->mtu.conn_handle, &peerInfo.m_desc) == 0) {
pServer->m_pServerCallbacks->onMTUChange(event->mtu.value, peerInfo);
}
pServer->m_pServerCallbacks->onMTUChange(event->mtu.value, peerInfo);
return 0;
break;
} // BLE_GAP_EVENT_MTU
case BLE_GAP_EVENT_NOTIFY_TX: {
NimBLECharacteristic* pChar = nullptr;
for(auto &it : pServer->m_notifyChrVec) {
if(it->getHandle() == event->notify_tx.attr_handle) {
pChar = it;
for (auto& chr : pServer->m_notifyChrVec) {
if (chr->getHandle() == event->notify_tx.attr_handle) {
pChar = chr;
}
}
@ -602,28 +571,24 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
}
pChar->m_pCallbacks->onStatus(pChar, event->notify_tx.status);
return 0;
break;
} // BLE_GAP_EVENT_NOTIFY_TX
case BLE_GAP_EVENT_ADV_COMPLETE:
case BLE_GAP_EVENT_ADV_COMPLETE: {
# if CONFIG_BT_NIMBLE_EXT_ADV
case BLE_GAP_EVENT_SCAN_REQ_RCVD:
return NimBLEExtAdvertising::handleGapEvent(event, arg);
# else
return NimBLEAdvertising::handleGapEvent(event, arg);
# endif
// BLE_GAP_EVENT_ADV_COMPLETE | BLE_GAP_EVENT_SCAN_REQ_RCVD
} // BLE_GAP_EVENT_ADV_COMPLETE | BLE_GAP_EVENT_SCAN_REQ_RCVD
case BLE_GAP_EVENT_CONN_UPDATE: {
rc = ble_gap_conn_find(event->connect.conn_handle, &peerInfo.m_desc);
if (rc != 0) {
return 0;
if (ble_gap_conn_find(event->connect.conn_handle, &peerInfo.m_desc) == 0) {
pServer->m_pServerCallbacks->onConnParamsUpdate(peerInfo);
}
pServer->m_pServerCallbacks->onConnParamsUpdate(peerInfo);
return 0;
break;
} // BLE_GAP_EVENT_CONN_UPDATE
case BLE_GAP_EVENT_REPEAT_PAIRING: {
@ -653,12 +618,12 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
}
if (pServer->m_getPeerNameOnConnect) {
pServer->getPeerNameInternal(event->enc_change.conn_handle,
NIMBLE_SERVER_GET_PEER_NAME_ON_AUTH_CB);
pServer->getPeerNameImpl(event->enc_change.conn_handle, NIMBLE_SERVER_GET_PEER_NAME_ON_AUTH_CB);
} else {
pServer->m_pServerCallbacks->onAuthenticationComplete(peerInfo);
}
return 0;
break;
} // BLE_GAP_EVENT_ENC_CHANGE
case BLE_GAP_EVENT_IDENTITY_RESOLVED: {
@ -668,7 +633,7 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
}
pServer->m_pServerCallbacks->onIdentity(peerInfo);
return 0;
break;
} // BLE_GAP_EVENT_IDENTITY_RESOLVED
# if CONFIG_BT_NIMBLE_EXT_ADV
@ -678,9 +643,7 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
return BLE_ATT_ERR_INVALID_HANDLE;
}
pServer->m_pServerCallbacks->onPhyUpdate(peerInfo,
event->phy_updated.tx_phy,
event->phy_updated.rx_phy);
pServer->m_pServerCallbacks->onPhyUpdate(peerInfo, event->phy_updated.tx_phy, event->phy_updated.rx_phy);
return 0;
} // BLE_GAP_EVENT_PHY_UPDATE_COMPLETE
# endif
@ -709,22 +672,20 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
}
pServer->m_pServerCallbacks->onConfirmPassKey(peerInfo, event->passkey.params.numcmp);
//TODO: Handle out of band pairing
} else if (event->passkey.params.action == BLE_SM_IOACT_OOB) {
static uint8_t tem_oob[16] = {0};
pkey.action = event->passkey.params.action;
for (int i = 0; i < 16; i++) {
pkey.oob[i] = tem_oob[i];
}
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_OOB; ble_sm_inject_io result: %d", rc);
//////////////////////////////////
// TODO: Handle out of band pairing
// static uint8_t tem_oob[16] = {0};
// pkey.action = event->passkey.params.action;
// for (int i = 0; i < 16; i++) {
// pkey.oob[i] = tem_oob[i];
// }
// rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
// NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_OOB; ble_sm_inject_io result: %d", rc);
} else if (event->passkey.params.action == BLE_SM_IOACT_NONE) {
NIMBLE_LOGD(LOG_TAG, "No passkey action required");
}
NIMBLE_LOGD(LOG_TAG, "<< handleGATTServerEvent");
return 0;
break;
} // BLE_GAP_EVENT_PASSKEY_ACTION
default:
@ -735,27 +696,25 @@ int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
return 0;
} // handleGapEvent
/**
* @brief STATIC callback to handle events from the NimBLE stack.
* @brief GATT event handler.
*/
int NimBLEServer::handleGattEvent(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg) {
NIMBLE_LOGD(LOG_TAG, "Gatt %s event", (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR ||
ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) ? "Read" : "Write");
int NimBLEServer::handleGattEvent(uint16_t connHandle, uint16_t attrHandle, ble_gatt_access_ctxt* ctxt, void* arg) {
NIMBLE_LOGD(LOG_TAG,
"Gatt %s event",
(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR || ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) ? "Read" : "Write");
auto pAtt = static_cast<NimBLELocalValueAttribute*>(arg);
const auto& val = pAtt->getAttVal();
NimBLEConnInfo peerInfo{};
ble_gap_conn_find(conn_handle, &peerInfo.m_desc);
ble_gap_conn_find(connHandle, &peerInfo.m_desc);
switch (ctxt->op) {
case BLE_GATT_ACCESS_OP_READ_DSC:
case BLE_GATT_ACCESS_OP_READ_CHR: {
// If the packet header is only 8 bytes this is a follow up of a long read
// so we don't want to call the onRead() callback again.
if(ctxt->om->om_pkthdr_len > 8 ||
conn_handle == BLE_HS_CONN_HANDLE_NONE ||
val.size() <= (ble_att_mtu(conn_handle) - 3)) {
if (ctxt->om->om_pkthdr_len > 8 || connHandle == BLE_HS_CONN_HANDLE_NONE ||
val.size() <= (ble_att_mtu(connHandle) - 3)) {
pAtt->readEvent(peerInfo);
}
@ -801,7 +760,7 @@ int NimBLEServer::handleGattEvent(uint16_t conn_handle, uint16_t attr_handle,
/**
* @brief Set the server callbacks.
*
* As a %BLE server operates, it will generate server level events such as a new client connecting or a previous client
* As a BLE server operates, it will generate server level events such as a new client connecting or a previous client
* disconnecting. This function can be called to register a callback handler that will be invoked when these
* events are detected.
*
@ -814,10 +773,10 @@ void NimBLEServer::setCallbacks(NimBLEServerCallbacks* pCallbacks, bool deleteCa
m_deleteCallbacks = deleteCallbacks;
} else {
m_pServerCallbacks = &defaultCallbacks;
m_deleteCallbacks = false;
}
} // setCallbacks
/**
* @brief Remove a service from the server.
*
@ -864,8 +823,7 @@ void NimBLEServer::removeService(NimBLEService* service, bool deleteSvc) {
# if !CONFIG_BT_NIMBLE_EXT_ADV
NimBLEDevice::getAdvertising()->removeServiceUUID(service->getUUID());
# endif
}
} // removeService
/**
* @brief Adds a service which was either already created but removed from availability,\n
@ -877,8 +835,7 @@ void NimBLEServer::removeService(NimBLEService* service, bool deleteSvc) {
void NimBLEServer::addService(NimBLEService* service) {
// Check that a service with the supplied UUID does not already exist.
if (getServiceByUUID(service->getUUID()) != nullptr) {
NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s",
std::string(service->getUUID()).c_str());
NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s", std::string(service->getUUID()).c_str());
}
// If adding a service that was not removed add it and return.
@ -892,7 +849,6 @@ void NimBLEServer::addService(NimBLEService* service) {
serviceChanged();
}
/**
* @brief Resets the GATT server, used when services are added/removed after initialization.
*/
@ -923,33 +879,29 @@ void NimBLEServer::resetGATT() {
m_svcChanged = false;
m_gattsStarted = false;
}
} // resetGATT
# if CONFIG_BT_NIMBLE_EXT_ADV
/**
* @brief Start advertising.
* @param [in] inst_id The extended advertisement instance ID to start.
* @param [in] instId The extended advertisement instance ID to start.
* @param [in] duration How long to advertise for in milliseconds, 0 = forever (default).
* @param [in] max_events Maximum number of advertisement events to send, 0 = no limit (default).
* @param [in] maxEvents Maximum number of advertisement events to send, 0 = no limit (default).
* @return True if advertising started successfully.
* @details Start the server advertising its existence. This is a convenience function and is equivalent to
* retrieving the advertising object and invoking start upon it.
*/
bool NimBLEServer::startAdvertising(uint8_t inst_id,
int duration,
int max_events) {
return getAdvertising()->start(inst_id, duration, max_events);
bool NimBLEServer::startAdvertising(uint8_t instId, int duration, int maxEvents) const {
return getAdvertising()->start(instId, duration, maxEvents);
} // startAdvertising
/**
* @brief Convenience function to stop advertising a data set.
* @param [in] inst_id The extended advertisement instance ID to stop advertising.
* @param [in] instId The extended advertisement instance ID to stop advertising.
* @return True if advertising stopped successfully.
*/
bool NimBLEServer::stopAdvertising(uint8_t inst_id) {
return getAdvertising()->stop(inst_id);
bool NimBLEServer::stopAdvertising(uint8_t instId) const {
return getAdvertising()->stop(instId);
} // stopAdvertising
/**
@ -1005,86 +957,78 @@ bool NimBLEServer::getPhy(uint16_t connHandle, uint8_t* txPhy, uint8_t* rxPhy) {
* @details Start the server advertising its existence. This is a convenience function and is equivalent to
* retrieving the advertising object and invoking start upon it.
*/
bool NimBLEServer::startAdvertising(uint32_t duration) {
bool NimBLEServer::startAdvertising(uint32_t duration) const {
return getAdvertising()->start(duration);
} // startAdvertising
#endif
/**
* @brief Stop advertising.
* @return True if advertising stopped successfully.
*/
bool NimBLEServer::stopAdvertising() {
bool NimBLEServer::stopAdvertising() const {
return getAdvertising()->stop();
} // stopAdvertising
# endif
/**
* @brief Get the MTU of the client.
* @returns The client MTU or 0 if not found/connected.
* @brief Get the MTU value of a client connection.
* @param [in] connHandle The connection handle of the client to get the MTU value for.
* @returns The MTU or 0 if not found/connected.
*/
uint16_t NimBLEServer::getPeerMTU(uint16_t conn_id) {
return ble_att_mtu(conn_id);
uint16_t NimBLEServer::getPeerMTU(uint16_t connHandle) const {
return ble_att_mtu(connHandle);
} // getPeerMTU
/**
* @brief Request an Update the connection parameters:
* * Can only be used after a connection has been established.
* @param [in] conn_handle The connection handle of the peer to send the request to.
* @param [in] connHandle The connection handle of the peer to send the request to.
* @param [in] minInterval The minimum connection interval in 1.25ms units.
* @param [in] maxInterval The maximum connection interval in 1.25ms units.
* @param [in] latency The number of packets allowed to skip (extends max interval).
* @param [in] timeout The timeout time in 10ms units before disconnecting.
*/
void NimBLEServer::updateConnParams(uint16_t conn_handle,
uint16_t minInterval, uint16_t maxInterval,
uint16_t latency, uint16_t timeout)
{
ble_gap_upd_params params;
void NimBLEServer::updateConnParams(
uint16_t connHandle, uint16_t minInterval, uint16_t maxInterval, uint16_t latency, uint16_t timeout) const {
ble_gap_upd_params params = {.itvl_min = minInterval,
.itvl_max = maxInterval,
.latency = latency,
.supervision_timeout = timeout,
.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN,
.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN};
params.latency = latency;
params.itvl_max = maxInterval; // max_int = 0x20*1.25ms = 40ms
params.itvl_min = minInterval; // min_int = 0x10*1.25ms = 20ms
params.supervision_timeout = timeout; // timeout = 400*10ms = 4000ms
params.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; // Minimum length of connection event in 0.625ms units
params.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units
int rc = ble_gap_update_params(conn_handle, &params);
int rc = ble_gap_update_params(connHandle, &params);
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
}
} // updateConnParams
/**
* @brief Request an update of the data packet length.
* * Can only be used after a connection has been established.
* @details Sends a data length update request to the peer.
* The Data Length Extension (DLE) allows to increase the Data Channel Payload from 27 bytes to up to 251 bytes.
* The peer needs to support the Bluetooth 4.2 specifications, to be capable of DLE.
* @param [in] conn_handle The connection handle of the peer to send the request to.
* @param [in] tx_octets The preferred number of payload octets to use (Range 0x001B-0x00FB).
* @param [in] connHandle The connection handle of the peer to send the request to.
* @param [in] octets The preferred number of payload octets to use (Range 0x001B-0x00FB).
*/
void NimBLEServer::setDataLen(uint16_t conn_handle, uint16_t tx_octets) {
void NimBLEServer::setDataLen(uint16_t connHandle, uint16_t octets) const {
# if defined(CONFIG_NIMBLE_CPP_IDF) && !defined(ESP_IDF_VERSION) || \
(ESP_IDF_VERSION_MAJOR * 100 + ESP_IDF_VERSION_MINOR * 10 + ESP_IDF_VERSION_PATCH) < 432
return;
# else
uint16_t tx_time = (tx_octets + 14) * 8;
uint16_t tx_time = (octets + 14) * 8;
int rc = ble_gap_set_data_len(conn_handle, tx_octets, tx_time);
int rc = ble_gap_set_data_len(connHandle, octets, tx_time);
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Set data length error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
}
# endif
} // setDataLen
bool NimBLEServer::setIndicateWait(uint16_t conn_handle) {
bool NimBLEServer::setIndicateWait(uint16_t connHandle) {
for (auto i = 0; i < CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) {
if(m_indWait[i] == conn_handle) {
if (m_indWait[i] == connHandle) {
return false;
}
}
@ -1092,17 +1036,15 @@ bool NimBLEServer::setIndicateWait(uint16_t conn_handle) {
return true;
}
void NimBLEServer::clearIndicateWait(uint16_t conn_handle) {
void NimBLEServer::clearIndicateWait(uint16_t connHandle) {
for (auto i = 0; i < CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) {
if(m_indWait[i] == conn_handle) {
if (m_indWait[i] == connHandle) {
m_indWait[i] = BLE_HS_CONN_HANDLE_NONE;
return;
}
}
}
/** Default callback handlers */
void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) {
NIMBLE_LOGD("NimBLEServerCallbacks", "onConnect(): Default");
@ -1112,8 +1054,7 @@ void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer, NimBLEConnInfo& con
NIMBLE_LOGD("NimBLEServerCallbacks", "onConnect(): Default");
} // onConnect
void NimBLEServerCallbacks::onDisconnect(NimBLEServer* pServer,
NimBLEConnInfo& connInfo, int reason) {
void NimBLEServerCallbacks::onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) {
NIMBLE_LOGD("NimBLEServerCallbacks", "onDisconnect(): Default");
} // onDisconnect

View file

@ -12,123 +12,122 @@
* Author: kolban
*/
#ifndef MAIN_NIMBLESERVER_H_
#define MAIN_NIMBLESERVER_H_
#ifndef NIMBLE_CPP_SERVER_H_
#define NIMBLE_CPP_SERVER_H_
#include "nimconfig.h"
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
class NimBLEServer;
class NimBLEServerCallbacks;
#include "NimBLEUtils.h"
#include "NimBLEAddress.h"
#if CONFIG_BT_NIMBLE_EXT_ADV
#include "NimBLEExtAdvertising.h"
# if defined(CONFIG_NIMBLE_CPP_IDF)
# include "host/ble_gap.h"
# else
#include "NimBLEAdvertising.h"
# include "nimble/nimble/host/include/host/ble_gap.h"
# endif
#include "NimBLEService.h"
#include "NimBLECharacteristic.h"
#include "NimBLEConnInfo.h"
/**** FIX COMPILATION ****/
# undef min
# undef max
/**************************/
# include <string>
# include <vector>
# include <array>
# define NIMBLE_ATT_REMOVE_HIDE 1
# define NIMBLE_ATT_REMOVE_DELETE 2
#define onMtuChanged onMTUChange
class NimBLEService;
class NimBLEServerCallbacks;
class NimBLEUUID;
class NimBLEConnInfo;
class NimBLEAddress;
class NimBLEService;
class NimBLECharacteristic;
# if CONFIG_BT_NIMBLE_EXT_ADV
class NimBLEExtAdvertising;
# else
class NimBLEAdvertising;
# endif
/**
* @brief The model of a %BLE server.
* @brief The model of a BLE server.
*/
class NimBLEServer {
public:
size_t getConnectedCount();
void start();
uint8_t getConnectedCount() const;
bool disconnect(uint16_t connHandle, uint8_t reason = BLE_ERR_REM_USER_CONN_TERM) const;
bool disconnect(const NimBLEConnInfo& connInfo, uint8_t reason = BLE_ERR_REM_USER_CONN_TERM) const;
void setCallbacks(NimBLEServerCallbacks* pCallbacks, bool deleteCallbacks = true);
void updateConnParams(uint16_t connHandle, uint16_t minInterval, uint16_t maxInterval, uint16_t latency, uint16_t timeout) const;
NimBLEService* createService(const char* uuid);
NimBLEService* createService(const NimBLEUUID& uuid);
NimBLEService* getServiceByUUID(const char* uuid, uint16_t instanceId = 0) const;
NimBLEService* getServiceByUUID(const NimBLEUUID& uuid, uint16_t instanceId = 0) const;
NimBLEService* getServiceByHandle(uint16_t handle) const;
void removeService(NimBLEService* service, bool deleteSvc = false);
void addService(NimBLEService* service);
void setCallbacks(NimBLEServerCallbacks* pCallbacks,
bool deleteCallbacks = true);
uint16_t getPeerMTU(uint16_t connHandle) const;
std::vector<uint16_t> getPeerDevices() const;
NimBLEConnInfo getPeerInfo(uint8_t index) const;
NimBLEConnInfo getPeerInfo(const NimBLEAddress& address) const;
NimBLEConnInfo getPeerInfoByHandle(uint16_t connHandle) const;
std::string getPeerName(const NimBLEConnInfo& connInfo) const;
void getPeerNameOnConnect(bool enable);
void advertiseOnDisconnect(bool enable);
void setDataLen(uint16_t connHandle, uint16_t tx_octets) const;
# if CONFIG_BT_NIMBLE_EXT_ADV
NimBLEExtAdvertising* getAdvertising();
bool startAdvertising(uint8_t inst_id,
int duration = 0,
int max_events = 0);
bool stopAdvertising(uint8_t inst_id);
NimBLEExtAdvertising* getAdvertising() const;
bool startAdvertising(uint8_t instanceId, int duration = 0, int maxEvents = 0) const;
bool stopAdvertising(uint8_t instanceId) 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);
# endif
# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
NimBLEAdvertising* getAdvertising();
bool startAdvertising(uint32_t duration = 0);
#endif
bool stopAdvertising();
void start();
NimBLEService* getServiceByUUID(const char* uuid, uint16_t instanceId = 0);
NimBLEService* getServiceByUUID(const NimBLEUUID &uuid, uint16_t instanceId = 0);
NimBLEService* getServiceByHandle(uint16_t handle);
int disconnect(uint16_t connID,
uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
int disconnect(const NimBLEConnInfo &connInfo,
uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
void updateConnParams(uint16_t conn_handle,
uint16_t minInterval, uint16_t maxInterval,
uint16_t latency, uint16_t timeout);
void setDataLen(uint16_t conn_handle, uint16_t tx_octets);
uint16_t getPeerMTU(uint16_t conn_id);
std::vector<uint16_t> getPeerDevices();
NimBLEConnInfo getPeerInfo(size_t index);
NimBLEConnInfo getPeerInfo(const NimBLEAddress& address);
NimBLEConnInfo getPeerIDInfo(uint16_t id);
std::string getPeerName(const NimBLEConnInfo& connInfo);
void getPeerNameOnConnect(bool enable);
#if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
void advertiseOnDisconnect(bool);
NimBLEAdvertising* getAdvertising() const;
bool startAdvertising(uint32_t duration = 0) const;
bool stopAdvertising() const;
# endif
private:
NimBLEServer();
~NimBLEServer();
friend class NimBLECharacteristic;
friend class NimBLEService;
friend class NimBLEDevice;
friend class NimBLEAdvertising;
friend class NimBLEService;
friend class NimBLECharacteristic;
# if CONFIG_BT_NIMBLE_EXT_ADV
friend class NimBLEExtAdvertising;
friend class NimBLEExtAdvertisementData;
# else
friend class NimBLEAdvertising;
# endif
bool m_gattsStarted;
NimBLEServer();
~NimBLEServer();
bool m_gattsStarted : 1;
bool m_getPeerNameOnConnect : 1;
bool m_svcChanged : 1;
bool m_deleteCallbacks : 1;
# if !CONFIG_BT_NIMBLE_EXT_ADV
bool m_advertiseOnDisconnect;
bool m_advertiseOnDisconnect : 1;
# endif
bool m_getPeerNameOnConnect;
bool m_svcChanged;
NimBLEServerCallbacks* m_pServerCallbacks;
bool m_deleteCallbacks;
uint16_t m_indWait[CONFIG_BT_NIMBLE_MAX_CONNECTIONS];
std::vector<uint16_t> m_connectedPeersVec;
// uint16_t m_svcChgChrHdl; // Future use
std::vector<NimBLEService*> m_svcVec;
std::vector<NimBLECharacteristic*> m_notifyChrVec;
std::array<uint16_t, CONFIG_BT_NIMBLE_MAX_CONNECTIONS> m_connectedPeers;
std::array<uint16_t, CONFIG_BT_NIMBLE_MAX_CONNECTIONS> m_indWait;
static int handleGapEvent(struct ble_gap_event* event, void* arg);
static int peerNameCB(uint16_t conn_handle, const struct ble_gatt_error *error,
struct ble_gatt_attr *attr, void *arg);
std::string getPeerNameInternal(uint16_t conn_handle, int cb_type = -1);
static int handleGattEvent(uint16_t connHandle, uint16_t attrHandle, ble_gatt_access_ctxt* ctxt, void* arg);
static int peerNameCB(uint16_t connHandle, const ble_gatt_error* error, ble_gatt_attr* attr, void* arg);
std::string getPeerNameImpl(uint16_t connHandle, int cb_type = -1) const;
void serviceChanged();
void resetGATT();
bool setIndicateWait(uint16_t conn_handle);
void clearIndicateWait(uint16_t conn_handle);
static int handleGattEvent(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
bool setIndicateWait(uint16_t connHandle);
void clearIndicateWait(uint16_t connHandle);
}; // NimBLEServer
/**
* @brief Callbacks associated with the operation of a %BLE server.
*/
@ -232,5 +231,5 @@ public:
# endif
}; // NimBLEServerCallbacks
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
#endif /* MAIN_NIMBLESERVER_H_ */
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
#endif // NIMBLE_CPP_SERVER_H_

View file

@ -17,8 +17,13 @@
#include "nimconfig.h"
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
# include "NimBLEDevice.h"
# include "NimBLEService.h"
# if CONFIG_BT_NIMBLE_EXT_ADV
# include "NimBLEExtAdvertising.h"
# else
# include "NimBLEAdvertising.h"
# endif
# include "NimBLEDevice.h"
# include "NimBLEUtils.h"
# include "NimBLELog.h"