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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 0 additions & 56 deletions src/NimBLEClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -551,62 +551,6 @@ uint16_t NimBLEClient::getConnHandle() const {
return m_connHandle;
} // getConnHandle

/**
* @brief Clear the connection information for this client.
* @note This is designed to be used to reset the connection information after
* calling setConnection(), and should not be used to disconnect from a peer.
* To disconnect from a peer, use disconnect().
*/
void NimBLEClient::clearConnection() {
m_connHandle = BLE_HS_CONN_HANDLE_NONE;
m_peerAddress = NimBLEAddress{};
} // clearConnection

/**
* @brief Set the connection information for this client.
* @param [in] connInfo The connection information.
* @return True on success.
* @note Sets the connection established flag to true.
* @note If the client is already connected to a peer, this will return false.
* @note This is designed to be used when a connection is made outside of the
* NimBLEClient class, such as when a connection is made by the
* NimBLEServer class and the client is passed the connection info.
* This enables the GATT Server to read the attributes of the client connected to it.
*/
bool NimBLEClient::setConnection(const NimBLEConnInfo& connInfo) {
if (isConnected()) {
NIMBLE_LOGE(LOG_TAG, "Already connected");
return false;
}

m_peerAddress = connInfo.getAddress();
m_connHandle = connInfo.getConnHandle();
return true;
} // setConnection

/**
* @brief Set the connection information for this client.
* @param [in] connHandle The connection handle.
* @note Sets the connection established flag to true.
* @note This is designed to be used when a connection is made outside of the
* NimBLEClient class, such as when a connection is made by the
* NimBLEServer class and the client is passed the connection handle.
* This enables the GATT Server to read the attributes of the client connected to it.
* @note If the client is already connected to a peer, this will return false.
* @note This will look up the peer address using the connection handle.
*/
bool NimBLEClient::setConnection(uint16_t connHandle) {
// we weren't provided the peer address, look it up using ble_gap_conn_find
NimBLEConnInfo connInfo;
int rc = ble_gap_conn_find(connHandle, &connInfo.m_desc);
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Connection info not found");
return false;
}

return setConnection(connInfo);
} // setConnection

/**
* @brief Retrieve the address of the peer.
* @return A NimBLEAddress instance with the peer address data.
Expand Down
6 changes: 2 additions & 4 deletions src/NimBLEClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,6 @@ class NimBLEClient {
void setClientCallbacks(NimBLEClientCallbacks* pClientCallbacks, bool deleteCallbacks = true);
std::string toString() const;
uint16_t getConnHandle() const;
void clearConnection();
bool setConnection(const NimBLEConnInfo& connInfo);
bool setConnection(uint16_t connHandle);
uint16_t getMTU() const;
bool exchangeMTU();
bool secureConnection(bool async = false) const;
Expand Down Expand Up @@ -140,6 +137,7 @@ class NimBLEClient {
ble_gap_conn_params m_connParams;

friend class NimBLEDevice;
friend class NimBLEServer;
}; // class NimBLEClient

/**
Expand All @@ -155,7 +153,7 @@ class NimBLEClientCallbacks {
*/
virtual void onConnect(NimBLEClient* pClient);

/**
/**
* @brief Called when a connection attempt fails.
* @param [in] pClient A pointer to the connecting client object.
* @param [in] reason Contains the reason code for the connection failure.
Expand Down
196 changes: 68 additions & 128 deletions src/NimBLEServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
# include "NimBLEDevice.h"
# include "NimBLELog.h"

# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
# include "NimBLEClient.h"
# endif

# if defined(CONFIG_NIMBLE_CPP_IDF)
# include "services/gap/ble_svc_gap.h"
# include "services/gatt/ble_svc_gatt.h"
Expand All @@ -41,7 +45,6 @@ static NimBLEServerCallbacks defaultCallbacks;
*/
NimBLEServer::NimBLEServer()
: m_gattsStarted{false},
m_getPeerNameOnConnect{false},
m_svcChanged{false},
m_deleteCallbacks{false},
# if !CONFIG_BT_NIMBLE_EXT_ADV
Expand All @@ -63,6 +66,10 @@ NimBLEServer::~NimBLEServer() {
if (m_deleteCallbacks) {
delete m_pServerCallbacks;
}

if (m_pClient != nullptr) {
delete m_pClient;
}
}

