2020-03-29 17:44:20 -06:00
|
|
|
/*
|
|
|
|
|
* NimBLEServer.cpp
|
|
|
|
|
*
|
|
|
|
|
* Created: on March 2, 2020
|
|
|
|
|
* Author H2zero
|
2020-05-13 22:03:56 -06:00
|
|
|
*
|
2020-03-29 17:44:20 -06:00
|
|
|
* Originally:
|
|
|
|
|
*
|
|
|
|
|
* BLEServer.cpp
|
|
|
|
|
*
|
|
|
|
|
* Created on: Apr 16, 2017
|
|
|
|
|
* Author: kolban
|
|
|
|
|
*/
|
|
|
|
|
|
2020-05-13 22:03:56 -06:00
|
|
|
#include "nimconfig.h"
|
2021-09-06 21:14:43 -06:00
|
|
|
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
# include "NimBLEServer.h"
|
|
|
|
|
# include "NimBLEDevice.h"
|
|
|
|
|
# include "NimBLELog.h"
|
|
|
|
|
|
|
|
|
|
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
|
|
|
|
# include "services/gap/ble_svc_gap.h"
|
|
|
|
|
# include "services/gatt/ble_svc_gatt.h"
|
|
|
|
|
# else
|
|
|
|
|
# include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h"
|
|
|
|
|
# include "nimble/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h"
|
|
|
|
|
# endif
|
2024-06-24 15:22:56 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
# define NIMBLE_SERVER_GET_PEER_NAME_ON_CONNECT_CB 0
|
|
|
|
|
# define NIMBLE_SERVER_GET_PEER_NAME_ON_AUTH_CB 1
|
2024-06-24 15:22:56 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
static const char* LOG_TAG = "NimBLEServer";
|
2020-03-29 17:44:20 -06:00
|
|
|
static NimBLEServerCallbacks defaultCallbacks;
|
|
|
|
|
|
|
|
|
|
/**
|
2024-11-24 19:59:56 -07:00
|
|
|
* @brief Construct a BLE Server
|
2020-03-29 17:44:20 -06:00
|
|
|
*
|
2024-11-24 19:59:56 -07:00
|
|
|
* This class is not designed to be individually instantiated.
|
|
|
|
|
* Instead it should be created the NimBLEDevice API.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
NimBLEServer::NimBLEServer()
|
|
|
|
|
: m_gattsStarted{false},
|
|
|
|
|
m_getPeerNameOnConnect{false},
|
|
|
|
|
m_svcChanged{false},
|
|
|
|
|
m_deleteCallbacks{false},
|
|
|
|
|
# if !CONFIG_BT_NIMBLE_EXT_ADV
|
|
|
|
|
m_advertiseOnDisconnect{false},
|
|
|
|
|
# endif
|
|
|
|
|
m_pServerCallbacks{&defaultCallbacks},
|
2024-11-25 18:41:10 -07:00
|
|
|
m_svcVec{} {
|
2024-11-24 19:59:56 -07:00
|
|
|
m_connectedPeers.fill(BLE_HS_CONN_HANDLE_NONE);
|
2020-06-07 18:42:28 -06:00
|
|
|
} // NimBLEServer
|
2020-03-29 17:44:20 -06:00
|
|
|
|
2020-07-13 21:24:07 -06:00
|
|
|
/**
|
|
|
|
|
* @brief Destructor: frees all resources / attributes created.
|
|
|
|
|
*/
|
|
|
|
|
NimBLEServer::~NimBLEServer() {
|
2024-11-24 19:59:56 -07:00
|
|
|
for (const auto& svc : m_svcVec) {
|
|
|
|
|
delete svc;
|
2020-07-13 21:24:07 -06:00
|
|
|
}
|
2020-07-28 20:57:33 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
if (m_deleteCallbacks) {
|
2020-07-28 20:57:33 -06:00
|
|
|
delete m_pServerCallbacks;
|
|
|
|
|
}
|
2020-07-13 21:24:07 -06:00
|
|
|
}
|
|
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
/**
|
2024-11-24 19:59:56 -07:00
|
|
|
* @brief Create a BLE Service.
|
2020-03-29 17:44:20 -06:00
|
|
|
* @param [in] uuid The UUID of the new service.
|
2024-11-24 19:59:56 -07:00
|
|
|
* @return A pointer to the new service object.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
|
|
|
|
NimBLEService* NimBLEServer::createService(const char* uuid) {
|
2020-05-13 22:03:56 -06:00
|
|
|
return createService(NimBLEUUID(uuid));
|
2020-06-07 18:42:28 -06:00
|
|
|
} // createService
|
2020-03-29 17:44:20 -06:00
|
|
|
|
|
|
|
|
/**
|
2024-11-24 19:59:56 -07:00
|
|
|
* @brief Create a BLE Service.
|
2020-03-29 17:44:20 -06:00
|
|
|
* @param [in] uuid The UUID of the new service.
|
2024-11-24 19:59:56 -07:00
|
|
|
* @return A pointer to the new service object.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
NimBLEService* NimBLEServer::createService(const NimBLEUUID& uuid) {
|
2021-12-29 08:12:07 -07:00
|
|
|
NimBLEService* pService = new NimBLEService(uuid);
|
|
|
|
|
m_svcVec.push_back(pService);
|
2021-07-30 20:56:52 -06:00
|
|
|
serviceChanged();
|
2020-07-13 21:24:07 -06:00
|
|
|
|
2020-05-13 22:03:56 -06:00
|
|
|
return pService;
|
2020-03-29 17:44:20 -06:00
|
|
|
} // createService
|
|
|
|
|
|
|
|
|
|
/**
|
2024-11-24 19:59:56 -07:00
|
|
|
* @brief Get a BLE Service by its UUID
|
2021-02-08 15:28:32 +00:00
|
|
|
* @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.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid, uint16_t instanceId) const {
|
2021-02-08 15:28:32 +00:00
|
|
|
return getServiceByUUID(NimBLEUUID(uuid), instanceId);
|
2020-06-07 18:42:28 -06:00
|
|
|
} // getServiceByUUID
|
2020-03-29 17:44:20 -06:00
|
|
|
|
|
|
|
|
/**
|
2024-11-24 19:59:56 -07:00
|
|
|
* @brief Get a BLE Service by its UUID
|
2021-02-08 15:28:32 +00:00
|
|
|
* @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.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID& uuid, uint16_t instanceId) const {
|
2021-02-08 15:28:32 +00:00
|
|
|
uint16_t position = 0;
|
2024-11-24 19:59:56 -07:00
|
|
|
for (const auto& svc : m_svcVec) {
|
|
|
|
|
if (svc->getUUID() == uuid) {
|
|
|
|
|
if (position == instanceId) {
|
|
|
|
|
return svc;
|
2021-02-08 15:28:32 +00:00
|
|
|
}
|
|
|
|
|
position++;
|
2020-06-07 18:42:28 -06:00
|
|
|
}
|
|
|
|
|
}
|
2024-11-24 19:59:56 -07:00
|
|
|
|
2020-06-07 18:42:28 -06:00
|
|
|
return nullptr;
|
|
|
|
|
} // getServiceByUUID
|
2020-03-29 17:44:20 -06:00
|
|
|
|
2021-02-08 15:28:32 +00:00
|
|
|
/**
|
2024-11-24 19:59:56 -07:00
|
|
|
* @brief Get a BLE Service by its handle
|
2021-02-08 15:28:32 +00:00
|
|
|
* @param handle The handle of the service.
|
|
|
|
|
* @return A pointer to the service object or nullptr if not found.
|
|
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
NimBLEService* NimBLEServer::getServiceByHandle(uint16_t handle) const {
|
|
|
|
|
for (const auto& svc : m_svcVec) {
|
|
|
|
|
if (svc->getHandle() == handle) {
|
|
|
|
|
return svc;
|
2021-02-08 15:28:32 +00:00
|
|
|
}
|
|
|
|
|
}
|
2024-11-24 19:59:56 -07:00
|
|
|
|
2021-02-08 15:28:32 +00:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
2020-03-29 17:44:20 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
# if CONFIG_BT_NIMBLE_EXT_ADV
|
2020-03-29 17:44:20 -06:00
|
|
|
/**
|
|
|
|
|
* @brief Retrieve the advertising object that can be used to advertise the existence of the server.
|
2024-11-24 19:59:56 -07:00
|
|
|
* @return A pinter to an advertising object.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
NimBLEExtAdvertising* NimBLEServer::getAdvertising() const {
|
2020-06-07 18:42:28 -06:00
|
|
|
return NimBLEDevice::getAdvertising();
|
|
|
|
|
} // getAdvertising
|
2024-11-24 19:59:56 -07:00
|
|
|
# endif
|
2020-03-29 17:44:20 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
2022-04-10 10:21:45 -06:00
|
|
|
/**
|
|
|
|
|
* @brief Retrieve the advertising object that can be used to advertise the existence of the server.
|
2024-11-24 19:59:56 -07:00
|
|
|
* @return A pointer to an advertising object.
|
2022-04-10 10:21:45 -06:00
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
NimBLEAdvertising* NimBLEServer::getAdvertising() const {
|
2022-04-10 10:21:45 -06:00
|
|
|
return NimBLEDevice::getAdvertising();
|
|
|
|
|
} // getAdvertising
|
2024-11-24 19:59:56 -07:00
|
|
|
# endif
|
2020-03-29 17:44:20 -06:00
|
|
|
|
2021-07-30 20:56:52 -06:00
|
|
|
/**
|
|
|
|
|
* @brief Sends a service changed notification and resets the GATT server.
|
|
|
|
|
*/
|
|
|
|
|
void NimBLEServer::serviceChanged() {
|
2024-11-24 19:59:56 -07:00
|
|
|
if (m_gattsStarted) {
|
2021-07-30 20:56:52 -06:00
|
|
|
m_svcChanged = true;
|
|
|
|
|
ble_svc_gatt_changed(0x0001, 0xffff);
|
|
|
|
|
resetGATT();
|
|
|
|
|
}
|
2024-11-24 19:59:56 -07:00
|
|
|
} // serviceChanged
|
2021-07-30 20:56:52 -06:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
/**
|
2024-11-24 19:59:56 -07:00
|
|
|
* @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.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
|
|
|
|
void NimBLEServer::start() {
|
2024-11-24 19:59:56 -07:00
|
|
|
if (m_gattsStarted) {
|
|
|
|
|
return; //already started
|
2020-05-13 22:03:56 -06:00
|
|
|
}
|
|
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
int rc = ble_gatts_start();
|
|
|
|
|
if (rc != 0) {
|
2024-07-03 14:27:31 -06:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "ble_gatts_start; rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
|
|
|
return;
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 4
|
2020-03-29 17:44:20 -06:00
|
|
|
ble_gatts_show_local();
|
2024-11-24 19:59:56 -07:00
|
|
|
# endif
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2020-07-13 21:24:07 -06:00
|
|
|
// Get the assigned service handles and build a vector of characteristics
|
|
|
|
|
// with Notify / Indicate capabilities for event handling
|
2024-11-24 19:59:56 -07:00
|
|
|
for (const auto& svc : m_svcVec) {
|
|
|
|
|
if (svc->getRemoved() == 0) {
|
2024-07-12 20:42:53 -06:00
|
|
|
rc = ble_gatts_find_svc(svc->getUUID().getBase(), &svc->m_handle);
|
2024-11-24 19:59:56 -07:00
|
|
|
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");
|
2024-06-14 14:10:37 -06:00
|
|
|
continue; // Skip this service as it was not started
|
2020-07-13 21:24:07 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-25 18:41:10 -07:00
|
|
|
// Set the descriptor handles now as the stack does not set these when the service is started
|
|
|
|
|
for (const auto& chr : svc->m_vChars) {
|
2024-11-24 19:59:56 -07:00
|
|
|
for (auto& desc : chr->m_vDescriptors) {
|
|
|
|
|
ble_gatts_find_dsc(svc->getUUID().getBase(), chr->getUUID().getBase(), desc->getUUID().getBase(), &desc->m_handle);
|
2024-07-26 14:47:36 -06:00
|
|
|
}
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
|
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
|
|
|
|
m_gattsStarted = true;
|
2020-06-07 18:42:28 -06:00
|
|
|
} // start
|
2020-03-29 17:44:20 -06:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Disconnect the specified client with optional reason.
|
2024-11-24 19:59:56 -07:00
|
|
|
* @param [in] connHandle Connection handle of the client to disconnect.
|
2020-07-08 19:27:26 -06:00
|
|
|
* @param [in] reason code for disconnecting.
|
2024-11-24 19:59:56 -07:00
|
|
|
* @return True if successful.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
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;
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
return true;
|
2020-06-07 18:42:28 -06:00
|
|
|
} // disconnect
|
|
|
|
|
|
2024-06-08 12:06:57 -04:00
|
|
|
/**
|
|
|
|
|
* @brief Disconnect the specified client with optional reason.
|
|
|
|
|
* @param [in] connInfo Connection of the client to disconnect.
|
|
|
|
|
* @param [in] reason code for disconnecting.
|
|
|
|
|
* @return NimBLE host return code.
|
|
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
bool NimBLEServer::disconnect(const NimBLEConnInfo& connInfo, uint8_t reason) const {
|
2024-06-08 12:06:57 -04:00
|
|
|
return disconnect(connInfo.getConnHandle(), reason);
|
|
|
|
|
} // disconnect
|
2020-06-07 18:42:28 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
2020-06-07 18:42:28 -06:00
|
|
|
/**
|
|
|
|
|
* @brief Set the server to automatically start advertising when a client disconnects.
|
2024-11-24 19:59:56 -07:00
|
|
|
* @param [in] enable true == advertise, false == don't advertise.
|
2020-06-07 18:42:28 -06:00
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
void NimBLEServer::advertiseOnDisconnect(bool enable) {
|
|
|
|
|
m_advertiseOnDisconnect = enable;
|
2020-06-07 18:42:28 -06:00
|
|
|
} // advertiseOnDisconnect
|
2024-11-24 19:59:56 -07:00
|
|
|
# endif
|
2020-03-29 17:44:20 -06:00
|
|
|
|
2024-06-24 15:22:56 -06:00
|
|
|
/**
|
|
|
|
|
* @brief Set the server to automatically read the name from the connected peer before
|
|
|
|
|
* the onConnect callback is called and enables the override callback with name parameter.
|
|
|
|
|
* @param [in] enable Enable reading the connected peer name upon connection.
|
|
|
|
|
*/
|
|
|
|
|
void NimBLEServer::getPeerNameOnConnect(bool enable) {
|
|
|
|
|
m_getPeerNameOnConnect = enable;
|
|
|
|
|
} // getPeerNameOnConnect
|
2024-06-06 19:36:14 -06:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
/**
|
|
|
|
|
* @brief Return the number of connected clients.
|
|
|
|
|
* @return The number of connected clients.
|
|
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
uint8_t NimBLEServer::getConnectedCount() const {
|
|
|
|
|
size_t count = 0;
|
|
|
|
|
for (const auto& peer : m_connectedPeers) {
|
|
|
|
|
if (peer != BLE_HS_CONN_HANDLE_NONE) {
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-29 17:44:20 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
return count;
|
|
|
|
|
} // getConnectedCount
|
2020-03-29 17:44:20 -06:00
|
|
|
|
Add connection info class and access methods to server and client.
This adds the ability to access information about the current connection.
A new class was created to wrap the struct ble_gap_conn_desc with methods to retrieve the connection information.
Example server use:
```
for(auto i=0; i<pServer->getConnectedCount();i++) {
NimBLEConnInfo connInfo = pServer->getPeerInfo(i);
printf("Connected client %d info:\n", i);
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
Example client use:
```
if (pClient->isConnected()) {
NimBLEConnInfo connInfo = pClient->getConnInfo();
printf("Connection info:\n");
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
2021-05-07 09:02:43 -06:00
|
|
|
/**
|
2024-11-24 19:59:56 -07:00
|
|
|
* @brief Get a vector of the connected client handles.
|
|
|
|
|
* @return A vector of the connected client handles.
|
Add connection info class and access methods to server and client.
This adds the ability to access information about the current connection.
A new class was created to wrap the struct ble_gap_conn_desc with methods to retrieve the connection information.
Example server use:
```
for(auto i=0; i<pServer->getConnectedCount();i++) {
NimBLEConnInfo connInfo = pServer->getPeerInfo(i);
printf("Connected client %d info:\n", i);
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
Example client use:
```
if (pClient->isConnected()) {
NimBLEConnInfo connInfo = pClient->getConnInfo();
printf("Connection info:\n");
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
2021-05-07 09:02:43 -06:00
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
Add connection info class and access methods to server and client.
This adds the ability to access information about the current connection.
A new class was created to wrap the struct ble_gap_conn_desc with methods to retrieve the connection information.
Example server use:
```
for(auto i=0; i<pServer->getConnectedCount();i++) {
NimBLEConnInfo connInfo = pServer->getPeerInfo(i);
printf("Connected client %d info:\n", i);
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
Example client use:
```
if (pClient->isConnected()) {
NimBLEConnInfo connInfo = pClient->getConnInfo();
printf("Connection info:\n");
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
2021-05-07 09:02:43 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
return peers;
|
|
|
|
|
} // getPeerDevices
|
Add connection info class and access methods to server and client.
This adds the ability to access information about the current connection.
A new class was created to wrap the struct ble_gap_conn_desc with methods to retrieve the connection information.
Example server use:
```
for(auto i=0; i<pServer->getConnectedCount();i++) {
NimBLEConnInfo connInfo = pServer->getPeerInfo(i);
printf("Connected client %d info:\n", i);
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
Example client use:
```
if (pClient->isConnected()) {
NimBLEConnInfo connInfo = pClient->getConnInfo();
printf("Connection info:\n");
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
2021-05-07 09:02:43 -06:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Get the connection information of a connected peer by vector index.
|
|
|
|
|
* @param [in] index The vector index of the peer.
|
2024-11-24 19:59:56 -07:00
|
|
|
* @return A NimBLEConnInfo instance with the peer connection information, or an empty instance if not found.
|
Add connection info class and access methods to server and client.
This adds the ability to access information about the current connection.
A new class was created to wrap the struct ble_gap_conn_desc with methods to retrieve the connection information.
Example server use:
```
for(auto i=0; i<pServer->getConnectedCount();i++) {
NimBLEConnInfo connInfo = pServer->getPeerInfo(i);
printf("Connected client %d info:\n", i);
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
Example client use:
```
if (pClient->isConnected()) {
NimBLEConnInfo connInfo = pClient->getConnInfo();
printf("Connection info:\n");
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
2021-05-07 09:02:43 -06:00
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
NimBLEConnInfo NimBLEServer::getPeerInfo(uint8_t index) const {
|
|
|
|
|
if (index >= m_connectedPeers.size()) {
|
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Invalid index %u", index);
|
|
|
|
|
return NimBLEConnInfo{};
|
Add connection info class and access methods to server and client.
This adds the ability to access information about the current connection.
A new class was created to wrap the struct ble_gap_conn_desc with methods to retrieve the connection information.
Example server use:
```
for(auto i=0; i<pServer->getConnectedCount();i++) {
NimBLEConnInfo connInfo = pServer->getPeerInfo(i);
printf("Connected client %d info:\n", i);
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
Example client use:
```
if (pClient->isConnected()) {
NimBLEConnInfo connInfo = pClient->getConnInfo();
printf("Connection info:\n");
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
2021-05-07 09:02:43 -06:00
|
|
|
}
|
|
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
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++;
|
|
|
|
|
}
|
|
|
|
|
}
|
Add connection info class and access methods to server and client.
This adds the ability to access information about the current connection.
A new class was created to wrap the struct ble_gap_conn_desc with methods to retrieve the connection information.
Example server use:
```
for(auto i=0; i<pServer->getConnectedCount();i++) {
NimBLEConnInfo connInfo = pServer->getPeerInfo(i);
printf("Connected client %d info:\n", i);
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
Example client use:
```
if (pClient->isConnected()) {
NimBLEConnInfo connInfo = pClient->getConnInfo();
printf("Connection info:\n");
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
2021-05-07 09:02:43 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
return NimBLEConnInfo{};
|
|
|
|
|
} // getPeerInfo
|
Add connection info class and access methods to server and client.
This adds the ability to access information about the current connection.
A new class was created to wrap the struct ble_gap_conn_desc with methods to retrieve the connection information.
Example server use:
```
for(auto i=0; i<pServer->getConnectedCount();i++) {
NimBLEConnInfo connInfo = pServer->getPeerInfo(i);
printf("Connected client %d info:\n", i);
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
Example client use:
```
if (pClient->isConnected()) {
NimBLEConnInfo connInfo = pClient->getConnInfo();
printf("Connection info:\n");
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
2021-05-07 09:02:43 -06:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Get the connection information of a connected peer by address.
|
|
|
|
|
* @param [in] address The address of the peer.
|
2024-11-24 19:59:56 -07:00
|
|
|
* @return A NimBLEConnInfo instance with the peer connection information, or an empty instance if not found.
|
Add connection info class and access methods to server and client.
This adds the ability to access information about the current connection.
A new class was created to wrap the struct ble_gap_conn_desc with methods to retrieve the connection information.
Example server use:
```
for(auto i=0; i<pServer->getConnectedCount();i++) {
NimBLEConnInfo connInfo = pServer->getPeerInfo(i);
printf("Connected client %d info:\n", i);
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
Example client use:
```
if (pClient->isConnected()) {
NimBLEConnInfo connInfo = pClient->getConnInfo();
printf("Connection info:\n");
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
2021-05-07 09:02:43 -06:00
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
NimBLEConnInfo NimBLEServer::getPeerInfo(const NimBLEAddress& address) const {
|
|
|
|
|
NimBLEConnInfo peerInfo{};
|
|
|
|
|
if (ble_gap_conn_find_by_addr(address.getBase(), &peerInfo.m_desc) != 0) {
|
Add connection info class and access methods to server and client.
This adds the ability to access information about the current connection.
A new class was created to wrap the struct ble_gap_conn_desc with methods to retrieve the connection information.
Example server use:
```
for(auto i=0; i<pServer->getConnectedCount();i++) {
NimBLEConnInfo connInfo = pServer->getPeerInfo(i);
printf("Connected client %d info:\n", i);
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
Example client use:
```
if (pClient->isConnected()) {
NimBLEConnInfo connInfo = pClient->getConnInfo();
printf("Connection info:\n");
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
2021-05-07 09:02:43 -06:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "Peer info not found");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return peerInfo;
|
|
|
|
|
} // getPeerInfo
|
|
|
|
|
|
|
|
|
|
/**
|
2024-11-24 19:59:56 -07:00
|
|
|
* @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.
|
Add connection info class and access methods to server and client.
This adds the ability to access information about the current connection.
A new class was created to wrap the struct ble_gap_conn_desc with methods to retrieve the connection information.
Example server use:
```
for(auto i=0; i<pServer->getConnectedCount();i++) {
NimBLEConnInfo connInfo = pServer->getPeerInfo(i);
printf("Connected client %d info:\n", i);
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
Example client use:
```
if (pClient->isConnected()) {
NimBLEConnInfo connInfo = pClient->getConnInfo();
printf("Connection info:\n");
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
2021-05-07 09:02:43 -06:00
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
NimBLEConnInfo NimBLEServer::getPeerInfoByHandle(uint16_t connHandle) const {
|
|
|
|
|
NimBLEConnInfo peerInfo{};
|
|
|
|
|
if (ble_gap_conn_find(connHandle, &peerInfo.m_desc) != 0) {
|
Add connection info class and access methods to server and client.
This adds the ability to access information about the current connection.
A new class was created to wrap the struct ble_gap_conn_desc with methods to retrieve the connection information.
Example server use:
```
for(auto i=0; i<pServer->getConnectedCount();i++) {
NimBLEConnInfo connInfo = pServer->getPeerInfo(i);
printf("Connected client %d info:\n", i);
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
Example client use:
```
if (pClient->isConnected()) {
NimBLEConnInfo connInfo = pClient->getConnInfo();
printf("Connection info:\n");
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
2021-05-07 09:02:43 -06:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "Peer info not found");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return peerInfo;
|
|
|
|
|
} // getPeerIDInfo
|
|
|
|
|
|
2024-06-24 15:22:56 -06:00
|
|
|
/**
|
|
|
|
|
* @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
|
2024-11-24 19:59:56 -07:00
|
|
|
* it will be resumed, if not, the the RC value is checked to determine which callback
|
2024-06-24 15:22:56 -06:00
|
|
|
* should be called.
|
|
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
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;
|
2024-06-24 15:22:56 -06:00
|
|
|
|
|
|
|
|
if (rc == 0) {
|
|
|
|
|
if (attr) {
|
|
|
|
|
name->append(OS_MBUF_DATA(attr->om, char*), OS_MBUF_PKTLEN(attr->om));
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rc == BLE_HS_EDONE) {
|
2024-11-10 13:31:37 -07:00
|
|
|
if (pTaskData->m_flags != -1) {
|
2024-11-24 19:59:56 -07:00
|
|
|
NimBLEServer* pServer = (NimBLEServer*)pTaskData->m_pInstance;
|
2024-06-24 15:22:56 -06:00
|
|
|
NimBLEConnInfo peerInfo{};
|
2024-11-24 19:59:56 -07:00
|
|
|
ble_gap_conn_find(connHandle, &peerInfo.m_desc);
|
2024-06-24 15:22:56 -06:00
|
|
|
|
2024-11-10 13:31:37 -07:00
|
|
|
// check the flag to indicate which callback should be called.
|
|
|
|
|
if (pTaskData->m_flags == NIMBLE_SERVER_GET_PEER_NAME_ON_CONNECT_CB) {
|
2024-06-24 15:22:56 -06:00
|
|
|
pServer->m_pServerCallbacks->onConnect(pServer, peerInfo, *name);
|
2024-11-10 13:31:37 -07:00
|
|
|
} else if (pTaskData->m_flags == NIMBLE_SERVER_GET_PEER_NAME_ON_AUTH_CB) {
|
2024-06-24 15:22:56 -06:00
|
|
|
pServer->m_pServerCallbacks->onAuthenticationComplete(peerInfo, *name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "NimBLEServerPeerNameCB rc=%d; %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-10 13:31:37 -07:00
|
|
|
if (pTaskData->m_flags == -1) {
|
|
|
|
|
NimBLEUtils::taskRelease(*pTaskData, rc);
|
2024-06-24 15:22:56 -06:00
|
|
|
} else {
|
|
|
|
|
// If the read was triggered for callback use then these were allocated.
|
|
|
|
|
delete name;
|
|
|
|
|
delete pTaskData;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2024-11-24 19:59:56 -07:00
|
|
|
* @brief Implementation of the function that sends the read command.
|
2024-06-24 15:22:56 -06:00
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
std::string NimBLEServer::getPeerNameImpl(uint16_t connHandle, int cbType) const {
|
|
|
|
|
std::string* buf = new std::string{};
|
|
|
|
|
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(connHandle, 1, 0xffff, &uuid.u, NimBLEServer::peerNameCB, pTaskData);
|
2024-06-24 15:22:56 -06:00
|
|
|
if (rc != 0) {
|
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "ble_gattc_read_by_uuid rc=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
|
|
|
NimBLEConnInfo peerInfo{};
|
2024-11-24 19:59:56 -07:00
|
|
|
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) {
|
2024-06-24 15:22:56 -06:00
|
|
|
m_pServerCallbacks->onAuthenticationComplete(peerInfo, *buf);
|
|
|
|
|
}
|
|
|
|
|
delete buf;
|
2024-11-10 13:31:37 -07:00
|
|
|
delete pTaskData;
|
2024-11-24 19:59:56 -07:00
|
|
|
} else if (cbType == -1) {
|
2024-11-10 13:31:37 -07:00
|
|
|
NimBLEUtils::taskWait(*pTaskData, BLE_NPL_TIME_FOREVER);
|
|
|
|
|
rc = pTaskData->m_flags;
|
|
|
|
|
std::string name{*(std::string*)pTaskData->m_pBuf};
|
2024-06-24 15:22:56 -06:00
|
|
|
delete buf;
|
2024-11-10 13:31:37 -07:00
|
|
|
delete pTaskData;
|
2024-06-24 15:22:56 -06:00
|
|
|
|
|
|
|
|
if (rc != 0 && rc != BLE_HS_EDONE) {
|
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "getPeerName rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
// TaskData and name buffer will be deleted in the callback.
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Get the name of the connected peer.
|
|
|
|
|
* @param connInfo A reference to a NimBLEConnInfo instance to read the name from.
|
|
|
|
|
* @returns A string containing the name.
|
|
|
|
|
* @note This is a blocking call and should NOT be called from any callbacks!
|
|
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
std::string NimBLEServer::getPeerName(const NimBLEConnInfo& connInfo) const {
|
|
|
|
|
std::string name = getPeerNameImpl(connInfo.getConnHandle());
|
2024-06-24 15:22:56 -06:00
|
|
|
return name;
|
|
|
|
|
}
|
Add connection info class and access methods to server and client.
This adds the ability to access information about the current connection.
A new class was created to wrap the struct ble_gap_conn_desc with methods to retrieve the connection information.
Example server use:
```
for(auto i=0; i<pServer->getConnectedCount();i++) {
NimBLEConnInfo connInfo = pServer->getPeerInfo(i);
printf("Connected client %d info:\n", i);
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
Example client use:
```
if (pClient->isConnected()) {
NimBLEConnInfo connInfo = pClient->getConnInfo();
printf("Connection info:\n");
printf("Peer address: %s\n", connInfo.getAddress().toString().c_str());
printf("Peer ID address: %s\n", connInfo.getIdAddress().toString().c_str());
printf("Handle: %u\n", connInfo.getConnHandle());
printf("Interval: %u\n", connInfo.getConnInterval());
printf("Timeout: %u\n", connInfo.getConnTimeout());
printf("Latency: %u\n", connInfo.getConnLatency());
printf("MTU: %u\n", connInfo.getMTU());
printf("Master: %s\n", connInfo.isMaster()? "true":"false");
printf("Slave: %s\n", connInfo.isSlave()? "true":"false");
printf("Bonded: %s\n", connInfo.isBonded()? "true":"false");
printf("Authenticated: %s\n", connInfo.isAuthenticated()? "true":"false");
printf("Encrypted: %s\n", connInfo.isEncrypted()? "true":"false");
printf("Encryption Key Size: %u\n", connInfo.getSecKeySize());
}
```
2021-05-07 09:02:43 -06:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
/**
|
2024-11-24 19:59:56 -07:00
|
|
|
* @brief Gap event handler.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
int NimBLEServer::handleGapEvent(ble_gap_event* event, void* arg) {
|
2022-08-27 08:28:15 -06:00
|
|
|
NIMBLE_LOGD(LOG_TAG, ">> handleGapEvent: %s", NimBLEUtils::gapEventToString(event->type));
|
|
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
int rc = 0;
|
|
|
|
|
NimBLEConnInfo peerInfo{};
|
|
|
|
|
NimBLEServer* pServer = NimBLEDevice::getServer();
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
switch (event->type) {
|
2020-05-13 22:03:56 -06:00
|
|
|
case BLE_GAP_EVENT_CONNECT: {
|
2020-03-29 17:44:20 -06:00
|
|
|
if (event->connect.status != 0) {
|
|
|
|
|
/* Connection failed; resume advertising */
|
2020-06-07 18:42:28 -06:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "Connection failed");
|
2024-11-24 19:59:56 -07:00
|
|
|
# if !CONFIG_BT_NIMBLE_EXT_ADV
|
2020-03-29 17:44:20 -06:00
|
|
|
NimBLEDevice::startAdvertising();
|
2024-11-24 19:59:56 -07:00
|
|
|
# endif
|
2024-06-24 15:22:56 -06:00
|
|
|
} else {
|
2022-08-27 08:28:15 -06:00
|
|
|
rc = ble_gap_conn_find(event->connect.conn_handle, &peerInfo.m_desc);
|
2021-05-07 11:06:45 -06:00
|
|
|
if (rc != 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
for (auto& peer : pServer->m_connectedPeers) {
|
|
|
|
|
if (peer == BLE_HS_CONN_HANDLE_NONE) {
|
|
|
|
|
peer = event->connect.conn_handle;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-24 15:22:56 -06:00
|
|
|
|
|
|
|
|
if (pServer->m_getPeerNameOnConnect) {
|
2024-11-24 19:59:56 -07:00
|
|
|
pServer->getPeerNameImpl(event->connect.conn_handle, NIMBLE_SERVER_GET_PEER_NAME_ON_CONNECT_CB);
|
2024-06-24 15:22:56 -06:00
|
|
|
} else {
|
|
|
|
|
pServer->m_pServerCallbacks->onConnect(pServer, peerInfo);
|
|
|
|
|
}
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
|
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
break;
|
2020-05-13 22:03:56 -06:00
|
|
|
} // BLE_GAP_EVENT_CONNECT
|
|
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
case BLE_GAP_EVENT_DISCONNECT: {
|
2020-05-13 22:03:56 -06:00
|
|
|
// If Host reset tell the device now before returning to prevent
|
2022-07-31 11:00:12 -06:00
|
|
|
// any errors caused by calling host functions before resync.
|
2024-11-24 19:59:56 -07:00
|
|
|
switch (event->disconnect.reason) {
|
2020-03-29 17:44:20 -06:00
|
|
|
case BLE_HS_ETIMEOUT_HCI:
|
|
|
|
|
case BLE_HS_EOS:
|
|
|
|
|
case BLE_HS_ECONTROLLER:
|
|
|
|
|
case BLE_HS_ENOTSYNCED:
|
2024-07-04 10:56:30 -06:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "Disconnect - host reset, rc=%d", event->disconnect.reason);
|
2020-03-29 17:44:20 -06:00
|
|
|
NimBLEDevice::onReset(event->disconnect.reason);
|
|
|
|
|
break;
|
2020-05-13 22:03:56 -06:00
|
|
|
default:
|
2020-03-29 17:44:20 -06:00
|
|
|
break;
|
|
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
for (auto& peer : pServer->m_connectedPeers) {
|
|
|
|
|
if (peer == event->disconnect.conn.conn_handle) {
|
|
|
|
|
peer = BLE_HS_CONN_HANDLE_NONE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-07-13 21:24:07 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
if (pServer->m_svcChanged) {
|
2022-08-27 08:28:15 -06:00
|
|
|
pServer->resetGATT();
|
2020-07-13 21:24:07 -06:00
|
|
|
}
|
|
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
peerInfo.m_desc = event->disconnect.conn;
|
2022-08-27 08:28:15 -06:00
|
|
|
pServer->m_pServerCallbacks->onDisconnect(pServer, peerInfo, event->disconnect.reason);
|
2024-11-24 19:59:56 -07:00
|
|
|
# if !CONFIG_BT_NIMBLE_EXT_ADV
|
|
|
|
|
if (pServer->m_advertiseOnDisconnect) {
|
2022-08-27 08:28:15 -06:00
|
|
|
pServer->startAdvertising();
|
2020-06-07 18:42:28 -06:00
|
|
|
}
|
2024-11-24 19:59:56 -07:00
|
|
|
# endif
|
|
|
|
|
break;
|
2020-03-29 17:44:20 -06:00
|
|
|
} // BLE_GAP_EVENT_DISCONNECT
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
case BLE_GAP_EVENT_SUBSCRIBE: {
|
2024-11-24 19:59:56 -07:00
|
|
|
NIMBLE_LOGI(LOG_TAG,
|
|
|
|
|
"subscribe event; attr_handle=%d, subscribed: %s",
|
|
|
|
|
event->subscribe.attr_handle,
|
|
|
|
|
(event->subscribe.cur_notify ? "true" : "false"));
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-25 18:41:10 -07:00
|
|
|
for (const auto& svc : pServer->m_svcVec) {
|
|
|
|
|
for (const auto& chr : svc->m_vChars) {
|
|
|
|
|
if (chr->getHandle() == event->subscribe.attr_handle) {
|
|
|
|
|
rc = ble_gap_conn_find(event->subscribe.conn_handle, &peerInfo.m_desc);
|
|
|
|
|
if (rc != 0) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chr->m_pCallbacks->onSubscribe(chr,
|
|
|
|
|
peerInfo,
|
|
|
|
|
event->subscribe.cur_notify + event->subscribe.cur_indicate);
|
2020-06-21 20:26:16 -06:00
|
|
|
}
|
2020-06-07 18:42:28 -06:00
|
|
|
}
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
|
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
break;
|
2020-03-29 17:44:20 -06:00
|
|
|
} // BLE_GAP_EVENT_SUBSCRIBE
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
case BLE_GAP_EVENT_MTU: {
|
2024-11-24 19:59:56 -07:00
|
|
|
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);
|
2021-07-19 21:47:59 -06:00
|
|
|
}
|
|
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
break;
|
2020-03-29 17:44:20 -06:00
|
|
|
} // BLE_GAP_EVENT_MTU
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
case BLE_GAP_EVENT_NOTIFY_TX: {
|
2024-11-24 19:59:56 -07:00
|
|
|
NimBLECharacteristic* pChar = nullptr;
|
2021-05-17 14:08:02 -06:00
|
|
|
|
2024-11-25 18:41:10 -07:00
|
|
|
for (const auto& svc : pServer->m_svcVec) {
|
|
|
|
|
for (auto& chr : svc->m_vChars) {
|
|
|
|
|
if (chr->getHandle() == event->notify_tx.attr_handle) {
|
|
|
|
|
pChar = chr;
|
|
|
|
|
}
|
2021-05-17 14:08:02 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
if (pChar == nullptr) {
|
2021-05-17 14:08:02 -06:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
if (event->notify_tx.indication) {
|
|
|
|
|
if (event->notify_tx.status == 0) {
|
2022-08-26 20:40:21 -06:00
|
|
|
return 0; // Indication sent but not yet acknowledged.
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
|
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2022-08-26 20:40:21 -06:00
|
|
|
pChar->m_pCallbacks->onStatus(pChar, event->notify_tx.status);
|
2024-11-24 19:59:56 -07:00
|
|
|
break;
|
2020-03-29 17:44:20 -06:00
|
|
|
} // BLE_GAP_EVENT_NOTIFY_TX
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
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
|
2022-04-10 10:21:45 -06:00
|
|
|
return NimBLEAdvertising::handleGapEvent(event, arg);
|
2024-11-24 19:59:56 -07:00
|
|
|
# endif
|
|
|
|
|
} // BLE_GAP_EVENT_ADV_COMPLETE | BLE_GAP_EVENT_SCAN_REQ_RCVD
|
2020-09-13 20:36:59 -06:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
case BLE_GAP_EVENT_CONN_UPDATE: {
|
2024-11-24 19:59:56 -07:00
|
|
|
if (ble_gap_conn_find(event->connect.conn_handle, &peerInfo.m_desc) == 0) {
|
|
|
|
|
pServer->m_pServerCallbacks->onConnParamsUpdate(peerInfo);
|
2024-10-24 20:21:43 -07:00
|
|
|
}
|
2024-11-02 19:00:07 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
break;
|
2020-03-29 17:44:20 -06:00
|
|
|
} // BLE_GAP_EVENT_CONN_UPDATE
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2020-04-23 15:17:09 -06:00
|
|
|
case BLE_GAP_EVENT_REPEAT_PAIRING: {
|
|
|
|
|
/* We already have a bond with the peer, but it is attempting to
|
|
|
|
|
* establish a new secure link. This app sacrifices security for
|
|
|
|
|
* convenience: just throw away the old bond and accept the new link.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Delete the old bond. */
|
2022-08-27 08:28:15 -06:00
|
|
|
rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &peerInfo.m_desc);
|
2024-11-24 19:59:56 -07:00
|
|
|
if (rc != 0) {
|
2021-05-07 11:06:45 -06:00
|
|
|
return BLE_GAP_REPEAT_PAIRING_IGNORE;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-27 08:28:15 -06:00
|
|
|
ble_store_util_delete_peer(&peerInfo.m_desc.peer_id_addr);
|
2020-04-23 15:17:09 -06:00
|
|
|
|
|
|
|
|
/* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should
|
|
|
|
|
* continue with the pairing operation.
|
|
|
|
|
*/
|
|
|
|
|
return BLE_GAP_REPEAT_PAIRING_RETRY;
|
|
|
|
|
} // BLE_GAP_EVENT_REPEAT_PAIRING
|
2020-05-13 22:03:56 -06:00
|
|
|
|
|
|
|
|
case BLE_GAP_EVENT_ENC_CHANGE: {
|
2022-08-27 08:28:15 -06:00
|
|
|
rc = ble_gap_conn_find(event->enc_change.conn_handle, &peerInfo.m_desc);
|
2024-11-24 19:59:56 -07:00
|
|
|
if (rc != 0) {
|
2020-03-29 17:44:20 -06:00
|
|
|
return BLE_ATT_ERR_INVALID_HANDLE;
|
|
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-06-24 15:22:56 -06:00
|
|
|
if (pServer->m_getPeerNameOnConnect) {
|
2024-11-24 19:59:56 -07:00
|
|
|
pServer->getPeerNameImpl(event->enc_change.conn_handle, NIMBLE_SERVER_GET_PEER_NAME_ON_AUTH_CB);
|
2024-06-24 15:22:56 -06:00
|
|
|
} else {
|
|
|
|
|
pServer->m_pServerCallbacks->onAuthenticationComplete(peerInfo);
|
|
|
|
|
}
|
2024-11-24 19:59:56 -07:00
|
|
|
|
|
|
|
|
break;
|
2020-03-29 17:44:20 -06:00
|
|
|
} // BLE_GAP_EVENT_ENC_CHANGE
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-06-12 09:26:10 -06:00
|
|
|
case BLE_GAP_EVENT_IDENTITY_RESOLVED: {
|
|
|
|
|
rc = ble_gap_conn_find(event->identity_resolved.conn_handle, &peerInfo.m_desc);
|
2024-11-24 19:59:56 -07:00
|
|
|
if (rc != 0) {
|
2024-06-12 09:26:10 -06:00
|
|
|
return BLE_ATT_ERR_INVALID_HANDLE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pServer->m_pServerCallbacks->onIdentity(peerInfo);
|
2024-11-24 19:59:56 -07:00
|
|
|
break;
|
2024-06-12 09:26:10 -06:00
|
|
|
} // BLE_GAP_EVENT_IDENTITY_RESOLVED
|
|
|
|
|
|
2024-11-28 12:50:24 -07:00
|
|
|
# if CONFIG_BT_NIMBLE_EXT_ADV
|
|
|
|
|
case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: {
|
|
|
|
|
rc = ble_gap_conn_find(event->phy_updated.conn_handle, &peerInfo.m_desc);
|
2024-11-24 19:59:56 -07:00
|
|
|
if (rc != 0) {
|
2024-11-28 12:50:24 -07:00
|
|
|
return BLE_ATT_ERR_INVALID_HANDLE;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
pServer->m_pServerCallbacks->onPhyUpdate(peerInfo, event->phy_updated.tx_phy, event->phy_updated.rx_phy);
|
2024-11-28 12:50:24 -07:00
|
|
|
return 0;
|
2024-11-24 19:59:56 -07:00
|
|
|
} // BLE_GAP_EVENT_PHY_UPDATE_COMPLETE
|
|
|
|
|
# endif
|
2024-11-28 12:50:24 -07:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
case BLE_GAP_EVENT_PASSKEY_ACTION: {
|
2024-11-24 19:59:56 -07:00
|
|
|
struct ble_sm_io pkey = {0, 0};
|
2020-03-29 17:44:20 -06:00
|
|
|
|
|
|
|
|
if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
|
2024-11-24 19:59:56 -07:00
|
|
|
pkey.action = event->passkey.params.action;
|
2020-03-29 17:44:20 -06:00
|
|
|
// backward compatibility
|
|
|
|
|
pkey.passkey = NimBLEDevice::getSecurityPasskey(); // This is the passkey to be entered on peer
|
|
|
|
|
// if the (static)passkey is the default, check the callback for custom value
|
|
|
|
|
// both values default to the same.
|
2024-11-24 19:59:56 -07:00
|
|
|
if (pkey.passkey == 123456) {
|
2024-06-06 19:36:14 -06:00
|
|
|
pkey.passkey = pServer->m_pServerCallbacks->onPassKeyDisplay();
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
|
|
|
|
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
|
|
|
|
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_DISP; ble_sm_inject_io result: %d", rc);
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
} else if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
|
2022-01-15 12:43:17 -07:00
|
|
|
NIMBLE_LOGD(LOG_TAG, "Passkey on device's display: %" PRIu32, event->passkey.params.numcmp);
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-06-06 19:36:14 -06:00
|
|
|
rc = ble_gap_conn_find(event->passkey.conn_handle, &peerInfo.m_desc);
|
2024-11-24 19:59:56 -07:00
|
|
|
if (rc != 0) {
|
2024-06-06 19:36:14 -06:00
|
|
|
return BLE_ATT_ERR_INVALID_HANDLE;
|
|
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-09-29 15:59:42 -06:00
|
|
|
pServer->m_pServerCallbacks->onConfirmPassKey(peerInfo, event->passkey.params.numcmp);
|
2020-03-29 17:44:20 -06:00
|
|
|
} else if (event->passkey.params.action == BLE_SM_IOACT_OOB) {
|
2024-11-24 19:59:56 -07:00
|
|
|
// 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);
|
2020-03-29 17:44:20 -06:00
|
|
|
} else if (event->passkey.params.action == BLE_SM_IOACT_NONE) {
|
|
|
|
|
NIMBLE_LOGD(LOG_TAG, "No passkey action required");
|
|
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
break;
|
2020-03-29 17:44:20 -06:00
|
|
|
} // BLE_GAP_EVENT_PASSKEY_ACTION
|
|
|
|
|
|
2020-05-13 22:03:56 -06:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-03-29 17:44:20 -06:00
|
|
|
|
2020-05-13 22:03:56 -06:00
|
|
|
NIMBLE_LOGD(LOG_TAG, "<< handleGATTServerEvent");
|
2020-03-29 17:44:20 -06:00
|
|
|
return 0;
|
2020-06-07 18:42:28 -06:00
|
|
|
} // handleGapEvent
|
2020-03-29 17:44:20 -06:00
|
|
|
|
2024-07-26 14:47:36 -06:00
|
|
|
/**
|
2024-11-24 19:59:56 -07:00
|
|
|
* @brief GATT event handler.
|
2024-07-26 14:47:36 -06:00
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
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");
|
2024-11-25 18:41:10 -07:00
|
|
|
auto pAtt = static_cast<NimBLELocalValueAttribute*>(arg);
|
|
|
|
|
auto val = pAtt->getAttVal();
|
2024-07-26 14:47:36 -06:00
|
|
|
NimBLEConnInfo peerInfo{};
|
2024-11-24 19:59:56 -07:00
|
|
|
ble_gap_conn_find(connHandle, &peerInfo.m_desc);
|
2024-07-26 14:47:36 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
switch (ctxt->op) {
|
2024-07-26 14:47:36 -06:00
|
|
|
case BLE_GATT_ACCESS_OP_READ_DSC:
|
|
|
|
|
case BLE_GATT_ACCESS_OP_READ_CHR: {
|
2024-11-25 18:41:10 -07:00
|
|
|
// Don't call readEvent if this is an internal read (handle is NONE)
|
|
|
|
|
if (connHandle != BLE_HS_CONN_HANDLE_NONE) {
|
|
|
|
|
// If the packet header is only 8 bytes then 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 || pAtt->getAttVal().size() <= (ble_att_mtu(connHandle) - 3)) {
|
|
|
|
|
pAtt->readEvent(peerInfo);
|
|
|
|
|
}
|
2024-07-26 14:47:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ble_npl_hw_enter_critical();
|
|
|
|
|
int rc = os_mbuf_append(ctxt->om, val.data(), val.size());
|
|
|
|
|
ble_npl_hw_exit_critical(0);
|
|
|
|
|
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case BLE_GATT_ACCESS_OP_WRITE_DSC:
|
|
|
|
|
case BLE_GATT_ACCESS_OP_WRITE_CHR: {
|
2024-11-25 18:41:10 -07:00
|
|
|
uint16_t maxLen = val.max_size();
|
|
|
|
|
if (ctxt->om->om_len > maxLen) {
|
2024-07-26 14:47:36 -06:00
|
|
|
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-25 18:41:10 -07:00
|
|
|
uint8_t buf[maxLen];
|
2024-07-26 14:47:36 -06:00
|
|
|
uint16_t len = ctxt->om->om_len;
|
2024-11-24 19:59:56 -07:00
|
|
|
memcpy(buf, ctxt->om->om_data, len);
|
2024-07-26 14:47:36 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
os_mbuf* next;
|
2024-07-26 14:47:36 -06:00
|
|
|
next = SLIST_NEXT(ctxt->om, om_next);
|
2024-11-24 19:59:56 -07:00
|
|
|
while (next != NULL) {
|
2024-11-25 18:41:10 -07:00
|
|
|
if ((len + next->om_len) > maxLen) {
|
2024-07-26 14:47:36 -06:00
|
|
|
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
|
|
|
|
}
|
|
|
|
|
memcpy(&buf[len], next->om_data, next->om_len);
|
2024-11-24 19:59:56 -07:00
|
|
|
len += next->om_len;
|
|
|
|
|
next = SLIST_NEXT(next, om_next);
|
2024-07-26 14:47:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pAtt->writeEvent(buf, len, peerInfo);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return BLE_ATT_ERR_UNLIKELY;
|
|
|
|
|
} // handleGattEvent
|
|
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
/**
|
|
|
|
|
* @brief Set the server callbacks.
|
|
|
|
|
*
|
2024-11-25 18:41:10 -07:00
|
|
|
* 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
|
2020-03-29 17:44:20 -06:00
|
|
|
* events are detected.
|
|
|
|
|
*
|
|
|
|
|
* @param [in] pCallbacks The callbacks to be invoked.
|
2020-07-28 20:57:33 -06:00
|
|
|
* @param [in] deleteCallbacks if true callback class will be deleted when server is destructed.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2020-07-28 20:57:33 -06:00
|
|
|
void NimBLEServer::setCallbacks(NimBLEServerCallbacks* pCallbacks, bool deleteCallbacks) {
|
2024-11-24 19:59:56 -07:00
|
|
|
if (pCallbacks != nullptr) {
|
2020-05-13 22:03:56 -06:00
|
|
|
m_pServerCallbacks = pCallbacks;
|
2024-11-24 19:59:56 -07:00
|
|
|
m_deleteCallbacks = deleteCallbacks;
|
2020-05-13 22:03:56 -06:00
|
|
|
} else {
|
|
|
|
|
m_pServerCallbacks = &defaultCallbacks;
|
2024-11-24 19:59:56 -07:00
|
|
|
m_deleteCallbacks = false;
|
2020-05-13 22:03:56 -06:00
|
|
|
}
|
2020-03-29 17:44:20 -06:00
|
|
|
} // setCallbacks
|
|
|
|
|
|
2020-07-13 21:24:07 -06:00
|
|
|
/**
|
|
|
|
|
* @brief Remove a service from the server.
|
|
|
|
|
*
|
|
|
|
|
* @details Immediately removes access to the service by clients, sends a service changed indication,
|
2022-07-31 11:00:12 -06:00
|
|
|
* and removes the service (if applicable) from the advertisements.
|
2020-07-13 21:24:07 -06:00
|
|
|
* 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.
|
2024-11-24 19:59:56 -07:00
|
|
|
if (service->getRemoved() > 0) {
|
|
|
|
|
if (deleteSvc) {
|
|
|
|
|
for (auto it = m_svcVec.begin(); it != m_svcVec.end(); ++it) {
|
2021-07-30 20:56:52 -06:00
|
|
|
if ((*it) == service) {
|
2020-07-13 21:24:07 -06:00
|
|
|
delete *it;
|
|
|
|
|
m_svcVec.erase(it);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int rc = ble_gatts_svc_set_visibility(service->getHandle(), 0);
|
2024-11-24 19:59:56 -07:00
|
|
|
if (rc != 0) {
|
2020-07-13 21:24:07 -06:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-26 14:47:36 -06:00
|
|
|
service->setRemoved(deleteSvc ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE);
|
2021-07-30 20:56:52 -06:00
|
|
|
serviceChanged();
|
2024-11-24 19:59:56 -07:00
|
|
|
# if !CONFIG_BT_NIMBLE_EXT_ADV
|
2020-07-13 21:24:07 -06:00
|
|
|
NimBLEDevice::getAdvertising()->removeServiceUUID(service->getUUID());
|
2024-11-24 19:59:56 -07:00
|
|
|
# endif
|
|
|
|
|
} // removeService
|
2020-07-13 21:24:07 -06:00
|
|
|
|
|
|
|
|
/**
|
2021-05-23 13:07:00 -06:00
|
|
|
* @brief Adds a service which was either already created but removed from availability,\n
|
|
|
|
|
* or created and later added to services list.
|
2020-07-30 20:16:58 -06:00
|
|
|
* @param [in] service The service object to add.
|
2020-07-13 21:24:07 -06:00
|
|
|
* @note If it is desired to advertise the service it must be added by
|
|
|
|
|
* calling NimBLEAdvertising::addServiceUUID.
|
|
|
|
|
*/
|
|
|
|
|
void NimBLEServer::addService(NimBLEService* service) {
|
2021-05-23 13:07:00 -06:00
|
|
|
// Check that a service with the supplied UUID does not already exist.
|
2024-11-24 19:59:56 -07:00
|
|
|
if (getServiceByUUID(service->getUUID()) != nullptr) {
|
|
|
|
|
NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s", std::string(service->getUUID()).c_str());
|
2021-05-23 13:07:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If adding a service that was not removed add it and return.
|
|
|
|
|
// Else reset GATT and send service changed notification.
|
2024-11-24 19:59:56 -07:00
|
|
|
if (service->getRemoved() == 0) {
|
2021-05-23 13:07:00 -06:00
|
|
|
m_svcVec.push_back(service);
|
2020-07-13 21:24:07 -06:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-26 14:47:36 -06:00
|
|
|
service->setRemoved(0);
|
2021-07-30 20:56:52 -06:00
|
|
|
serviceChanged();
|
2020-07-13 21:24:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Resets the GATT server, used when services are added/removed after initialization.
|
|
|
|
|
*/
|
|
|
|
|
void NimBLEServer::resetGATT() {
|
2024-11-24 19:59:56 -07:00
|
|
|
if (getConnectedCount() > 0) {
|
2020-07-13 21:24:07 -06:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NimBLEDevice::stopAdvertising();
|
|
|
|
|
ble_gatts_reset();
|
|
|
|
|
ble_svc_gap_init();
|
|
|
|
|
ble_svc_gatt_init();
|
|
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
for (auto it = m_svcVec.begin(); it != m_svcVec.end();) {
|
2024-07-26 14:47:36 -06:00
|
|
|
if ((*it)->getRemoved() > 0) {
|
|
|
|
|
if ((*it)->getRemoved() == NIMBLE_ATT_REMOVE_DELETE) {
|
2020-07-13 21:24:07 -06:00
|
|
|
delete *it;
|
|
|
|
|
it = m_svcVec.erase(it);
|
|
|
|
|
} else {
|
|
|
|
|
++it;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(*it)->start();
|
|
|
|
|
++it;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
m_svcChanged = false;
|
2020-07-13 21:24:07 -06:00
|
|
|
m_gattsStarted = false;
|
2024-11-24 19:59:56 -07:00
|
|
|
} // resetGATT
|
2020-07-13 21:24:07 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
# if CONFIG_BT_NIMBLE_EXT_ADV
|
2020-03-29 17:44:20 -06:00
|
|
|
/**
|
|
|
|
|
* @brief Start advertising.
|
2024-11-24 19:59:56 -07:00
|
|
|
* @param [in] instId The extended advertisement instance ID to start.
|
2022-04-10 10:21:45 -06:00
|
|
|
* @param [in] duration How long to advertise for in milliseconds, 0 = forever (default).
|
2024-11-24 19:59:56 -07:00
|
|
|
* @param [in] maxEvents Maximum number of advertisement events to send, 0 = no limit (default).
|
2022-04-10 10:21:45 -06:00
|
|
|
* @return True if advertising started successfully.
|
|
|
|
|
* @details Start the server advertising its existence. This is a convenience function and is equivalent to
|
2020-03-29 17:44:20 -06:00
|
|
|
* retrieving the advertising object and invoking start upon it.
|
|
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
bool NimBLEServer::startAdvertising(uint8_t instId, int duration, int maxEvents) const {
|
|
|
|
|
return getAdvertising()->start(instId, duration, maxEvents);
|
2020-03-29 17:44:20 -06:00
|
|
|
} // startAdvertising
|
|
|
|
|
|
2022-04-10 10:21:45 -06:00
|
|
|
/**
|
|
|
|
|
* @brief Convenience function to stop advertising a data set.
|
2024-11-24 19:59:56 -07:00
|
|
|
* @param [in] instId The extended advertisement instance ID to stop advertising.
|
2022-04-10 10:21:45 -06:00
|
|
|
* @return True if advertising stopped successfully.
|
|
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
bool NimBLEServer::stopAdvertising(uint8_t instId) const {
|
|
|
|
|
return getAdvertising()->stop(instId);
|
2022-04-10 10:21:45 -06:00
|
|
|
} // stopAdvertising
|
2024-11-28 12:50:24 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Request an update to the PHY used for a peer connection.
|
|
|
|
|
* @param [in] connHandle the connection handle to the update the PHY for.
|
|
|
|
|
* @param [in] txPhyMask TX PHY. Can be mask of following:
|
|
|
|
|
* - BLE_GAP_LE_PHY_1M_MASK
|
|
|
|
|
* - BLE_GAP_LE_PHY_2M_MASK
|
|
|
|
|
* - BLE_GAP_LE_PHY_CODED_MASK
|
|
|
|
|
* - BLE_GAP_LE_PHY_ANY_MASK
|
|
|
|
|
* @param [in] rxPhyMask RX PHY. Can be mask of following:
|
|
|
|
|
* - BLE_GAP_LE_PHY_1M_MASK
|
|
|
|
|
* - BLE_GAP_LE_PHY_2M_MASK
|
|
|
|
|
* - BLE_GAP_LE_PHY_CODED_MASK
|
|
|
|
|
* - BLE_GAP_LE_PHY_ANY_MASK
|
|
|
|
|
* @param phyOptions Additional PHY options. Valid values are:
|
|
|
|
|
* - BLE_GAP_LE_PHY_CODED_ANY (default)
|
|
|
|
|
* - BLE_GAP_LE_PHY_CODED_S2
|
|
|
|
|
* - BLE_GAP_LE_PHY_CODED_S8
|
|
|
|
|
* @return True if successful.
|
|
|
|
|
*/
|
|
|
|
|
bool NimBLEServer::updatePhy(uint16_t connHandle, uint8_t txPhyMask, uint8_t rxPhyMask, uint16_t phyOptions) {
|
|
|
|
|
int rc = ble_gap_set_prefered_le_phy(connHandle, txPhyMask, rxPhyMask, phyOptions);
|
|
|
|
|
if (rc != 0) {
|
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Failed to update phy; rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rc == 0;
|
|
|
|
|
} // updatePhy
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Get the PHY used for a peer connection.
|
|
|
|
|
* @param [in] connHandle the connection handle to the get the PHY for.
|
|
|
|
|
* @param [out] txPhy The TX PHY.
|
|
|
|
|
* @param [out] rxPhy The RX PHY.
|
|
|
|
|
* @return True if successful.
|
|
|
|
|
*/
|
|
|
|
|
bool NimBLEServer::getPhy(uint16_t connHandle, uint8_t* txPhy, uint8_t* rxPhy) {
|
|
|
|
|
int rc = ble_gap_read_le_phy(connHandle, txPhy, rxPhy);
|
|
|
|
|
if (rc != 0) {
|
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Failed to read phy; rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rc == 0;
|
|
|
|
|
} // getPhy
|
2024-11-24 19:59:56 -07:00
|
|
|
# endif
|
2022-04-10 10:21:45 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
|
2022-04-10 10:21:45 -06:00
|
|
|
/**
|
|
|
|
|
* @brief Start advertising.
|
2022-08-26 19:32:01 -06:00
|
|
|
* @param [in] duration The duration in milliseconds to advertise for, default = forever.
|
2022-04-10 10:21:45 -06:00
|
|
|
* @return True if advertising started successfully.
|
2022-08-26 19:32:01 -06:00
|
|
|
* @details Start the server advertising its existence. This is a convenience function and is equivalent to
|
2022-04-10 10:21:45 -06:00
|
|
|
* retrieving the advertising object and invoking start upon it.
|
|
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
bool NimBLEServer::startAdvertising(uint32_t duration) const {
|
2022-08-26 19:32:01 -06:00
|
|
|
return getAdvertising()->start(duration);
|
2022-04-10 10:21:45 -06:00
|
|
|
} // startAdvertising
|
|
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
/**
|
|
|
|
|
* @brief Stop advertising.
|
2022-04-10 10:21:45 -06:00
|
|
|
* @return True if advertising stopped successfully.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
bool NimBLEServer::stopAdvertising() const {
|
2022-04-10 10:21:45 -06:00
|
|
|
return getAdvertising()->stop();
|
2021-09-12 19:09:02 -06:00
|
|
|
} // stopAdvertising
|
2024-11-24 19:59:56 -07:00
|
|
|
# endif
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
/**
|
2024-11-24 19:59:56 -07:00
|
|
|
* @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.
|
2020-06-07 18:42:28 -06:00
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
uint16_t NimBLEServer::getPeerMTU(uint16_t connHandle) const {
|
|
|
|
|
return ble_att_mtu(connHandle);
|
|
|
|
|
} // getPeerMTU
|
2020-06-07 18:42:28 -06:00
|
|
|
|
|
|
|
|
/**
|
2021-01-20 15:20:11 -07:00
|
|
|
* @brief Request an Update the connection parameters:
|
|
|
|
|
* * Can only be used after a connection has been established.
|
2024-11-24 19:59:56 -07:00
|
|
|
* @param [in] connHandle The connection handle of the peer to send the request to.
|
2021-01-20 15:20:11 -07:00
|
|
|
* @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.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
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};
|
|
|
|
|
|
|
|
|
|
int rc = ble_gap_update_params(connHandle, ¶ms);
|
|
|
|
|
if (rc != 0) {
|
2020-06-07 18:42:28 -06:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
2020-05-13 22:03:56 -06:00
|
|
|
}
|
2021-09-12 19:09:02 -06:00
|
|
|
} // 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.
|
2024-11-24 19:59:56 -07:00
|
|
|
* @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).
|
2021-09-12 19:09:02 -06:00
|
|
|
*/
|
2024-11-24 19:59:56 -07:00
|
|
|
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
|
2021-09-13 20:45:36 -06:00
|
|
|
return;
|
2024-11-24 19:59:56 -07:00
|
|
|
# else
|
|
|
|
|
uint16_t tx_time = (octets + 14) * 8;
|
2021-09-12 19:09:02 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
int rc = ble_gap_set_data_len(connHandle, octets, tx_time);
|
|
|
|
|
if (rc != 0) {
|
2021-09-12 19:09:02 -06:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "Set data length error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
|
|
|
}
|
2024-11-24 19:59:56 -07:00
|
|
|
# endif
|
2021-09-12 19:09:02 -06:00
|
|
|
} // setDataLen
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2020-06-07 18:42:28 -06:00
|
|
|
/** Default callback handlers */
|
2022-08-27 08:28:15 -06:00
|
|
|
void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) {
|
2020-05-13 22:03:56 -06:00
|
|
|
NIMBLE_LOGD("NimBLEServerCallbacks", "onConnect(): Default");
|
2020-03-29 17:44:20 -06:00
|
|
|
} // onConnect
|
|
|
|
|
|
2024-06-24 15:22:56 -06:00
|
|
|
void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, std::string& name) {
|
|
|
|
|
NIMBLE_LOGD("NimBLEServerCallbacks", "onConnect(): Default");
|
|
|
|
|
} // onConnect
|
|
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
void NimBLEServerCallbacks::onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) {
|
2020-05-13 22:03:56 -06:00
|
|
|
NIMBLE_LOGD("NimBLEServerCallbacks", "onDisconnect(): Default");
|
2020-03-29 17:44:20 -06:00
|
|
|
} // onDisconnect
|
|
|
|
|
|
2022-08-27 08:28:15 -06:00
|
|
|
void NimBLEServerCallbacks::onMTUChange(uint16_t MTU, NimBLEConnInfo& connInfo) {
|
2021-07-19 21:47:59 -06:00
|
|
|
NIMBLE_LOGD("NimBLEServerCallbacks", "onMTUChange(): Default");
|
|
|
|
|
} // onMTUChange
|
|
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
uint32_t NimBLEServerCallbacks::onPassKeyDisplay() {
|
2024-06-06 19:36:14 -06:00
|
|
|
NIMBLE_LOGD("NimBLEServerCallbacks", "onPassKeyDisplay: default: 123456");
|
2020-03-29 17:44:20 -06:00
|
|
|
return 123456;
|
2024-11-24 19:59:56 -07:00
|
|
|
} // onPassKeyDisplay
|
2020-03-29 17:44:20 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
void NimBLEServerCallbacks::onConfirmPassKey(NimBLEConnInfo& connInfo, uint32_t pin) {
|
2020-03-29 17:44:20 -06:00
|
|
|
NIMBLE_LOGD("NimBLEServerCallbacks", "onConfirmPIN: default: true");
|
2024-09-29 15:59:42 -06:00
|
|
|
NimBLEDevice::injectConfirmPasskey(connInfo, true);
|
2022-08-27 08:28:15 -06:00
|
|
|
} // onConfirmPIN
|
2020-03-29 17:44:20 -06:00
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
void NimBLEServerCallbacks::onIdentity(NimBLEConnInfo& connInfo) {
|
2024-06-12 09:26:10 -06:00
|
|
|
NIMBLE_LOGD("NimBLEServerCallbacks", "onIdentity: default");
|
|
|
|
|
} // onIdentity
|
|
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
void NimBLEServerCallbacks::onAuthenticationComplete(NimBLEConnInfo& connInfo) {
|
2024-06-06 19:36:14 -06:00
|
|
|
NIMBLE_LOGD("NimBLEServerCallbacks", "onAuthenticationComplete: default");
|
|
|
|
|
} // onAuthenticationComplete
|
|
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
void NimBLEServerCallbacks::onAuthenticationComplete(NimBLEConnInfo& connInfo, const std::string& name) {
|
2024-06-24 15:22:56 -06:00
|
|
|
NIMBLE_LOGD("NimBLEServerCallbacks", "onAuthenticationComplete: default");
|
|
|
|
|
} // onAuthenticationComplete
|
|
|
|
|
|
2024-11-24 19:59:56 -07:00
|
|
|
void NimBLEServerCallbacks::onConnParamsUpdate(NimBLEConnInfo& connInfo) {
|
2024-10-24 20:21:43 -07:00
|
|
|
NIMBLE_LOGD("NimBLEServerCallbacks", "onConnParamsUpdate: default");
|
|
|
|
|
} // onConnParamsUpdate
|
|
|
|
|
|
2024-11-28 12:50:24 -07:00
|
|
|
# if CONFIG_BT_NIMBLE_EXT_ADV
|
|
|
|
|
void NimBLEServerCallbacks::onPhyUpdate(NimBLEConnInfo& connInfo, uint8_t txPhy, uint8_t rxPhy) {
|
|
|
|
|
NIMBLE_LOGD("NimBLEServerCallbacks", "onPhyUpdate: default, txPhy: %d, rxPhy: %d", txPhy, rxPhy);
|
|
|
|
|
} // onPhyUpdate
|
|
|
|
|
# endif
|
|
|
|
|
|
2021-09-06 21:14:43 -06:00
|
|
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|