diff --git a/src/NimBLEClient.cpp b/src/NimBLEClient.cpp index 3d7cc108..13907fda 100644 --- a/src/NimBLEClient.cpp +++ b/src/NimBLEClient.cpp @@ -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. diff --git a/src/NimBLEClient.h b/src/NimBLEClient.h index b558b338..cbb5a9b6 100644 --- a/src/NimBLEClient.h +++ b/src/NimBLEClient.h @@ -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; @@ -140,6 +137,7 @@ class NimBLEClient { ble_gap_conn_params m_connParams; friend class NimBLEDevice; + friend class NimBLEServer; }; // class NimBLEClient /** @@ -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. diff --git a/src/NimBLEServer.cpp b/src/NimBLEServer.cpp index 1e13c3f1..21c10f45 100644 --- a/src/NimBLEServer.cpp +++ b/src/NimBLEServer.cpp @@ -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" @@ -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 @@ -63,6 +66,10 @@ NimBLEServer::~NimBLEServer() { if (m_deleteCallbacks) { delete m_pServerCallbacks; } + + if (m_pClient != nullptr) { + delete m_pClient; + } } /** @@ -169,7 +176,7 @@ void NimBLEServer::serviceChanged() { */ void NimBLEServer::start() { if (m_gattsStarted) { - return; //already started + return; // already started } int rc = ble_gatts_start(); @@ -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. @@ -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(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(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. */ @@ -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; @@ -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(); } @@ -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 @@ -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(arg); - auto val = pAtt->getAttVal(); + auto pAtt = static_cast(arg); + auto val = pAtt->getAttVal(); NimBLEConnInfo peerInfo{}; ble_gap_conn_find(connHandle, &peerInfo.m_desc); @@ -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 @@ -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"); @@ -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 diff --git a/src/NimBLEServer.h b/src/NimBLEServer.h index 1bc2bf0f..035561a6 100644 --- a/src/NimBLEServer.h +++ b/src/NimBLEServer.h @@ -29,7 +29,6 @@ # undef max /**************************/ -# include # include # include @@ -48,6 +47,9 @@ class NimBLEExtAdvertising; # else class NimBLEAdvertising; # endif +# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) +class NimBLEClient; +# endif /** * @brief The model of a BLE server. @@ -72,11 +74,15 @@ class NimBLEServer { NimBLEConnInfo getPeerInfo(uint8_t index) const; NimBLEConnInfo getPeerInfo(const NimBLEAddress& address) const; NimBLEConnInfo getPeerInfoByHandle(uint16_t connHandle) const; - std::string getPeerName(const NimBLEConnInfo& connInfo) const; - void getPeerNameOnConnect(bool enable); void advertiseOnDisconnect(bool enable); void setDataLen(uint16_t connHandle, uint16_t tx_octets) const; +# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) + NimBLEClient* getClient(uint16_t connHandle); + NimBLEClient* getClient(const NimBLEConnInfo& connInfo); + void deleteClient(); +# endif + # if CONFIG_BT_NIMBLE_EXT_ADV NimBLEExtAdvertising* getAdvertising() const; bool startAdvertising(uint8_t instanceId, int duration = 0, int maxEvents = 0) const; @@ -105,7 +111,6 @@ class NimBLEServer { ~NimBLEServer(); bool m_gattsStarted : 1; - bool m_getPeerNameOnConnect : 1; bool m_svcChanged : 1; bool m_deleteCallbacks : 1; # if !CONFIG_BT_NIMBLE_EXT_ADV @@ -115,17 +120,19 @@ class NimBLEServer { std::vector m_svcVec; std::array m_connectedPeers; - static int handleGapEvent(struct ble_gap_event* event, void* arg); - static int handleGattEvent(uint16_t connHandle, uint16_t attrHandle, ble_gatt_access_ctxt* ctxt, void* arg); - static int peerNameCB(uint16_t connHandle, const ble_gatt_error* error, ble_gatt_attr* attr, void* arg); - std::string getPeerNameImpl(uint16_t connHandle, int cb_type = -1) const; - void serviceChanged(); - void resetGATT(); +# if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) + NimBLEClient* m_pClient{nullptr}; +# endif + + static int handleGapEvent(struct ble_gap_event* event, void* arg); + static int handleGattEvent(uint16_t connHandle, uint16_t attrHandle, ble_gatt_access_ctxt* ctxt, void* arg); + void serviceChanged(); + void resetGATT(); }; // NimBLEServer /** - * @brief Callbacks associated with the operation of a %BLE server. + * @brief Callbacks associated with the operation of a BLE server. */ class NimBLEServerCallbacks { public: @@ -134,26 +141,16 @@ class NimBLEServerCallbacks { /** * @brief Handle a client connection. * This is called when a client connects. - * @param [in] pServer A pointer to the %BLE server that received the client connection. + * @param [in] pServer A pointer to the BLE server that received the client connection. * @param [in] connInfo A reference to a NimBLEConnInfo instance with information. * about the peer connection parameters. */ virtual void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo); - /** - * @brief Handle a client connection. - * This is called when a client connects. - * @param [in] pServer A pointer to the %BLE server that received the client connection. - * @param [in] connInfo A reference to a NimBLEConnInfo instance with information. - * @param [in] name The name of the connected peer device. - * about the peer connection parameters. - */ - virtual void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, std::string& name); - /** * @brief Handle a client disconnection. - * This is called when a client discconnects. - * @param [in] pServer A pointer to the %BLE server that received the client disconnection. + * This is called when a client disconnects. + * @param [in] pServer A pointer to the BLE server that received the client disconnection. * @param [in] connInfo A reference to a NimBLEConnInfo instance with information * about the peer connection parameters. * @param [in] reason The reason code for the disconnection. @@ -189,14 +186,6 @@ class NimBLEServerCallbacks { */ virtual void onAuthenticationComplete(NimBLEConnInfo& connInfo); - /** - * @brief Called when the pairing procedure is complete. - * @param [in] connInfo A reference to a NimBLEConnInfo instance with information - * @param [in] name The name of the connected peer device. - * about the peer connection parameters. - */ - virtual void onAuthenticationComplete(NimBLEConnInfo& connInfo, const std::string& name); - /** * @brief Called when the peer identity address is resolved. * @param [in] connInfo A reference to a NimBLEConnInfo instance with information