/**
Expand Down Expand Up @@ -169,7 +176,7 @@ void NimBLEServer::serviceChanged() {
*/
void NimBLEServer::start() {
if (m_gattsStarted) {
return; //already started
return; // already started
}

int rc = ble_gatts_start();
Expand Down Expand Up @@ -249,15 +256,6 @@ void NimBLEServer::advertiseOnDisconnect(bool enable) {
} // advertiseOnDisconnect
# endif

/**
* @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

/**
* @brief Return the number of connected clients.
* @return The number of connected clients.
Expand Down Expand Up @@ -340,100 +338,6 @@ NimBLEConnInfo NimBLEServer::getPeerInfoByHandle(uint16_t connHandle) const {
return peerInfo;
} // getPeerIDInfo

/**
* @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 resumed, if not, the the RC value is checked to determine which callback
* should be called.
*/
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;

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) {
if (pTaskData->m_flags != -1) {
NimBLEServer* pServer = (NimBLEServer*)pTaskData->m_pInstance;
NimBLEConnInfo peerInfo{};
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) {
pServer->m_pServerCallbacks->onConnect(pServer, peerInfo, *name);
} else if (pTaskData->m_flags == NIMBLE_SERVER_GET_PEER_NAME_ON_AUTH_CB) {
pServer->m_pServerCallbacks->onAuthenticationComplete(peerInfo, *name);
}
}
} else {
NIMBLE_LOGE(LOG_TAG, "NimBLEServerPeerNameCB rc=%d; %s", rc, NimBLEUtils::returnCodeToString(rc));
}

if (pTaskData->m_flags == -1) {
NimBLEUtils::taskRelease(*pTaskData, rc);
} else {
// If the read was triggered for callback use then these were allocated.
delete name;
delete pTaskData;
}

return rc;
}

/**
* @brief Implementation of the function that sends the read command.
*/
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);
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(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 (cbType == -1) {
NimBLEUtils::taskWait(*pTaskData, BLE_NPL_TIME_FOREVER);
rc = pTaskData->m_flags;
std::string name{*(std::string*)pTaskData->m_pBuf};
delete buf;
delete pTaskData;

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!
*/
std::string NimBLEServer::getPeerName(const NimBLEConnInfo& connInfo) const {
std::string name = getPeerNameImpl(connInfo.getConnHandle());
return name;
}

/**
* @brief Gap event handler.
*/
Expand Down Expand Up @@ -465,11 +369,7 @@ int NimBLEServer::handleGapEvent(ble_gap_event* event, void* arg) {
}
}

if (pServer->m_getPeerNameOnConnect) {
pServer->getPeerNameImpl(event->connect.conn_handle, NIMBLE_SERVER_GET_PEER_NAME_ON_CONNECT_CB);
} else {
pServer->m_pServerCallbacks->onConnect(pServer, peerInfo);
}
pServer->m_pServerCallbacks->onConnect(pServer, peerInfo);
}

break;
Expand Down Expand Up @@ -497,6 +397,11 @@ int NimBLEServer::handleGapEvent(ble_gap_event* event, void* arg) {
}
}

if (pServer->m_pClient->m_connHandle == event->disconnect.conn.conn_handle) {
// If this was also the client make sure it's flagged as disconnected.
pServer->m_pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
}

if (pServer->m_svcChanged) {
pServer->resetGATT();
}
Expand Down Expand Up @@ -619,12 +524,7 @@ int NimBLEServer::handleGapEvent(ble_gap_event* event, void* arg) {
return BLE_ATT_ERR_INVALID_HANDLE;
}

if (pServer->m_getPeerNameOnConnect) {
pServer->getPeerNameImpl(event->enc_change.conn_handle, NIMBLE_SERVER_GET_PEER_NAME_ON_AUTH_CB);
} else {
pServer->m_pServerCallbacks->onAuthenticationComplete(peerInfo);
}

pServer->m_pServerCallbacks->onAuthenticationComplete(peerInfo);
break;
} // BLE_GAP_EVENT_ENC_CHANGE

Expand Down Expand Up @@ -705,8 +605,8 @@ int NimBLEServer::handleGattEvent(uint16_t connHandle, uint16_t attrHandle, ble_
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);
auto val = pAtt->getAttVal();
auto pAtt = static_cast<NimBLELocalValueAttribute*>(arg);
auto val = pAtt->getAttVal();
NimBLEConnInfo peerInfo{};
ble_gap_conn_find(connHandle, &peerInfo.m_desc);

Expand Down Expand Up @@ -1029,15 +929,59 @@ void NimBLEServer::setDataLen(uint16_t connHandle, uint16_t octets) const {
# endif
} // setDataLen

# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
/**
* @brief Create a client instance from the connection handle.
* @param [in] connHandle The connection handle to create a client instance from.
* @return A pointer to the NimBLEClient instance or nullptr if there was an error.
* @note Only one instance is supported subsequent calls will overwrite the previous
* client connection information and data.
*/
NimBLEClient* NimBLEServer::getClient(uint16_t connHandle) {
NimBLEConnInfo connInfo;
int rc = ble_gap_conn_find(connHandle, &connInfo.m_desc);
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Client info not found");
return nullptr;
}

return getClient(connInfo);
} // getClient

/**
* @brief Create a client instance from the NimBLEConnInfo reference.
* @param [in] connInfo The connection info to create a client instance from.
* @return A pointer to the NimBLEClient instance or nullptr if there was an error.
* @note Only one instance is supported subsequent calls will overwrite the previous
* client connection information and data.
*/
NimBLEClient* NimBLEServer::getClient(const NimBLEConnInfo& connInfo) {
if (m_pClient == nullptr) {
m_pClient = new NimBLEClient(connInfo.getAddress());
}

m_pClient->deleteServices(); // Changed peer connection delete the database.
m_pClient->m_peerAddress = connInfo.getAddress();
m_pClient->m_connHandle = connInfo.getConnHandle();
return m_pClient;
} // getClient

/**
* @brief Delete the NimBLEClient instance that was created with `getClient()`
*/
void NimBLEServer::deleteClient() {
if (m_pClient != nullptr) {
delete m_pClient;
m_pClient = nullptr;
}
} // deleteClient
# endif

/** Default callback handlers */
void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) {
NIMBLE_LOGD("NimBLEServerCallbacks", "onConnect(): Default");
} // onConnect

void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, std::string& name) {
NIMBLE_LOGD("NimBLEServerCallbacks", "onConnect(): Default");
} // onConnect

void NimBLEServerCallbacks::onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) {
NIMBLE_LOGD("NimBLEServerCallbacks", "onDisconnect(): Default");
} // onDisconnect
Expand All @@ -1052,9 +996,9 @@ uint32_t NimBLEServerCallbacks::onPassKeyDisplay() {
} // onPassKeyDisplay

void NimBLEServerCallbacks::onConfirmPassKey(NimBLEConnInfo& connInfo, uint32_t pin) {
NIMBLE_LOGD("NimBLEServerCallbacks", "onConfirmPIN: default: true");
NIMBLE_LOGD("NimBLEServerCallbacks", "onConfirmPasskey: default: true");
NimBLEDevice::injectConfirmPasskey(connInfo, true);
} // onConfirmPIN
} // onConfirmPasskey

void NimBLEServerCallbacks::onIdentity(NimBLEConnInfo& connInfo) {
NIMBLE_LOGD("NimBLEServerCallbacks", "onIdentity: default");
Expand All @@ -1064,10 +1008,6 @@ void NimBLEServerCallbacks::onAuthenticationComplete(NimBLEConnInfo& connInfo) {
NIMBLE_LOGD("NimBLEServerCallbacks", "onAuthenticationComplete: default");
} // onAuthenticationComplete

void NimBLEServerCallbacks::onAuthenticationComplete(NimBLEConnInfo& connInfo, const std::string& name) {
NIMBLE_LOGD("NimBLEServerCallbacks", "onAuthenticationComplete: default");
} // onAuthenticationComplete

void NimBLEServerCallbacks::onConnParamsUpdate(NimBLEConnInfo& connInfo) {
NIMBLE_LOGD("NimBLEServerCallbacks", "onConnParamsUpdate: default");
} // onConnParamsUpdate
Expand Down
Loading
Loading